How to Make Simple Physics Engine ?
BlitzMax Forums/BlitzMax Programming/How to Make Simple Physics Engine ?
| ||
How can i make a simple physics engine for my platform game? i have used Box2D before in BlitzMax but i dont want to use that. i just want a fairly simple physics engine where you can push blocks about in a platform game. they should fall off platforms and slide down slopes , and they should be able to be pushed in groups as well. i dont need them to tip over or anything like that, but i dont want them to pass through each other. it would be a bit a bit like pushing stacks of crates about this is very similar to what i want :) Pugsy on Amiga/Megadrive(Genesis) had a system where you can throw objects and stack them. heres an example of just this part http://www.youtube.com/watch?v=OvtkBeJbrYs obviously the Amiga isnt the most powerful computer in the world (CPU is 7.14mhz in Europe) so this wasnt a proper physics engine, but i would like to know how to do something like this. thank you. im not sure how to get objects to push each other about. i know how to handle the physics of an individual object, just not sure how to handle all the objects at once. do i have to check each object against every other object? and theres also the walls/floor to consider i appreciate any help :) |
| ||
I hate to ask, buy why not use box2d? I've never used it I'm sure you would be able to control the rotation of an object like you can in other physics engines. But to answer your question, just consider simple forces on the object(s) you wish to move.. if the desired movement would result in a penetration with a movable object, put the force on that too, and continue until a) you run out of energy (perhaps the player can only push 6 crates in a row), b) you don't have any penetrations or c)an object penetrates an immovable object such as a floor or wall and the force is cancelled out. Gravity is simply a downward force that must be applied to every object every update (unless you employ a system to denote which objects are inactive). For sliding; if gravity straight down causes penetration with the ground, see if applying gravity at 45° to the left or right will allow the object to free fall a little (adjust the 45° value to suit your use). For a quick (but not completely relevant example of mine) try this; http://www.blitzmonkeys.com/index.php?topic=188.0 Cheers Matt |
| ||
I highly recommend reinventing the wheel. I do it all the time. It's why I never get anything done...well that and I have a full-time job. I would do some googling for "simple 2d physics engine" and start experimenting. Last edited 2010 |
| ||
There's a number of existing physics engines available for Blitzmax already: box2d, chipmunk, farseer, and more. |
| ||
I like reinventing the wheel too. How could I ever invent my own wheel if I don't practice first by reinventing others wheels? Physics engine is always a simulation. Everything depends on how accurate simulation you want. Puggsy seems to have physics that is not in any way realistic. Having no object rotations and rotational inertia saves you from a lot of trouble. So instead of friction, islands (objects that touch each other) and complex collision response calculation, you get away with rather simple code. Gravity, collision detection, simple collision response are things I'd start with. You might need simple friction to handle slopes and possibly islands to handle objects pushing each other. Island is just an array telling these objects touch. Islands are handled as one object until they are broken apart. Putting it all together, you'll need: - Gravity - Bounding box collision detection (fast and simple) - Simple collision math (object transfers half its directional energy to another object of same wheight or 2/3 if the other is double the wheight, you get the idea...) - Resting contact (think of very tiny magnetism) - Islands (objects having resting contact between them create an island) - Friction (a static value will do) |
| ||
A very important part of a physics simulation is timing. I would highly recommend searching for "Gaffer on Games" and "Fix Your TimeStep". His physics tutorials are top-notch and well..he's a genius. Last edited 2010 |
| ||
thanks for the help. my platform game is tile based, and to use box2d i would have to describe the environment using vertices and lines. which is a lot of hard work. my man moves at a constant speed and in box2d you have to use forces to move objects which makes it very hard to get things to move like they should in games. i did start to make a platform game in box2d but its not really made for games like that, you kind of have to botch things to get the man to stay on slopes - without falling down etc. it is of course possible to make such a game but i decided to make mine in the old-school way. i didnt want anything complicated or even a realistic physics simulation- just some pushable blocks that could also be pushed in stacks. they dont need to rotate. slopes is not a problem or checking against the environment because i can use the same code i used for the main character for each block i wish to move. my main problem is, if say i push a block - i then have to check if it pushes another block, and if the block it is pushing against is against a wall then neither should move. this is the bit i most struggle with - checking all the possible collisions. for example a tall object could push more than one object if pushed into them. and an object might move that stopped another object from moving earlier, so i would have to go back and check that first object again. do i need to use a recursive algorithm? anyway thanks for all the help, i have a lot to think about from reading your responses. i think i will try and get something up and running and see where i get stuck :) |
| ||
look up a tutorial on vectors, |
| ||
thanks slenkar, i know the basic ones, like for doing gravity etc, but i will take a look i found this program i wrote quite a while ago, which actually almost does what i want. its not very tidy im afraid but it uses recursion to push blocks around. if you run it you can see it kind of does what i want. Some of the blocks seem to go thru each other ocassionally, but i can probably fix that. is this the best way of doing it? - with recursion? -------------------------------------------------------- (Z=moves player block left, X moves player block right ';' moves up and '.' moves down) block 4 is meant to be an unpushable block, and you can move the blocks to different positions by pushing them with the player block. you can also move the block by using the mouse (left click to pick up, right click to drop) SuperStrict Graphics 1024,768 '-------------- DrawRect 0,0,128,32 Global image:TImage=CreateImage(32,32) 'square block Global image2:TImage=CreateImage(4,4) 'pointer GrabImage(image,0,0,0) GrabImage(image2,0,0,0) Cls SetBlend SOLIDBLEND Type block Field id:Int,x:Float,y:Float Field cxv:Float,cyv:Float,xv:Float,yv:Float Field mov:Int,mass:Int Field mvd:Int ' set to 1 when object has moved usind initial force(added cxv and cyv) EndType Global block_list:TList= New TList Global bmass_list:TList= New TList Global moving:Int=0'set if automatically moving objects Global grav:Int=1 'set for gravity Global num_block:Int=10,pl_ob:Int=2 'player object number Global m_freq:Int=2 Global p:block Global ir:Int=0 Global m:Int Global gr:Int,drwpt:Int,lb:Int,mx:Int,my:Int Global rb:Int,ps:Int,lk:Int,rk:Int,uk:Int,dk:Int Global dbk:Int,dbg:Int Global hit:Int,xoff:Float,yoff:Float Global c:Int Local b:block Global spd:Float=1 Local xd:Int,yd:Int Local sdk:Int,am:Int 'Global xh:Int,yh:Int '------------- initialise block positions Rem For m=1 To num_block b:block=New block ReadData b.id,b.x,b.y,b.xv,b.yv If b.id=1 Then p=b 'player block set to first object b.mass=10 If m=4 Then b.mass=999 block_list.addlast b Next End Rem rand_blocks() Global sel:block=Null gr=0;drwpt=True While Not KeyDown(KEY_ESCAPE) Cls mx=MouseX();my=MouseY() lb=MouseDown(1);rb=MouseDown(2) dbk=KeyDown(KEY_D) 'debug key sdk=KeyDown(KEY_Q) 'auto diag right/up for debugging If sdk Then am=True If dbk Then dbg=True DrawText " px "+p.x+" py "+p.y,0,0 If sel=Null Then ps=0 Else ps=1 DrawText " ir "+ir+" sel "+ps,0,16 lk=KeyDown(KEY_Z);rk=KeyDown(KEY_X) uk=KeyDown(KEY_SEMICOLON);dk=KeyDown(KEY_PERIOD) '------mouse selection and player movement For b=EachIn block_list If lb And sel=Null hit=ptinrect(mx,my,b.x,b.y,b.x+31,b.y+31) If hit sel=b xoff=mx-b.x ; yoff=my-b.y EndIf EndIf If rb And sel=b b.x=b.x-xoff;b.y=b.y-yoff xoff=0;yoff=0 sel=Null EndIf If b=sel Then b.x=mx;b.y=my;drwpt=False 'If b.id=4 Then b.xv=0.1 'If b.id Mod 4=0 Then b.xv=-0.1;b.yv=-0.2 If b<>p And b.mov=True b.xv=b.cxv;b.yv=b.cyv EndIf If b=p b.xv=0;b.yv=0 If am Then b.xv=1;b.yv=-1 If lk Then b.xv=-spd If rk Then b.xv=spd If uk Then b.yv=-spd If dk Then b.yv=spd EndIf Next '--------- collision detection ir=0 'If dbg Then DebugStop() For b=EachIn block_list If b<>sel Then moveobject(b,Varptr xd,Varptr yd) Next '------draw images If drwpt Then DrawImage image2,mx,my,0 ' draw mouse pointer c=0 For b=EachIn block_list c=c+1 c=c Mod 6 Select c 'draw each block a different colour Case 0 SetColor 0,255,255 Case 1 SetColor 255,255,255 Case 2 SetColor 255,0,0 Case 3 SetColor 255,255,0 Case 4 SetColor 0,0,255 Case 5 SetColor 255,0,255 EndSelect If sel=b DrawImage image,Int(b.x-xoff),Int(b.y-yoff),0 SetColor 255,255,255 DrawText ""+b.id,Int(b.x-xoff)+5,Int(b.y-yoff)+5 Else DrawImage image,Int(b.x),Int(b.y),0 SetColor 255,255,255 DrawText ""+b.id,Int(b.x)+5,Int(b.y)+5 EndIf Next SetColor 255,255,255 Flip 1 Wend End Function moveobject:Int(bl:block,xdc:Int Ptr,ydc:Int Ptr ) 'returns 0 if object hasn't moved 'xdc is true if object has moved in xdir 're Local cond:Int=True Local b2:block=New block Local nx:Float,ny:Float,nbx:Float,nby:Float Local xh:Int,yh:Int Local cc:Int,hm:Int=0 Local ltx:Int,lty:Int Local scx:Int=0,scy:Int=0 Local xd:Int,yd:Int ir=ir+1 'If bl<>p And bl.mov=True ' bl.xv=bl.cxv;bl.yv=bl.cyv 'EndIf hm=True;cond=True 'ox=bl.x;oy=bl.y nx=bl.x+bl.xv; ny=bl.y+bl.yv 'If Int(ox)<>Int(nx) Or Int(ny)<>Int(oy) 'only check on pixel boundary 'If nx>992 Or nx<1 Then bl.xv=0;hm=False;scx=True;xdc[0]=True 'If ny>737 Or ny<1 Then bl.yv=0;hm=False;scy=True;ydc[0]=True For b2=EachIn block_list If b2<>bl And b2<>sel nx=bl.x+bl.xv; ny=bl.y+bl.yv If nx>992 Or nx<1 Then bl.xv=0;hm=False;scx=True;xdc[0]=True;cond=False If ny>600 Or ny<1 Then bl.yv=0;hm=False;scy=True;ydc[0]=True;cond=False nx=bl.x+bl.xv; ny=bl.y+bl.yv nbx=b2.x; nby=b2.y cc=rectsoverlap(nx,ny,31,31,nbx,nby,31,31) If cc xh=rectsoverlap(nx,ny-bl.yv,31,31,nbx,nby,31,31) 'false if can move x yh=rectsoverlap(nx-bl.xv,ny,31,31,nbx,nby,31,31) 'false if can move y If bl.mass>=b2.mass If dbg Then DebugStop 'b2.xv=bl.xv;b2.yv=bl.yv If xh=0 And yh=0 Then xh=True If xh If bl.xv>0 Then b2.xv=(bl.x+bl.xv+Sgn(bl.xv))-b2.x+31 If bl.xv<0 Then b2.xv=(bl.x+bl.xv+Sgn(bl.xv))-b2.x-31 EndIf If yh If bl.yv>0 Then b2.yv=(bl.y+bl.yv+1)-b2.y+31 If bl.yv<0 Then b2.yv=(bl.y+bl.yv-1)-b2.y-31 EndIf 'these work for sliding If xh And bl.yv<>0 Then b2.yv=bl.yv*0.9 If yh And bl.xv<>0 Then b2.xv=bl.xv*0.9 If ir>num_block*2 Delay 1000 WaitKey() Print "Infinite Recursion? " Print xh+" "+yh Print "bl.xv "+bl.xv+" bl.yv "+bl.yv+" b2.xv "+b2.xv+" b2.yv "+b2.yv End EndIf hm=moveobject(b2,Varptr xd,Varptr yd) If hm=False Then cond=False If hm=False If xd And xh Then bl.xv=0;xdc[0]=True 'for speed do bl.xh=not xh If yd And yh Then bl.yv=0;ydc[0]=True EndIf Else hm=False cond=False If xh Then bl.xv=0;xdc[0]=True 'for speed do bl.xh=not xh If yh Then bl.yv=0;ydc[0]=True 'bl.xv=0;bl.yv=0 'If xh Then bl.xv=0 'If yh Then bl.yv=0 'If bl.xv=0 And bl.yv=0 Then hm=False EndIf EndIf EndIf Next bl.x=bl.x+bl.xv; bl.y=bl.y+bl.yv 'If bl.xv<>0 Then xdc[0]=True 'If bl.yv<>0 Then ydc[0]=True If bl.mov And grav=0 And bl<>p 'If Not (scx Or scy) Then bl.cxv=bl.xv;bl.cyv=bl.yv If scx Then bl.cxv=-bl.cxv If scy Then bl.cyv=-bl.cyv EndIf bl.xv=0;bl.yv=0 b2=Null 'cond=hm Return cond End Function Function rectsoverlap:Int(x0:Float,y0:Float,w0:Float,h0:Float,x2:Float,y2:Float,w2:Float,h2:Float) If x0>(x2+w2)Or(x0+w0)<x2 Then Return False If y0>(y2+h2)Or(y0+h0)<y2 Then Return False Return True End Function Function ptinrect:Int(px:Int,py:Int,x0:Int,y0:Int,x2:Int,y2:Int) If px>x0 And px<x2 And py>y0 And py<y2 Then Return True Return False End Function '--------data for blocks (id,xpos,ypos,xv,yv) DefData 1,60,400,0,0 DefData 2,100,100,0,0 DefData 3,99,200,0,0 DefData 4,132,300,1,0 DefData 5,200,330,0,0 DefData 6,192,500,0,0 DefData 7,180,200,0,0 DefData 8,192,500,0,0 DefData 9,192,500,0,0 DefData 10,192,500,0,0 Function rand_blocks() Local b:block,m:Int,m2:block Local it:Int,hit:Int Local x:Int,y:Int Local rf:Float For m=1 To num_block b:block=New block b.id=m If m=pl_ob Then p=b 'player block set to first object b.mass=10 If m=4 Then b.mass=999 'If m=2 Then b.mov=True;b.cxv=-1 If grav And m<>pl_ob b.mov=True b.cyv=0.2 EndIf If moving If m Mod m_freq=0 And m<>pl_ob b.mov=True 'rf=Rand(-1,1) b.cxv=Rand(-1,1);b.cyv=Rand(-1,1) EndIf EndIf it=0 Repeat it = it+1 x=Rand(0,992);y=Rand(0,550) For m2=EachIn block_list hit= rectsoverlap(x,y,31,31,m2.x,m2.y,31,31) If hit Then Exit Next If it>800 Then Print "TOO crowded!";End Until hit=False b.x=x;b.y=y block_list.addlast b Next End Function Last edited 2010 |
| ||
you seem to have it all figured out already, looking at the demo, physics systems ive used in the past dont work well with a playercontrolled body, the player goes through the other blocks when you walk into one.But they were 3D. I had a little play with this system and i didnt notice any of that going on, oddball made a physics system that takes player controlled thingies into account nicely. Its also got editors n nice stuff If you dont enjoy making your own engine his might be an option. Last edited 2010 Last edited 2010 |
| ||
thank you yes i was pleased to find that! it doesnt quite work yet because you cant push stacks of objects as one by just pushing the bottom block. i will have to look into that. also it crashes with certain configurations of objects and goes into an infinite recursion loop. im not sure how to fix that yet. the objects werent landing flush on the floor in the code above but ive fixed that now at least anyway. (doing the easy bits first) thanks for the help but i dont really want to use a physics engine as such, since the block pushing is only a small part of the game - like sometimes you might have to push a block to a place where you can use it jump up onto a higher platform. i have already made a lot of the platform game, and it has a real time map editor - so you can edit the levels as you play - but its tile based so its not really compatible with proper physics engines. if i was to use a physics engine i would have to describe each block i add to the map in terms of vertices, which would be too complicated considering its not really a physics platformer. i just need something simple. i hope i can get this to work ok. here is a video that shows the map editor + (some secret places) in my game, this is from a while ago (its a lot better now, it has more variety and has sound effects but does still have rubbish graphics lol ). you can see its a grid/tile based game, and doesnt really use physics in the sense that a lot of platformers these days do, so thats why i dont want to use a proper physics engine http://www.youtube.com/watch?v=bgC_neRi3kc |
| ||
cool, in real life you cant push stacks around, so you may need a wooden cart to transport columns |
| ||
yes a wooden cart would be cool, i might have a go at that in the future, if i decide to have more complicated block sections. the good news is it that i got it all the block 'physics' working in my game, you can have as many blocks as you want and they stack up, and if you push the bottom one in the stack all the other ones above move. also the blocks bounce on springs and move on conveyor belts and go up and down slopes (u can push a whole stack or row of blocks up and down slopes) which is nice. i will post a video and code, when i refine and tidy it a bit more, but the basic stuff is all working now. to do the stacking i made a pass through the objects before the movement loop and if a block was moving in the horizontal direction i checked to see if a block was above it and if there was one i set the xvector on that block to the same as the one below it. i used recursion again to do this. i still have a few tweaks to make regarding the main characters interaction with the blocks though. thanks for all the help and ideas Last edited 2010 |
| ||
Just look up some basic physics stuff that you need. Find equations for the relationships between mass, acceleration, force, friction, and velocity. It's not that hard from that point to convert them to code. It only gets hard when you have to worry about irregular collision, rotation, and what not. If everything is represented by fixed rectangles, it becomes pretty simple, because forces can be calculated by converting stuff into their x and y components(cosine/sine). |