繁体   English   中英

如何在游戏中添加状态?

[英]How can I add States to my game?

在我当前的游戏中,应该有不同的状态,例如,当我在游戏的主菜单中时,状态将变为“ MainMenu”;如果我在游戏(游戏)中,则状态将为“游戏” ”。

现在,它只是启动游戏而不是MainMenu。 所以我的问题是如何添加它,使其以应有的方式工作?

编辑:我当然希望游戏在MainMenu-STATE中启动,以防万一:)然后按“播放”开始游戏,“退出”退出或“选项”,依此类推。

编辑2:第一个代码具有无效的Statefunction。 底部的代码具有有效的Statefunction。 为什么我似乎无法使它适用于第一个代码?

码:

package Game.Window;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.util.Random;

import Game.Framework.AudioPlayer;
import Game.Framework.KeyInput;
import Game.Framework.ObjectId;
import Game.Framework.Texture;
import Game.Interfaces.MainMenu;
import Game.Objects.Block;
import Game.Objects.Player;

public class Game extends Canvas implements Runnable{
    private static final long serialVersionUID = -3258890003398871268L;

    private boolean running = false;
    private Thread thread;

    public static int WIDTH, HEIGHT;

    // Buffers the "Level" and "Background"
    private BufferedImage Level = null, Background = null;

    Handler handler;
    Camera cam;
    static Texture tex;

    Random rand = new Random();

    public enum STATE{
        MainMenu,
        Game,
    };

    public static STATE gameState = STATE.MainMenu;

    public void init(){
        WIDTH = getWidth();
        HEIGHT = getHeight();

        AudioPlayer.load();
        AudioPlayer.getMusic("music").loop();

        tex = new Texture();

        BufferedImageLoader loader = new BufferedImageLoader();
        Level = loader.loadImage("/Level.png"); // Loads the image "Level"
        Background = loader.loadImage("/BackGround.png"); // Loads the image "Background"

        handler = new Handler();

        cam = new Camera(0, 0);

        LoadImageLevel(Level);

        this.addKeyListener(new KeyInput(handler, null));
    }
    public synchronized void start(){
        if(running)
            return;
        running = true;
        thread = new Thread(this);
        thread.start();
    }
    // The Game_Loop
    public void run(){
        init();
        this.requestFocus();
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int updates = 0;
        int frames = 0;

        while(running){
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;

            while(delta >= 1){
                tick();
                updates++;
                delta--;
            }
            render();
            frames++;

            if(System.currentTimeMillis() - timer > 1000){
                timer += 1000;
                System.out.println("FPS: " + frames + " - TICKS: " + updates);
                frames = 0;
                updates = 0;
            }
        }
    }
    private void tick(){
        if(Game.gameState == STATE.Game){
            handler.tick();
        }else if(Game.gameState == STATE.MainMenu){
            //MainMenu.tick();
        }

        for(int i = 0; i < handler.object.size(); i++){
            if(handler.object.get(i).getId() == ObjectId.Player){
                cam.tick(handler.object.get(i));
            }
        }
    }
    private void render(){
        BufferStrategy bs = this.getBufferStrategy();
        if(bs == null){
            this.createBufferStrategy(3);
            return;
        }

        Graphics g = bs.getDrawGraphics();
        Graphics2D g2d = (Graphics2D) g;
        // The background
        g.setColor(new Color(25, 191, 224));
        g.fillRect(0, 0, getWidth(), getHeight());

        // Beginning of the Camera
        g2d.translate(cam.getX(), cam.getY());

            for(int xx = 0; xx < Background.getWidth() * 10; xx += Background.getWidth())
                g.drawImage(Background, xx, 50, this);
            handler.render(g);

        g2d.translate(-cam.getX(), -cam.getY());
        // Ending of the Camera
        g.dispose();
        bs.show();
    }
    private void LoadImageLevel(BufferedImage image){
        int w = image.getWidth();
        int h = image.getHeight();

        System.out.println("Width, Height: " + w + " " + h);

        for(int xx = 0; xx < h; xx++){
            for(int yy = 0; yy < h; yy++){
                int pixel = image.getRGB(xx, yy);
                int red = (pixel >> 16) & 0xff;
                int green = (pixel >> 8) & 0xff;
                int blue = (pixel) & 0xff;

                if(red == 255 && green == 255 && blue == 255) handler.addObject(new Block(xx*32, yy*32, 0, ObjectId.Block));
                if(red == 0 && green == 255 && blue == 0) handler.addObject(new Block(xx*32, yy*32, 1, ObjectId.Block));
                if(red == 0 && green == 38 && blue == 255) handler.addObject(new Player(xx*32, yy*32, handler, ObjectId.Player));
            }
        }
    }
    public static Texture getInstance(){
        return tex;
    }
}

MainMenu:

package Game.Interfaces;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import Game.Framework.AudioPlayer;
import Game.Window.Game;
import Game.Window.Game.STATE;
import Game.Window.Handler;

public class MainMenu extends MouseAdapter{

    private Game game;
    private Handler handler;

    public MainMenu(Game game, Handler handler){
        this.game = game;
        this.handler = handler;
    }

    public void mousePressed(MouseEvent e){
        int mx = e.getX();
        int my = e.getY();

        if(Game.gameState == STATE.MainMenu){
            if(mouseOver(mx, my, 10, 10, 50, 50)){
                AudioPlayer.getSound("menu_sound").play();
                Game.gameState = STATE.Game;
                return;
            }
        }
    }
    public void mouseReleased(MouseEvent e){
    }
    private boolean mouseOver(int mx, int my, int x, int y, int WIDTH, int HEIGHT){
        if(mx > x && mx < x + WIDTH){
            if(my > y && my < y + HEIGHT){
                return true;
            }else return false;
        }else return false;
    }
    public void tick(){
    }
    public void render(Graphics g){
        if(Game.gameState == STATE.MainMenu){
            Font fnt1 = new Font("Arial", 1, 50);

            g.setFont(fnt1);
            g.setColor(Color.WHITE);
            g.drawRect(10, 10, 100, 100);
            g.drawString("Main Menu", 10, 10);
        }
    }
}

在tick和render方法中,我知道我将只需要勾选并渲染特定的STATE,所以如果我在MainMenu中,它将只勾选并渲染它。

这些状态在此游戏中起作用:

package Game;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;

public class Game extends Canvas implements Runnable{

    private static final long serialVersionUID = 7364682855700581664L;

    public static final int WIDTH = 800, HEIGHT = WIDTH / 12 * 9;

    private Thread thread;
    private boolean running = false;

    public static boolean paused = false;
    public int diff = 0; 

    // 0 = EASY
    // 1 = NORMAL
    // 2 = HARD

    private Random r;
    private Handler handler;
    private HUD hud;
    private Spawner spawner;
    private Menu menu;

    public enum STATE {
        Menu,
        Options,
        Game,
        Select,
        Lose
    };

    public static STATE gameState = STATE.Menu;

    public Game(){
        hud = new HUD();
        handler = new Handler();
        menu = new Menu(this, handler, hud);
        this.addKeyListener(new KeyInput(handler, this));
        this.addMouseListener(menu);

        AudioPlayer.load();
        AudioPlayer.getMusic("music").loop();

        new Window(WIDTH, HEIGHT, "Test Game", this);

        spawner = new Spawner(handler, hud, this);
        r = new Random();

        if(gameState == STATE.Game){
            handler.addObject(new Player(WIDTH/2-32, HEIGHT/2-32, ID.Player, handler));
            handler.addObject(new BasicEnemy(r.nextInt(Game.WIDTH - 50), r.nextInt(Game.HEIGHT - 50), ID.BasicEnemy, handler));
        }
    }

    public synchronized void start(){
        thread = new Thread(this);
        thread.start();
        running = true;
    }

    public synchronized void stop(){
        try{
            thread.join();
            running = false;
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    public void run(){
        this.requestFocus();
        long lastTime = System.nanoTime();
        double amountOfTicks = 60.0;
        double ns = 1000000000 / amountOfTicks;
        double delta = 0;
        long timer = System.currentTimeMillis();
        int frames = 0;
        while(running){
            long now = System.nanoTime();
            delta += (now - lastTime) / ns;
            lastTime = now;
            while(delta >= 1){
                tick();
                delta--;
            }
            if(running)
                render();
            frames++;

            if(System.currentTimeMillis() - timer > 1000){
                timer += 1000;
                System.out.println("FPS: " + frames);
                frames = 0;
            }
        }
        stop();
    }

    private void tick(){
        if(gameState == STATE.Game){
            if(!paused){
                hud.tick();
                spawner.tick();
                handler.tick();

                if(HUD.PlayerHealth < 1){
                    HUD.PlayerHealth = 100;
                    //hud.setLevel(1);
                    //hud.setScore(0);
                    gameState = STATE.Lose;
                    handler.clearEnemies();
                }
            }

        }else if(gameState == STATE.Menu  || gameState == STATE.Lose || gameState == STATE.Select){
            menu.tick();
            handler.tick();
        }
    }

    private void render(){
        BufferStrategy bs = this.getBufferStrategy();
        if(bs == null){
            this.createBufferStrategy(3);
            return;
        }

        Graphics g = bs.getDrawGraphics();

        g.setColor(Color.BLACK);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        handler.render(g);

        if(paused){
            g.setColor(Color.RED);
            g.drawString("PAUSED", 370, 260);
        }

        if(gameState == STATE.Game){
            hud.render(g);
        }else if(gameState == STATE.Menu || gameState == STATE.Options  || gameState == STATE.Lose || gameState == STATE.Select){
            menu.render(g);
    }

        g.dispose();
        bs.show();
    }

    public static float clamp(float var, float min, float max){
        if(var >= max)
            return var = max;
        else if(var <= min)
            return var = min;
        else
            return var;
    }

    public static void main(String args[]){
        new Game();
    }
}

从一个通用类继承,然后使用一个堆栈并在其顶部呈现该项目。 也将输入事件发送到该项目。 更改状态后,只需将新的状态推入堆栈顶部,并在完成后将其弹出以返回上一个状态即可。
当然,当游戏开始时,您必须将要呈现的第一个状态(即菜单)放入堆栈中。

如果状态只有两个,则还可以简单地使用一个变量来存储要渲染的活动状态以及向其发送输入事件等,然后在更改状态时更新该变量。
在这种情况下,当游戏开始时,只需将包含菜单的场景设置为活动状态即可。

您可以通过两种不同的方式重新设计游戏。

选项1:

Finite State machine with a pre-defined workflow :如果您事先知道游戏的所有状态并且状态机几乎是固定的,并且以后没有更改,则建议使用

选项2:

Behavioural tress ::如果游戏行为频繁变化,则建议使用。 您可以在不影响当前行为的情况下将行为动态添加到现有树中。

有关更多详细信息,请参阅以下相关的SE问题。

如何在Java中实现FSM-有限状态机

暂无
暂无

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

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