Collision Problem.

BlitzMax Forums/BlitzMax Programming/Collision Problem.

Paul "Taiphoz"(Posted 2011) [#1]


In the above example, the red land area is my collision layer for my level, the black box, and smaller yellow box's are my player, and where on the player I am checking collisions.

First of all to keep my player on the land I do a check at his feet, loop through small amounts until its touching or just on top of the land.

I then check to see if the left is touching anything and the right and nudge the players x left or right to stop it touching.

this is actually buggy and for some reason the left check seems to get ignored sometimes.

Also another problem is at pos3 if I jump into a land mass as soon as my feet hit it, my loop code bounces me to the top of it, iv tried a number of things to avoid this but they all didnt work.

so little help is needed, if you have a better of of checking player collisions on a large image like mine please let me know. oh the land mass in the air, I want to be able to jump through it, but only land on it if my feet actually hit the top of it.

	Method Collisions()
		debugstop
		
		Local LeftCheck:Int
		Local RightCheck:Int
		Local FootCheck:Int
		
		' Im pre checking these here because as the method grows, I may need to call the same chack at the
		' same pos more than once.
		footcheck = ImagesCollide(footcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 )
		rightcheck = ImagesCollide(rightcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 )
		leftcheck = ImagesCollide(leftcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 )
		

		If footcheck = 0
			fallspeed = fallspeed + .5
			gravity:+fallspeed
		End If

		'keep the player on top of the collision layer.
		Local ontop = 0
		Local steps= 0
		Repeat
			If ImagesCollide(footcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 ) = 1  
				y:-.2
				fallspeed = 0
				steps:+1
			Else
				ontop=1
			End If					

			If ImagesCollide(rightcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 ) = 1 And state<>state_jump 
				x:-.2
			End If		
				
			If ImagesCollide(leftcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 ) = 1  And state<>state_jump
				x:+ .2
				''debugstop
			End If	
						
		Until ontop=1
		
	End Method


Last edited 2011


Jesse(Posted 2011) [#2]
it's kind of hard to actually see what it's doing wrong from that bit of code. It can be a number of reason not having to do anything with the that code. it might be better if you can post an executable or even better the complete source code.


AdamRedwoods(Posted 2011) [#3]
You should keep your collisions separate from your movement.
Collisions are best used when the code returns true or false if there's a collision, makes it easier to debug and get working right.

I can see in your code that you have If....EndIf..... and then do another ImagesCollide. But yet you have movement (y:-0.2) going on before another collision, so that will affect subsequent collision checks.
Is this the way you want to do this? Probably not. Separate your functionality. One way I do this is by using a NEWPOSX, NEWPOSY variable, and setting the new player's position when all the collisions are done checking the old position.


Paul "Taiphoz"(Posted 2011) [#4]
yeah think I get what your saying, so call my update, do all the moveing by setting a newx newy, and then at the end in a new method/function do all collision checks and if there are any dont set the current x,y to the new x,y

or am I getting something wrong ?

God my memory is so bad Iv not touched code in years, taking my time getting back into things im sure iv made some other really stupid mistakes in the code so far I might just post the full source for some suggestions on how to clean it up. dont want to retain any old bad habbits.

'Black Night Test Code.
Strict

Framework brl.glmax2d
Import  brl.freeaudioaudio
Import  brl.linkedlist
Import  brl.math
Import  brl.random
Import  brl.wavloader
Import  brl.bmploader

Import brl.pngloader
Import brl.tgaloader
Import brl.jpgloader
Import brl.oggloader

SetGraphicsDriver GLMax2DDriver()

Global GFX_Width		:Int 	= 	1024
Global GFX_Height		:Int 	= 	768

Graphics GFX_Width,GFX_Height,0



Global bg_Sky:TImage = LoadImage ("sprite/level1/bground_sky.png")
Global bg_Back:TImage = LoadImage ("sprite/level1/Ground_back_3.png")
Global bg_Coll:TImage = LoadImage ("sprite/level1/ground_coll_3.png")
Global bg_Fore:TImage = LoadImage ("sprite/level1/ground_fore_3.png")


Global footcollisionImage:TImage = LoadImage ("sprite/footcollision.png")
Global leftcollisionImage:TImage = LoadImage ("sprite/leftcollision.png")
Global rightcollisionImage:TImage = LoadImage ("sprite/rightcollision.png")



Const State_Idle:Int	 	= 	1
Const State_run:Int	 	= 	2
Const State_attack:Int	 	 = 	3
Const State_jump:Int	 	= 	4
Const State_kneel:Int	 	= 	5


Const Direction_left:Int 	= 	1
Const Direction_right:Int 	 = 	2
Const Direction_up:Int 	 = 	2


Global level_offset:Int =0
Global map_push:Int = 350
Global CurrentLevel:Int = 1

Type level
	Field x:Int
	Field y:Int
	Field name:String
	Field skyimage:TImage
	Field bgImage:TImage
	Field colImage:TImage
	Field foreImage:TImage
	Field levelOffset:Int
	Field segment:Int
	Field totalsegments:Int
	Field totalwidth:Int
	Field mappush:Int
	Field prevSeg:Int
	Field nextSeg:Int
	Field zorder:Int
	
	Method New ()
		name = "Level " + CurrentLevel
		segment = 1
		x = 0
	
		'bgimage = LoadImage ("sprite/level" + currentlevel + "/ground_back_" + segment + ".png")
		'colimage = LoadImage ("sprite/level" + currentlevel + "/ground_coll_" + segment + ".png")
		'foreimage = LoadImage ("sprite/level" + currentlevel + "/ground_fore_" + segment + ".png")
		'skyimage = LoadImage ("sprite/level" + currentlevel + "/bground_sky.png")
		
		'y = gfx_height-ImageHeight(colimage)		
		
	End Method
	
	Method loadlevel(newlevel:Int)
		'do level loading here.
	End Method
End Type
	
Global Levels:level = New level
levels.Loadlevel(CurrentLevel)

Type Player
	
	Const RunRight_offset		=	1
	Const Runleft_offset		=	0
	Const idleRight_offset		=	5
	Const idleleft_offset		=	4
	Const attackRight_offset	=	3
	Const attackleft_offset	=	2
	
	Field x:Int
	Field y:Int

	Field oldx:Int
	Field oldy:Int
	
	Field runspeed:Float
	Field direction:Int
	
	Field image:TImage
	
	Field image_run:TImage
	Field image_idle:TImage
	Field image_attack:TImage
	
	Field frame:Int
	Field framerate:Int = 100
	Field frametime:Int = MilliSecs()
	
	Field Gravity:Float = 5

	
	Field state:Int=State_idle
	
	Method Draw()
		''debugstop
		Select State
			Case State_idle
				Select direction
					Case Direction_right
						DrawImage image , X , Y , frame + (idleright_offset*7)
					Case direction_left
						DrawImage image , X , Y , frame + (idleleft_offset*7)
				End Select
			Case State_run
				Select direction
					Case Direction_right
						DrawImage image , X , Y , frame + (runright_offset*7)
					Case direction_left
						DrawImage image , X , Y , frame + (runleft_offset*7)
				End Select	
			Case State_jump
				Select direction
					Case Direction_right
						DrawImage image , X , Y , frame + (runright_offset*7)
					Case direction_left
						DrawImage image , X , Y , frame + (runleft_offset*7)
				End Select						
			Case State_attack
				Select direction
					Case Direction_right
						DrawImage image , X , Y , frame + (attackright_offset*7)
					Case direction_left
						DrawImage image , X , Y , frame + (attackleft_offset*7)
				End Select
			Case State_kneel
				Select direction
					Case Direction_right
						DrawImage image , X , Y , frame + (idleright_offset*7)
					Case direction_left
						DrawImage image , X , Y , frame + (idleleft_offset*7)
				End Select				
		End Select

		
		DrawImage footcollisionImage , X , Y
		DrawImage leftcollisionImage , X , Y
		DrawImage rightcollisionImage , X , Y
		
		SetColor 255 , 255 , 255
		Local data:String = "x ["+String.Fromfloat(x)+"] y ["+String.Fromfloat(y)+"]"
		DrawText data , 1 , 1
		DrawText "x = " + player1.x , 1 , 20
		DrawText "frametime = " + frametime , 1 , 40
		DrawText "framerate = " + framerate , 1 , 60
	End Method 
	
	Method update()
		
		oldy = y
		oldx = x
		

		y = y + gravity
		
			
		collisions()
		
		If MilliSecs() - framerate > frametime
			If frame =< 5
				frame = frame + 1
			Else
				frame = 0
			End If
			
			frametime = MilliSecs()
		End If				

		
		If x > map_push Then x = map_push
		
		If KeyHit(KEY_SPACE)
			state = state_jump
		End If
		
		If state = state_jump
			Select direction
				Case direction_right
					''debugstop
					If x => map_push
						level_offset:- runspeed
						x = map_push  
					Else
						x:+ runspeed	
					End If

								
				Case direction_left
					If x <= map_push And level_offset<0
						level_offset:+ runspeed
						x = map_push  
					Else
						x:- runspeed	
					End If			
								
						
				Case direction_up
					'
			End Select
		End If
			
		If KeyDown(KEY_D) And state<>state_attack And state<>State_jump And state<>state_kneel
			state = State_run
			
			direction=Direction_right
			
			If x => map_push
				level_offset:- runspeed
				x = map_push  
			Else
				x:+ runspeed	
			End If
		End If
	
		If KeyDown(KEY_A) And state<>state_attack And state<>State_jump And state<>state_kneel
			state = State_run
			direction = Direction_left
			
			If x <= map_push And level_offset<0
				level_offset:+ runspeed
				x = map_push  
			Else
				x:- runspeed	
			End If
		
		End If
		
		If KeyDown(key_A) = 0 And KeyDown(key_d) = 0 And state<>State_attack And state<>state_jump And state<>state_kneel
			'not moving so set state to idle
			state = state_idle
	
		End If
		
		If MouseHit(1) And state <> state_attack And state <> state_kneel
			state = state_attack
			frame=0
			DebugStop
		End If		
		
		Select State
			Case State_idle
				player1.framerate=200
			Case State_run
				player1.framerate=100
			Case State_attack
				'debugstop
				player1.framerate = 17
				If frame => 6
					state=state_idle
				End If
			Case state_kneel
				player1.framerate = 1000
			Default
				framerate=100
		End Select
		
		If player1.framerate = 1000
			Local g:Int =1
		End If
	End Method
	
	Method Collisions()
		'debugstop
		
		If ImagesCollide(footcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 ) = 0
			
			
		End If

		'keep the player on top of the collision layer.
		Local ontop = 0

		Repeat
			If ImagesCollide(footcollisionImage , X , Y , 0 , bg_Coll , level_offset , gfx_height - ImageHeight(bg_Coll) , 0 ) = 1  
				y:-.2
			Else
				ontop:+ 1
				If state <> state_attack
					state = state_idle
				Else
					'
				End If
			End If												
		Until ontop => 1
		
	End Method
	
	Method New ()
		frametime=MilliSecs()
		framerate = 100
		runspeed = 4
		direction = Direction_left
		state = state_run
		image = LoadAnimImage("sprite/player.png" , 132 , 135 , 0 , 42)
		
		x	= 350
		y 	= 600
		
	End Method
	
End Type

Global Player1:player = New player


Repeat
	Cls
		
		update()
		render()
			
	Flip
Until KeyHit(KEY_ESCAPE) Or AppTerminate()


Function Update()
	''debugstop
	player1.update()
	

End Function


Function Render()
	''debugstop
	DrawImage bg_Sky , 0 , 0
	DrawImage bg_Back , level_offset , gfx_height-ImageHeight(bg_back)
	DrawImage bg_Coll , level_offset , gfx_height-ImageHeight(bg_Coll)
	player1.draw()
	DrawImage bg_Fore , level_offset , gfx_height-ImageHeight(bg_Fore)
	
End Function



Paul "Taiphoz"(Posted 2011) [#5]
EDIT - think the above code might be a revision where i ripped out the jump code i had cos , well it sucked.

Last edited 2011