3
\$\begingroup\$

I'm making a RPG with libGDX. I've loaded a TiledMap and now I'm implementing the player movement. The view is top-down.

In my game I want two ways of input: one is using the ARROW keys to move the player. This implementation works pretty well, including collisions. The second one is a movement based in the mouse. When I click, then the player starts to follow the mouse pointer

 private void autoMove(float speed)
{
    //Start or stop moving
    if (Gdx.input.justTouched()) 
    {
        autoMoving = !autoMoving; 
    }

    //Start follow the mouse
    if (autoMoving)
    {
        //Get direction
        Vector3 point = this.getStage().getViewport().getCamera().unproject(new Vector3(Gdx.input.getX(),Gdx.input.getY(),0));
        dir = new Vector2(point.x - pos.x, point.y- pos.y);

        //Normalize
        dir.nor();

        //Set correct animation
        if (Math.abs(dir.x) <= 0.5)
        {
            if (dir.y >= 0)
            {
                lookingDirection = UP;
            }
            else
            {
                lookingDirection = DOWN;
            }

        }
        else
        {
            if (dir.x >= 0)
            {
                lookingDirection = RIGHT;
            }
            else
            {
                lookingDirection = LEFT;
            }
        }

        //Scale to speed and move
        dir.scl(speed);
        pos.add(dir);
    }

As you can see, I use global variable dirto store the direction of the player. Now I want to handle the collisions with this input. However, I'm not able to do this. I've tried, for example, using pos.add(dir.scl(-1.0f)) but doing this the player gets blocked in every direction. After that, I tried to make the same but blocking only x or y movement based on the lookingDirecion variable. However, player can be looking at right and move a bit upwards, to it's possible to "hack" the system and introduce the player inside the block. I tried with more complex if structures but they didn't worked at all.

The collision code looks like this, if it's useful.

public void checkBounds(float speed)
{
    for (int i=0; i < map.getWidthInTiles(); i++)
    {
        for (int j=0; j < map.getHeightInTiles(); j++)
        {
            //bound is player's rectangle. colBounds are map's impenetrable objects.
            if (bound.overlaps(map.colBounds[i][j]))
            {
                if (!autoMoving) //Control with ARROW keys
                {
                    if (lookingDirection == UP)
                    {
                        pos.y -= speed;
                    }
                    else if (lookingDirection == DOWN)
                    {
                        pos.y += speed;
                    }
                    else if (lookingDirection == RIGHT)
                    {
                        pos.x -= speed;
                    }
                    else if (lookingDirection == LEFT)
                    {
                        pos.x += speed;
                    }
                }
                else
                {
                    //MOUSE COLLISION DETECTION
                }
            }
        }
    }

The question is: how can I implement the collision detection for this kind of movement?

Thank you!

\$\endgroup\$
  • \$\begingroup\$ Have you considered using Box2D? It's always useful to use what readily available resources there are to achieve something rather than reinventing the wheel. \$\endgroup\$ – driima Jul 12 '15 at 13:53
  • \$\begingroup\$ Yes, I know that Box2D can manage collisions. However I'm not going to use physics in my game, I only want to handle collisions. I think that using a complete physics library only for that is a bit excessive. Or it isn't? \$\endgroup\$ – VictorSeven Jul 12 '15 at 14:17
  • \$\begingroup\$ I don't see why not. It's better to have something and not need it, than need something and not have it. That's just me though, but by the looks of it, your code will become harder to manage if and when you choose to expand it further. \$\endgroup\$ – driima Jul 12 '15 at 14:26
1
\$\begingroup\$

Collision detection shouldn't depend on input. You should aim to make your movement and collision systems as generic as possible.

Not only that but I'm seeing an issue with the logic that happens during your frame. You seem to be doing something along the lines of:

//Detect input

//Detect collision

//Move according to facing direction 

//Draw 

Correct me if I've made a mistake with that.

Usually the order of operations for a frame involving collision detection is:

//Detect input

//Move player (usually adding velocity to position)

//Detect collisions and return overlap between player and wall

//Move player back so it's no longer colliding

//Draw

Of course this isn't even as generic as it can get but it's relative to your problem.

During the DetectInput stage you should determine your velocity. If the player has clicked why not set a velocity that doesn't change unless the player clicks again or right clicks to stop. Otherwise just move the player if a key or keys are down in a certain direction. Then you can apply that velocity to position, detect collision and react.

If this is more involved than you want it to be I'd suggest using something like Box2D to handle the collision logic for you so you can just worry about getting your player walking around the way you want.

\$\endgroup\$
  • \$\begingroup\$ I'm using the second order you proposed. I move the player first and then I go back if it's colliding. In fact, the velocity of the player is always "speed", because I normalize the vector and then scale by speed -that's means that the new norm is always speed, just as you said. Everything you point is already implemented. The problem is that I'm not able to manage the collision when I move with the mouse because the character can be facing right but moving a bit upwards. Velocity is not of the form (vx,0) or (0,vy) but (vx,vy). And that's the problem. \$\endgroup\$ – VictorSeven Jul 15 '15 at 15:30
  • \$\begingroup\$ The direction of velocity shouldn't have anything to do with collision detection. During the frame if the character's AABB (axis aligned bounding box) collides with wall's AABB then you should move the character back. Right now you're relying on the player's velocity to react to the collision. Instead you should determine how much your character overlaps the wall when you detect collision and move back by that overlapping vector. \$\endgroup\$ – Honeybunch Jul 15 '15 at 16:44
  • \$\begingroup\$ Great, I understand. I'm basing my code on the speed, but you suggest to do it with the overlapping. Of course with the keys and only 4 directions both points of view are the same, but not when I use the mouse. I'll try that, thank you! \$\endgroup\$ – VictorSeven Jul 16 '15 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.