tile collision

BlitzPlus Forums/BlitzPlus Beginners Area/tile collision

El Neil(Posted 2006) [#1]
hi guys and girls.

i'm making a game where a ball bounces off some platforms and walls. these surfaces are made using a tile map. there are tiles for the four corners and each of the sides, so i can make boxes of any size or shape.

the ball is affected by gravity and im trying to make it bounce off the surfaces on collision. the problem is that the surfaces are only 10 pixels thick and the ball can travel up to 15 pixels in every game "tick". this means that sometimes the ball passes straight through the surface instead of colliding.

also, this means that sometimes the ball gets stuck in the surfaces. for example, if the ball bounces onto the floor and the collision is detected in the middle of the floor instead of the edge (because of the glitch), the line of code

yspeed = (0 - yspeed)

reverses the direction of travel, but because gravity is affecting the ball, it gets stuck.

is there a better way to approach all this?

el neil


DjBigWorm(Posted 2006) [#2]
I had the same problem , I came up with a an idea. I have a low res screen and a pixel only to represent my palyer. the pixel is able to move 1 pixel or 100 pixels. and it is always stopped by only another pixel in the road. The way I approache this was remember where my pixel is at the begining of the main loop. Then, I figure out what direction I want to travel and count from the original location till i determined that another pixel was in the road. To maybe simplify this the pixel is a an x loction of 10. I press the right key to travel x+5. Once I know the I am gonna travel x+5. Another loop check for pixel color from my original location one at a time. If no other colors were detected along the way then x+5 is applied to my x value. Now say there is a white pixel in the way of my normal 5 movement speed. Then when it got to the third pixel the loop would return a 3. Making my pixel appear to be stopped by the solid wall no matter what speed I was going.
;Below might help you out.
.make a 320,240 image in black background and make obsticles in a white color to see this in action. play with the movement speed and it is always stopped with perfect collision detection:) Maybe impracticle idea, but it works!!


Graphics 320,240
back=LoadImage ("testscreen.bmp")
xloc=10
yloc=20
speed=2 ; the speed that we will travel at
.main
Repeat
time1 = MilliSecs() ;time at start of processing loop
;start code here
DrawBlock back,0,0
;choose a random color

;draw our dot

currxloc=xloc ; remember the old xlocation
curryloc=yloc
Gosub basic_controls

Color Rnd(255),Rnd(255),Rnd(255)
Plot xloc,yloc
;xloc is the new location
Text 0,0,"speed traveling="+(xloc-currxloc)

Flip
;this code must go at the very end of the loop
time2 = MilliSecs() ;time at end of processing loop
time3 = time2 - time1 ;number of miiliseconds to process loop
time4 = fRate - time3 ;number of milliseconds to delay each processing loop to achieve dynamically accurate framerate
If time4=>0
Delay time4 ;delay execution
EndIf
Until KeyDown(1) ; escape
End

.basic_controls
If KeyDown(205) ;right key
If xloc<320
xloc=xloc+speed
EndIf
EndIf

If KeyDown(203) ;left key
If xloc>0
xloc=xloc-speed
EndIf
EndIf

Gosub checkx_floor



If KeyDown(200) ;up key
If yloc>0
yloc=yloc-speed
EndIf
EndIf

If KeyDown(208) ;down key
If yloc<240
yloc=yloc+speed
EndIf
EndIf
Gosub checky_floor
Return

.checkx_floor ; this goes pixel at at time and sees if we have collided with the floor
;check floor left and right
dir=xloc-currxloc ; dir is letting us know what dir we are going.
counter=0 ; reset the location traveled
If dir>0 ; see if the location is positive if so then set the counter positive
counter=1
;Stop
EndIf
If dir<0 ; see if the location is negative if so then set counter negative
counter=-1
EndIf
; check to see if we have changed x location
If counter<>0 ; if there was a change in the x location
; starting from the old location count until we hit something or count past 10
xstart=currxloc ; this is the start location of where we are
leave=0
ll=0
Repeat
;read the color
GetColor xstart,yloc
If ColorRed ()=0 ; checks to see if we are on a color other than black
okxlocation=xstart
Else
diff=(okxlocation-xloc)
xloc=xloc+diff
;Stop
ll=1
EndIf
xstart=xstart+counter ; add a value to where we are
leave=leave+1
Until ll=1 Or leave=speed+1; ll=1 means we are ok to leave the loop
EndIf
Return
.checky_floor
dir=yloc-curryloc ; dir is letting us know what dir we are going.
counter=0 ; reset the location traveled
If dir>0 ; see if the location is positive if so then set the counter positive
counter=1
EndIf
If dir<0 ; see if the location is negative if so then set counter negative
counter=-1
EndIf
; check to see if we have changed x location
If counter<>0 ; if there was a change in the x location
; starting from the old location count until we hit something or count past 10
ystart=curryloc ; this is the start location of where we are
leave=0
ll=0
Repeat
;read the color
GetColor xloc,ystart
If ColorRed ()=0 ; checks to see if we are on a color other than black
okylocation=ystart
Else
diff=(okylocation-yloc)
yloc=yloc+diff
;Stop
ll=1
EndIf
ystart=ystart+counter ; add a value to where we are
leave=leave+1
Until ll=1 Or leave=speed+1; ll=1 means we are ok to leave the loop
EndIf
Return


Grey Alien(Posted 2006) [#3]
that approach of tracing a line is a good idea, plusI've seen a clever mathematical way to do the same thing before ...

Also you can increase your logic speed so ticks occur more frequently.


El Neil(Posted 2006) [#4]
cheers worm. i had your idea in mind before i posted, but the main reason i didnt do it straight away was that if the ball was 1 pixel away from the wall and moving at a speed of 15 then it would appear to slow down before it bounced. also, as my game is tiled in a 20 x 20 grid and the tiles are objects of type "tile", i have to check each tile in turn for a collision on each loop. there are 4 possible collision directions (up, down, left, right) for each tile, so thats already 1600 possible checks on each loop happening already. adding more checks (ie between the ball and the tiles before i move the ball) would just complicate things. there must be a quiker way of doing it (no offence).

i dont know :( i just wanna make some games.


whats the maths way of doing it then, alien?

thanks again worm.

neil


Grey Alien(Posted 2006) [#5]
sorry I don't know. I just know I saw it once. try posting in the general forum and someone might answer. Really it's to do with working out the line that the ball is travelling along (and speed) and where it intersects solid objects (using a foumula), plus also the time it hit can be worked out precisely.


Andres(Posted 2006) [#6]
Function MoveBall(accuracy# = 1.0)
	Local Distance# = GetDistance(0, 0, BallXSpeed, BallYSpeed)
	Local Angle# = GetAngle(0, 0, BallXSpeed, BallYSpeed)
	For i# = 0 To Distance# Step 0
		BallX = BallX + Cos(Angle#) * Distance# * accuracy#
		BallY = BallY + Cos(Angle#) * Distance# * accuracy#
		i = i + Distance# * accuracy#
		If Collided() Then Return False
	Next
	Return True
End Function

Function GetAngle#(basex, basey, targetx, targety)
	If targety>basey-1 Then
		angle=ACos((targetx-basex)/Sqr((targetx-basex)*(targetx-basex)+(targety-basey)*(targety-basey)))
	Else
		If targetx>basex-1 Then
			angle=270+90-ACos((targetx-basex)/Sqr((targetx-basex)*(targetx-basex)+(targety-basey)*(targety-basey)))
		Else
			angle=360-ACos((targetx-basex)/Sqr((targetx-basex)*(targetx-basex)+(targety-basey)*(targety-basey)))
		EndIf
	EndIf

	If targetx=basex And targety=basey Then Return 0 Else Return angle
End Function

Function GetDistance#(x1#, y1#, x2#, y2#)
	Return Sqr((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
End Function


function MoveBall(accuracy#) will move the ball and return true if no collision was detected else will be returned false.
accuracy# values can be in range of 0 - 1
function Collided() is missing so you'll have to write it yourself though you should already have it.


El Neil(Posted 2006) [#7]
blimey. thank you very much. ive kind of "bodged" it already so it works enough for now, but ill keep your code in case my efforts don't do the job. i basically detected a collision and moved the ball to the edge of the surface manually before drawing it again, giving the illusion that it bounced. i have also limited the speed so the ball can't pass through the wall in one "tick". it should be enough to do what i want but i will probably need your code for next time.

thank you again andres,

neil


Andres(Posted 2006) [#8]
The accuracy is actually inverted the smaller it is the more accurate it is.