Please help: collisions

Blitz3D Forums/Blitz3D Beginners Area/Please help: collisions

olo(Posted 2008) [#1]
i am working on a "game" but i have some problems. Here is my code so far, it isnt complete and i havnt added the text that displays the score. Dont laugh at my bad coding ;)


welcome()

Function welcome()
	Graphics 1024, 768
	screen=LoadImage("ice_escape1.bmp")
	DrawImage screen, 0,0
	While Not KeyDown(1)
	
		If KeyDown(28) Then Return
		If KeyDown(57) Then Return 
		
	Wend
	
	End Function
	
	

.start
Graphics3D 1280,1024
SetBuffer BackBuffer()

SeedRnd MilliSecs()

;collisions
type_player=1
type_obstacle=2
type_sphere=3
type_ring=4

;camera
camera=CreateCamera()
PositionEntity camera, -360.132,5,692.037
RotateEntity camera, 0,180, 0
EntityType camera, type_player
EntityRadius camera, 2


CameraClsColor camera, 0,0,0

;sound
sound=LoadSound("phaser.wav")

;lights
light=CreateLight()
RotateEntity light,90,0,0


;heightmap and the terrain
maze=LoadTerrain("heightmap6.bmp")
ScaleEntity maze, 5,100,5
PositionEntity maze, -500,0,-500
tex1=LoadTexture("ice1.jpg")
ScaleTexture tex1, 50,50
EntityTexture maze, tex1

;penguins
Dim spheres(10000)
For s=0 To 100
spheres(s)=LoadMesh("penguin.3ds")
ScaleEntity spheres(s), 0.05,0.05,0.05
PositionEntity spheres(s), Rand(500,-500), 3,Rand(500,-500)
EntityColor spheres(s), 95,95,95

EntityType spheres(s), type_sphere
EntityRadius spheres(s), 1
RotateEntity spheres(s), 0,-80,0
Next

;making rings(gems)
Dim rings(1000)
For r=0 To 100
rings(r)=LoadMesh("ring1.3ds")
ScaleEntity rings(r), 0.05,0.05,0.05
PositionEntity rings(r), Rand(500,-500), 3,Rand(500,-500)
EntityColor rings(r), 255,255,26

EntityType rings(r), type_ring
EntityRadius rings(r), 0.3
Next


;destination uncone...
cone=CreateCone()
PositionEntity cone, -407, 15, -16.5
EntityColor cone, 255,0,0
ScaleEntity cone, 5,5,5
EntityType maze, type_obstacle
EntityRadius maze, 0.1

;collisions
Collisions type_player, type_obstacle,2,1

Collisions type_player,type_sphere,2,1

Collisions type_sphere,type_player,2,1

Collisions type_player, type_ring,2,1

Collisions type_ring, type_player,2,1

;the timer
starttime=MilliSecs()

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;makes game run
While Not KeyDown(1)

If KeyDown (72)=True Then velocity#=velocity#+0.02
If KeyDown (76)=True Then velocity#=velocity#-0.02
If KeyDown (77)=True Then TurnEntity camera, 0,-1,0
If KeyDown (75)=True Then TurnEntity camera, 0,1,0
MoveEntity camera, 0,0,velocity#

;pausing
If KeyDown(25) Then 
Cls
pause=LoadImage ("ice_pause.bmp")
	DrawImage pause,0,0
	Flip
	WaitKey()
	
	EndIf

	If KeyHit(57) Then PlaySound sound

;making spheres move randomly
For i=0 To 100
MoveEntity spheres(i), Rnd(-0.5,0.5), 0, Rnd(-1.2,1.2)
 
Next

;ending game
For b=0 To 100
If timeleft < 0 Or crash#=1 Then 
     Cls
Graphics 1024,768  
End=LoadImage ("ice_end.bmp")
     DrawImage End,0,0
     Flip
     WaitKey() 
     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start
     EndIf

