Fredbill30 wrote: |
---|
I'm still unsure how to do this. |
Yeah. It's tricky. I always had frustrations getting tile based collision to work the way I wanted. And in fact... I never did... which is why I stopped using it. Get ready for a wall of text.
One problem that nagged me was this one:
1 2 3 4 5 6 7 8
|
####
####
####..
####..
####
OO ####
OO ####
####
|
# = a wall tile
O = the rect of the object
. = the rect the object is moving to
As you can see if you allow for diagonal movement like this, it will not catch this collision. This is what's called "tunneling" ...ie, moving so fast you actually move through a wall. Another instance of this:
If you're falling fast enough, you can fall right through a thin floor.
One approach to solving this problem is to make your walls/objects bigger, and don't let the objects move so fast. But that's a very debilitating workaround, especially if you have sloped or "drop-thru" floors (where the floor could be literally 1 pixel thick in places).
Your problem is loosly related:
Here the 'X' indicates the object's new position and the wall overlap. Checking the new object position (the dot) in relationship to the wall position (the #) won't work because the object tunneled part way through the wall. If you were to eject based just on that position... you would eject left, causing the object to tunnel
all the way through the wall.
But in fact... desired behavior here is to eject right.
This problem is trivial
if you are only moving along one axis. The above problem has a clear solution:
1 2 3 4
|
##
.X#~~ OO
.X#~~ OO
##
|
# = wall
O = original object position
. = object attempted position
X = . overlapped with #
~ = object position after ejection
You can use the object's velocity to determine how far along the axis to push the object.
IE: if the object is moving left and you want to eject right, you'd set
object.left = wall.right
Or if the object is moving right and you want to eject left:
object.right = wall.left
However.. this approach utterly fails if you are moving along both X,Y axis. Such an example:
It's clear the ejection here is wrong... but according to the above logic it's doing exactly what it's supposed to. It sees a collision and it sees leftward movement, so it ejects right.
So what's the best way to solve it?
I don't know what the "best" way is... but I settled on something like the below to address both the ejection issue and the tunnelling issue.
#1 - forget about ejection. Rather than trying to push the object out of a wall... stop them from entering the wall in the first place.
#2 - move one axis at a time. This has its own problems... especially when the object is moving at high speeds... but it makes detecting wall collisions much easier.
#3 - check every tile along the path of the object's motion... not just the tile at their final destination. This is the only way to prevent tunnelling with tile-based collision.
From what I remember of my last implementation, I wrote 4 functions... one for moving in each direction. The functions would take a starting point and a destination point and step through all the tiles between those two points... and would figure out how far you could move in that direction until you hit a wall.
But that was a long time ago. The last project I did with tile based collision was such a nightmare that I left it forever.
Anyway I don't know if any of this helped. hahaha