A collision system

BlitzMax Forums/MiniB3D Module/A collision system

Ninjacrat(Posted 2007) [#1]
I can't make any sense of the collision system. It seems entirely horrible. I could say something nice like 'I'm sure it made more sense back in Blitz3D', but I _owned_ B3D and I could never make sense of it back then either. :)

So I made a simpler one. There are only four commands:

collide (Checks for collision between two entities using sphere-to-mesh check)
collide_sphere (Checks for collision between two entities using sphere-to-sphere check)
latestcollision (gets data object from an entity's most recent collision)
resetentities (must be called before moving anything every frame)

It uses as much of the default behaviour as possible to avoid weird side effects, so it's not as efficient as it could be. But it should still be faster than the default (fingers crossed).

Strict
Import sidesign.minib3d
'Rem
Graphics3D 640, 480

Local cube:TMesh=CreateCube()
cube.PositionEntity -5,0,0
cube.EntityRadius 1
	
Local sphere:TMesh=CreateSphere()
sphere.PositionEntity 0,0,0
sphere.EntityRadius 1

Local sphere2:TMesh=CreateSphere()
sphere2.PositionEntity 0,1,0
sphere2.EntityRadius 1

Local cam:TCamera=CreateCamera()
cam.PositionEntity 0,0,-5

'hardwareinfo.displayinfo

While Not AppTerminate() And Not KeyHit(KEY_ESCAPE)

	ResetEntities

	If KeyDown(KEY_LEFT) cube.MoveEntity -0.1,0,0
	If KeyDown(KEY_RIGHT) cube.MoveEntity 0.1,0,0
	If KeyDown(KEY_UP) cube.MoveEntity 0,0.1,0
	If KeyDown(KEY_DOWN) cube.MoveEntity 0,-0.1,0

	If collide (cube, sphere)
		Print "THUMP!"
		Print "You hit the lower sphere at: " + latestcollision (cube).x + ", "..
		+ latestcollision (cube).y + ", " + latestcollision (cube).z
	End If
	If collide (cube, sphere2) Print "BUMP!"

	RenderWorld

	Flip

Wend
'EndRem

Function collide (ent:TEntity, ent2:TMesh)
	Local old = ent.no_collisions

	If TCollision.QuickCheck(ent,ent2)
		ent2.TreeCheck()
	
		TCollision.SphereToMesh(ent,ent2)
	EndIf
	
	If old < ent.no_collisions Return 1
End Function

Function collide_sphere (ent:TEntity, ent2:TEntity)
	If TCollision.SphereToSphere(ent,ent2)
		ent.no_collisions=ent.no_collisions+1			
		Local i=ent.no_collisions-1		
		ent.collision=ent.collision[..i+1]		
		ent.collision[i]=New TCollisionImpact
		ent.collision[i].ent=ent2

		Return 1
	EndIf
End Function

Function latestcollision:TCollisionImpact (ent:TEntity)
	If ent.no_collisions = 0 Return Null

	Return ent.collision[ent.no_collisions-1]
End Function

Function resetentities(list:TList=Null)
	If Not list	list = TEntity.entity_list

	For Local loop:TEntity = EachIn list
		loop.ResetEntity
	Next
EndFunction

If you give it a go, or especially if you give a go and find a bug, please let me know!


Dreamora(Posted 2007) [#2]
Seriously bad idea what you are doing there with the slicing.
Use a list and just return TCollisionImpact(list.last()) instead, will be worlds faster


Ninjacrat(Posted 2007) [#3]
The only slicing in there was copy-pasted verbatim from the source code. :)

Thanks for the advice, though.


Dreamora(Posted 2007) [#4]
didn't know that but in that case its a problem there as well as slicing with 1 is the worst thing to do if you know it will grow later. ( I know that it can't be removed there as it is accessed by index as well ... )


simonh(Posted 2007) [#5]
I don't believe it impacts on performance - only a small number of slices are usually performed, and on small arrays.


Dreamora(Posted 2007) [#6]
if small <= 8 then yes.