collisions with moving objects

BlitzMax Modules Forums/MiniB3D/collisions with moving objects

I am embarking on a fun-filled journey into 3D Mathematics with the hope of coming up with a wonderful demo for all to enjoy and learn from.

Using MiniB3D's built in collision system I am trying to come up with a reusable, easy to understand system of applying collision responses to moving objects.

I realize that Klepto2 is working on a Newton Dynamics Module (very excited about that!) but I think it will be useful to understand thge miniB3D/Blitz3D collision system a little better.


scenario:
I have a mesh called "Level" and a sphere called "Player"

I have collisions set
Const PLAYER_TYPE = 1
Const LEVEL_TYPE = 2
Const MOVING_TYPE = 3
Const SPHERE2MESH = 4
Const ELLIPSE2MESH = 2
Const RESPONSE_FULL_SLIDE = 2

Collisions PLAYER_TYPE,LEVEL_TYPE , ELLIPSE2MESH , RESPONSE_FULL_SLIDE	


this works very well. the player slides around the mesh (I have a small bit of gravity pulling him (-Y) direction.

I also have moving platforms that are of collision type 'LEVEL_TYPE'. These platforms simply move up and down on a timer (+y and -y)

PROBLEM: when the player is on top of the +Y moving platform, he falls through. after perusing Simonh's collision code, It confirmed that Collision detection is hard. The cool thing is that I can get the Collision Normals (CollisionNX,NY,NZ) and all of the other collision info each frame. It is just trying to figure out the best way to use it that has me stumped. Also, MiniB3D has a very nice TVector class that may come in handy.




I am working on a solution to the 2 moving 3D entities problem

possible solutions:
1. get the Velocity Vector of the Platform (old position - new position) and apply that exact amount to the Player Entity.

2. Parent the entity to the platform when it collides. then all movement will be in the 'parent space' (i.e the local coordinate system of the platform) until the player either jumps off or moves to the edge and falls off. then I would 'unparent' the player from the platform. (and maybe 'parent' the player to the 'Level' mesh?)

3. convert all movements to a 3D vector and add the player vector to the platform vector. (Velocity vector)

4. Use a line pick from the bottom of the player down. if it hits a platformadjust the position of the player to match the pick position.

now, finally my question:

what method would you use?

I could create a function that would parent/unparent based on collisions that would not occur every frame. i.e would have a bit of 'parent memory' so I would not have to call EntityParent too much.

it seems tha advantage of parenting is that if a platform is rotating, the rotation axis would be that of the parent and the player would maintain the correct position and rotation.

I do not have any (good) code to post, hopefully a demo real soon...

You could try using this code. I'll probably incorporate it into MiniB3D at some point.

It works simply by pretending that the destination entity is moving but in fact moving the source entity in the opposite direction to the destionation entity.

ha ha. some user by the name of simonh posted that 3 years ago.

I *just* got done converting this over to blitzmax when you posted. fits the bill nicely. I changed the playermesh to a cube to visualize the rotations.

very nice code by the way.


' Dynamic Collisions Example
' --------------------------
Import sidesign.MiniB3D
'Include "dcol_lib.bb" ' must be used at start of program

Graphics3D 640,480


cam=CreateCamera() 
	 PositionEntity cam,0,12,-10
	 RotateEntity cam,30,0,0
light=CreateLight()

' Create source entity
sphere=CreateCube()
	EntityColor sphere,0,0,255 
	PositionEntity sphere,0,5,0

' Give sphere a collision Type For Collisions with non-dynamic objects, i.e. the ground in this Case
EntityType sphere,1
EntityRadius sphere,1

' Create ground - this won't be moving and so will not be part of the dynamic collision system.
' It will be part of the normal collision system however so apply collision Type To it And enable Collisions with sphere.
plane=CreateCube()
	ScaleEntity plane,100,1,100
	MoveEntity plane,0,-1,0
	EntityColor plane,0,255,0
	EntityType plane,2

' Set up normal sliding Collisions between sphere And plane
Collisions 1,2,2,2

' NOW THE DYNAMIC STUFF - *** Important comments highlighted by stars ***

' Create first destination entity - platform 1
platform1=CreateCylinder(6)
 ScaleEntity platform1,2,6,2
 EntityColor platform1,255,255,0
	PositionEntity platform1,-10,-8,8

' Create second destination entity - platform 2
platform2=CreateCube()
 ScaleEntity platform2,4,4,4 
 EntityColor platform2,255,0,0
	PositionEntity platform2,10,0,8

src_type=3 ' assign a collision Type For source collision entity (sphere)
des_type=4 ' assign a collision Type For destination collision entity (platforms)

' *** Set dynamic collision pairs ***
DCO_SetPair(sphere,platform1,src_type,des_type,1.0) ' parameters - src_entity,des_entity,src_type,des_type,src_radius=1.0
DCO_SetPair(sphere,platform2,src_type,des_type,1.0)

' *** Enable Collisions For dynamic pairs ***
Collisions src_type,des_type,2,2

While Not KeyDown(1)
 
	' Control sphere
	sph_x#=0
	sph_z#=0
	If KeyDown(KEY_A)=True Then sph_x=-.4
	If KeyDown(KEY_D)=True Then sph_x=.4
	If KeyDown(KEY_S)=True Then sph_z=-.4
	If KeyDown(KEY_W)=True Then sph_z=.4

	' Apply gravity To sphere
	MoveEntity sphere,0,-.5,0

	' Make our platforms dynamic - move them!
	MoveEntity platform1,0,Sin(angle#)*0.1,0
	angle#=angle#+1
	TurnEntity platform2,0,1,0
	TranslateEntity platform2,0,0,Sin(angle#)*0.1
	TurnEntity platform1,0,1,0
	MoveEntity sphere,sph_x,sph_y,sph_z

	' *** Call DCO_Update functions, with UpdateWorld inbetween them ***
	DCO_UpdateA()
	UpdateWorld 0
	DCO_UpdateB()
	
	' *** Usual UpdateWorld call ***
	UpdateWorld
	
	' *** For best results, Try experimenting with the order of the above four Function calls ***
	
	RenderWorld
	
	' Output dynamic collision information - the dynamic collision system works best If you use these values To implement
	' proper bouncing physics between source entity And destination entity
	Text 0,0,"EntityCollided: "+DCO_EntityCollided()
	Text 0,20,"CollisionNX: "+DCO_CollisionNX#()
	Text 0,40,"CollisionNY: "+DCO_CollisionNY#()
	Text 0,60,"CollisionNZ: "+DCO_CollisionNZ#()
	
	Flip

Wend

End










' Dynamic collision lib by Simon Harrison (si@...)

' You are free To use this source code how you like, however a credit in any programs that use it would be appreciated.

' Limitations:
' Only works with spheres as source entities
' Only works If the source entity is colliding with one dynamic entity at once

' Functions:
' DCO_SetPair(src_ent,des_ent,src_type,des_type,src_rad=1.0)
' DCO_UpdateA()
' DCO_UpdateB()
' DCO_EntityCollided()
' DCO_CollisionNX()
' DCO_CollisionNY()
' DCO_CollisionNZ()

' * See included example For demonstration of system.

Global DCO_pair_pos
Global DCO_ent
Global DCO_nx#
Global DCO_ny#
Global DCO_nz#

Type DCO_pair

	Global List:TList = CreateList()
	Field src_ent:Tentity
	Field src_col:Tentity
	Field src_type:Int
	Field src_rad:Float
	Field des_ent:Tentity
	Field des_col:Tentity
	Field des_type:Int
	
End Type

Function DCO_SetPair(src_ent:Tentity ,des_ent:Tentity ,src_type:Int ,des_type:Int ,src_rad=1.0)

	
	Local c:DCO_pair=New DCO_pair
	ListAddLast DCO_pair.List , c	' add the new object to the list
	
	c.src_ent=src_ent
	c.src_type=src_type
	c.src_rad=src_rad
	
	c.des_ent=des_ent
	c.des_type=des_type
	
	c.src_col=CreatePivot() 
	EntityRadius c.src_col,src_rad
	c.des_col=CopyEntity(des_ent)  ' was CopyEntity(des_ent)
	EntityAlpha c.des_col,0
	
	DCO_pair_pos=DCO_pair_pos+(MeshWidth(Tmesh(c.des_col))*2)
	DCO_pair_pos=DCO_pair_pos+1000
	PositionEntity c.des_col,DCO_pair_pos,DCO_pair_pos,0
	
	EntityType c.src_col,src_type
	EntityType c.des_col,des_type
	
	ResetEntity c.src_col
	ResetEntity c.des_col
	
End Function

Function DCO_UpdateA()

	Local dx#,dy#,dz#,pivo,pivv

	For c:DCO_pair = EachIn DCO_Pair.List

		dx#=EntityX#(c.src_ent)-EntityX#(c.des_ent)
		dy#=EntityY#(c.src_ent)-EntityY#(c.des_ent)
		dz#=EntityZ#(c.src_ent)-EntityZ#(c.des_ent)

		pivo=CreatePivot()
		pivv=CreatePivot(pivo)
		
		PositionEntity pivo,EntityX#(c.des_col),EntityY#(c.des_col),EntityZ#(c.des_col)
		
		RotateEntity pivo,0,0,0
		
		PositionEntity pivv,dx#,dy#,dz#,False

		RotateEntity pivo,-EntityPitch#(c.des_ent),-EntityYaw#(c.des_ent),-EntityRoll#(c.des_ent)

		PositionEntity c.src_col,EntityX#(pivv,True),EntityY#(pivv,True),EntityZ#(pivv,True)
		
		FreeEntity pivo
		
	Next

End Function

Function DCO_UpdateB()

	Local col:Tentity
	
	Local dx#,dy#,dz#,dx2#,dy2#,dz2#,ddx#=0,ddy#=0,ddz#=0
	Local pivo:Tpivot
	Local pivv:Tpivot
	Local pivn:Tpivot
	
	DCO_ent=0
	For c:DCO_pair=EachIn DCO_Pair.List
				
		 col = EntityCollided(c.src_col,c.des_type)
		
		If col = c.des_col
	
			DCO_ent=c.des_ent
	
			dx#=EntityX#(c.src_ent)-EntityX#(c.des_ent)
			dy#=EntityY#(c.src_ent)-EntityY#(c.des_ent)
			dz#=EntityZ#(c.src_ent)-EntityZ#(c.des_ent)
		
			dx2#=EntityX#(c.src_col)-EntityX#(c.des_col)
			dy2#=EntityY#(c.src_col)-EntityY#(c.des_col)
			dz2#=EntityZ#(c.src_col)-EntityZ#(c.des_col)
	
			pivo=CreatePivot()
			pivv=CreatePivot(pivo)
			pivn=CreatePivot(pivo) ' piv used To translate collsion normals
			
			PositionEntity pivo,0,0,0
	
			RotateEntity pivo,-EntityPitch#(c.des_ent),-EntityYaw#(c.des_ent),-EntityRoll#(c.des_ent)
			
			PositionEntity pivv,dx2#,dy2#,dz2#,True
			PositionEntity pivn,CollisionNX#(c.src_col,1),CollisionNY#(c.src_col,1),CollisionNZ#(c.src_col,1),True
			
			RotateEntity pivo,0,0,0
			
			' platform normals
			DCO_nx#=EntityX#(pivn)
			DCO_ny#=EntityY#(pivn)
			DCO_nz#=EntityZ#(pivn)
			
			dx2#=EntityX#(pivv)
			dy2#=EntityY#(pivv)
			dz2#=EntityZ#(pivv)
	
			ddx#=dx2#-dx#
			ddy#=dy2#-dy#
			ddz#=dz2#-dz#
							
			FreeEntity pivo
		
			TranslateEntity c.src_ent,ddx#,ddy#,ddz#
		
			'Exit
		
		EndIf
				
	Next

End Function

Function DCO_EntityCollided()

	Return DCO_ent

End Function

Function DCO_CollisionNX#()

	Return DCO_nx#

End Function

Function DCO_CollisionNY#()

	Return DCO_ny#

End Function

Function DCO_CollisionNZ#()

	Return DCO_nz#