LibGDX - 地图边界

时间:2015-12-19 21:46:37

标签: java libgdx collision-detection

概要

好吧,我正在制作一个自上而下的JRPG,今天我就像'是的,我要破坏整个地图碰撞的事情!'。我失败了。

问题

所以我上网并查看了'LibGDX平铺地图碰撞检测'并找到了一个关于地图对象的really neat post,所以我添加了一个地图对象层并做了所有这些商业并且用这个小方法出来了确保玩家可以在地图上自由移动,但同时也无法退出,但每次我尝试时最终都会产生可怕的结果,例如玩家离开屏幕。最新的错误是玩家在步行动画时卡住而无法移动到其他地方!

代码

package com.darkbyte.games.tfa.game.entity.entities;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.math.Rectangle;
import com.darkbyte.games.tfa.game.entity.Entity;
import com.darkbyte.games.tfa.game.entity.SpriteSheet;
import com.darkbyte.games.tfa.game.world.map.MapManager;
import com.darkbyte.games.tfa.render.Batch;
import com.darkbyte.games.tfa.render.Camera;

public class Player extends Entity {

    // The constructor for the player class
    public Player(String name, SpriteSheet spriteSheet) {
        super(name, spriteSheet);
        direction = Direction.DOWN;
        collisionBox = new Rectangle(x, y, 64, 64);
    }

    // A flag to see if the player is moving
    private boolean isMoving;
    // The variable that holds the state time
    private float stateTime;

    // The player's walking animations
    private Animation[] walkAnimations = {
            spriteSheet.getAnimation(8, 8, 1 / 16f),
            spriteSheet.getAnimation(9, 8, 1 / 16f),
            spriteSheet.getAnimation(10, 8, 1 / 16f),
            spriteSheet.getAnimation(11, 8, 1 / 16f) };
    // The player's static frames
    private TextureRegion[] staticFrames = {
            spriteSheet.getTexture(8, 0),
            spriteSheet.getTexture(9, 0),
            spriteSheet.getTexture(10, 0),
            spriteSheet.getTexture(11, 0) };

    // The render code for the player
    @Override
    public void render() {
        // Makes the camera follow the player
        Camera.setCameraPosition(x, y);
        Batch.getGameBatch().setProjectionMatrix(Camera.getCamera().combined);

        // Updates the state time
        stateTime += Gdx.graphics.getDeltaTime();

        // Gets the player's direction, if the player's moving, it sets the
        // current frame to the frame that would be played at the current moment
        // based on the state time
        // If the player isn't moving, it sets the current frame to the static
        // frame associated to the direction
        switch (direction) {
        case UP:
            if(isMoving) {
                currentFrame = walkAnimations[0].getKeyFrame(stateTime, true);
            } else
                currentFrame = staticFrames[0];
            break;
        case LEFT:
            if(isMoving) {
                currentFrame = walkAnimations[1].getKeyFrame(stateTime, true);
            } else
                currentFrame = staticFrames[1];
            break;
        case DOWN:
            if(isMoving) {
                currentFrame = walkAnimations[2].getKeyFrame(stateTime, true);
            } else
                currentFrame = staticFrames[2];
            break;
        case RIGHT:
            if(isMoving) {
                currentFrame = walkAnimations[3].getKeyFrame(stateTime, true);
            } else
                currentFrame = staticFrames[3];
            break;
        }
    }

