简体   繁体   English

如何在libgdx中创建自动操作? (scene2d)

[英]How do I create automatic actions in libgdx? (scene2d)

I'm new to libgdx and android development. 我是libgdx和android开发的新手。 I'm writing my first game, a recreation the original "Simon" game for experience. 我正在写我的第一个游戏,一个娱乐原始的“西蒙”游戏的经验。 I am using scene2d, using each button as an actor, each with ClickListeners in their constructors. 我正在使用scene2d,使用每个按钮作为actor,每个按钮都在其构造函数中使用ClickListeners。

What I am really struggling on right now is how to "perform" the AI sequence, as in: I need to visually display the computer "pressing" the buttons for each turn. 我现在正在努力的是如何“执行”AI序列,如:我需要在视觉上显示计算机“按下”每个回合的按钮。 I am able to get the sounds to play and to append an integer to an ArrayList, but it seems that it will only do this before it draws my textures. 我能够播放声音并将一个整数附加到ArrayList,但它似乎只会在绘制纹理之前执行此操作。 So when I launch the program, I will hear a random beep, and see a random number appended to my ArrayList in the log, and THEN I will finally see my actors ready to be clicked/touched. 因此,当我启动程序时,我会听到一声随机的嘟嘟声,并在日志中看到一个随机数附加到我的ArrayList中,然后我终于看到我的演员已经准备好被点击/触摸了。 I'm confused on how to fix this. 我对如何解决这个问题感到困惑。 Here is some code from my game. 这是我游戏中的一些代码。 Please excuse the sloppiness, as I am a beginner and it is a work in progress. 请原谅,因为我是初学者,这是一项正在进行的工作。 There are probably better ways to approach what I'm trying to do, but for right now, I just want it to work. 可能有更好的方法来处理我正在尝试做的事情,但就目前而言,我只是想让它发挥作用。

I have learned a bit about Actions, but I can't seem to get it to work. 我已经学习了一些关于动作的内容,但我似乎无法让它发挥作用。 It seems like they require some input for an action to take place. 看起来他们需要一些输入来进行动作。

Note: I have my unlit and lit buttons stacked with the unlit version created last, so that the lit button appears once I set the unlit button's visibility to false. 注意:我的未点亮和点亮的按钮与最后创建的未点亮版本堆叠在一起,因此一旦我将未点亮按钮的可见性设置为false,就会出现点亮的按钮。 I realize it might not be the best way to do this. 我意识到这可能不是最好的方法。

Here is my main game class: 这是我的主要游戏类:

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.ArrayList;


public class XimonGame extends Game {

    private SpriteBatch batch;
    private Stage stage;
    private OrthographicCamera camera;
    XimonButton actor_g;
    XimonButton actor_gLit;
    XimonButton actor_r;
    XimonButton actor_rLit;
    XimonButton actor_y;
    XimonButton actor_yLit;
    XimonButton actor_b;
    XimonButton actor_bLit;
    public static ArrayList<Integer> playerList;
    public static ArrayList<Integer> computerList;
    public static ButtonSequencer buttonSequencer;



