Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1075929 Posts in 44152 Topics- by 36119 Members - Latest Member: Royalhandstudios

December 29, 2014, 04:03:16 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)Determine bounce with tiles
Pages: [1]
Print
Author Topic: Determine bounce with tiles  (Read 857 times)
FTLRalph
Level 0
***


What?


View Profile WWW Email
« on: September 16, 2013, 03:49:51 PM »

Hey guys, running into an issue here.

I have a map made of tiles, each tile is either a full wall or not (for the time being).  I also have a free-moving object.

To detect if this free-moving object is hitting a wall, I simply check the center point, for example:

Code:
if (isWall(x + originX, y + originY) == true)
// is in a wall tile

Now here's my issue.  How can I figure out how to accurately "bounce" the object off of any given tile when all I have is if the current x, y position is or is not in a wall tile?

For example, if the object is going straight up and collides with a wall tile I want it to bounce and start moving down.  But if the object is moving diagonally northwest and enters a wall, how do I know whether to bounce the object off to the south or to the east?

I figure you all know what bouncing looks like, but here's an image.

I feel like I might need to mess around with detecting the collision normals and applying them to the object's velocity somehow, but I'm not sure how.

Any help appreciated, thanks!
Logged

Gregg Williams
Level 10
*****


Retromite code daemon


View Profile WWW Email
« Reply #1 on: September 16, 2013, 04:06:57 PM »

I'd probably switch to polygon based collision. However you could also probably just do what tons of racing games use to do. Have multiple sensor bars coming off your objects and based on which ones hit the tile is the direction you bounce. Games like Super Sprint used techniques like this to handle reflecting off the race course walls correctly. Although those objects usually only had 16 or 32 angles in which they moved at.
Logged

Saishy
Level 0
**



View Profile WWW
« Reply #2 on: September 18, 2013, 06:08:04 AM »

If your walls can only be in a X or Y vector direction. (Meaning that no walls are diagonally)
You can simply revert the X and Y components of a vector for a simply reflection.

Velocity.X = -Velocity.X;
Velocity.Y = -Velocity.Y;

It doesn't really matter the angle which the object collides as long as the walls are only horizontally or vertically aligned.
Logged

A Certain Programmer  Programming for non-fiction
Noogai03
Level 6
*


WHOOPWHOOPWHOOPWHOOP


View Profile WWW Email
« Reply #3 on: September 18, 2013, 08:59:10 AM »

Saishy's method works, except you need to make sure you only flip the correct axis. One way to do this is check for collision separately on each axis and only reverse velocity on the one with collisions
Logged

So long and thanks for all the pi
Qqwy
Level 1
*


To who might ever read this: I love you!


View Profile WWW
« Reply #4 on: September 19, 2013, 09:54:23 PM »

Assuming you want your bouncing object to move freely, and not in full-tile steps, I would do something similar to what follows:



