Hey, guys I've got a question that I can't seem to find any info on, so heres hoping someone here can point me in the right direction.
I've got a tile engine game and I'm struggling with how to controll the players movement.
when I move the character left, right, up or down it behaves fine. I check all the tiles along the leading eadge of the characters bounding box and check to see if he's move into any solid areas. if he has then I back him up to the very edge.
Now this works fine for the 4 cardinal directions, but whenever I have a velocity that is off the axis (for example velocity.x = 12 and velocity.y = 10) then I start running into strange glitches.
I've tried using axis projection to back the character out of the collision appropriately but then the character jumps along edges or sometimes skips right through them...
the problem comes from the fact that a character can sometimes collide with 2 or more tiles and the projection vectors that back the character out of collision don't match (obviously)
any one have any advice as to how I should handle this or where I can find some info that might help?
Heres the code for the collision detection in case you're wondering
POINT level::move(LPOBJ o) {
RECT objPos;
int txStart, txEnd;
int tyStart, tyEnd;
int tx; // tilemap xposition
int ty;
int tv; // tilemap attribute value
POINT newVel;
bool collision = false;
objPos = o->getBoundingBox();
objPos.left += o->m_velocity.x;
objPos.right += o->m_velocity.x;
objPos.top += o->m_velocity.y;
objPos.bottom += o->m_velocity.y;
txStart = objPos.left / m_tileWidth; // tilemap start position
txEnd = objPos.right / m_tileWidth; // tilemap end position
tyStart = objPos.top / m_tileHeight; // tilemap start position
tyEnd = objPos.bottom / m_tileHeight; // tilemap end position
newVel.x = o->m_velocity.x;
newVel.y = o->m_velocity.y;
//
// check the horizontal edges
//
if (o->m_velocity.y < 0) {
for (tx=txStart; tx <= txEnd; tx++) {
// check top row
tv = m_layer[0].tilemap[tyStart * m_layer[0].max_tile_x + tx];
if (tv & SOLID_BIT) {
newVel.y += (tyStart * m_tileHeight + m_tileHeight) - objPos.top;
collision = true;
g_Error.write("\ntop collision!");
break;
}
}
}
else if (o->m_velocity.y > 0) {
for (tx=txStart; tx <= txEnd; tx++) {
// check bottom row
tv = m_layer[0].tilemap[tyEnd * m_layer[0].max_tile_x + tx];
if (tv & SOLID_BIT) {
newVel.y -= objPos.bottom - (tyEnd * m_tileHeight - 1);
g_Error.write("\nbottom collision!");
collision = true;
break;
}
}
}
if (o->m_velocity.x < 0) {
for (ty=tyStart; ty <= tyEnd; ty++) {
// check top row
tv = m_layer[0].tilemap[ty * m_layer[0].max_tile_x + txStart];
if (tv & SOLID_BIT) {
newVel.x += (txStart * m_tileWidth + m_tileWidth) - objPos.left;
g_Error.write("\nleft collision!");
collision = true;
break;
}
}
}
else if (o->m_velocity.x > 0) {
for (ty=tyStart; ty <= tyEnd; ty++) {
// check bottom row
tv = m_layer[0].tilemap[ty * m_layer[0].max_tile_x + txEnd];
if (tv & SOLID_BIT) {
newVel.x -= objPos.right - (txEnd * m_tileWidth - 1);
g_Error.write("\nright collision!");
collision = true;
break;
}
}
}
if (collision) {
if (abs(newVel.x) < abs(newVel.y)) {
newVel.y = 0;
}
else {
newVel.x = 0;
}
}
else
g_Error.write("\nno collision!");
return newVel;
}
and heres the code that uses the collision
void PlayerTestMove(LPOBJ o) {
POINT v;
v.x = v.y = 0;
if (g_Input.getKey(DIK_LEFT))
v.x = -HORIZ;
if (g_Input.getKey(DIK_RIGHT))
v.x = HORIZ;
if (g_Input.getKey(DIK_UP))
v.y = -VERT;
if (g_Input.getKey(DIK_DOWN))
v.y = VERT;
o->setVelocity(v);
POINT nv = g_Level->move(o);
o->setVelocity(nv);
o->updatePosition();
}