More on collisions

Blitz3D Forums/Blitz3D Beginners Area/More on collisions

Uhfgood(Posted 2005) [#1]
I find if I move my object very slowly, say 0.02 units at a time, that when collisions are on, the object gets stuck, and won't move after while.

Any idea of why a sphere won't be able to move over a bunch of cubes when it's moving fairly slowly?

Can anyone point me to any good tutorial's or even sources on using blitz3d collisions correctly? Because it's hard trying to figure out how to use them blindly.


Uhfgood(Posted 2005) [#2]
Here i'll post some source so you can see it in action.

Notice you can't move because speed is set to .02 instead of something higher

; m = member, b = boolean

Const b_DebugMode = False

; This won't have positional information
; as blitz will do that for me.  It will
; have velocity, speed, and gravity parameters
; probably some blitz collision information as well
Type TGameObject

	Field m_entity
	Field m_xVelocity#
	Field m_yVelocity#
	Field m_zVelocity#
	Field m_xSpeed#
	Field m_ySpeed#
	Field m_zSpeed#	
	Field mb_useGravity
	Field m_gravity#
	
End Type

Global debugtxt$ = ""

; most of the game entities
; to copy all the playfield 'cells'
; from; Gametoken is the piece that 
; moves around the board.

Global camera, light, gameToken.TGameObject
Dim Playfield( 12, 12 )

Global logfile

;;; General Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Function fn_AddDebugTxt( txt$ )

	debugTxt = debugTxt + txt$ + "|"
 
End Function

Function fn_ShowDebugTxt( txt$ )

	If( Right( txt, 1 ) <> "|" ) Then txt = txt + "|"

	ty = 0
	Repeat
		tx = Instr( txt, "|" )
		If( tx > 0 )
			Text( 0, ty, Left( txt, tx - 1 ) )
			txt = Right( txt, Len( txt ) - tx )
			ty = ty + 10
		End If
	Until tx = 0
	
	debugTxt$ = ""
	
End Function

Function fn_OpenLogFile()

	If( b_DebugMode = True )
	
		Cdate$ = CurrentDate$()
		Ctime$ = CurrentTime$()
		Cdir$ = CurrentDir$()
		logdir$ = Cdir$ + "log"
		
		If( FileType( logdir$ ) = 0 )
			CreateDir( logdir$ )
		End If
		
		LogFileName$ = logdir$ + "\" + Cdate$ + "log.txt"
		
		If( FileType( logdir$ ) = 2 )
			
			If( FileType( LogFileName$ ) = 1 )
				logfile = OpenFile( LogFileName$ )
				Repeat
					SeekFile( logfile, i )
					i = i + 1
				Until Eof( logfile )	
			Else
				logfile = WriteFile( LogFileName$ )
		
			End If
			
			If( logfile <> 0 )
			
				WriteLine( logfile, "" )
				WriteLine( logfile, LogFileName$ + " opened successfully." )
				WriteLine( logfile, "" )
				WriteLine( logfile, "log file opened on " + Cdate$ + " at " + Ctime$ + "." )
		
			Else
				DebugLog( "Could not create or open log file." )	
			End If
			
		End If
	
	End If
	
End Function ; fn_OpenLogFile()

;--------------------------------------;

Function fn_CloseLogFile()

	If( b_DebugMode = True )
	
		If( logfile <> 0 )
		
			WriteLine( logfile, "Logging successful, closing log file." )
			WriteLine( logfile, "" )
			WriteLine( logfile, "---" )
			CloseFile( logfile )
		
		End If
	
	End If

End Function ; fn_CloseLogFile()

;--------------------------------------;

; This function generally creates everything in 
; the game.  First the camera, then the light, then
; playfield and finally the game token.
Function fn_CreateWorld()

	; camera 
	camera=CreateCamera() 
	PositionEntity( camera, 6, 4, -12.5 )
	temppivot = CreatePivot()
	PositionEntity( temppivot, 6, 0, -6 )
	PointEntity( camera, temppivot )
	FreeEntity( temppivot )
	
	; light
	AmbientLight 32, 32, 32
	light=CreateLight() 
	RotateEntity light, 60, 0, 0

	; playfield boundry walls
	wallone = CreateCube()
	ScaleEntity( wallone, .5, 1, 7 )
	PositionEntity( wallone, -1, .5, -5.5 )
	EntityAlpha( wallone, .25 )
	EntityType( wallone, 3 )
		
	walltwo = CreateCube()
	ScaleEntity( walltwo, .5, 1, 7 )
	PositionEntity( walltwo, 12, .5, -5.5 )
	EntityAlpha( walltwo, .25 )
	EntityType( walltwo, 3 )
		
	wallthree = CreateCube()
	ScaleEntity( wallthree, 6, 1, .5 )
	PositionEntity( wallthree, 5.5, .5, -12 )
	EntityAlpha( wallthree, .25 )
	EntityType( wallthree, 3 )
		
	wallfour = CreateCube()
	ScaleEntity( wallfour, 6, 1, .5 )
	PositionEntity( wallfour, 5.5, .5, 1 )
	EntityAlpha( wallfour, .25 )	
	EntityType( wallfour, 3 )
	
	fn_CreatePlayfield()
	fn_CreateGameToken()

	; 2 = playfield (cube array array)
	Collisions( 1, 2, 2, 3 )
	Collisions( 1, 3, 2, 3 )
	
End Function ; fn_CreateWorld()

;--------------------------------------;

; free everything
Function fn_DestroyWorld()

	fn_DestroyGameToken()
	fn_DestroyPlayfield()

	FreeEntity( light )	
	FreeEntity( camera )
	
End Function ; fn_DestroyWorld

Function fn_ManageCollisions()

	; cell y is as you're looking from the top down, essentially the 2d
	; version used the y coordinates, but as y literally goes up and down
	; i have to worry about the z position (in and out of the screen)
	
	readjusted_z# = -EntityZ( gameToken\m_entity )
	
	fn_AddDebugTxt( "x = " + EntityX( gameToken\m_entity ) + " y = " + EntityZ( gameToken\m_entity ) )
	ul_x = ( EntityX( gameToken\m_entity ) - 0.45 )
	ul_y = ( readjusted_z# - 0.45 )
	fn_AddDebugTxt( "upperleft x = " + ul_x + " upperleft y = " + ul_y )
	ur_x = ( EntityX( gameToken\m_entity ) + 0.45 )
	ur_y = ( readjusted_z# - 0.45 )
	fn_AddDebugTxt( "upperright x = " + ur_x + " upperright y = " + ur_y )
	ll_x = ( EntityX( gameToken\m_entity ) - 0.45 )
	ll_y = ( readjusted_z# + 0.45 )
	fn_AddDebugTxt( "lowerleft x = " + ll_x + " lowerleft y = " + ll_y )
	lr_x = ( EntityX( gameToken\m_entity ) + 0.45 )
	lr_y = ( readjusted_z# + 0.45 )
	fn_AddDebugTxt( "lowerright x = " + lr_x + " lowerright y = " + lr_y )
	
	If( EntityCollided( gameToken\m_entity, 2 ) = Playfield( ul_x, ul_y ) )
		EntityColor( Playfield( ul_x, ul_y ), 32, 32, 32 )
	End If
	If( EntityCollided( gameToken\m_entity, 2 ) = Playfield( ur_x, ur_y ) )
		EntityColor( Playfield( ur_x, ur_y ), 32, 32, 32 )
	End If
	If( EntityCollided( gameToken\m_entity, 2 ) = Playfield( ll_x, ll_y ) )
		EntityColor( Playfield( ll_x, ll_y ), 32, 32, 32 )
	End If
	If( EntityCollided( gameToken\m_entity, 2 ) = Playfield( lr_x, lr_y ) )
		EntityColor( Playfield( lr_x, lr_y ), 32, 32, 32 )
	End If
	
End Function

;;; Playfield related functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Create the playfield, which at the moment
; is nothing more than an array of cubes.
Function fn_CreatePlayfield()

	; initial cube as a starting point
	Local cube = CreateCube() 
	ScaleEntity( cube, 0.5, 0.5, 0.5 )
	; 12 x 12 game board ( 0 - 11 = 12 positions )
	; note using y for z, swapping axes as the 2d
	; gameboard is being layed out flat like a table
	For y = 0 To 11
		For x = 0 To 11
			If( y > 0 ) Then adj_y = -y
			; create each "cell"
			Playfield( x, y ) = CopyEntity( cube )
			; position it relative to the other cells
			PositionEntity( Playfield( x, y ), x, 0, adj_y )
			EntityType( Playfield( x, y ), 2 )
			; give it a random color for indentity
			EntityColor( Playfield( x, y ), Rand( 63, 192 ), Rand( 63, 192 ), Rand( 63, 192 ) )
		Next
	Next
	
	; no more need for the cube
	FreeEntity( cube )
	
End Function ; fn_CreatePlayfield

;--------------------------------------;

; free up all the cells essentially
Function fn_DestroyPlayfield()

	For y = 0 To 11
		For x = 0 To 11
			FreeEntity( Playfield( x, y ) )
		Next
	Next

End Function ; fn_DestroyPlayfield

;;; Game Token Related Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; The piece the player directs
Function fn_CreateGameToken()

	gameToken = fn_CreateGameObject()
	
	; Make sure it created correctly
	If( gameToken <> Null )

		; now create the mesh/model etc
		gameToken\m_entity = CreateSphere()
		ScaleEntity( gameToken\m_entity, 0.45, 0.45, 0.45 )
		EntityType( gameToken\m_entity, 1 )
		PositionEntity( gameToken\m_entity, 5.5, 2, -5.5 )
		EntityRadius( gameToken\m_entity, .45 )
		ResetEntity( gameToken\m_entity )
		gameToken\m_xSpeed# = 0.02
		gameToken\m_ySpeed# = 0.0
		gameToken\m_zSpeed# = 0.02
		gameToken\m_xVelocity# = 0.0
		gameToken\m_yVelocity# = 0.0
		gameToken\m_zVelocity# = 0.0
		gameToken\mb_useGravity = True
		gameToken\m_gravity# = -.01
	Else
		RuntimeError( "Could not create game token." )
	End If
		
End Function ; fn_CreateGameToken()

;--------------------------------------;

; get rid of the game piece
Function fn_DestroyGameToken()

	fn_DestroyGameObject( gameToken )
	
End Function ; fn_DestroyGameToken()

;--------------------------------------;

Function fn_MoveGameToken()

	If( gameToken\mb_useGravity = True )
		gameToken\m_yVelocity# = gameToken\m_yVelocity# + gameToken\m_gravity#
	End If
	
	If( KeyDown( 200 ) )
		gameToken\m_zVelocity# = gameToken\m_zSpeed#
	Else If( KeyDown( 208 ) )
		gameToken\m_zVelocity# = -gameToken\m_zSpeed#
	Else
		gameToken\m_zVelocity# = 0
	End If

	If( KeyDown( 203 ) )
		gameToken\m_xVelocity# = -gameToken\m_xSpeed#
	Else If( KeyDown( 205 ) )
		gameToken\m_xVelocity# = gameToken\m_xSpeed#
	Else
		gameToken\m_xVelocity# = 0
	End If
	
	dx# = gameToken\m_xVelocity#
	dy# = gameToken\m_yVelocity#
	dz# = gameToken\m_zVelocity#
	
	TranslateEntity( gameToken\m_entity, dx#, dy#, dz# )
	
End Function

;;; TGameObject Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; A quick note about game object functions.  It's not always
; good to create super long function names, so most of the
; game object functions shortend TGameObject as TGOb For instance
; fn_TGObXXX() - where XXX is the rest of the function name.

;--------------------------------------;

; create and return a game object (game entity,
; but since this is blitz i called it an object)
Function fn_CreateGameObject.TGameObject()

	; 'o' is temporary
	Local o.TGameObject
	
	; create it make sure everything went well
	o.TGameObject = New TGameObject
	If( o <> Null )
		Return( o )
	Else
		RuntimeError( "Could not create game object." )
	End If
	
End Function ; fn_CreateGameObject.TGameObject()

;--------------------------------------;

; Get rid of it
Function fn_DestroyGameObject( o.TGameObject )

	; if there's an entity created free it first
	If( o\m_entity <> 0 )
		FreeEntity( o\m_entity )
	End If
	
	Delete( o )
	
End Function ; fn_DestroyGameObject( o.TGameObject )

;--------------------------------------;

Function fn_TGObSetXVelocity( o.TGameObject, value# )

	o\m_xVelocity# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetXVelocity#( o.TGameObject )

	Return( o\m_xVelocity# )
	
End Function

;--------------------------------------;

Function fn_TGObSetYVelocity( o.TGameObject, value# )

	o\m_yVelocity# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetYVelocity#( o.TGameObject )

	Return( o\m_yVelocity# )
	
End Function

;--------------------------------------;

Function fn_TGObSetZVelocity( o.TGameObject, value# )

	o\m_zVelocity# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetZVelocity#( o.TGameObject )

	Return( o\m_zVelocity# )
	
End Function

;--------------------------------------;

Function fn_TGObSetXSpeed( o.TGameObject, value# )

	o\m_xSpeed# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetXSpeed#( o.TGameObject )

	Return( o\m_xSpeed# )
	
End Function

;--------------------------------------;

Function fn_TGObSetYSpeed( o.TGameObject, value# )

	o\m_ySpeed# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetYSpeed#( o.TGameObject )

	Return( o\m_ySpeed# )
	
End Function

;--------------------------------------;

Function fn_TGObSetZSpeed( o.TGameObject, value# )

	o\m_zSpeed# = value#
	
End Function

;--------------------------------------;

Function fn_TGObGetZSpeed#( o.TGameObject )

	Return( o\m_zSpeed# )
	
End Function

;--------------------------------------;

Function fn_TGObSetGravityFlag( o.TGameObject, b_flag )

	o\mb_useGravity = b_flag

End Function

;--------------------------------------;

Function fn_TGObGetGravityFlag( o.TGameObject )

	Return( o\mb_useGravity )
	
End Function

;--------------------------------------;

Function fn_TGObSetGravity( o.TGameObject, value# )

	o\m_gravity = value

End Function

;--------------------------------------;

Function fn_TGObGetGravity#( o.TGameObject )

	Return( o\m_gravity# )
	
End Function

;--------------------------------------;

.main

Graphics3D 640,480 
SetBuffer BackBuffer() 

fn_OpenLogFile()

fn_CreateWorld()

While Not KeyDown( 1 ) 
	fn_MoveGameToken()
	fn_AddDebugTxt( "Count collisions = " + CountCollisions( gameToken\m_entity ) )
	UpdateWorld
	fn_ManageCollisions()
	RenderWorld 
	fn_ShowDebugTxt( debugTxt )
	Flip 
Wend 

fn_DestroyWorld()

fn_CloseLogFile()

End 



RiverRatt(Posted 2005) [#3]
I tried your game. It looks like its coning along nicely.
For your problem, have you tried using clearcollisions?


Uhfgood(Posted 2005) [#4]
I haven't tried using it, but if I cleared them doesn't that mean it would no longer work?


RiverRatt(Posted 2005) [#5]
Just for the remainder of the current frame I think. This might be slow but I don't know. Never tried it.

You know you might just need to put fn_ManageCollisions()
before your ubdateworld.


Uhfgood(Posted 2005) [#6]
RiverRatt - thanks for the suggestions -

fn_MangageCollisions() is one of my own functions (note the fn_ to make it different from a blitz function) - essentially this reports what blocks the ball is sitting on, and of course the ball goes out of bounds if it's done before updateworld as updateworld manages collisions.

I will try ClearCollisions - right now i'm not concerned with speed, only that it works... later I will try to optimize it.

Thanks.


Uhfgood(Posted 2005) [#7]
ClearCollisions simply stops collisions from working, if I do that the sphere falls through the table.

Here's the thing - I enabled gravity (or something like) because later I may want to have more than a single level for the sphere to move over...

Secondly obviously any 3d games that use platforms do it (although they may do it with external collision libraries) - I need to figure out what i'm doing wrong, because even if there is a collision I should be able to move on top of the object.

Thirdly it's enitrely possible the problem lies with me using a bunch of individual cubes meaning it gets stuck because it's colliding with a bunch of different objects on the x-z plane - which means i'd have to make it a solid object - however again, I need to be able to detect collisions with individual squares, which I can do manually but that means relying again on my own collision stuff, and i'd much rather have blitz do it for me if such a feat is possible.


Stevie G(Posted 2005) [#8]
Uhfood , you were never resetting the yvelocity so it was a huge value the token was trying to move downwards ...

See your manage collisions function for what I changed.

Also, trust me on this .. using constants for your collision types is much easier to follow .. I included some in your main program.



Oh .. and now you have an array out of bounds when you hit the outer walls ... can't be arsed looking at that right now .. sorry.

Stevie


Uhfgood(Posted 2005) [#9]
What does it mean to use 'constraints' ? Some special blitz functions to do it?

But wow you're right, the y velocity wasn't getting reset... I guess I didn't remember to do this from when I was messing with my own platform (2d) code, where you reset y velocity when hitting a platform. Anyways thanks alot for that...

Keith


Stevie G(Posted 2005) [#10]
Eh.. admittedly I do have constraints on the brain with the verlet car engine I'm building but I did say constants :o

More Specifically these ....


Const TOKEN = 1
Const BLOCKS = 2
Const WALLS = 3
Collisions TOKEN, BLOCKS, 2 , 3
Collisions TOKEN, WALLS , 2, 3

and ...

EntityType( gameToken\m_entity, TOKEN )

etc..





Uhfgood(Posted 2005) [#11]
oh how stupid of me lol :-)

Yeah constants in due time ;-)

I'm just working roughly, when I get to the next stage i'll clean it up. Usually how I work... i'll just do some quick and dirty code and then go back put them into functions, comment and take out the 'magic numbers' :-)


Stevie G(Posted 2005) [#12]
You should get into doing it to start with ... makes life much easier when debugging etc..


Rook Zimbabwe(Posted 2005) [#13]
Ufhgood... maybe you could use {CODEBOX} instead of {CODE}??? Nice code though!!!

Why is everyone plopping their functions in FRONT???

RZ


Uhfgood(Posted 2005) [#14]
"Ufhgood... maybe you could use {CODEBOX} instead of {CODE}??? Nice code though!!!"

I didn't know about codebox

"Why is everyone plopping their functions in FRONT???

RZ"

What do you mean in front?


RiverRatt(Posted 2005) [#15]
Uhfgood; Do you program in C++?


Uhfgood(Posted 2005) [#16]
In C, I do a scant c++ :-)