    @Override
    public void create () {
        batch = new SpriteBatch();
        // Creating camera
        camera = new OrthographicCamera(800, 480);

        // Creating stage and actors
        stage = new Stage(new FitViewport(800, 480, camera));

        // Creating ArrayLists & ButtonSequencer
        playerList = new ArrayList<Integer>();
        computerList = new ArrayList<Integer>();
        buttonSequencer = new ButtonSequencer();

        // Appending initial random number to computerList:
        buttonSequencer.appendRandomNumber(1, 4, computerList);
        System.out.println("Created computer's ArrayList.\nInitial number is: "
        + computerList.toString());
        System.out.println("Size of computerList is currently " + computerList.size());

        // Creating (constructing) actors. Parameter info:
        // XimonButton("[png file]", x, y, width, height, "[name]")
        actor_g = new XimonButton("img/green.png", 190, 240, 210, 210, 1);
        System.out.println(actor_g.toString() + " created.");
        // Lit version of button
        actor_gLit = new XimonButton("img/green_on.png", 190, 240, 210, 210, 0);

        actor_r = new XimonButton("img/red.png", 400, 240, 210, 210, 2);
        System.out.println(actor_r.toString() + " created.");
        // Lit version of button
        actor_rLit = new XimonButton("img/red_on.png", 400, 240, 210, 210, 0);

        actor_y = new XimonButton("img/yellow.png", 190, 30, 210, 210, 3);
        System.out.println(actor_y.toString() + " created.");
        // Lit version of button
        actor_yLit = new XimonButton("img/yellow_on.png", 190, 30, 210, 210, 0);

        actor_b = new XimonButton("img/blue.png", 400, 30, 210, 210, 4);
        System.out.println(actor_b.toString() + " created.");
        // Lit version of button
        actor_bLit = new XimonButton("img/blue_on.png", 400, 30, 210, 210, 0);


//        ADDING ACTORS
//
        // Green buttons:
        stage.addActor(actor_gLit);
        stage.addActor(actor_g);
        // Red buttons:
        stage.addActor(actor_rLit);
        stage.addActor(actor_r);
        // Yellow buttons:
        stage.addActor(actor_yLit);
        stage.addActor(actor_y);
        // Blue buttons:
        stage.addActor(actor_bLit);
        stage.addActor(actor_b);

        Gdx.input.setInputProcessor(stage);

    }
    @Override
    public void render () {

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        super.render();
        batch.end();

        // Setting fullscreen
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        // Restore stage's viewport
        stage.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true);

        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();

    }



    @Override
    public void setScreen(Screen screen) {
        super.setScreen(screen);
    }

    @Override
    public Screen getScreen() {
        return super.getScreen();
    }

    @Override
    public void resize (int width, int height) {
            super.resize(width, height);
    }

    @Override
    public void pause () {
        super.pause();
    }

    @Override
    public void resume () {
        super.resume();
    }

    public void dispose () {
        stage.dispose();
    }




}

And here is my Actor class for the buttons: 这是按钮的Actor类:

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.actions.RunnableAction;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.mygdx.game.XimonGame;

import java.util.ArrayList;

class XimonButton extends Actor {

    Sprite sprite;
    private Sound sound;
    private final int num;
    private int count;
    private final int code;
    public static boolean isComputerTurn = true;


    public XimonButton (String file, int x, int y, int w, int h, final int colorCode) {
        sprite = new Sprite(new Texture(Gdx.files.internal(file)));
        this.setBounds(x, y, w, h);
        this.num = colorCode;
        count = 0;
        code = colorCode;

            if (colorCode == 1) {
                sound = Gdx.audio.newSound(Gdx.files.internal("sounds/Green.wav"));
            }
            else if (colorCode == 2) {
                sound = Gdx.audio.newSound(Gdx.files.internal("sounds/Red.wav"));
            }
            else if (colorCode == 3) {
                sound = Gdx.audio.newSound(Gdx.files.internal("sounds/Yellow.wav"));
            }
            else if (colorCode == 4) {
                sound = Gdx.audio.newSound(Gdx.files.internal("sounds/Blue.wav"));
            }

        setTouchable(Touchable.disabled);

//        Perform the AI's turn:
        try {
            performAISequence();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        // Used to handle touch input
        addListener(new ClickListener() {

            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                sound.play(0.4f);
                if (XimonButton.this.isVisible()) XimonButton.this.setVisible(false);


//                System.out.println("Current player list contains:");
//                for (int i=0; i < playerList.size(); i++) {
//                    System.out.println(playerList.get(i));
//                }

                return true;
            }

            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {

//                Stop the sound and "turn off" the button light
                sound.stop();
                XimonButton.this.setVisible(true);


//                 Count the number of touches for this turn
                XimonGame.buttonSequencer.incrementCount();
                System.out.println("Count is: " + XimonGame.buttonSequencer.getCount());
                System.out.println("Color code is: " + colorCode);

//                 Append the colorCode to the playerList.
//                 Loop through the computer list to check if current touch matches
//                 the computer's num for the index in the ArrayList.
                XimonGame.playerList.add(colorCode);
                System.out.println("Player list is: " + XimonGame.playerList.toString() + "\n");
//

            }


        });


    }

