Libgdx每个对象的不同输入侦听器

时间:2019-01-04 14:02:02

标签: java android libgdx box2d

我正在尝试创建一个游戏,需要为每个对象使用多个不同的输入侦听器(检测器)。我有一个名为“ Blocker”的类,它是在此处创建“块”形状的地方。在我的主要游戏屏幕类中,由于需要10个“积木”,我从Block类创建了一个由10个积木实例组成的数组。

我直接在Block类中实现了GestureDetector接口。

这是Block类:

public class Block implements GestureDetector.GestureListener {
    GameScreen gameScreen;
    Controller game;

    public Body block;

    float screenWidth;

    Stack distance;
    Stack time;

    //Calculated speed to be used once block is released
    public float speed;

    //Becomes true when user starts panning
    public boolean isPaning = false;
    public boolean isReleased = false;
    public boolean isActive = false;

    //Tracks user drag location
    public float panLocation;

    //Becomes true when the user release block
    public boolean released = false;

    public Block(GameScreen gameScreen, Controller game){
        this.gameScreen = gameScreen;
        this.game = game;

        distance = new Stack();
        time = new Stack();

        screenWidth = gameScreen.screenWidth;

        //Creates block that stops balls
        block = createBlock();
        //Sets properties
        setBlockProperties(block);
    }

    public Body createBlock(){
        float tmp = (screenWidth - gameScreen.goalPostThickness);
        float xPos = tmp/gameScreen.PPM;
        Body bBody;
        BodyDef def = new BodyDef();
        def.type = BodyDef.BodyType.DynamicBody;
        def.position.set(xPos, 0);
        def.fixedRotation = true;
        bBody = gameScreen.world.createBody(def);

        return bBody;
    }


     //Sets radius, density, etc.
    public void setBlockProperties(Body body){
        float gbt = screenWidth / 75;  //Goal post thickness

        // Create a circle shape and set its radius to 6
        PolygonShape square = new PolygonShape();
        square.setAsBox(gameScreen.goalPostThickness/gameScreen.PPM, (gameScreen.goalWidth/2)/gameScreen.PPM);

        // Create a fixture definition to apply our shape to
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = square;
        fixtureDef.density = 3.5f;
        fixtureDef.friction = 0.4f;
        fixtureDef.restitution = 0.6f; // Make it bounce a little bit

        fixtureDef.filter.categoryBits = 0x0004;
        fixtureDef.filter.maskBits = 0x0002;

        // Create our fixture and attach it to the body
        Fixture fixture = block.createFixture(fixtureDef);

        square.dispose();
    }

