Collision Help...

Blitz3D Forums/Blitz3D Beginners Area/Collision Help...

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Hey StOrM3,

After reading your original post yesterday, I thought I'd have a go at helping you out so I wrote the following basic concept code today. It's how I understand your game concept works, from the various posts you've made here.

I hadn't seen any of your source code before today so I'm probably doing things differently to you but it contains all the stuff I remember you having trouble with: collisions, smooth control (mouse control may need tweaking), combination hits, etc.

Hope it's of some use. Feel free to ask any questions, if I can help. BTW, seems like you've got a really nice game concept there - keep up the hard work!

	Graphics3D 800,600,32
	SetBuffer BackBuffer()

	WireFrame 0
	AntiAlias 0

	SeedRnd MilliSecs()

	Global frame_count%
	Global fps%
	Global slowest_fps%
	Global fps_timeout%
	Global frame_time%
	Global slowest_frame%
	Global frame_start%
	fps_timer = CreateTimer(60)
	slowmo% = False
	wiref% = False
	
	cam = CreateCamera()
	PositionEntity cam,0,1.5,-36
	CameraZoom cam,1.5
	
	light = CreateLight()
	
	Type gridT
		Field entity
		Field ID
		Field row%, col%
	End Type
			
	Const END_ROW% = 14
	Const END_COL% = 20
	Const GRID_START_X# = Float(-END_COL)
	Const GRID_START_Y# = Float(END_ROW)
	Const KEY_MOVE_FRAMES% = 8
	Const SHOOT_SPEED# = 1.0
	
	; Grid object IDs.
	Const ID_NEW_PLAYER% = -1
	Const ID_SPACE% = 0
	Const ID_WALL% = 1
	Const ID_RED_BALL% = 2
	Const ID_GREEN_BALL% = 3
	Const ID_YELLOW_BALL% = 4
	Const ID_CYAN_BALL% = 5
	Const ID_HORZ_END% = 7
	Const ID_VERT_END% = 8
	Const ID_SET_RANDOM% = 9
	
	Const CLOCKWISE% = 1
	Const ANTICLOCKWISE% = -1

	Const TYPE_PLAYER% = 1
	Const TYPE_WALL% = 2
	Const TYPE_BALL% = 3
	
	Global move_row% = 0
	Global move_col% = 1
	Global move_dx#, move_dy#
	Global move_count%
	Global player_moving% = False

	Dim grid.gridT(END_ROW,END_COL)
	create_level()

	Global player.gridT = New gridT
	player\entity = CreateSphere()
	player\ID = ID_NEW_PLAYER
	position_player(2,10)
	EntityShininess player\entity,1
	EntityType player\entity,TYPE_PLAYER
	EntityRadius player\entity,.9,.9

	Collisions TYPE_PLAYER,TYPE_BALL,1,1
	Collisions TYPE_PLAYER,TYPE_WALL,1,1

	
	; --- Main loop ---
	
	While Not KeyHit(1)
		frame_start = MilliSecs()
	
		If KeyHit(28) Then slowmo = Not slowmo
		If KeyHit(14)
			wiref = Not wiref
			WireFrame wiref
		EndIf

		control_player()
		update_player()	
		
		UpdateWorld
		RenderWorld
		
		frame_time = MilliSecs() - frame_start	
		show_info()

		WaitTimer(fps_timer)
		Flip(1)

		If slowmo Then Delay 500
	Wend

	ClearWorld	

	End


; Initial level grid layout info.
.grid_data
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,1
Data 1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,1
Data 1,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,1
Data 1,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,1
Data 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
Data 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1



;
; Player control handler.
;
Function control_player()

	If Not player_moving
		
		mxs = MouseXSpeed()
		MoveMouse 400,300
		
		If mxs
			frames = Abs(mxs/3)
			If frames > 10 Then frames = 10
			frames = 11 - frames
			move_player(Sgn(mxs),frames)
		Else
			If KeyHit(57) Or MouseHit(1)
				shoot_player()
			Else
				If KeyDown(203) Then move_player(-1,KEY_MOVE_FRAMES)
				If KeyDown(205) Then move_player(1,KEY_MOVE_FRAMES)
			EndIf
		EndIf
	EndIf

