How to Make Simple Physics Engine ?

BlitzMax Forums/BlitzMax Programming/How to Make Simple Physics Engine ?

Rico(Posted 2010) [#1]
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 :)


matibee(Posted 2010) [#2]
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


Chroma(Posted 2010) [#3]
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


xlsior(Posted 2010) [#4]
There's a number of existing physics engines available for Blitzmax already: box2d, chipmunk, farseer, and more.


Jasu(Posted 2010) [#5]
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)


Chroma(Posted 2010) [#6]
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


Rico(Posted 2010) [#7]
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 :)


slenkar(Posted 2010) [#8]
look up a tutorial on vectors,


Rico(Posted 2010) [#9]
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


slenkar(Posted 2010) [#10]
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


Rico(Posted 2010) [#11]
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


slenkar(Posted 2010) [#12]
cool, in real life you cant push stacks around, so you may need a wooden cart to transport columns


Rico(Posted 2010) [#13]
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


Yahfree(Posted 2010) [#14]
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).