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
相关产品推荐
相关产品推荐

