You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LibGDX RPG游戏:实现玩家触门+按空格切换屏幕求助

解决LibGDX中玩家接触门并按空格切换屏幕的问题

我来帮你搞定这个门的屏幕切换功能!你的现有代码已经有了Box2D接触监听的基础,但还需要补充跟踪玩家与门的接触状态和检测空格键输入的逻辑。下面是一步步的修改方案:

1. 修复接触监听器的字符串比较问题(重要!)

首先,你的WorldContactListener里用==比较字符串是错误的,Java中字符串相等要用equals(),而且要先判断userData不为null避免空指针。同时我们要添加代码跟踪玩家是否接触门:

public class WorldContactListener implements ContactListener {
    // 新增:跟踪玩家是否正在接触门
    private boolean isPlayerTouchingDoor = false;

    // 提供getter让外部访问状态
    public boolean isPlayerTouchingDoor() {
        return isPlayerTouchingDoor;
    }

    @Override
    public void beginContact(Contact contact) {
        Fixture fixA = contact.getFixtureA();
        Fixture fixB = contact.getFixtureB();

        // 保留原有的头部碰撞逻辑,修复字符串比较
        if ((fixA.getUserData() != null && fixA.getUserData().equals("head")) ||
            (fixB.getUserData() != null && fixB.getUserData().equals("head"))) {
            Fixture shape = fixA.getUserData().equals("head") ? fixA : fixB;
            Fixture object = shape == fixA ? fixB : fixA;
            if (object.getUserData() instanceof InteractiveTileObject) {
                ((InteractiveTileObject) object.getUserData()).onHeadHit();
            }
        }

        // 新增:检测玩家与门的接触
        if ((isPlayerFixture(fixA) && isDoorFixture(fixB)) ||
            (isPlayerFixture(fixB) && isDoorFixture(fixA))) {
            isPlayerTouchingDoor = true;
        }
    }

    @Override
    public void endContact(Contact contact) {
        Fixture fixA = contact.getFixtureA();
        Fixture fixB = contact.getFixtureB();

        // 新增:玩家离开门时重置状态
        if ((isPlayerFixture(fixA) && isDoorFixture(fixB)) ||
            (isPlayerFixture(fixB) && isDoorFixture(fixA))) {
            isPlayerTouchingDoor = false;
        }
    }

    // 辅助方法:判断是否为玩家的Fixture
    private boolean isPlayerFixture(Fixture fixture) {
        return fixture.getUserData() != null && fixture.getUserData().equals("player");
    }

    // 辅助方法:判断是否为门的Fixture
    private boolean isDoorFixture(Fixture fixture) {
        return fixture.getUserData() instanceof DoorToSchool;
    }

    @Override
    public void preSolve(Contact contact, Manifold oldManifold) {}

    @Override
    public void postSolve(Contact contact, ContactImpulse impulse) {}
}

2. 给玩家的Fixture设置UserData

在你的玩家类中,创建Body和Fixture时,给玩家的Fixture设置userData为"player",这样接触监听器才能识别玩家:

// 示例:玩家类中创建Fixture的代码
BodyDef bdef = new BodyDef();
bdef.type = BodyDef.BodyType.DynamicBody;
// ... 设置玩家位置等
Body playerBody = world.createBody(bdef);

PolygonShape shape = new PolygonShape();
shape.setAsBox(/* 玩家宽度/高度的一半,按PPM转换 */);

FixtureDef fdef = new FixtureDef();
fdef.shape = shape;
fdef.density = 1.0f;
// 关键:设置玩家的UserData
fdef.userData = "player";

playerBody.createFixture(fdef);
shape.dispose();

3. 在游戏主循环中检测输入并切换屏幕

在你的当前游戏Screen类中,持有WorldContactListener的引用,然后在render方法中检测空格键是否按下,同时玩家正在接触门:

public class CurrentScreen implements Screen {
    private MamsGame game;
    private World world;
    private WorldContactListener contactListener;

    public CurrentScreen(MamsGame game) {
        this.game = game;
        world = new World(new Vector2(0, -9.8f), true);
        // 初始化接触监听器并绑定到World
        contactListener = new WorldContactListener();
        world.setContactListener(contactListener);
        // ... 初始化其他元素(玩家、门等)
    }

    @Override
    public void render(float delta) {
        // ... 原有渲染逻辑(更新World、绘制元素等)
        world.step(delta, 6, 2);

        // 检测空格键输入(用isKeyJustPressed确保只触发一次切换)
        if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE) && contactListener.isPlayerTouchingDoor()) {
            // 切换到目标屏幕(比如SchoolScreen)
            game.setScreen(new SchoolScreen(game));
            // 释放当前屏幕资源
            this.dispose();
        }
    }

    // ... 其他Screen方法(resize、show、hide等)
}

4. 保留你的DoorToSchool类(无需修改)

你的DoorToSchool类已经正确设置了fixture.setUserData(this),接触监听器可以通过这个识别门,所以不需要修改:

public class DoorToSchool extends InteractiveTileObject{
    public DoorToSchool(World world, TiledMap map, Rectangle bounds){
        super(world,map,bounds);
        fixture.setUserData(this);
    }

    @Override
    public void onHeadHit() {
        Gdx.app.log("DoorToSchool","Collision");
    }
}

这样修改后,当玩家接触门并按下空格键时,就会触发屏幕切换啦!

内容的提问来源于stack exchange,提问作者Praneetmek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:27:43