If CountCollisions (spheres(b))
            crash=CollisionEntity (spheres(b),1)
    		HideEntity crash
		crash#=crash#+1
EndIf



If CountCollisions (rings(b))
		ring=CollisionEntity (rings(b),2)
		HideEntity ring
	score#=score#+1
EndIf
Next

UpdateWorld
RenderWorld

;the time
CurrentTime = MilliSecs() 
	timeleft= 240000 - ((CurrentTime - starttime))
	Text 800,10,"Time Remaining: "+TimeLeft /1000



Flip

Wend

End 



What i would like is that when the player(camera) touches a ring, the ring dissapears and the score goes up by one. i've made some penguins which you cant touch , if you do then you lose. The problem is that i do not know how to make the collision with the rings and the score thing.

When i tried, the collisions with the rings acted exactly the same as with the penguins. In other words, when i touched a ring, i lost...

Please help me.. i have been trying for too long and need some advice.

thanks Olo


Ross C(Posted 2008) [#2]
Have you tried using EntityCollided ( entity,type ) to get what entity has collided? Then you can determine whether it's a ring or a penguin.

If EntityCollided( player, type_ring) > 0 then
   ; An entity with the specified collision type, has collided with the player. You can identify this entity by querying EntityCollided(player,type_ring)
End if



olo(Posted 2008) [#3]
ok thanx for posting some help but i do not understand :(

here is the game (what is want it to be):

-it is a maze

-there are penguins which you cannot touch and you also cannot touch the walls

-there are rings..when you touch one, you get one point and the ring dissapears

problems (many):

-when i touch the wall, the whole terrain dissapears
If timeleft < 0 Or crash#=1 Then 
     Cls
Graphics 1024,768  
End=LoadImage ("ice_end.bmp")
     DrawImage End,0,0
     Flip
     WaitKey() 
     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start
     EndIf

If CountCollisions (camera)
            crash=CollisionEntity (camera,1)
    		HideEntity crash
		crash#=crash#+1
EndIf


-when i touch a penguin it also dissapears and nothing else happens (using same code as above)

-the only thing i have that i want is the dissapearing rings..when i touch them

i would really apreciate it you could help me solve any of these problems i have. Thanks again and please try to help me.

Olo


Ross C(Posted 2008) [#4]
Don't use count collisions at all :o) There is no need.

Do you store your rings in types? Or arrays?


olo(Posted 2008) [#5]
arrays.. what would i use insted of countcollisions?


olo(Posted 2008) [#6]
please help me, i really need some suggestions or advice...anyone

just give me some suggestions or things i could try


Ross C(Posted 2008) [#7]
EntityCollided(). It returns whether an entity was collided with.

It would be a bit easier to use types to store your rings.

But, instead of blitz collisions, for the rings, i'd say it would be easier to use entitydistance() to check for collisions with coins.

What i do notice is your placing your coins but only storing the entity in the array. If you use types, you can store more information about your entities alot easier. You can do this with arrays, but it's not as readable i don't think.

I'll knock something together.


olo(Posted 2008) [#8]
ok thank you so much

i really appreciate your help ;)


olo(Posted 2008) [#9]
i have come up with something although it is not exactly what i was looking for..

Now whenever i touch a ring it dissapears but when i touch a penguin or the walls nothing happens. The collision is there, not allowing me to go through but i dont get the 'you lose screen'.

Thanks to you, Ross C, i solved one problem, a couple to go.


olo(Posted 2008) [#10]
i still have some probelms :(

Thanks to Ross C, i have made the disapearing rings but whenever i crash into a penguin or the wall nothing happens except that i stop due to the collision. What i was aiming for is:

-i hit a penguin
-there is a collision detection
-the 'game over' screen pops up

i had it before but when i added the rings it stopped working

here is the code that i am using..Please correct any mistakes:
If timeleft < 0 Or crash#=1 Then 
     Cls
Graphics 1024,768  
End=LoadImage ("ice_end.bmp")
     DrawImage End,0,0
     Flip
     WaitKey() 
     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start
     EndIf

If EntityCollided (camera, type_sphere) > 0 Then
            crash=CollisionEntity (camera,1)
    				crash#=crash#+1
EndIf


thanks again, Olo


Ross C(Posted 2008) [#11]
There is a good few things wrong here.

For instance:


;ending game
For b=0 To 100
If timeleft < 0 Or crash#=1 Then 
     Cls
     Graphics 1024,768  
     End=LoadImage ("ice_end.bmp")
     DrawImage End,0,0
     Flip
     WaitKey() 
     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start
EndIf


Just won't work. "END" is a also a blitz command. You can assign things to it and use it to draw, but to avoid confusion, you should probably change this to something else. Also, try and avoid loading images whilst the game has started. Preload as much as possible.

     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start


Your program will never go back to the beginning, as the first IF statement will catch the spacebar being pressed first and end the application.

The penguins are disappearing because:

If CountCollisions (spheres(b))
            crash=CollisionEntity (spheres(b),1)
    		HideEntity crash
		crash#=crash#+1
EndIf


Again, confused about the coding used :o)

Your assigning the entity that has crashed, to the "crash" variable, then hiding it, THEN setting it to 1 more and making the number a floating point number with the #.

Firstly, when you set an entity to a variable, the variable will hold a handle (presumably a memory location) of the entity. This will usually be quite a large number (eg. 1034293). So adding one to this, doesn't make much sense...

Anyway, the reason the penguin is disappearing, is because you saying:

            crash=CollisionEntity (spheres(b),1)
    		HideEntity crash


Get the entity that has collided with the player. Then hide it. Also, you NEED to set your variables to GLOBAL before you run the main loop that runs the game. That way you can access them from within functions if need be, and they will always retain their values.

Again, remember the # after a variable is used to making the variable into a float. Only use this if you actually need a floating point value. Else, stick to integers.

So, i have recoded some parts, moved some parts into functions to keep the main loops cleaner and easier to understand. I have used distance checking on the rings instead of blitz collisions. Should work better. I don't have the media, but it should work fine :o)

welcome()

.start
Graphics3D 1280,1024
SetBuffer BackBuffer()

SeedRnd MilliSecs()

;collisions
Const type_player=1
Const type_penguin=2
Const type_sphere=3
Const type_ring=4


;Set up camera
Global camera = CreateCamera()
PositionEntity camera, -360.132,5,692.037
RotateEntity camera, 0,180, 0
CameraClsColor camera, 0,0,0
EntityType camera, type_player
EntityRadius camera, 2


;sound
Global sound=LoadSound("phaser.wav")

;lights
Global light=CreateLight()
RotateEntity light,90,0,0


;heightmap and the terrain
Global maze=LoadTerrain("heightmap6.bmp")
ScaleEntity maze, 5,100,5
PositionEntity maze, -500,0,-500

Global tex1=LoadTexture("ice1.jpg")
ScaleTexture tex1, 50,50
EntityTexture maze, tex1

;destination uncone...
Global cone=CreateCone()
PositionEntity cone, -407, 15, -16.5
EntityColor cone, 255,0,0
ScaleEntity cone, 5,5,5
EntityType maze, type_obstacle
EntityRadius maze, 0.1

; set up the rings

Type ring
	Field entity
	Field size ; use this for distance checking
End Type

For loop = 0 To 100
	r.ring = New ring
		r\entity = LoadMesh("ring1.3ds")
		r\size = 0.3
		ScaleEntity r\entity, 0.05, 0.05, 0.05
		PositionEntity r\entity, Rand(-500,500), 3, Rand(-500,500)
		EntityColor r\entity, 255,255,26
		
		EntityType r\entity, type_ring
		EntityRadius r\entity, 0.3
Next

; Set up the penguins

Type penguin
	Field entity
End Type

For loop = 0 To 100
	p.penguin = New penguin
		p\entity = LoadMesh("penguin.3ds")

		ScaleEntity p\entity, 0.05, 0.05, 0.05
		PositionEntity p\entity, Rand(-500,500), 3, Rand(-500,500)
		EntityColor p\entity, 95,95,95
		RotateEntity p\entity,0,-80,0
		
		EntityType p\entity, type_penguin
		EntityRadius p\entity, 1
Next

Global end_image = LoadImage("ice_end.bmp")
Global pause = LoadImage ("ice_pause.bmp")


;collisions
Collisions type_player, type_obstacle,2,1

Collisions type_player,type_sphere,2,1

Collisions type_sphere,type_player,2,1

Collisions type_player, type_ring,2,1 

;Collisions type_ring, type_player,2,1 ; no need to set up this collision boths ways, since the rings don't move.

;the timer and other variables
Global starttime=MilliSecs()
Global crash = 0
Global score = 0
Global velocity# = 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;makes game run
While Not KeyDown(1)

	If KeyDown (72)=True Then velocity#=velocity#+0.02
	If KeyDown (76)=True Then velocity#=velocity#-0.02
	If KeyDown (77)=True Then TurnEntity camera, 0,-1,0
	If KeyDown (75)=True Then TurnEntity camera, 0,1,0
	MoveEntity camera, 0,0,velocity#

	;pausing
	If KeyDown(25) Then 
		Cls
		DrawImage pause,0,0
		Flip
		WaitKey()	
	EndIf

	If KeyHit(57) Then PlaySound sound

	move_penguins()
	check_ring_collisions()
	check_penguin_collisions()
	
	If timeleft < 0 Or crash = 1 Then 
		end_game()
	End If

	UpdateWorld
	RenderWorld

	;the time
	CurrentTime = MilliSecs() 
	timeleft= 240000 - ((CurrentTime - starttime))
	Text 800,10,"Time Remaining: "+TimeLeft /1000

	Flip
Wend
End

Function welcome()
	Graphics 1024, 768
	screen=LoadImage("ice_escape1.bmp")
	DrawImage screen, 0,0
	While Not KeyDown(1)
	
		If KeyDown(28) Then Return
		If KeyDown(57) Then Return 
		
	Wend
	
End Function

Function end_game()
 
    Cls
	Graphics 1024,768  
	DrawImage end_image,0,0
    Flip
	; keep repeating until one of the keys is pressed below.
    Repeat
	    WaitKey()
		If KeyHit (57) Then Goto start
	Until KeyHit(1) Or KeyHit(28)
	End
	
  
 
End Function

; move the penguins randomly.
Function move_penguins()

	For p.penguin = Each penguin
	
		MoveEntity p\entity, Rnd(-0.5,0.5), 0, Rnd(-1.2,1.2)
		
	Next
	
End Function

; Use distance checking, instead of blitz collisions. Quicker i say :o) And cleaner.
Function check_ring_collisions()

	For r.ring = Each ring
	
		If EntityDistance#(camera,r\entity) < r\size Then
		
			FreeEntity r\entity
			Delete r.ring
			score = score + 1
			
		End If
		
	Next
	
End Function

Function check_penguin_collisions()

	Local temp_entity = EntityCollided(camera,type_penguin)

	If temp_entity > 0 Then ; if you have touched a penguin, then
	
		crash = 1 ; set the crash variable.
		
	End If
	
End Function




olo(Posted 2008) [#12]
thanks so much, it works now. i really appreciate you writing so much to help me. Thanks again, Olo


Ross C(Posted 2008) [#13]
No worries man :o)


olo(Posted 2008) [#14]
------------------------------------------------------------

i have got everything how i wanted it to be and everything is great (thanks to Ross) but i would like to add one more thing to my "game".

Right now whenever i touch the wall or a 'penguin' then i automatically lose. I would like to add some "lives" for the player so that he can hit the wall severall times before he loses.

here is the code but it doesnt work :(..please correct the mistakes

crash=5
If timeleft < 0 Or crash=0 Then 
     Cls
Graphics 1024,768  
End=LoadImage ("ice_end.bmp")
     DrawImage End,0,0
     Flip
     WaitKey() 
     If KeyDown(1) Or (57) Or (28) Then End
     If KeyHit (57) Then Goto start
     EndIf

If EntityCollided (camera, type_sphere) > 0 Then
            sphere=CollisionEntity (camera,1)    				
crash=crash-1
EndIf

If EntityCollided (camera, type_obstacle) > 0 Then
		wall=CollisionEntity (camera,1)
	crash=crash-1
EndIf


and here i display the amount of lives left, so that the player can see how many times he can touch the wall or 'penguin' again:
Text 450,10, "Lives Left: "+crash



So the problem is that whenever i touch the wall or penguin, the amount of lives goes down by 1. The bad thing is that when i move away from the object, my amount of lives go back up. :(

please help...anyone


olo(Posted 2008) [#15]
here is an example i made which is basically the same problem- I would like that when the sphere touches the cube the life goes down by one and stays that way.
PLEASE TRY THIS YOURSELF BY COPYING THIS CODE TO YOUR B3D

---use the left and right arrow keys to move sphere---

Graphics3D 800,600

  type_cube=1
  type_sphere=2

  SetBuffer BackBuffer()

  camera=CreateCamera()
  CameraViewport camera,0,0,800,600
  PositionEntity camera,0,0,-5

  light=CreateLight()

  cube=CreateCube()
  PositionEntity cube,-5,0,5
  EntityColor cube,70,80,190
  EntityType cube,type_cube

  sphere=CreateSphere(12)
  PositionEntity sphere,5,0,5
  EntityColor sphere,170,80,90
  EntityType sphere,type_sphere

  Collisions type_sphere,type_cube,3,1

  While Not KeyHit(1)

If KeyDown(205)=True Then MoveEntity sphere, 0.5,0,0
If KeyDown(203)=True Then MoveEntity sphere, -0.5,0,0

lives=5
 	
If EntityCollided(sphere,type_cube)> 0 Then
 		ball=CollisionEntity (sphere, 1) 
	lives=lives-1
EndIf

 UpdateWorld
  RenderWorld

  

  Text 335,500,"Lives Left: "+lives
  Flip

  Wend

  End



mtnhome3d(Posted 2008) [#16]
remove lives=5 from your loop and put where you load your camera and such. currently you are reseting lives to 5 every time the code gets to that point and then you are subtracting from that.


olo(Posted 2008) [#17]
Thanks so much man, :D I have been trying for ages


KillerX(Posted 2008) [#18]
You Should Replace
For loop = 0 To 100
	p.penguin = New penguin
		p\entity = LoadMesh("penguin.3ds")

		ScaleEntity p\entity, 0.05, 0.05, 0.05
		PositionEntity p\entity, Rand(-500,500), 3, Rand(-500,500)
		EntityColor p\entity, 95,95,95
		RotateEntity p\entity,0,-80,0
		
		EntityType p\entity, type_penguin
		EntityRadius p\entity, 1
Next


with

Penguin = LoadMesh("penguin.3ds")

		ScaleEntity Penguin, 0.05, 0.05, 0.05

		EntityColor Penguin, 95,95,95
		RotateEntity Penguin,0,-80,0
		
		EntityType Penguin, type_penguin
		EntityRadius Penguin, 1

For loop = 0 To 100
	p.penguin = New penguin
	
p\entity = CopyEntity(penguin)
PositionEntity p\entity, Rand(-500,500), 3, Rand(-500,500)
Next
FreeEntity Penguin

It will run faster.


olo(Posted 2008) [#19]
oh thanks, my game was starting to get a bit slow..thanks again :D


Ross C(Posted 2008) [#20]
Yep sorry, bad programming on my part there! Copyentity is a dam sight faster! Good spot.