如何在游戏中添加状态?

时间:2015-12-17 18:20:01

标签: java awt state

在我目前的游戏中应该有不同的状态,例如当我在游戏的主菜单中时,如果我在游戏中,状态将转向#Main; MainMenu"游戏)状态将是"游戏"。

现在它只是开始游戏GAME而不是MainMenu。所以我的问题是如何添加它以使其按照应有的方式工作?

编辑:我希望游戏在MainMenu-STATE开始,如果不清楚的话:)然后按"播放"开始游戏游戏,"退出"退出或"选项"等等。

编辑2:第一个代码具有非工作状态函数。底部的代码有一个功能正常的状态功能。为什么我似乎无法使其适用于第一个代码?

代码:

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();
    }
}

2 个答案:

答案 0 :(得分:0)

从公共类继承,然后使用堆栈并在其顶部呈现项目。也将输入事件发送到该项目。一旦改变了状态,只需将新的状态推到堆栈顶部并在完成后弹出它以返回到前一个状态 当然,当游戏开始时,你必须在堆栈中放入要渲染的第一个状态,即菜单。

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

答案 1 :(得分:0)

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

选项1:

Finite State machine with a pre-defined workflow:建议您提前知道游戏的所有状态,状态机几乎是固定的,未来不会有任何变化

选项2:

Behavioural tress:如果游戏行为经常发生变化,建议使用。您可以动态地向现有树添加行为,而不会影响当前行为。

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

How to implement a FSM - Finite State Machine in Java