• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Need suggestions on this glitch in my game

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I'm having issues with players bouncing on the world bounds. Basically the first function "isInsideWorld" checks if a object is still inside worldBounds and returns a pointer to which side its colliding with. The second function "handleWallCollision" resolves the collision and inverts the direction that the object is moving. This works for all cases except for corners where the object simply disapears through the world bounds. And I'm not sure how to go about solving it, any pointers?

JASS:
bool isInsideWorld(struct Object* o, int *side)
{
    int w = o->w / 2;
    int h = o->h / 2;
    int x = o->center_x;
    int y = o->center_y;
    int window_w = getWindowWidth();
    int window_h = getWindowHeight();
    int topX = x - w;
    int topY = y - h;
    int botX = x + w;
    int botY = y + h;
    bool isInside = true;
    isInside = (topX > 0 && topY > 0 && botX < window_w && botY < window_h);
    if (isInside == false)
    {
        if (x > window_w - 30) {
            *side = WORLD_RIGHT;
        }
        else if (x < 30) {
            *side = WORLD_LEFT;
        }
        else if (y > window_h - 40) {
            *side = WORLD_BOT;
        }
        else if (y < 40) {
            *side = WORLD_TOP;
        }
    }
    return isInside;
}

void handleWallCollision(int i, int side)
{
    if (side == WORLD_TOP) {
        object[i].delta_y = object[i].delta_y *-1;
        object[i].speed_y = object[i].speed_y *-1;
    }
    if (side == WORLD_BOT) {
        object[i].delta_y = object[i].delta_y *-1;
        object[i].speed_y = object[i].speed_y *-1;
    }
    if (side == WORLD_LEFT) {
        object[i].delta_x = object[i].delta_x *-1;
        object[i].speed_x = object[i].speed_x *-1;
    }
    if (side == WORLD_RIGHT) {
        object[i].delta_x = object[i].delta_x *-1;
        object[i].speed_x = object[i].speed_x *-1;
    }
    object_move(&object[i]);
}
 
Level 29
Joined
Jul 29, 2007
Messages
5,174
To answer your question, I'd use a bit flag instead, e.g. first bit is left, second bit top, etc.
In fact, I'd not even use a pointer, but rather return it instead.
If flag != 0, collision occurs.

Do note, however, that you are assuming here that the object will immediately get out of the collision in the same frame.
In the case it doesn't, the object will keep inverting its velocity and never escape the bounds.

In general, collision detection and response is a huge and complicated subject.

And just to nitpick, why are you writing struct and generally writing C code when using C++? Also you can *= -1, it's shorter :p
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Yeah collision detection turned out to be a pain in the arse to make. I solved the issue with a dumb fix. But things can get stuck and with a client heavy application this might cause for units being out of sync on the other clients.
To stop this you need to make the game engine use a constant time tick period. If one client falls behind you can accelerate it to the last key frame by dropping the waits between frames. If the client never catches up (CPU too slow) then you have to slow the game tick rate for all clients.

This works for all cases except for corners where the object simply disapears through the world bounds. And I'm not sure how to go about solving it, any pointers?
You force the object velocity in a direction away from the wall. Assuming large y is top, small y is bottom, large x is right and small x is left (you might have y inverted).

C++:
void handleWallCollision(int i, int side)
{
    if (side == WORLD_TOP) {
        auto const speed = object[i].speed_y;
        if (speed > 0) {
            object[i].delta_y*= -1;
            object[i].speed_y*= -1;
        }
    }
    if (side == WORLD_BOT) {
        auto const speed = object[i].speed_y;
        if (speed < 0) {
            object[i].delta_y*= -1;
            object[i].speed_y*= -1;
        }
    }
    if (side == WORLD_LEFT) {
        auto const speed = object[i].speed_x;
        if (speed < 0) {
            object[i].delta_x*= -1;
            object[i].speed_x*= -1;
        }
    }
    if (side == WORLD_RIGHT) {
        auto const speed = object[i].speed_x;
        if (speed > 0) {
            object[i].delta_x*= -1;
            object[i].speed_x*= -1;
        }
    }
    object_move(&object[i]);
}

You might want to separate x and y collision. The above should work however there may be artefacts when exiting via corners as right and left take priority over bottom and top so it may go off top or bottom for a frame or so until x is back inside the world so y can get inverted. Either use flags like suggested above or separate the routine to deal with x and y boundary clamping separately.
 
Status
Not open for further replies.
Top