第一个 Java 游戏未呈现

First Java Game Not Rendering

我决定尝试制作游戏并且我喜欢 Java,所以我开始学习教程 here。我确实偏离了几次视频,因为我觉得它更清晰,同时与教程的代码同义,但我认为不会以任何方式影响代码的工作方式。例如,对我来说应该只有一个渲染器和对象注册表实例是有意义的,所以我将它们设为单例。

我目前的代码应该创建一个黑色背景的 window,window 中间的蓝色方块代表玩家,这很有效。然而,它也应该响应 wasd 键而四处滑动,并且无论如何都更缓慢地向一个方向漂移。相反,它什么都不做。

我花了不少于一个小时来弄清楚为什么它不起作用。它似乎滴答作响,数据看起来正在正确更新,但即使我的渲染方法也被调用,屏幕也没有改变。

这是我目前所有的代码,因为我对这个问题一无所知。很抱歉列出了整个项目。

public class Game implements Runnable {
    private final Thread thread;
    private boolean running = false;

    Game() {
        thread = new Thread(this);
    }

    public static void main(String[] args) {
        Game game = new Game();
        game.start();
        new Player(600,450,0));
    }

    private void start() {
        thread.start();
        running = true;
    }

    @Override
    public void run() {
        double tps = 10.0;
        double nsPerTick = 1000000000 / tps;
        double delta = 0;
        int frames = 0;
        long timer = System.currentTimeMillis();
        long lTime = System.nanoTime();
        long now;
        while (running) {
            now = System.nanoTime();
            delta += (now - lTime) / nsPerTick;
            lTime = now;
            while (delta >= 1) {
                Registry.getInstance().tick();
                delta--;
            }
            if (running) Renderer.getInstance().run();
            frames++;

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

        }
        stop();
    }

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

}
public class Renderer extends Canvas {
    private static final Renderer renderer = new Renderer();
    private final Window window;
    private final BufferStrategy bs;
    private final Graphics g;
    boolean black = true;

    private Renderer() {
        window = new Window(1200, 900, "First Game", this);
        this.createBufferStrategy(2);
        bs = this.getBufferStrategy();
        g = bs.getDrawGraphics();
        addKeyListener(Controller.getInstance());
    }

    public static Renderer getInstance() {return renderer;}

    public void run() {
        g.setColor(Color.BLACK);
        //this was to see if even the background would update, it wouldn't
        //g.setColor(black ? Color.BLACK : Color.WHITE);
        //black = !black;
        g.fillRect(0,0,1200, 900);

        Registry.getInstance().render();

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

    public Graphics getGraphics() {return g;}

    private static class Window extends Canvas {
        private Window(int width, int height, String title, Renderer renderer) {
            JFrame frame = new JFrame(title);
            frame.setPreferredSize(new Dimension(width, height));
            frame.setMinimumSize(new Dimension(width, height));
            frame.setMaximumSize(new Dimension(width, height));
            frame.setResizable(false);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationRelativeTo(null);
            frame.add(renderer);
            frame.setVisible(true);
        }
    }

}
public class Registry {
    private static final Registry reg = new Registry();
    private final LinkedList<GameObject> objects = new LinkedList<>();

    private Registry() {

    }

    public static Registry getInstance() { return reg; }

    public void tick() { //System.out.println("tick");
        objects.forEach(GameObject::tick); }

    public void render() { objects.forEach(GameObject::render); }

    public void add(GameObject gameObject) { objects.add(gameObject); }

    public void remove(GameObject gameObject) { objects.remove(gameObject);}

}
public class Controller extends KeyAdapter {
    private static final Controller controller = new Controller();
    private final HashMap<Character,Boolean> keyStates = new HashMap<>();

    private Controller() {

    }

    public static Controller getInstance() {
        return controller;
    }

    public void keyPressed(KeyEvent e) {
        if (!keyStates.getOrDefault(e.getKeyChar(), true)) System.out.println(e.getKeyChar() + " down");
        keyStates.put(e.getKeyChar(),true);
    }

    public void keyReleased(KeyEvent e) {
        keyStates.put(e.getKeyChar(),false);
        System.out.println(e.getKeyChar() + " up " + keyStates.size());
    }

    public boolean isKeyDown(char c) {return keyStates.getOrDefault(c,false);}

}
public abstract class GameObject {
    protected Graphics graphics = Renderer.getInstance().getGraphics();
    protected final ObjectType type;
    protected float x,y,r;

    protected GameObject(ObjectType objectType, float x, float y, float r) {
        this.type = objectType;
        this.x = x;
        this.y = y;
        this.r = r;
        Registry.getInstance().add(this);
    }

    public abstract void tick();
    public abstract void render();

    public void destroy() { Registry.getInstance().remove(this); }

    public float getX() { return x; }
    public void setX(float x) { this.x = x; }
    public float getY() { return y; }
    public void setY(float y) { this.y = y; }
    public float getR() { return r; }
    public void setR(float r) { this.r = r; }
}
public class Player extends GameObject {
    private final Controller controller;

    public Player(float x, float y, float r) {
        super(ObjectType.PLAYER, x, y, r);
        controller = Controller.getInstance();
    }

    @Override
    public void tick() {
        this.x += 1;
        if (controller.isKeyDown('w')) x += 2;
        if (controller.isKeyDown('a')) y -= 2;
        if (controller.isKeyDown('s')) x -= 2;
        if (controller.isKeyDown('d')) y += 2;
    }

    @Override
    public void render() {
        graphics.setColor(Color.BLUE);
        graphics.fillRect((int) (this.x-12),(int) (this.y-12), 24,24);
    }
}

问题出在你对Graphics的处理上。只有一个活动图形对象可以有效处理。

重构您的代码,以便通过目标方法通过参数传递当前 Graphics 对象(如此处:Player.render() 应变为 Player.render(Gpahics g)。并摆脱 Gameobject.graphics成员变量。那是罪魁祸首。

除此之外,进行简单渲染的最佳方法是覆盖 paint(Graphics g) 方法或 paintComponents(Graphics g),并从 JPanel/Canvas 上的外部调用 repaint() .这样,UI 会自行绘制,处理实际频率,如果有的话也会绘制默认 components/design。