    // The tick code for the player
    @Override
    public void tick() {
        // The object to represent the bounds of the land on the map
        RectangleMapObject land = (RectangleMapObject) MapManager.getCurrentMap().getMap().getLayers().get("collision").getObjects().get("land");

        // Checks if the player is within the bounds of the map
        if(land.getRectangle().contains(collisionBox)) {
            // If the player is moving but the arrow keys aren't pressed, sets isMoving to false
            isMoving = (isMoving && (Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)
                    || Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)
                    || Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)
                    || Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)));

            // Checks to see if the arrow / WASD keys are pressed and moves the
            // player in the correct direction at the speed of 1.5 pixels/tick
            // (45/second)
            // It also sets the players state to moving and corresponds it's
            // direction to the key pressed
            // Doesn't move if opposing keys are pressed
            if(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)) {
                if(!(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN))) {
                    direction = Direction.UP;
                    y += 1.5f;
                    isMoving = true;
                }
            }

            if(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)) {
                if(!(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT))) {
                    direction = Direction.LEFT;
                    isMoving = true;
                    x -= 1.5f;
                }
            }

            if(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)) {
                if(!(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP))) {
                    direction = Direction.DOWN;
                    y -= 1.5f;
                    isMoving = true;
                }
            }

            if(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)) {
                if(!(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT))) {
                    direction = Direction.RIGHT;
                    x += 1.5f;
                    isMoving = true;
                }
            }
        } else {
            if(!isMoving) {
                // If the player's just spawned puts the player to the map's spawn point
                x = MapManager.getCurrentMap().getPlayerSpawnX();
                y = MapManager.getCurrentMap().getPlayerSpawnY();
            } else { // If not, it just moves them back till they're no longer out of the map
                if(x > (land.getRectangle().getX() + land.getRectangle().getWidth())) x -= 1.5;
                if(y > (land.getRectangle().getY() + land.getRectangle().getHeight())) y -= 1.5;
            }
        }

        // Synchronises the collision box with the player's x and y position
        collisionBox.x = x;
        collisionBox.y = y;
    }

    // Returns if the player is moving
    public boolean isMoving() {
        return isMoving;
    }
}

你们可以做到这一点,当他到达他停止的边境时,他仍然可以继续向其他方向移动而不是保持静止!

感谢阅读!

1 个答案:

答案 0 :(得分:0)

此刻听起来你只是复制/粘贴它,你需要先熟悉它。如果您不知道它的作用,那么您应该学习或停止项目imho。

无论如何,据我所知,它只是一个根据移动方向处理动画帧的玩家类。完全没有与碰撞检测有关。它确实更新了某种collisionBox,但是其他功能是在其他地方处理的,可能是在父类实体中?

我的猜测是这是一个平铺图,单位仅限于网格。检测瓷砖是否存在非常容易。

private boolean tileExists(int tileX, int tileY, tile[][] map)
{
  return tileX >= 0 && tileY >= 0 &&
    tileX < map.length && tileY < map[0].length;
}

现在每当实体请求移动时,您应检查目标是否在地图范围内。

private void moveRequest(int destinationX, int destinationY, Tile[][] map)
{
  //Just return if the tile is outside of the map
  if (!tileExists(destinationX, destinationY, map) return;
  //Same goes for your other checks...
  //Return if the tile is not walkable
  if (!tileIsWalkable(destinationX, destinationY, map) return;
  //Return if the tile is already occupied
  if (tileIsOccupied(destinationX, destinationY, otherEntities) return;
  //etc..  
  //Now the move is valid and you can set it's state to moving in that direction.
}

瓷砖地图不是很难理解。我将尝试让您更好地了解瓷砖地图。你有一个2D数组,你可以在其中存储你的瓷砖。瓷砖有宽度和高度,你可以自己制作瓷砖引擎:

    //Find out which tiles to draw based on the camera position and viewport size.
    int startX = (int)(camera.position.x - camera.viewportWidth / 2) / tileWidth;
    int startY = (int)(camera.position.y - camera.viewportHeight / 2) / tileHeight;
    int endX = (int)(startX + camera.viewportWidth / tileWidth) + 1;
    int endY = (int)(startY + camera.viewportHeight / tileHeight) + 1;

    //Loop using this data as boundaries 
    for (int y = startY; y < endY; y++)
    {
        for (int x = startX; x < endX; x++)
        {
            //If out of bounds continue to next tile.
            if (!tileExists(x, y, map) continue;
            //Now all we need to draw the on screen tiles properly:
            //x == tile position x in array
            //y == tile position y in array
            //World position of this tile:
            //worldX = x * tileWidth;
            //worldY = y * tileHeight;
            //Let's draw:
            batch.draw(map[x][y].getTexture, worldX, worldY,
             tileWidth, tileHeight)
        }
    }

这里根本没有任何魔法。仅绘制屏幕上的内容,如上例所示,对于较大的地图非常重要。除此之外,你应该首先在后面画东西。你有几种方法可以做到这一点,最容易但功能最少的只是与物体分开的地面,可以遮挡东西并在以后画出来。

角色,生物或其他实体可以使用世界位置并轻松转换回平铺位置。

tileX = worldX / tileWidth;
tileY = worldY / tileHeight;

因此,如果您想移动具有世界位置的东西,首先使用上述方法计算它的平铺位置。然后查找此图块是否有效移动到。然后阻止该瓷砖用于其他瓷砖并移动到它。