End Function


;
; Updates player's movement and handles collisions.
;
Function update_player()

	If player_moving
		ent = EntityCollided(player\entity,TYPE_BALL)
		If ent
			; A ball was hit...
			ball.gridT = Object.gridT(EntityName(ent))
			
			If player\ID <> ball\ID
				player_is_ball(ball\ID)
				reset_player()
				position_player(player\row,player\col)
			Else
				remove_connected(ball)
				reset_player()
				position_player(player\row,player\col)
			EndIf
		Else
			ent = EntityCollided(player\entity,TYPE_WALL)
			If ent
				; A wall was hit...
				reset_player()
				position_player(player\row,player\col)
			Else
				; Player moving clockwise/anti-clockwise...
				TranslateEntity player\entity,move_dx,move_dy,0		
				move_count = move_count - 1
				If Not move_count Then reset_player()
			EndIf
		EndIf
	EndIf
		
End Function


;
; Recusively removes all connected balls of the same type.
;
Function remove_connected(ball.gridT)

	row = ball\row
	col = ball\col
	ID = ball\ID

	HideEntity ball\entity
	ball\ID = ID_SPACE

	If grid(row,col-1)\ID = ID Then remove_connected(grid(row,col-1))
	If grid(row,col+1)\ID = ID Then remove_connected(grid(row,col+1))
	If grid(row-1,col)\ID = ID Then remove_connected(grid(row-1,col))
	If grid(row+1,col)\ID = ID Then remove_connected(grid(row+1,col))
		
End Function


;
; Turns player into a ball of type ID.
;
Function player_is_ball(ID)

	Select ID
		Case ID_RED_BALL
			EntityColor player\entity,155,0,0
		Case ID_GREEN_BALL
			EntityColor player\entity,0,155,0
		Case ID_YELLOW_BALL
			EntityColor player\entity,155,155,0
		Case ID_CYAN_BALL
			EntityColor player\entity,0,155,155
	End Select

	player\ID = ID

End Function


;
; Resets player's status ready for a new movement.
;
Function reset_player()

	player_moving = False
	
	; Flush all input accumulated while moving.
	MouseXSpeed()
	FlushMouse 
	FlushKeys

End Function


;
; Moves player around ball grid.
; dir    - 1=clockwise, -1=anti-clockwise
; frames - Number of animation frames to make the move.
;
Function move_player(dir%, frames%)
	
	mr = move_row * Sgn(dir) ; Sgn() ensures dir is either CLOCKWISE
	mc = move_col * Sgn(dir) ; or ANTICLOCKWISE.

	new_row = player\row + mr
	new_col = player\col + mc

	If dir = CLOCKWISE
		Select grid(new_row,new_col)\ID
			Case ID_HORZ_END
				move_row = mc : move_col = 0
				new_row = player\row + (move_row*2)
				new_col = player\col + (mc*2)
			Case ID_VERT_END	
				move_col = -mr : move_row = 0
				new_row = player\row + (mr*2)
				new_col = player\col + (move_col*2)
		End Select
	Else
		Select grid(new_row,new_col)\ID
			Case ID_HORZ_END
				move_row = mc : move_col = 0
				new_row = player\row + (move_row*-2)
				new_col = player\col + (mc*2)
			Case ID_VERT_END
				move_col = -mr : move_row = 0
				new_row = player\row + (mr*2)
				new_col = player\col + (move_col*-2)
		End Select
	EndIf
				
	player\row = new_row
	player\col = new_col
	
	; Calculate movement animation to get from old position to new one.
	start_x# = EntityX(player\entity)
	start_y# = EntityY(player\entity)		
	end_x# = GRID_START_X + (new_col*2)
	end_y# = GRID_START_Y - (new_row*2)
	move_dx# = (end_x - start_x) / frames
	move_dy# = (end_y - start_y) / frames
	move_count = frames
	player_moving = True

End Function

;
; Set up player to shoot forward.
;
Function shoot_player()

	If player\row = 2
		move_dx = 0 : move_dy = -SHOOT_SPEED
	ElseIf player\row = END_ROW-2
		move_dx = 0 : move_dy = SHOOT_SPEED
	ElseIf player\col = 2
		move_dx = SHOOT_SPEED : move_dy = 0
	ElseIf player\col = END_COL-2
		move_dx = -SHOOT_SPEED : move_dy = 0
	EndIf

	player_moving = True
	move_count = 9999		; Make sure we can reach a wall!

End Function


;
; Positions player onscreen at level grid row,col.
;
Function position_player(row%, col%)

	player\row = row
	player\col = col
	PositionEntity player\entity,GRID_START_X+(col*2),GRID_START_Y-(row*2),0
	ResetEntity player\entity
	
End Function


;
; Create all level objects.
;
Function create_level()

	pos_x# = GRID_START_X
	pos_y# = GRID_START_Y

	Restore grid_data

	For row = 0 To END_ROW
		For col = 0 To END_COL
			this.gridT = New gridT
			this\row = row
			this\col = col
						
			Read datum
			
			Select datum
				Case ID_WALL
					ent = CreateCube()
					ScaleMesh ent,1,1,Rnd(1,3)			; For a more interesting looking wall
					EntityColor ent,0,0,Rand(100,255)   ;
					PositionEntity ent,pos_x,pos_y,0			
					EntityType ent,TYPE_WALL
					EntityRadius ent,1,1
					NameEntity ent,Handle(this) 
					this\entity = ent
					this\ID = ID_WALL
				Case ID_SET_RANDOM
					ent = CreateSphere()
					EntityShininess ent,1
					PositionEntity ent,pos_x,pos_y,0			
					EntityType ent,TYPE_BALL
					EntityRadius ent,1,1
					NameEntity ent,Handle(this)
					this\entity = ent

					random_ball = Rand(ID_RED_BALL,ID_CYAN_BALL)
					Select random_ball
						Case ID_RED_BALL
							EntityColor ent,155,0,0
						Case ID_GREEN_BALL
							EntityColor ent,0,155,0
						Case ID_YELLOW_BALL
							EntityColor ent,155,155,0
						Case ID_CYAN_BALL
							EntityColor ent,0,155,155
					End Select
					this\ID = random_ball
				Default
					this\ID = datum
			End Select
			
			grid(row,col) = this
			pos_x = pos_x + 2.0
		Next

		pos_x = GRID_START_X
		pos_y = pos_y - 2.0
	Next

End Function


;
; Display debug info
;
Function show_info()
	
	If fps_timeout
		frame_count = frame_count + 1

		If MilliSecs() > fps_timeout Then
			fps_timeout = MilliSecs() + 1000 
			fps = frame_count 
			frame_count = 0 
		
			If fps < slowest_fps Or slowest_fps = 0 Then slowest_fps = fps
		EndIf 
		
		If frame_time > slowest_frame Then slowest_frame = frame_time
		
		Color 0,255,0
		Text 10,10," Triangles: " + TrisRendered()
		Color 255,255,0
		Text 10,25," Millisecs: " + frame_time
		Text 10,40,"   Slowest: " + slowest_frame
		Color 0,255,255
		Text 10,55,"       FPS: " + fps
		Text 10,70,"     Worst: " + slowest_fps
		Color 255,255,255
		Text 200,10,"Move mouse right or press right arrow key to move clockwise"
		Text 200,25,"Move mouse left or press left arrow key to move anti-clockwise"
		Text 200,40,"Click left mouse button or press SPACE to shoot"
	Else
		; First call initialization.
		fps_timeout = MilliSecs() + 1000 
	EndIf
	
End Function