    //EVERYTHING BELOW IS FOR USER INPUT
     @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
                                                                              return false;
                                                                                           }

    @Override
    public boolean tap(float x, float y, int count, int button) {
                                                                      return false;
                                                                                   }

    @Override
    public boolean longPress(float x, float y) {
                                                     return false;
                                                                  }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
                                                                             return false;
                                                                                          }

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) {
        isPaning = true;

        Vector3 input = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
        long currentTime = System.currentTimeMillis();
        double seconds = currentTime / 1000.0;
        //Input is backwards (Y down) to camera so this swaps it
        game.cam.unproject(input);
        float meters = input.y / gameScreen.PPM;
        distance.push(new Double(meters));
        time.push(new Double(seconds));

        setPanLocation(input.y);

        //Incase pan stop is not triggered, speed is still calculated
        if ((input.y / gameScreen.PPM) >= gameScreen.boundaryLocation){
            isPaning = false;
            speed = calculateSpeed(distance, time);
            setCheckRelease(true);
        }
        return false;
    }

    @Override
    public boolean panStop(float x, float y, int pointer, int button) {
        isPaning = false;

        Vector3 input = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
        long currentTime = System.currentTimeMillis();
        double seconds = currentTime / 1000.0;

        //Input is backwards (Y down) to camera so this swaps it
        game.cam.unproject(input);
        float meters = input.y / gameScreen.PPM;
        distance.push(new Double (meters));
        time.push(new Double (seconds));

        speed = calculateSpeed(distance, time);

        //System.out.println("Calculated speed: " + speed );
        //System.out.println("Stop time: " + meters);
        setCheckRelease(true);
        return false;
    }

    @Override
    public boolean zoom(float initialDistance, float distance) {
                                                                     return false;
                                                                                  }

    @Override
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
        return false;
    }

    @Override
    public void pinchStop() {

    }

    public void setPanLocation(float v){
                                              panLocation = v;
                                                              }

    public float getPanLocation(){
                                        return panLocation;
                                                           }

    public void setCheckRelease(boolean check){
                                                     released = check;
                                                                      }

    public boolean getCheckRelease(){
                                           return released;
                                                           }

    //Calculates speed from the drag time and distance
    public float calculateSpeed(Stack distance, Stack time){
        boolean checkDifference = false;
        int popCount = 0;

        double tmpDis = 0;
        double tmpTime = 0;

        double endDistance = (Double) distance.pop();
        double endTime = (Double) time.pop();

        //pop elements until there can be a calculated difference
        //between start and end time/distance
        while (!checkDifference) {
            tmpDis = (Double) distance.pop();
            tmpTime = (Double) time.pop();

            if (tmpDis != endDistance && tmpTime != endTime){
                checkDifference = true;
            }
            popCount++;
        }
        //System.out.println("Pop count: " + popCount);

        double startDistance = tmpDis;
        double startTime = tmpTime;

        double finalDistance = endDistance - startDistance;
        double finalTime = endTime - startTime;

//        System.out.println("START DISTANCE: " + startDistance);
//        System.out.println("START TIME: " + startTime);
//        System.out.println("END DISTANCE: " + endDistance);
//        System.out.println("END TIME: " + endTime);
//        System.out.println("FINAL DISTANCE: " + finalDistance);
//        System.out.println("FINAL TIME: " + finalTime);


        double speed = (finalDistance/finalTime);
        float tmp = (float) speed;

        //System.out.println("DOUBLE SPEED: " + speed);


        return tmp;

    }
}

我正在游戏屏幕类中使用inputMultiplexer尝试创建多个输入侦听器:

        multiplexer = new InputMultiplexer();
        for (int i = 0; i < 10 ; i++) {
            blockObj[i] = new Block(this, game);
            multiplexer.addProcessor(new GestureDetector(blockObj[i]));
        }

我正在使用isActive变量来设置当前正在使用的块。但是,即使此方法可行,只要下一个块变为活动状态,它就会从先前的块中获取信息,例如拖动位置。

2 个答案:

答案 0 :(得分:0)

其他模块从其他模块等接收触摸事件的原因是由于您的设计方式。目前,对于您的设计,我无法想到解决此问题的合理方法。

但是,我认为只要稍加重构,就可以得到想要的东西。首先,我建议您研究scenes。您的Block类应扩展Actor

通过这样做,我们可以将Block与舞台一起使用,并用它做许多更复杂的事情。您绝对应该看一下actor中的hit()方法。您将需要重写该方法,以便“块”可以处理触摸事件。

如果您查看我上面链接的Scenes2d教程的“其他侦听器”部分,则可以看到它支持ActorGestureListener

这可能需要大量的重构,我不能保证这是最好的解决方案,因为我看不到您的所有代码,也不知道您要做什么,但是当前的问题是什么设置是所有块在触摸屏幕时都会接收事件,而不仅仅是实际触摸到的块。

答案 1 :(得分:0)

将BLOCK类扩展为Actor将使您可以在主代码中附加侦听器。然后,您可以使用:

for(Block block : blockobj)
{
  block.addListener(new InputListener(){  

   //You can add different listeners like ActorGestureListener etc...
   // press Ctrl + O while the cursor is inside this block to override methods.


 });


}