    public void performAISequence () throws InterruptedException {

        setTouchable(Touchable.disabled);

        for (int i = 0; i < XimonGame.computerList.size(); i++) {

            if (code == XimonGame.computerList.get(i)) {
                sound.play(0.4f);
                XimonButton.this.setVisible(false);
                Thread.sleep(XimonGame.buttonSequencer.getRandomInt(400,600));
                sound.stop();
                XimonButton.this.setVisible(true);
                Thread.sleep(XimonGame.buttonSequencer.getRandomInt(100,150));

            }

        }
        setTouchable(Touchable.enabled);
    }


    @Override
    public void draw (Batch batch, float parentAlpha) {
        batch.draw(sprite, this.getX(), this.getY(), this.getWidth(), this.getHeight());

    }

    @Override
    public void act(float delta) {
        super.act(delta);





    }
}

Also: 也:

import java.util.ArrayList;
import java.util.Random;

public class ButtonSequencer {

    public Random rand;
    private int turn = 0;
    private int count;


//    public static void addPlayerNums(int code) {
//        XimonGame.playerList.add(code);
//    }

    public int getCount() {
        return count;
    }

    public void incrementCount() {
        count++;
    }

    public void appendRandomNumber(int min, int max, ArrayList<Integer> computerList) {
        rand = new Random();
        int random = rand.nextInt((max - min) + 1) + min;
        computerList.add(random);
        turn++;

    }


    public int getRandomInt(int min, int max) {
        rand = new Random();
        return rand.nextInt((max - min) + 1) + min;
    }



}

Sorry for pasting so much code, but if there's something wrong, I don't know where it is or what to do, so I figured it would be a good idea to share most of it. 很抱歉粘贴了这么多代码,但如果出现问题,我不知道它在哪里或做什么,所以我认为分享大部分内容是个好主意。

There's too much code there for me to comment on everything, but the biggest glaring error I see is the use of Thread.sleep . 那里有太多代码可供我评论所有内容,但我看到的最大的明显错误是使用Thread.sleep This will cause your game to freeze until the thread is done sleeping. 这将导致游戏冻结,直到线程完成睡眠。

Libgdx is not built for multi-threading, and so you need to think in terms of setting stuff up on timers. Libgdx不是为多线程而构建的,因此您需要考虑在计时器上设置内容。 Events that take a while need to have timers that decrements on each run of the render loop, and fire their events when their timers run down. 需要一段时间的事件需要在渲染循环的每次运行时减少计时器,并在计时器运行时触发它们的事件。

Since you're using stage2d, this becomes very easy because the Actions keep their own timers and you can chain them together in a sequence. 由于您正在使用stage2d,因此这很容易,因为Actions会保留自己的计时器,您可以按顺序将它们链接在一起。 Read up on stage2d's Actions system . 阅读stage2d的Actions系统 You can create your own actions and chain them together with a SequenceAction with DelayActions in the middle. 您可以创建自己的动作,并将SequenceAction与DelayActions一起链接在一起。

Here's an example. 这是一个例子。 I'm not really familiar with your whole game structure, so I'm not sure if this will work with your code, but it should give you a basic idea of how to do this. 我不是很熟悉你的整个游戏结构,所以我不确定这是否适用于你的代码,但它应该让你基本了解如何做到这一点。

public void performAISequence (){

        //Get a sequence action from the pool (to avoid unnecessary allocation)
        //and give it the first action
        SequenceAction sequence = Actions.sequence(Actions.touchable(Touchable.disabled));

        for (int i = 0; i < XimonGame.computerList.size(); i++) {

            if (code == XimonGame.computerList.get(i)) {
                sequence.addAction(Actions.runnable(playSoundRunnable));
                sequence.addAction(Actions.hide());
            }

            //Want to delay it for every item in list, because it may need to wait for other buttons
            sequence.addAction(Actions.delay(BUTTON_DELAY_TIME));

            if (code == XimonGame.computerList.get(i)) {
                sequence.addAction(Actions.show());
                sequence.addAction(Actions.runnable(stopSoundRunnable));
            }

            sequence.addAction(Actions.touchable(Touchable.enabled));

        }

        this.addAction(sequence);

    }

Runnable playSoundRunnable = new Runnable(){
    public void run(){
        sound.play(0.4f);
    }
};

Runnable stopSoundRunnable = new Runnable(){
    public void run(){
        sound.stop();
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM