0
\$\begingroup\$

I am creating a game wherein an apple is being shot with an arrow. The apple's location is the XY location of the user input and the arrow actor has to move to that location using the code actor.moveto. The problem is the arrow only moves only once to the user input's direction. I know that the moveTo action of the actor is updated many times per second when I called stageArrow.act in the update method so I am wondering why the arrow only moves once. Here's my code:

appleclass.java

public class AppleClass implements Screen {

Arrow arrow;
private final MainApp app;
public Image ShotImage;

public AppleClass(final MainApp app){
        this.app = app;
        this.stageApple = new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));
        this.stageArrow =new Stage(new StretchViewport(app.screenWidth,app.screenHeight , app.camera));

        arrow = new ArrowClass(app);

    }

@Override
    public void show() {

        InputMultiplexer inputMultiplexer = new InputMultiplexer();
        inputMultiplexer.addProcessor(stageApple);
        inputMultiplexer.addProcessor(stageArrow);
        Gdx.input.setInputProcessor(inputMultiplexer);

        arrow();

    }

    public void arrow(){
        arrow.isTouchable();
        stageArrow.addActor(arrow);
        arrow.addAction((moveTo(Gdx.input.getX(),Gdx.input.getY(),0.3f)));   //===> only executes once.
        arrow.addListener(new InputListener(){
            public void enter(InputEvent event, float x, float y, int pointer, Actor fromActor){


            if (Gdx.input.isTouched()){
                        ShotImage.setVisible(true);

                          }
                        }
                    });}

}

@Override
    public void render(float delta) {                        

        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        update(delta);
}

public void update(float deltaTime){


        stageApple.draw();
        stageArrow.draw();

        stageApple.act(deltaTime);
        stageArrow.act(deltaTime);


    }

ArrowClass.java

public class ArrowClass extends Actor {
    MainApp app;
    AppleClass appleClass;
    public Texture arrowTexture;

    public ArrowClass(final MainApp app){
        this.app = app;
        arrowTexture = new Texture("medievalarrow.png");
        this.setSize(arrowWidth, arrowHeight);
        this.setTouchable(Touchable.enabled);
        this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
        this.setOrigin(0,0);

}
@Override
    public void draw(Batch batch, float parentAlpha) {
        super.draw(batch, parentAlpha);


        final float delta = Gdx.graphics.getDeltaTime();
        this.act(delta);

        app.batch.begin();
        app.batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
        app.batch.end();

    }
}

Any help will be highly appreciated. Thanks.

\$\endgroup\$
1
\$\begingroup\$

I think the problem is because you are calling this.act(delta) in your ArrowClass' draw method. When you call Stage#act(), it will call the act method on all of its actors for you. Since you're calling it once when you draw and again when you update the stage, it's moving at twice the normal speed and that could be causing it to reach its destination prematurely.

A few other comments about your code, if I may:

First, you probably don't want two separate stages- unless you're using Scene2D.UI, you would normally have a single stage with Arrow and Apple added to it as actors.

Second, when you override Actor#draw(), you should use the batch it passes you to do the rendering instead of using the one from app. You also don't want to call begin() and end() inside your draw method- these are 'expensive' and you only want to call them once per frame. However, if you just use the batch that is passed to draw(), the Stage class will handle beginning and ending for you and you won't need to call them explicitly.

Third, you actually don't need to call super.draw(batch, parentAlpha) because it's an empty method in the Actor class.

Thus, your class could be simplified to the following:

public class ArrowClass extends Actor {
    AppleClass appleClass; // You never set this; you may not need it
    Texture arrowTexture;

    public ArrowClass(MainApp app, arrowWidth, arrowHeight) {
        arrowTexture = new Texture("medievalarrow.png");
        this.setSize(arrowWidth, arrowHeight);
        this.setTouchable(Touchable.enabled);
        this.setBounds(app.screenWidth*0.45f,0,arrowWidth,arrowHeight);
        this.setOrigin(0,0);

}
@Override
    public void draw(Batch batch, float parentAlpha) {
        batch.draw(arrowTexture, getX(),getY(),getWidth(),getHeight());
    }
}
\$\endgroup\$
  • \$\begingroup\$ Is there any disadvantage of using two stages for my actors? I have tried putting both actors on the same stage and from what I remember it caused me some trouble so I separated them. \$\endgroup\$ – JAlmazan Dec 6 '16 at 7:21
  • \$\begingroup\$ It's not the end of the world, but in general it's a bad practice- you're going to repeat yourself twice, and you're still going to have the bug that was causing a single stage to break hidden somewhere in your code. \$\endgroup\$ – John Dec 6 '16 at 7:25
  • \$\begingroup\$ Oh ok, I thought it's also expensive on the part of graphic memory. Thanks for your answer though, I'll update you if it fixes my code's issue. \$\endgroup\$ – JAlmazan Dec 6 '16 at 7:37
  • \$\begingroup\$ It still doesn't work . I deleted this.act on ArrowClass and it doesn't fix the issue. \$\endgroup\$ – JAlmazan Dec 6 '16 at 8:19
  • \$\begingroup\$ Can you take a look at my question here: gamedev.stackexchange.com/questions/136318/… \$\endgroup\$ – JAlmazan Jan 25 '17 at 8:21
1
\$\begingroup\$

I have found the answer to my own question, I have separated both class to a different stage and this solution works. I know that there is a better way of doing this and I am open for any edits or future answers. This is the code for using more than one stage :

        InputMultiplexer inputMultiplexer = new InputMultiplexer();
        inputMultiplexer.addProcessor(stage);
        inputMultiplexer.addProcessor(stage2);
        Gdx.input.setInputProcessor(inputMultiplexer);
\$\endgroup\$
0
\$\begingroup\$

I have not used stage actions that much, but I think that with

arrow.addAction((moveTo(Gdx.input.getX(),Gdx.input.getY(),0.3f)));

you are telling the arrow to move to its destination in 0.3 seconds.

Try changing the 0.3f to something bigger and see what happens.

\$\endgroup\$
  • \$\begingroup\$ I have used stage actions because if I'm not mistaken it's the best way to update the location of my Images according to the location of the input, like in this program, the arrow follows where the input is pointing on the screen. \$\endgroup\$ – JAlmazan Dec 6 '16 at 8:41
  • \$\begingroup\$ I changed the duration to 3f and nothing happens. \$\endgroup\$ – JAlmazan Dec 6 '16 at 8:42
  • \$\begingroup\$ Maybe the moveTo action of scene2d actors is not properly updated to execute 60x per second. I just can't pinpoint what's wrong in my code. \$\endgroup\$ – JAlmazan Dec 6 '16 at 8:57
  • 1
    \$\begingroup\$ I would just drop the stage action approach and move the arrow myself. Even if it did work, it would be annoying to handle the speed of the arrow. You set the time for the movement so the speed would be dependent on the distance to the target. \$\endgroup\$ – IronMonkey Dec 6 '16 at 9:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.