box2d:如何防止角色在半空中跳跃?

时间:2011-04-18 10:44:46

标签: box2d

所以我一直在玩iOS上的box2d(认为这个问题并不仅限于iOS),而且我有一个小型演示,当用户通过{{点击屏幕时,玩家角色跳跃1}}。

在大多数情况下,它有效。除非我在玩家处于半空中时点击,再次调用ApplyLinearImpulse,并且玩家再次“跳跃”,但是在半空中。现在,在现实生活中做到这一点非常简洁,但你做不到,而且我更喜欢我的玩家也无法做到这一点。

所以我一直试图想出一个不错的方法来防止跳跃,而玩家已经跳了,我不知道从哪里开始 - 我最好的想法是尝试这样的事情:

  • 使用固定关节将仅作为传感器的身体连接到播放器的底部。
  • 当玩家跳跃时,禁用跳跃,直到前面提到的传感器检测到碰撞(即当玩家“落地”某些东西时,可能是或可能不是地面)。
  • 一旦检测到碰撞,重新启用跳跃。

我不确定我有多喜欢这个想法,其中一个,我不确定是否将传感器连接到我的播放器底部是检测我的播放器精灵底部碰撞的“最聪明”方式。我还没试过这个,我想反过来得到SO的输入,看看是否有人能提供更好的选择。有什么想法吗?

编辑: mafutrct有一个很好的建议:尝试某种向下的测试,使用从我的玩家身体向下直射的光线,并查看该光线是否在短距离内与另一个物体相交(即,在我的播放器正下方 - 是否可以用box2d进行光线投射命中测试?

3 个答案:

答案 0 :(得分:5)

我的投票结果是“玩家脚上的传感器”方法。如果你真的想要进行光线类型检查,你可以让传感器夹具成为边缘,但通常我认为能够指定一个区域更有用,特别是如果你的角色能够同时站在一个以上的东西上,并且如果您有兴趣保持最新的清单列表。如果您是在图形编辑器中创建玩家的身体,那么放置和查看传感器也会更加直观,而不是通过编程方式使用光线投射。我相信脚传感器方法整体上的cpu成本也较低,而且比自己实施光线投射检查的工作量少。我写了一篇关于它的详细教程,我希望它有用:http://www.iforce2d.net/b2dtut/jumpability

答案 1 :(得分:3)

你需要检查跳跃时脚是否接触地面。

根据您的型号,测量您的脚与地面之间的距离。从模型中心应用矢量并检查顶点命中,或者(更复杂)检查描述脚部区域的多边形的第一个垂直命中。

只是检查任何碰撞失败,因为你可能会跳到墙上,这仍然算作半空(除非你玩虚幻竞技场,它是一个跳墙)。

我不熟悉你的软件,所以这只是一个想法 - 如果实际上有用的话会很棒。祝你好运:)

答案 2 :(得分:2)

解决此问题的方法是创建一个实现ContactListener的类,然后在创建World时,将.setContactListener()创建到您的类。现在,您的班级将收到所有碰撞的通知。从那里你创建一个标志,如果玩家与任何地面物体接触。

假设您已将形状'userData设置为GameObject构造函数中的相关GameObjects(shapeDef.userData = this;)。假设你有一个用于定义游戏中GameObject类型的枚举,那么你就有了一个联系人监听器:

import org.jbox2d.dynamics.ContactListener;
import org.jbox2d.dynamics.contacts.ContactPoint;
import org.jbox2d.dynamics.contacts.ContactResult;
import android.util.Log;

import GameObject.GAME_OBJECT_TYPE;

public class CollisionChecker implements ContactListener {

    private boolean groundCollision = false;

    @Override
    public void add(ContactPoint arg0) {
        // Called when a contact point is added. This includes the geometry and the forces.
    }

    @Override
    public void persist(ContactPoint arg0) {
        // Called when a contact point persists. This includes the geometry and the forces.
    }

    @Override
    public void remove(ContactPoint arg0) {
        // Called when a contact point is removed. This includes the last computed geometry and forces.
    }

    @Override
    public void result(ContactResult arg0) {
        // This is called once the collision has been resolved 

        GAME_OBJECT_TYPE a = ((GameObject) arg0.shape1.getUserData()).getType();
        GAME_OBJECT_TYPE b = ((GameObject) arg0.shape2.getUserData()).getType();
        //check for ground
        groundCollision = check(a, b, GAME_OBJECT_TYPE.ground);
    }

    private boolean check(GAME_OBJECT_TYPE a, GAME_OBJECT_TYPE b, GAME_OBJECT_TYPE test){
        if (a == test && b == GAME_OBJECT_TYPE.player){
            return true;
        }
        else if (a == GAME_OBJECT_TYPE.player && b == test){
            return true;
        }
        return false;
    }

    public boolean isGroundCollision(){
        return groundCollision;
    }

    public void step() {
        /*
        if (groundCollision)
            Log.d("COLLSN", "We have a collision with ground");*/
        //after logic, reset the state variables
        reset();
    }

    private void reset(){
        groundCollision = false;
    }
}

现在您在播放器中创建一个跳转布尔值。当他跳跃时,将其设置为true。当旗帜成立时,他不能再跳。使用'collisionChecker.isGroundCollision()'测试每一帧与地面的碰撞。发生碰撞时,再次设置player.jump = false。

这里有一个问题,如果你有垂直地面,玩家将能够跳墙。如果玩家撞到地面,他也可以跳得更多。要解决这些问题,请检查'arg0.position'以找出联系人与玩家对象相关的位置。如果接触不在玩家的下方,那么他就会撞到他的头或撞墙。