Collision Problem

BlitzMax Modules Forums/MiniB3D/Collision Problem

Take a look at this vid. It shows the ball colliding with the hoarding and it gets stuck...

http://download.newstargames.com/misc/NSS4/CollisionProb1.avi

This example show the ball colliding with the rear of the hoarding and it rebounds in the wrong direction...

http://download.newstargames.com/misc/NSS4/CollisionProb3.avi

However, as you can see, if the ball bounces off the stadium wall it responds fine. This is also the case if I align the advert hoardings perfectly horizontal or verticle which makes me think it is a bug in minib3d.

This is the code i'm using...
Collisions(CTYPE_BALL, CTYPE_GOALNET, 2, 1)
		Collisions(CTYPE_BALL, CTYPE_GOALPOST, 2, 1)
		Collisions(CTYPE_BALL, CTYPE_WALL, 2, 1)
		Collisions(CTYPE_BALL, CTYPE_STADIUM, 2, 1) ' Hoardings use this.


For Local i:Int = 1 To CountCollisions(mesh)
				Local ent:TEntity = CollisionEntity(mesh, i)

				Local Nx# = CollisionNX(mesh, 1) 
				Local Ny# = CollisionNY(mesh, 1) 
				Local Nz# = CollisionNZ(mesh, 1) 
			
				Local VdotN# = vecVelocity.x*Nx# + vecVelocity.y*Ny# + vecVelocity.z*Nz#
									
				Local NFx# = -2.0 * Nx# * VdotN# 
				Local NFy# = -2.0 * Ny# * VdotN# 
				Local NFz# = -2.0 * Nz# * VdotN# 
										
				Local bounce:Float = 0.8
				vecVelocity.x = (vecVelocity.x + NFx#) * bounce
				vecVelocity.y = (vecVelocity.y + NFy#) * bounce
				vecVelocity.z = (vecVelocity.z + NFz#) * bounce
			Next


Any idea?

Hard to tell when your links are dead!

Hmmm...

Try changing the response mode to 2 (slide).

Also try changing the loop as follows:

For Local i:Int = 1 To CountCollisions(mesh)

	Local ent:TEntity = CollisionEntity(mesh, i)

	Local Nx# :+ CollisionNX(mesh, 1) 
	Local Ny# :+ CollisionNY(mesh, 1) 
	Local Nz# :+ CollisionNZ(mesh, 1) 

Next

Local VdotN# = vecVelocity.x*Nx# + vecVelocity.y*Ny# + vecVelocity.z*Nz#
							
Local NFx# = -2.0 * Nx# * VdotN# 
Local NFy# = -2.0 * Ny# * VdotN# 
Local NFz# = -2.0 * Nz# * VdotN# 
							
Local bounce:Float = 0.8
vecVelocity.x = (vecVelocity.x + NFx#) * bounce
vecVelocity.y = (vecVelocity.y + NFy#) * bounce
vecVelocity.z = (vecVelocity.z + NFz#) * bounce
Not sure if either change will do anything but worth a try.

Tried your code (after a little tweak, doesn't like Local Nx# :+) but no difference.

Forgot to mention I'd tried response mode 2. I get different results but still not right...

http://download.newstargames.com/misc/NSS4/CollisionProb4.avi
http://download.newstargames.com/misc/NSS4/CollisionProb5.avi

Si, I'm sure it's something to do with rotated meshes. Generally the collisions between the ball and stadium respond perfectly (even hitting the sloping stands and seating). If I do RotateEntity(stadium, 0, 20, 0) suddenly everything goes awry.

Ah yes, the returned collision normals are wonky.

To fix, comment out lines 187-195 in TCollision.bmx - these lines:

TEntity.TFormPoint ent.collision[i].x#,ent.collision[i].y#,ent.collision[i].z#,ent2_hit,Null
ent.collision[i].x#=TEntity.tformed_x
ent.collision[i].y#=TEntity.tformed_y
ent.collision[i].z#=TEntity.tformed_z

TEntity.TFormNormal ent.collision[i].nx#,ent.collision[i].ny#,ent.collision[i].nz#,ent2_hit,Null
ent.collision[i].nx#=TEntity.tformed_x
ent.collision[i].ny#=TEntity.tformed_y
ent.collision[i].nz#=TEntity.tformed_z


Hi Si. That doesn't fix it I'm afraid. Take a look at this. Depending on the direction that the ball is moving, I get different results from the same collision entity.

http://download.newstargames.com/misc/NSS4/CollisionProb6.avi

Are you resetting nx/ny/nz before the loop ?

Hmmm, not sure why your code might be failing. I've written a small program here that demonstrates some ball bouncing code that works OK - just run it from the minib3d examples folder:

Import "../minib3d.bmx"

Strict

Local width=640,height=480,depth=16,mode=0,hertz=60

Graphics3D width,height,depth,mode,hertz

' bullet type
Type TBullet

	Global list:TList=CreateList()
	Global no ' no of bullets
	Field ent:TMesh
	Field x#,y#,z#
	Field vx#,vy#,vz#
	Field life ' life counter
	
	' create bullet
	Function Shoot(x#,y#,z#,nx#,ny#,nz#)
	
		Local bull:TBullet=New TBullet
		no=no+1
		bull.ent=CreateSphere()
		EntityColor bull.ent,64+Rand(191),64+Rand(191),64+Rand(191)
		bull.x#=x#
		bull.y#=y#
		bull.z#=z#
		bull.vx#=nx#
		bull.vy#=ny#
		bull.vz#=nz#
		PositionEntity bull.ent,x#,y#,z#,True
		EntityType bull.ent,1
		EntityRadius bull.ent,1
		ResetEntity bull.ent
		ListAddLast(list,bull)

	End Function
	
	' update bullet
	Method Update()
	 
		' life counter is over 600, so bullet hasn't collided with anything for a long time - free it
		If life>600
			ListRemove list,Self
			FreeEntity ent
			no=no-1
			Return
		EndIf
		
		life=life+1 ' increase bullet life counter
	
		x#=EntityX(ent)
		y#=EntityY(ent)
		z#=EntityZ(ent)
	
		' check to see if the entity collided with the level
		Local entity_hit = CountCollisions(ent)

		' if the entity collided with the level, make it bounce
		If entity_hit
	
			' bullet has collided with level - reset life counter
			life=0

			' get the normal of the surface which the entity collided with
			Local nx# = CollisionNX#(ent,1)
			Local ny# = CollisionNY#(ent,1)
			Local nz# = CollisionNZ#(ent,1)

			' compute the dot product of the entity's motion vector and the normal of the surface collided with
			Local vdotn# = vx#*nx# + vy#*ny# + vz#*nz#
			
			' calculate the normal force
			Local nfx# = -2.0 * nx# * vdotn#
			Local nfy# = -2.0 * ny# * vdotn# 
			Local nfz# = -2.0 * nz# * vdotn#

			' add the normal force to the direction vector. 
			vx# = vx# + nfx#
			vy# = vy# + nfy#
			vz# = vz# + nfz#

		EndIf
		
		' apply gravity
		Local GRAVITY#=0.01
		vy#=vy#-GRAVITY#

		' update position values
	
		x#=x#+vx#
		y#=y#+vy#
		z#=z#+vz#
			
		PositionEntity ent,x#,y#,z#
	
	End Method
	
End Type

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

Local light:TLight=CreateLight(1)
RotateEntity light,90,0,0

Local mesh:TMesh=LoadMesh("media/test.b3d")
ScaleMesh mesh,10,10,10
RotateEntity mesh,0,30,0

' set collision radius and types
EntityRadius cam,1,1
EntityType cam,1
EntityType mesh,2

' enable collisions
Collisions 1,2,2,2

' used by fps code
Local old_ms=MilliSecs()
Local renders
Local fps

While Not KeyDown(KEY_ESCAPE)		

	' control camera
	MoveEntity cam,KeyDown(KEY_D)-KeyDown(KEY_A),0,KeyDown(KEY_W)-KeyDown(KEY_S)
	TurnEntity cam,KeyDown(KEY_DOWN)*2-KeyDown(KEY_UP)*2,KeyDown(KEY_LEFT)*2-KeyDown(KEY_RIGHT)*2,0

	' shoot bullet
	If KeyHit(KEY_SPACE)
	
		TFormNormal 0,0,0.05,cam,Null
	
		TBullet.Shoot(EntityX#(cam,True),EntityY#(cam,True),EntityZ#(cam,True),TFormedX(),TFormedY(),TFormedZ())

	EndIf
	
	' update bullets
	For Local bull:TBullet=EachIn TBullet.list
		bull.Update()
	Next

	UpdateWorld
	RenderWorld
	
	renders=renders+1

	' calculate fps
	If MilliSecs()-old_ms>=1000
		old_ms=MilliSecs()
		fps=renders
		renders=0
	EndIf
	
	Text 0,0,"FPS: "+String(fps)
	Text 0,20,"Press space to shoot a bullet"
	Text 0,40,"No. of bullets: "+TBullet.no

	Flip
	
Wend

End


If you can reproduce the problem by writing a very small program with just the ball bouncing against an advertising hoarding, that would be a huge help.

Ah man, I found it after a couple of hours of messing with your example. A bug in my code obviously. For some reason I was using a negative z velocity in TranslateEntity to apply curve to the ball flight. This was screwing things completely after a collision. I feel bad now for messing you about, sorry.

It's OK - without this topic I wouldn't have known the normals bug existed!