Code:
if(collidesWithTile(obj.x+velocity.x, obj.y, obj.width, obj.height){
velocity.x = -velocity.x;
}

if(collidesWithTile(obj.x, obj.y+velocity.y, obj.width, obj.height){
velocity.y = -velocity.y;
}


Now the collision function itself might be slightly harder to construct. The easiest would be to enter all the tiles you create in a big array, and through it checking against each of the tile's positions and sizes:

Code:
function collideWithTile(objx, objy, objwidth, objheight){
    var collides = false;
    foreach(tiles as tile){
        if(objx+objwidth > tile.x &&
           objx < tile.x+tile.width &&
           objy+objheight > tile.y &&
           objy < tile.y+tile.height){
              collides = true;
        }
    }
    return collides;
}



This is fine when using small tilemaps, but when using many tiles it might slow the game down significantly. If that's the case, you could use optimization techniques like QuadTrees to improve the speed.


Logged



Ř̺͈̮ͬͣ͑͂͊̐a̲͈̲̩̫͍̟̕i̪̪̩̼̩̊̽ͫn̴b̗̠͈̯̲͡ͅo̥̤͓̥̩̾͐ẅ̺́͢ ̴̙̑̍̅o̰̹͙̻̭̘̅͌͐̾ͅf̖̖͖͍̽̅̉͡ ͓̱͓͔̖̣̗ͭC̽҉̗̼̳̖͇̳h̺͕͠a̵̾ͤ͆́́o̼̙͖͎͍̳̅̿ͣs͓̒̌̀  FOCUS-Bytebeat
Quarry
Level 10
*****



View Profile WWW
« Reply #5 on: September 21, 2013, 04:59:56 AM »

Code:
function collideWithTile(objx, objy, objwidth, objheight){
    var collides = false;
    foreach(tiles as tile){
        if(objx+objwidth > tile.x &&
           objx < tile.x+tile.width &&
           objy+objheight > tile.y &&
           objy < tile.y+tile.height){
              collides = true;
        }
    }
    return collides;
}
is pretty dumb so do this
Code:
function collideWithTile(objx, objy, objwidth, objheight){
    foreach(tiles as tile){
        if(objx+objwidth > tile.x &&
           objx < tile.x+tile.width &&
           objy+objheight > tile.y &&
           objy < tile.y+tile.height){
              return true;
        }
    }
    return false;
}
Logged

 
Wilson Saunders
Level 5
*****


Nobody suspects the hamster


View Profile WWW
« Reply #6 on: September 23, 2013, 02:03:42 PM »

To expand upon Gregg Williams's suggestion of using "sensor bars" here is a little code of how I would implement an Break out style bouncing dynamic which is what I think the OP is asking for:

Code:
function ReactWithBrick(Ball myBall, Brick myBrick){
  if(myBrick.IsInside(myBall.x - myBall.radius, myBall.y) && myBall.dx < 0){
    myBall.dx = -1*myBall.dx;
  }
  if(myBrick.IsInside(myBall.x + myBall.radius, myBall.y) && myBall.dx > 0){
    myBall.dx = -1*myBall.dx;
  }
  if(myBrick.IsInside(myBall.x, myBall.y - myBall.radius) && myBall.dy < 0){
    myBall.dy = -1*myBall.dy;
  }
  if(myBrick.IsInside(myBall.x, myBall.y + myBall.radius) && myBall.dy > 0){
    myBall.dy = -1*myBall.dy;
  }
}
Logged

Play my games at http://monkeydev.com/
Qqwy
Level 1
*


To who might ever read this: I love you!


View Profile WWW
« Reply #7 on: September 24, 2013, 12:00:35 PM »

@Quarry, thank you for correcting. I wrote that code very late at night. Indeed, not returning when a positive result is found would be dumb, since it is wastes performance time.
Thanks!
Logged



Ř̺͈̮ͬͣ͑͂͊̐a̲͈̲̩̫͍̟̕i̪̪̩̼̩̊̽ͫn̴b̗̠͈̯̲͡ͅo̥̤͓̥̩̾͐ẅ̺́͢ ̴̙̑̍̅o̰̹͙̻̭̘̅͌͐̾ͅf̖̖͖͍̽̅̉͡ ͓̱͓͔̖̣̗ͭC̽҉̗̼̳̖͇̳h̺͕͠a̵̾ͤ͆́́o̼̙͖͎͍̳̅̿ͣs͓̒̌̀  FOCUS-Bytebeat
z84c00
Level 0
***


View Profile
« Reply #8 on: September 26, 2013, 08:15:22 AM »

Actually, if you make your tiles uniform ( i.e. 16x8 or something like that ) you don't even have to step through all your tiles and it just becomes a loopup into a 2d array.

Just a thought :-)

-Z8
Logged
TheHermit
Level 0
**



View Profile WWW Email
« Reply #9 on: September 27, 2013, 05:44:32 AM »

Conceptually there are eight cases that can occur if you're bouncing a circular object off of a rectangular one. Four of those are 'object hits one of the flat walls', and the other four are 'object hits a corner'. Doing the collision with the corners is probably not necessary unless you're going for a game with precise physics that really matter to the game (like pool). However, if you want to do corner collisions, here's how:

- First, check if the bounding box of your object overlaps with the tile. If not, no collision.
- If the bounding box overlaps, check for each wall whether the center of your moving object is directly above the wall and whether that center is closer to the wall than the object's radius. For example, a tile whose extents are from (tx,ty) to (tx+w, ty+h) colliding with an object whose coordinates are (x,y) with radius r:

Code:
if ( (x>=tx)&&(x<=tx+w)&&(y+r<ty+h)&&(y+r>ty) )
   // collision with top wall
...

- If you have not collided with any of the flat segments, check the distance between your object center and all of the vertices at the corners of the tiles. If this is <= r, you have a corner collision. For a corner collision, you have some vector N = (x-cx, y-cy) where cx and cy are the coordinates of the corner. You want to update your velocity like so:

v' = v-2*(N dot v)*N / |N|^2

If you want an inelastic collision, replace 2 with (1-E), where E=0 is totally inelastic and epsilon=1 is E.

There's a bit of a subtle point to the corner collisions - you want to exclude vertices where two solid tiles meet, or you can get weird bounces at the tile intersections depending on the order you evaluate collisions in.


All of this is complicated by the fact that for finite timestep size, your object will slightly overlap the tile when you're determining collision, which can cause things like 'teleporting through a corner' or getting stuck inside the tile due to the collision code assigning a velocity insufficient to cause your object to exit the tile by the next frame.

Generally what I do is I not only invert the velocity along the normal (e.g. vx -> -vx for hitting the left/right sides of a tile) but I also re-position the object so its 'just touching'. That way I guarantee that it won't collide again next frame. This is especially important if you want the collisions to lose a bit of energy (so you do vx -> -0.9*vx, for example), since if you don't do this you're guaranteed to get 'trapped' in the tile.

Logged

Urban Hermit Games

Games: Travelogue, Rebound Recon, Heat Sink
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic