tile collision
BlitzPlus Forums/BlitzPlus Beginners Area/tile collision
| ||
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 |
| ||
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 |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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 |
| ||
The accuracy is actually inverted the smaller it is the more accurate it is. |