Jump to content

Josh

Staff
  • Posts

    23,269
  • Joined

  • Last visited

Everything posted by Josh

  1. There's an update available now. This compiles the Framework commands into the main engine so that Lua can access the entire framework command set. C++ programs will now more closely resemble the results you see in the editor, because water, sky, and other settings can be controlled with Lua and any programming language.
  2. This example shows how to use BlitzMax, Framework, and Lua together seamlessly! Framework is a little different from the main engine. Although it is compiled into the DLL, it is not compiled into the engine module. This allows the programmer to make their own customizations to the code. However, it also means we have to generate a code file of glue functions for Lua to be able to access the Framework commands. The attached example shows how to do this. You can also use this method to expose your own BlitzMax types to Lua! Any time your command set changes, you need to regenerate the Lua glue code. This is done by commenting out the line that includes the glue code, and uncommenting the code that generates it: 'Include "lua-gluefunctions.bmx" generateGlueCode("lua-gluefunctions.bmx") End Then switch the comments back to run the program: Include "lua-gluefunctions.bmx" 'generateGlueCode("lua-gluefunctions.bmx") 'End This allows your Lua scripts to access the entire framework command set, as well as your own types. You also need to set the value of the global Lua variable "fw". This is done with the included SetScriptObject() function, which just uses Lua commands to set a variable. The Framework code is distributed as code files instead of a module, mostly because BlitzMax does not allow compiling a module with the name "Framework". fwtest.zip
  3. You might want to start with a simple hard-coded app to see if this idea actually works, before you start adding a UI. I have no idea if the results will be useful or not.
  4. Yeah, I think this is a good idea. Maybe an SBX can be saved as a model + automatically generated script. Until then, I recommend creating pivots in the mesh, and then using FindChild() to see where the lights should be positioned.
  5. Ha, that is brilliant! You could start with a photo and have a program that enters all the unique values into an image to make the palette. Here's my attempt. I just resized the image (using pixel resize, so there is no blending of colors). I scaled it back up so it was easier to see.
  6. Use the Quake palette to test with.
  7. Solutions like that result in loss of resolution, which is why things start looking washed out instead of warm. We want consistency of similar hues, not a loss of resolution. Notice the colors are different, but look somehow consistent: Here's a good example of "random colors syndrome": Here is the same image multiplied by an orange tint. This looks like a lot of the screenshots I have seen. Even though the tint sort of forces it to look consistent, there is a loss of resolution and the odd colors still look odd: Relying too much on colored lighting only washes out detail and makes everything look muddy.
  8. One problem I notice a lot is inconsistency in coloration of scenes. The recent contrast/saturation/brightness controls I added help a bit, but I think the original texture data has to be consistent. If you look at most AAA games, their textures somehow have a uniform appearance, and they just look like they belong together. Unfortunately, we seem to have a lot of problems doing this. Here is the palette from the game "Quake": And an example of consistent textures, even if it is a little extreme: Here's an idea I had that might help with this problem: First, you define a palette of colors. Maybe this can be a 32x32 image with different browns, greens, blues, etc. for each pixel. It doesn't matter what order they are in. You just define some colors that look good together. This programs loads this image and reads the pixels into different possible values. They can be converted to HSL and stored. Then the program starts loading a directory of textures, recursively. For each image found, it does the following: For each pixel of an image, it converts the pixel to HSL. Then it compares the pixel hue and saturation to the values of the palette, and finds the closest match. Then it saves a new copy of the image, using the replaced hue and saturation values, and retaining the original brightness value. You could use this to make all your greens look similar. It might automatically create a consistent color theme, something that we developers seem to have a very hard time with. If you don't like the results, edit your palette image and re-run the application. I don't have time to write something like this, but I thought I would put the idea out there.
  9. This is a known problem. I have to redo some of the vegetation rendering stuff soon, so it will be resolved at that time. Nice scene, BTW!
  10. The trees appear to have no specular reflection. Your ambient light level is very bright and isn't tinted blue. I'd also enable edge antialiasing.
  11. Half-Life 2 is the only Havok game I know I have played, and when you push objects in the game, the movement is extremely jittery. Maybe it has gotten better in recent years. There's been a pretty good case made by people wanting to use other physics libraries. I don't think I can support other libraries officially, because it is very hard to get all the functionality we have working with every physics lib, but I don't see a problem with other people implementing their own. I'll begin to design things with this in mind, and figure out exactly what it would entail to completely disable Newton.
  12. Fortunately if I change this, any code that worked with byte ptrs should work with vec3 objects as well.
  13. That's a pretty good idea.
  14. I would create a new object with settings that control your game settings, in the same way the environment\atmosphere object controls global settings.
  15. Josh

    TextHeight

    Yeah, TextHeight() is unnecessary since you would never care about the height of a particular string. You care about the height of the tallest letter possible.
  16. I am not sure why I chose to use byte ptrs in BlitzMax. A Vec3 makes more sense to me, don't you think?
  17. The controller/terrain bug was fixed. That's really neat. Who would have thought a few years ago that programmers would be able to slap a few assets into a program and get something that looks this good?
  18. No, because I wrote the controller implementation. Maybe I can cap the max force that can be applied.
  19. I would use particles with a refractive material.
  20. If you are doing a lot of AI or other processing code, a compiled language will be needed. If you are doing something simpler, Lua will be fine. You can also use a combination of a compiled language together with Lua.
  21. Josh

    Future Ideas

    How can mysql perform a fast query for an object within a range of an X/Z position? Y position can be ignored, since most games don't have much of a vertical component. I have tried for a long time to think of a way to sort objects in two dimensions, but it doesn't seem possible without putting them into some kind of grid structure.
  22. Josh

    Future Ideas

    That's probably accurate. It's probably impossible to make a networked system with the problems I described.
  23. Josh

    Vec3 setting

    And it's better to use require() than dofile()!
  24. For the crawler model, I ended up using the Reset() function to get around the problem of repositioning the controller. This is written for multistate Lua, so it needs some small changes to work: dofile("scripts/base.lua") dofile("scripts/math.lua") dofile("scripts/linkedlist.lua") AINodeScanRange=100 AnimationWalk=0 AnimationIdle=1 animspeed={} animspeed[AnimationWalk]=0.036 animspeed[AnimationIdle]=0.01 dummynode=LoadModel("abstract::info_ai_node.gmf") if dummynode~=nil then dummynode:Hide() end function Cleanup() if dummynode~=nil then dummynode:Free() dummynode=nil end end function Reset(model) local entity=entitytable[model] if entity==nil then return end entity.controller:SetPosition(Vec3(model.position.x,model.position.y+0.9,model.position.z)) entity.angle=model.rotation.y+180.0 model:SetTarget(nil,0) end function UnlockKeys(model) model:SetTarget(nil) end function SetKey(model,key,value) local entity=entitytable[model] if entity==nil then return 1 end if key=="enabled" then if entity.controller~=nil then if value=="0" then entity.controller:SetMass(0) else entity.controller:SetMass(10) end end end return base_SetKey(model,key,value) end function Spawn(model) local entity=base_Spawn(model) entity.angle=model.rotation.y entity.controller=CreateController(1.8,0.45,0.25,45) entity.controller:SetPosition(entity.model.position) entity.controller:SetRotation(entity.model.rotation) entity.controller:Move(Vec3(0,0.9,0)) entity.controller:SetCollisionType(1,0) entity.controller:SetMass(10) entity.currentanimation=0 if entity.model:CountAnimations()<2 then --LoadAnimation(entity.model,"abstract::actor_cartoon2.gmf") end function entity:ChooseNewNode(ainode) local nodes={} local i local count=0 local newtarget --Create a table of all AI nodes this node is connected to for i=0,15 do nodes[count]=ainode:GetTarget(i) if nodes[count]~=nil then if nodes[count]~=self.prevnode then --avoid doubling back count=count+1 end end end --Choose a random node if count>0 then newtarget=nodes[math.random(0,count-1)] self.model:SetTarget(newtarget,0) else --no node found, so let's just use the previous node --self.model:SetTarget(self.prevnode,0) self.model:SetTarget(nil,0) end --if ainode~=nil then self.prevnode=ainode --end end function entity:Update() local dx,dz,p local target local ainode local closestainode=nil local closestdistance=10000000.0 local perfectangle local noderadius local movement=0 target=self.model:GetTarget(0) --b=CurrentWorld().entities --If target is nil, we need to choose an AI node to move to if target==nil then if dummynode~=nil then for ainode in iterate(dummynode.reference.instances) do if ainode~=self.prevnode then if ainode:Hidden()==0 then d=EntityDistance(ainode,self.model) if d<AINodeScanRange then --dismiss nodes that are far away if PointVisible(self.model.aabb:Center(),ainode.mat:Translation(),0,COLLISION_AILINEOFSIGHT)==1 then --line-of-sight test if d<closestdistance then closestdistance=d closestainode=ainode end end end end end end --Found a valid AI node, so set the target if closestainode~=nil then self.model:SetTarget(closestainode,0) end end end --We have a target node to move to if target~=nil then --Figure out angle between actor and target dx=target.mat.tx-self.model.mat.tx dz=target.mat.tz-self.model.mat.tz perfectangle=math.deg(math.atan2(-dx,dz)) --Calculate angle between the actor and the target and adjust as necessary. --This provides a smoother more natural movement, and the character takes --the easiest path instead of pointing straight at the target node. local noderadius=tonumber(target:GetKey("radius","4.0")) local noderange=tonumber(target:GetKey("range","1.0")) --Get the distance between the projected entity vector and the node model:SetRotation(Vec3(0,self.angle,0),1) local d=LineCircleDistance(model.mat.tx,model.mat.tz,model.mat.tx+model.mat.kx*100.0,model.mat.tz+model.mat.kz*100.0,target.mat.tx,target.mat.tz,3.0,1,0) --If the distance is over the radius, increment the angle towards the node local turnradius = 1.0 turnradius = turnradius+clamp( 90.0*(1.0 - clamp( d/1.0,0 ,1) ),0,10 ) if math.abs(d)>noderadius then self.angle=IncAngle(perfectangle,self.angle,turnradius*AppSpeed()) end --Choose new node when target node is close enough --We only care about the 2D distance on the XZ plane if math.sqrt(dx*dx+dz*dz)<noderange then self:ChooseNewNode(target) end movement=2 self.currentanimation=0 else movement=0 self.currentanimation=1 end --Update the controller self.controller:Update(self.angle,movement,0,0,40,1) self.model:SetPosition(self.controller.position) self.model:SetRotation(self.controller.rotation) self.model:Move(Vec3(0,-0.9,0)) self.model:Turn(Vec3(0,180,0)) local frame=AppTime()*0.08 frame=math.mod(frame,130-70)+70 if EntityCulled(model,fw.Main.camera)==0 then self.model:Animate(frame,1,0,1) end end return entity end function Update(model) local entity for model,entity in pairs(entitytable) do if entity.model:Hidden()==0 then if entity.enabled~=0 then entity:Update() end end end end function Kill(model) local entity=entitytable[model] if entity~=nil then if entity.controller~=nil then entity.controller:Free() entity.controller=nil end end base_Kill(model) end
×
×
  • Create New...