Added a couple files

This commit is contained in:
Kayne Ruse
2014-12-27 04:02:08 +11:00
parent 8f4cc1c28f
commit 7e2f6a2835
+125
View File
@@ -0,0 +1,125 @@
Abstract:
The goal of this pseudocode is to create a collision system that brings several
colliding bodies to a near-contact state (no space between the bodies, but not
overlapping), while preserving the motion of said bodies. For simplicity, I've
decided to use a square box (BoundingBox, or BBox for short) for the collidable
bodies.
Example:
My current game has a tiled-map, where the tiles are arranged on a 2D grid. The
tiles each have a flag indicating if they are solid (i.e. collidable) or not. I
also have characters walking around on these tile maps, that must not intersect
with solid tiles. For stylistic reasons, I want characters moving at an angle
to "slide" along these walls, and continue along with their original velocity
when they've circumvented the obstacles.
I'd also like to keep the possibility of non-grid collisions using this logic
open (for objects like trees, etc.) if the code allows it.
Obviously, there are many in depth issues that I will need to take into
account when writing this logic, that have been glossed over or omitted in this
article.
-------------------------
```
velocity = motion + speed
if (collision(position + velocity)) then
if (collision(position + {velocity.x, 0})) then
velocity.x = 0
end
if (collision(position + {0, velocity.y})) then
velocity.y = 0
end
end
position = position + velocity
```
This code is a basic outline for a collision system that preserves the object's
motion, but it still leaves several pixels of space between the bounding boxes.
Notably, it also treats "collision" as an abstract concept, rather than as an
event that could happen multiple times per frame.
-------------------------
```
velocity = motion + speed
if (collisionSimple(BOXSET, position + velocity)) then
velocity.x = collisionX(BOXSET, velocity.x)
velocity.y = collisionY(BOXSET, velocity.y)
end
position = position + velocity
```
Here, collisions are still abstract, but "BOXSET" is defined externally
(probably as a set of solid boxes, and their positions). This does require more
in depth calculations, as well as three specialized utility functions, but the
results might be what I'm looking for.
If there are any collisions between the player object and the given box set,
then collisionX() and collisionY() are called to calculate the new distance
that the character will move.
-------------------------
```
bool collisionSimple(BOXSET, newPos):
for_each box in BOXSET do
if (box.overlap(PLAYER.box + newPos)) then
return true
end
end
return false
end
```
collisionSimple() first runs through the BOXSET, checking if any of the given
bounding boxes would collide with the player object's new position (just
pretend PLAYER is accessible). In this case, non-tile bounding boxes can be
included as part of BOXSET; they're treated just the same. The optimal outcome
is that there are no collisions.
A possible, but flawed, optimization that could be preformed here is to remove
any elements from BOXSET that do not collide with newPos, and let the other
utility functions operate only on what remains. However, if there are any
collisions, than newPos is not the algorithm's final result, therefore any
final result that the algorithm would calculate based on the remaining elements
would not have been checked against the removed elements.
Just something to note.
-------------------------
```
var collisionX(BOXSET, velocityX):
var ret = velocityX
for_each box in BOXSET do
if (box.overlap(PLAYER.box + PLAYER.position + {velocityX,0})) then
if (velocityX > 0) then
ret = min(ret, box.west - PLAYER.position.x)
else
ret = max(ret, box.east - PLAYER.position.x)
end
end
end
return ret
end
```
Two things: 1. collisionX() and collisionY() should be identical except for the
axis of operation and 2. if a player object is "sliding" along a wall (or
stuck), then these functions will be called every frame.
collisionX() and collisionY() check the sides of the elements in BOXSET, and if
there's a box that the player would collide with, given the current distance to
move, than the distance is reduced, based on if the character is moving left or
right (or up or down).
An unfortunate bug I can already see is that this logic doesn't check corners;
it might be possible to get stuck on a corner of a wall, but if this becomes an
issue in my implementation I will update this article with that information,
and you can promptly ignore it.