Java 是什么原因导致图形2D渲染出现口吃/延迟

Java 是什么原因导致图形2D渲染出现口吃/延迟,java,swing,graphics2d,game-development,game-loop,Java,Swing,Graphics2d,Game Development,Game Loop,Mouse.java package game.input; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; // holds information about mouse events. // eg, presses of buttons. public class Mouse extends MouseAdapter

Mouse.java

package game.input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
    // the position of the mouse.
    public static int x, y;
    
    // Is the mouse pressed.
    public static boolean pressed;
    
    // Is the mouse held.
    public static boolean held;
    
    // Is the mouse hovered over the window.
    public static boolean focused;
    
    // Is the mouse being dragged.
    public static boolean dragging;
    
    // no mouse wheel support.
    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {}
    
    @Override
    public void mouseDragged(MouseEvent event) {
        x = event.getX();
        y = event.getY();
        dragging = true;
    }
    
    @Override
    public void mouseMoved(MouseEvent event) {
        x = event.getX();
        y = event.getY();
    }
    
    @Override
    public void mouseEntered(MouseEvent event) {
        focused = true;
    }
    
    @Override
    public void mouseExited(MouseEvent event) {
        focused = false;
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        held = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        held = false;
        dragging = false;
        pressed = true;
    }
}
package game.input;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

// holds information about key events.
public class Keyboard extends KeyAdapter {
    // which keys are being held down.
    private static boolean[] heldKeys;
    
    // which keys are being clicked
    private static boolean[] clickedKeys;
    
    // size of arrays.
    private final int size;
    
    public Keyboard() {
        // there are 255 valid key codes.
        // plus one for the array size.
        size = 256;
        
        clickedKeys = new boolean[size];
        heldKeys = new boolean[size];
    }
    
    // when the key is pressed.
    @Override
    public void keyPressed(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is being held.
        heldKeys[event.getKeyCode()] = true;
    }
    
    @Override
    public void keyReleased(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is let go.
        heldKeys[event.getKeyCode()] = false;
        
        // when key is let go, it gets interpreted as it being pressed.
        clickedKeys[event.getKeyCode()] = true;
    }
    
    // returns whether or not the key is held.
    public static boolean keyHeld(Key key) {
        if(heldKeys != null)
            return heldKeys[key.keyCode];
        return false;
    }
    
    // returns whether or not the key is clicked.
    public static boolean keyClicked(Key key) {
        if(clickedKeys != null)
            return clickedKeys[key.keyCode];
        return false;
    }
    
    // resets key input.
    public static void resetKeys() {
        if(clickedKeys != null)
            for(int i = 0; i < clickedKeys.length; i++)
                clickedKeys[i] = false;
    }
    
    public enum Key {
        // movement keys.
        LEFT(37), UP(38), RIGHT(39), DOWN(40),
        
        // x key.
        A(88),
        
        // z key.
        B(90),
        
        // enter key.
        START(10);
        
        private int keyCode;
        
        private Key(int keyCode) {
            this.keyCode = keyCode;
        }
    };
}
package game;

import java.awt.Graphics2D;

import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;

// creates a new game
public final class Game {
    // the window that the game resides in.
    private static BB_Window window;
    
    // the current room that is drawn to the window.
    private static Room room;
    
    private static GameLoop gameLoop;
    
    // game constructor cannot be called.
    private Game() {}
    
    // inits the game.
    // ie, adds input to the game (key and mouse).
    public static void init(BB_Window window) {
        if(gameLoop != null)
            return;
        
        // creates mouse and keyboard listeners.
        Mouse mouse = new Mouse();
        Keyboard keyboard = new Keyboard();
        
        // adds input listeners to the window.
        window.getJFrame().addKeyListener(keyboard);
        window.getCanvas().addMouseListener(mouse);
        window.getCanvas().addMouseMotionListener(mouse);
        
        // init game loop
        gameLoop = new GameLoop();
        
        // init window
        Game.window = window;
        
        gameLoop.start();
    }
    
    // updates the current room and resets input.
    protected static void update() {
        // if room doesn't exist, don't update it.
        if(room == null)
            return;
        
        // updates current room.
        Game.room.update();
        
        // resets mouse input.
        Mouse.pressed = false;
        
        // resets key input.
        Keyboard.resetKeys();
        
        // if a mouse or key button is clicked,
        // then it would have to be reset to false here.
    }
    
    // renders the current room.
    protected static void render() {
        // if room doesn't exist, don't render it.
        if(room == null)
            return;
        
        // creates graphics object from the window canvas.
        Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
        
        // creates the screen for next drawing.
        graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
        
        // renders the current room.
        Game.room.render(graphics);
        
        // shows the buffer.
        window.getCanvas().getBufferStrategy().show();
        
        // removes graphics object.
        graphics.dispose();
    }
    
    // sets the current room to a new one.
    public static void setRoom(Room newRoom) {
        newRoom.init();
        Game.room = newRoom;
    }
    
    // returns the current room.
    public static Room getRoom() {
        return Game.room;
    }
    
    // returns width of window.
    public static int getWindowWidth() {
        return window.getWidth();
    }
    
    // returns height of window.
    public static int getWindowHeight() {
        return window.getHeight();
    }
    
    // stops the game loop.
    public static void stop() {
        gameLoop.stop();
    }
}
package game;

public class GameLoop implements Runnable {
    // the thread that the game runs on.
    private Thread thread;
    
    // is the game running.
    private boolean running;
    
    // starts the game loop.
    // inits the thread and calls its start method.
    public void start() {
        // you can't start the game if it is started.
        if(running)
            return;
        
        // starts the game.
        running = true;
        
        // creates thread.
        thread = new Thread(this);
        
        // starts the game.
        // ie, calls thread.run();
        thread.start();
    }
    
    // stops the game loop.
    // interrupts the thread and terminates the currently running JVM.
    public void stop() {
        // you can't end the game if it is ended.
        if(!running)
            return;
        
        // ends the game.
        running = false;
        
        // interrupts the thread.
        // ie, ends the thread.
        // this will always end the thread,
        // because running is set to false.
        thread.interrupt();
        
        // ends the program.
        System.exit(0);
    }
    
    // this is the game loop.
    @Override
    public void run() {
        // holds information about each frames elapsed time.
        double start, previous = System.nanoTime() / 1_000_000_000.0;
        
        // time.
        double actualFrameTime, realTime = 0;
        
        // should the game be rendered.
        boolean render;
        
        // fps
        final int FPS = 60;
        final double DESIRED_FRAME_TIME = 1.0 / FPS;
        
        // while the game is running
        while(running) {
            // calculates the elapsed time of the frame.
            // converts from nano seconds to seconds
            // by dividing by one billion.
            start = System.nanoTime() / 1_000_000_000.0;
            actualFrameTime = start - previous;
            previous = start;
            
            // the game time is updated by the elapsed frame time.
            realTime += actualFrameTime;
            
            // resets it to back to false.
            render = false;
            
            // if time surpasses desired frame time, game should update.
            while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
                realTime -= DESIRED_FRAME_TIME;
                Game.update();
                
                // if the game is updated, the game should render.
                // if the game is not updated, the game doesn't render.
                render = true;
            }
            
            if(render)
                Game.render();
            // sleep if game should not render.
            // reduces cpu usage by a lot.
            else
                try {
                    // sleep for one millisecond.
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
package userInterface.containers;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

// the JFrame that the game will reside in.
public final class BB_Window {
    private JFrame window;
    private Canvas canvas;
    private Dimension windowDimension;
    
    // constructs the canvas, window, and buffer.
    public BB_Window(String title, int width, int height) {
        // creates dimension.
        windowDimension = new Dimension(width, height);
        
        // creates a canvas with a bunch of defaults.
        canvas = new Canvas();
        
        // sets a non-changeable size.
        canvas.setPreferredSize(windowDimension);
        canvas.setMinimumSize(windowDimension);
        canvas.setMaximumSize(windowDimension);
        
        // cannot be focused for event listeners.
        canvas.setFocusable(false);
        
        // creates window with a bunch of defaults.
        window = new JFrame();
        window.getContentPane().add(canvas);
        window.setTitle(title);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.pack();
        window.setVisible(true);
        
        // center of screen.
        window.setLocationRelativeTo(null);
        
        BufferStrategy bufferStrategy = canvas.getBufferStrategy();
        
        if(bufferStrategy == null)
            canvas.createBufferStrategy(3);
    }
    
    // returns the frame.
    public JFrame getJFrame() {
        return window;
    }
    
    // returns the window width.
    public int getWidth() {
        return windowDimension.width;
    }
    
    // returns the window height.
    public int getHeight() {
        return windowDimension.height;
    }
    
    // returns the canvas.
    public Canvas getCanvas() {
        return canvas;
    }
}
package game.room;

import java.awt.Graphics2D;

// future functionality might be added,
// which is why this class is abstract and not interface.

// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
    public abstract void init();
    public abstract void update();
    public abstract void render(Graphics2D graphics);
}
Keyboard.java

package game.input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
    // the position of the mouse.
    public static int x, y;
    
    // Is the mouse pressed.
    public static boolean pressed;
    
    // Is the mouse held.
    public static boolean held;
    
    // Is the mouse hovered over the window.
    public static boolean focused;
    
    // Is the mouse being dragged.
    public static boolean dragging;
    
    // no mouse wheel support.
    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {}
    
    @Override
    public void mouseDragged(MouseEvent event) {
        x = event.getX();
        y = event.getY();
        dragging = true;
    }
    
    @Override
    public void mouseMoved(MouseEvent event) {
        x = event.getX();
        y = event.getY();
    }
    
    @Override
    public void mouseEntered(MouseEvent event) {
        focused = true;
    }
    
    @Override
    public void mouseExited(MouseEvent event) {
        focused = false;
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        held = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        held = false;
        dragging = false;
        pressed = true;
    }
}
package game.input;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

// holds information about key events.
public class Keyboard extends KeyAdapter {
    // which keys are being held down.
    private static boolean[] heldKeys;
    
    // which keys are being clicked
    private static boolean[] clickedKeys;
    
    // size of arrays.
    private final int size;
    
    public Keyboard() {
        // there are 255 valid key codes.
        // plus one for the array size.
        size = 256;
        
        clickedKeys = new boolean[size];
        heldKeys = new boolean[size];
    }
    
    // when the key is pressed.
    @Override
    public void keyPressed(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is being held.
        heldKeys[event.getKeyCode()] = true;
    }
    
    @Override
    public void keyReleased(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is let go.
        heldKeys[event.getKeyCode()] = false;
        
        // when key is let go, it gets interpreted as it being pressed.
        clickedKeys[event.getKeyCode()] = true;
    }
    
    // returns whether or not the key is held.
    public static boolean keyHeld(Key key) {
        if(heldKeys != null)
            return heldKeys[key.keyCode];
        return false;
    }
    
    // returns whether or not the key is clicked.
    public static boolean keyClicked(Key key) {
        if(clickedKeys != null)
            return clickedKeys[key.keyCode];
        return false;
    }
    
    // resets key input.
    public static void resetKeys() {
        if(clickedKeys != null)
            for(int i = 0; i < clickedKeys.length; i++)
                clickedKeys[i] = false;
    }
    
    public enum Key {
        // movement keys.
        LEFT(37), UP(38), RIGHT(39), DOWN(40),
        
        // x key.
        A(88),
        
        // z key.
        B(90),
        
        // enter key.
        START(10);
        
        private int keyCode;
        
        private Key(int keyCode) {
            this.keyCode = keyCode;
        }
    };
}
package game;

import java.awt.Graphics2D;

import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;

// creates a new game
public final class Game {
    // the window that the game resides in.
    private static BB_Window window;
    
    // the current room that is drawn to the window.
    private static Room room;
    
    private static GameLoop gameLoop;
    
    // game constructor cannot be called.
    private Game() {}
    
    // inits the game.
    // ie, adds input to the game (key and mouse).
    public static void init(BB_Window window) {
        if(gameLoop != null)
            return;
        
        // creates mouse and keyboard listeners.
        Mouse mouse = new Mouse();
        Keyboard keyboard = new Keyboard();
        
        // adds input listeners to the window.
        window.getJFrame().addKeyListener(keyboard);
        window.getCanvas().addMouseListener(mouse);
        window.getCanvas().addMouseMotionListener(mouse);
        
        // init game loop
        gameLoop = new GameLoop();
        
        // init window
        Game.window = window;
        
        gameLoop.start();
    }
    
    // updates the current room and resets input.
    protected static void update() {
        // if room doesn't exist, don't update it.
        if(room == null)
            return;
        
        // updates current room.
        Game.room.update();
        
        // resets mouse input.
        Mouse.pressed = false;
        
        // resets key input.
        Keyboard.resetKeys();
        
        // if a mouse or key button is clicked,
        // then it would have to be reset to false here.
    }
    
    // renders the current room.
    protected static void render() {
        // if room doesn't exist, don't render it.
        if(room == null)
            return;
        
        // creates graphics object from the window canvas.
        Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
        
        // creates the screen for next drawing.
        graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
        
        // renders the current room.
        Game.room.render(graphics);
        
        // shows the buffer.
        window.getCanvas().getBufferStrategy().show();
        
        // removes graphics object.
        graphics.dispose();
    }
    
    // sets the current room to a new one.
    public static void setRoom(Room newRoom) {
        newRoom.init();
        Game.room = newRoom;
    }
    
    // returns the current room.
    public static Room getRoom() {
        return Game.room;
    }
    
    // returns width of window.
    public static int getWindowWidth() {
        return window.getWidth();
    }
    
    // returns height of window.
    public static int getWindowHeight() {
        return window.getHeight();
    }
    
    // stops the game loop.
    public static void stop() {
        gameLoop.stop();
    }
}
package game;

public class GameLoop implements Runnable {
    // the thread that the game runs on.
    private Thread thread;
    
    // is the game running.
    private boolean running;
    
    // starts the game loop.
    // inits the thread and calls its start method.
    public void start() {
        // you can't start the game if it is started.
        if(running)
            return;
        
        // starts the game.
        running = true;
        
        // creates thread.
        thread = new Thread(this);
        
        // starts the game.
        // ie, calls thread.run();
        thread.start();
    }
    
    // stops the game loop.
    // interrupts the thread and terminates the currently running JVM.
    public void stop() {
        // you can't end the game if it is ended.
        if(!running)
            return;
        
        // ends the game.
        running = false;
        
        // interrupts the thread.
        // ie, ends the thread.
        // this will always end the thread,
        // because running is set to false.
        thread.interrupt();
        
        // ends the program.
        System.exit(0);
    }
    
    // this is the game loop.
    @Override
    public void run() {
        // holds information about each frames elapsed time.
        double start, previous = System.nanoTime() / 1_000_000_000.0;
        
        // time.
        double actualFrameTime, realTime = 0;
        
        // should the game be rendered.
        boolean render;
        
        // fps
        final int FPS = 60;
        final double DESIRED_FRAME_TIME = 1.0 / FPS;
        
        // while the game is running
        while(running) {
            // calculates the elapsed time of the frame.
            // converts from nano seconds to seconds
            // by dividing by one billion.
            start = System.nanoTime() / 1_000_000_000.0;
            actualFrameTime = start - previous;
            previous = start;
            
            // the game time is updated by the elapsed frame time.
            realTime += actualFrameTime;
            
            // resets it to back to false.
            render = false;
            
            // if time surpasses desired frame time, game should update.
            while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
                realTime -= DESIRED_FRAME_TIME;
                Game.update();
                
                // if the game is updated, the game should render.
                // if the game is not updated, the game doesn't render.
                render = true;
            }
            
            if(render)
                Game.render();
            // sleep if game should not render.
            // reduces cpu usage by a lot.
            else
                try {
                    // sleep for one millisecond.
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
package userInterface.containers;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

// the JFrame that the game will reside in.
public final class BB_Window {
    private JFrame window;
    private Canvas canvas;
    private Dimension windowDimension;
    
    // constructs the canvas, window, and buffer.
    public BB_Window(String title, int width, int height) {
        // creates dimension.
        windowDimension = new Dimension(width, height);
        
        // creates a canvas with a bunch of defaults.
        canvas = new Canvas();
        
        // sets a non-changeable size.
        canvas.setPreferredSize(windowDimension);
        canvas.setMinimumSize(windowDimension);
        canvas.setMaximumSize(windowDimension);
        
        // cannot be focused for event listeners.
        canvas.setFocusable(false);
        
        // creates window with a bunch of defaults.
        window = new JFrame();
        window.getContentPane().add(canvas);
        window.setTitle(title);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.pack();
        window.setVisible(true);
        
        // center of screen.
        window.setLocationRelativeTo(null);
        
        BufferStrategy bufferStrategy = canvas.getBufferStrategy();
        
        if(bufferStrategy == null)
            canvas.createBufferStrategy(3);
    }
    
    // returns the frame.
    public JFrame getJFrame() {
        return window;
    }
    
    // returns the window width.
    public int getWidth() {
        return windowDimension.width;
    }
    
    // returns the window height.
    public int getHeight() {
        return windowDimension.height;
    }
    
    // returns the canvas.
    public Canvas getCanvas() {
        return canvas;
    }
}
package game.room;

import java.awt.Graphics2D;

// future functionality might be added,
// which is why this class is abstract and not interface.

// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
    public abstract void init();
    public abstract void update();
    public abstract void render(Graphics2D graphics);
}
GameLoop.java

package game.input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
    // the position of the mouse.
    public static int x, y;
    
    // Is the mouse pressed.
    public static boolean pressed;
    
    // Is the mouse held.
    public static boolean held;
    
    // Is the mouse hovered over the window.
    public static boolean focused;
    
    // Is the mouse being dragged.
    public static boolean dragging;
    
    // no mouse wheel support.
    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {}
    
    @Override
    public void mouseDragged(MouseEvent event) {
        x = event.getX();
        y = event.getY();
        dragging = true;
    }
    
    @Override
    public void mouseMoved(MouseEvent event) {
        x = event.getX();
        y = event.getY();
    }
    
    @Override
    public void mouseEntered(MouseEvent event) {
        focused = true;
    }
    
    @Override
    public void mouseExited(MouseEvent event) {
        focused = false;
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        held = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        held = false;
        dragging = false;
        pressed = true;
    }
}
package game.input;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

// holds information about key events.
public class Keyboard extends KeyAdapter {
    // which keys are being held down.
    private static boolean[] heldKeys;
    
    // which keys are being clicked
    private static boolean[] clickedKeys;
    
    // size of arrays.
    private final int size;
    
    public Keyboard() {
        // there are 255 valid key codes.
        // plus one for the array size.
        size = 256;
        
        clickedKeys = new boolean[size];
        heldKeys = new boolean[size];
    }
    
    // when the key is pressed.
    @Override
    public void keyPressed(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is being held.
        heldKeys[event.getKeyCode()] = true;
    }
    
    @Override
    public void keyReleased(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is let go.
        heldKeys[event.getKeyCode()] = false;
        
        // when key is let go, it gets interpreted as it being pressed.
        clickedKeys[event.getKeyCode()] = true;
    }
    
    // returns whether or not the key is held.
    public static boolean keyHeld(Key key) {
        if(heldKeys != null)
            return heldKeys[key.keyCode];
        return false;
    }
    
    // returns whether or not the key is clicked.
    public static boolean keyClicked(Key key) {
        if(clickedKeys != null)
            return clickedKeys[key.keyCode];
        return false;
    }
    
    // resets key input.
    public static void resetKeys() {
        if(clickedKeys != null)
            for(int i = 0; i < clickedKeys.length; i++)
                clickedKeys[i] = false;
    }
    
    public enum Key {
        // movement keys.
        LEFT(37), UP(38), RIGHT(39), DOWN(40),
        
        // x key.
        A(88),
        
        // z key.
        B(90),
        
        // enter key.
        START(10);
        
        private int keyCode;
        
        private Key(int keyCode) {
            this.keyCode = keyCode;
        }
    };
}
package game;

import java.awt.Graphics2D;

import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;

// creates a new game
public final class Game {
    // the window that the game resides in.
    private static BB_Window window;
    
    // the current room that is drawn to the window.
    private static Room room;
    
    private static GameLoop gameLoop;
    
    // game constructor cannot be called.
    private Game() {}
    
    // inits the game.
    // ie, adds input to the game (key and mouse).
    public static void init(BB_Window window) {
        if(gameLoop != null)
            return;
        
        // creates mouse and keyboard listeners.
        Mouse mouse = new Mouse();
        Keyboard keyboard = new Keyboard();
        
        // adds input listeners to the window.
        window.getJFrame().addKeyListener(keyboard);
        window.getCanvas().addMouseListener(mouse);
        window.getCanvas().addMouseMotionListener(mouse);
        
        // init game loop
        gameLoop = new GameLoop();
        
        // init window
        Game.window = window;
        
        gameLoop.start();
    }
    
    // updates the current room and resets input.
    protected static void update() {
        // if room doesn't exist, don't update it.
        if(room == null)
            return;
        
        // updates current room.
        Game.room.update();
        
        // resets mouse input.
        Mouse.pressed = false;
        
        // resets key input.
        Keyboard.resetKeys();
        
        // if a mouse or key button is clicked,
        // then it would have to be reset to false here.
    }
    
    // renders the current room.
    protected static void render() {
        // if room doesn't exist, don't render it.
        if(room == null)
            return;
        
        // creates graphics object from the window canvas.
        Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
        
        // creates the screen for next drawing.
        graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
        
        // renders the current room.
        Game.room.render(graphics);
        
        // shows the buffer.
        window.getCanvas().getBufferStrategy().show();
        
        // removes graphics object.
        graphics.dispose();
    }
    
    // sets the current room to a new one.
    public static void setRoom(Room newRoom) {
        newRoom.init();
        Game.room = newRoom;
    }
    
    // returns the current room.
    public static Room getRoom() {
        return Game.room;
    }
    
    // returns width of window.
    public static int getWindowWidth() {
        return window.getWidth();
    }
    
    // returns height of window.
    public static int getWindowHeight() {
        return window.getHeight();
    }
    
    // stops the game loop.
    public static void stop() {
        gameLoop.stop();
    }
}
package game;

public class GameLoop implements Runnable {
    // the thread that the game runs on.
    private Thread thread;
    
    // is the game running.
    private boolean running;
    
    // starts the game loop.
    // inits the thread and calls its start method.
    public void start() {
        // you can't start the game if it is started.
        if(running)
            return;
        
        // starts the game.
        running = true;
        
        // creates thread.
        thread = new Thread(this);
        
        // starts the game.
        // ie, calls thread.run();
        thread.start();
    }
    
    // stops the game loop.
    // interrupts the thread and terminates the currently running JVM.
    public void stop() {
        // you can't end the game if it is ended.
        if(!running)
            return;
        
        // ends the game.
        running = false;
        
        // interrupts the thread.
        // ie, ends the thread.
        // this will always end the thread,
        // because running is set to false.
        thread.interrupt();
        
        // ends the program.
        System.exit(0);
    }
    
    // this is the game loop.
    @Override
    public void run() {
        // holds information about each frames elapsed time.
        double start, previous = System.nanoTime() / 1_000_000_000.0;
        
        // time.
        double actualFrameTime, realTime = 0;
        
        // should the game be rendered.
        boolean render;
        
        // fps
        final int FPS = 60;
        final double DESIRED_FRAME_TIME = 1.0 / FPS;
        
        // while the game is running
        while(running) {
            // calculates the elapsed time of the frame.
            // converts from nano seconds to seconds
            // by dividing by one billion.
            start = System.nanoTime() / 1_000_000_000.0;
            actualFrameTime = start - previous;
            previous = start;
            
            // the game time is updated by the elapsed frame time.
            realTime += actualFrameTime;
            
            // resets it to back to false.
            render = false;
            
            // if time surpasses desired frame time, game should update.
            while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
                realTime -= DESIRED_FRAME_TIME;
                Game.update();
                
                // if the game is updated, the game should render.
                // if the game is not updated, the game doesn't render.
                render = true;
            }
            
            if(render)
                Game.render();
            // sleep if game should not render.
            // reduces cpu usage by a lot.
            else
                try {
                    // sleep for one millisecond.
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
package userInterface.containers;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

// the JFrame that the game will reside in.
public final class BB_Window {
    private JFrame window;
    private Canvas canvas;
    private Dimension windowDimension;
    
    // constructs the canvas, window, and buffer.
    public BB_Window(String title, int width, int height) {
        // creates dimension.
        windowDimension = new Dimension(width, height);
        
        // creates a canvas with a bunch of defaults.
        canvas = new Canvas();
        
        // sets a non-changeable size.
        canvas.setPreferredSize(windowDimension);
        canvas.setMinimumSize(windowDimension);
        canvas.setMaximumSize(windowDimension);
        
        // cannot be focused for event listeners.
        canvas.setFocusable(false);
        
        // creates window with a bunch of defaults.
        window = new JFrame();
        window.getContentPane().add(canvas);
        window.setTitle(title);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.pack();
        window.setVisible(true);
        
        // center of screen.
        window.setLocationRelativeTo(null);
        
        BufferStrategy bufferStrategy = canvas.getBufferStrategy();
        
        if(bufferStrategy == null)
            canvas.createBufferStrategy(3);
    }
    
    // returns the frame.
    public JFrame getJFrame() {
        return window;
    }
    
    // returns the window width.
    public int getWidth() {
        return windowDimension.width;
    }
    
    // returns the window height.
    public int getHeight() {
        return windowDimension.height;
    }
    
    // returns the canvas.
    public Canvas getCanvas() {
        return canvas;
    }
}
package game.room;

import java.awt.Graphics2D;

// future functionality might be added,
// which is why this class is abstract and not interface.

// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
    public abstract void init();
    public abstract void update();
    public abstract void render(Graphics2D graphics);
}
BB_Window.java

package game.input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
    // the position of the mouse.
    public static int x, y;
    
    // Is the mouse pressed.
    public static boolean pressed;
    
    // Is the mouse held.
    public static boolean held;
    
    // Is the mouse hovered over the window.
    public static boolean focused;
    
    // Is the mouse being dragged.
    public static boolean dragging;
    
    // no mouse wheel support.
    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {}
    
    @Override
    public void mouseDragged(MouseEvent event) {
        x = event.getX();
        y = event.getY();
        dragging = true;
    }
    
    @Override
    public void mouseMoved(MouseEvent event) {
        x = event.getX();
        y = event.getY();
    }
    
    @Override
    public void mouseEntered(MouseEvent event) {
        focused = true;
    }
    
    @Override
    public void mouseExited(MouseEvent event) {
        focused = false;
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        held = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        held = false;
        dragging = false;
        pressed = true;
    }
}
package game.input;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

// holds information about key events.
public class Keyboard extends KeyAdapter {
    // which keys are being held down.
    private static boolean[] heldKeys;
    
    // which keys are being clicked
    private static boolean[] clickedKeys;
    
    // size of arrays.
    private final int size;
    
    public Keyboard() {
        // there are 255 valid key codes.
        // plus one for the array size.
        size = 256;
        
        clickedKeys = new boolean[size];
        heldKeys = new boolean[size];
    }
    
    // when the key is pressed.
    @Override
    public void keyPressed(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is being held.
        heldKeys[event.getKeyCode()] = true;
    }
    
    @Override
    public void keyReleased(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is let go.
        heldKeys[event.getKeyCode()] = false;
        
        // when key is let go, it gets interpreted as it being pressed.
        clickedKeys[event.getKeyCode()] = true;
    }
    
    // returns whether or not the key is held.
    public static boolean keyHeld(Key key) {
        if(heldKeys != null)
            return heldKeys[key.keyCode];
        return false;
    }
    
    // returns whether or not the key is clicked.
    public static boolean keyClicked(Key key) {
        if(clickedKeys != null)
            return clickedKeys[key.keyCode];
        return false;
    }
    
    // resets key input.
    public static void resetKeys() {
        if(clickedKeys != null)
            for(int i = 0; i < clickedKeys.length; i++)
                clickedKeys[i] = false;
    }
    
    public enum Key {
        // movement keys.
        LEFT(37), UP(38), RIGHT(39), DOWN(40),
        
        // x key.
        A(88),
        
        // z key.
        B(90),
        
        // enter key.
        START(10);
        
        private int keyCode;
        
        private Key(int keyCode) {
            this.keyCode = keyCode;
        }
    };
}
package game;

import java.awt.Graphics2D;

import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;

// creates a new game
public final class Game {
    // the window that the game resides in.
    private static BB_Window window;
    
    // the current room that is drawn to the window.
    private static Room room;
    
    private static GameLoop gameLoop;
    
    // game constructor cannot be called.
    private Game() {}
    
    // inits the game.
    // ie, adds input to the game (key and mouse).
    public static void init(BB_Window window) {
        if(gameLoop != null)
            return;
        
        // creates mouse and keyboard listeners.
        Mouse mouse = new Mouse();
        Keyboard keyboard = new Keyboard();
        
        // adds input listeners to the window.
        window.getJFrame().addKeyListener(keyboard);
        window.getCanvas().addMouseListener(mouse);
        window.getCanvas().addMouseMotionListener(mouse);
        
        // init game loop
        gameLoop = new GameLoop();
        
        // init window
        Game.window = window;
        
        gameLoop.start();
    }
    
    // updates the current room and resets input.
    protected static void update() {
        // if room doesn't exist, don't update it.
        if(room == null)
            return;
        
        // updates current room.
        Game.room.update();
        
        // resets mouse input.
        Mouse.pressed = false;
        
        // resets key input.
        Keyboard.resetKeys();
        
        // if a mouse or key button is clicked,
        // then it would have to be reset to false here.
    }
    
    // renders the current room.
    protected static void render() {
        // if room doesn't exist, don't render it.
        if(room == null)
            return;
        
        // creates graphics object from the window canvas.
        Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
        
        // creates the screen for next drawing.
        graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
        
        // renders the current room.
        Game.room.render(graphics);
        
        // shows the buffer.
        window.getCanvas().getBufferStrategy().show();
        
        // removes graphics object.
        graphics.dispose();
    }
    
    // sets the current room to a new one.
    public static void setRoom(Room newRoom) {
        newRoom.init();
        Game.room = newRoom;
    }
    
    // returns the current room.
    public static Room getRoom() {
        return Game.room;
    }
    
    // returns width of window.
    public static int getWindowWidth() {
        return window.getWidth();
    }
    
    // returns height of window.
    public static int getWindowHeight() {
        return window.getHeight();
    }
    
    // stops the game loop.
    public static void stop() {
        gameLoop.stop();
    }
}
package game;

public class GameLoop implements Runnable {
    // the thread that the game runs on.
    private Thread thread;
    
    // is the game running.
    private boolean running;
    
    // starts the game loop.
    // inits the thread and calls its start method.
    public void start() {
        // you can't start the game if it is started.
        if(running)
            return;
        
        // starts the game.
        running = true;
        
        // creates thread.
        thread = new Thread(this);
        
        // starts the game.
        // ie, calls thread.run();
        thread.start();
    }
    
    // stops the game loop.
    // interrupts the thread and terminates the currently running JVM.
    public void stop() {
        // you can't end the game if it is ended.
        if(!running)
            return;
        
        // ends the game.
        running = false;
        
        // interrupts the thread.
        // ie, ends the thread.
        // this will always end the thread,
        // because running is set to false.
        thread.interrupt();
        
        // ends the program.
        System.exit(0);
    }
    
    // this is the game loop.
    @Override
    public void run() {
        // holds information about each frames elapsed time.
        double start, previous = System.nanoTime() / 1_000_000_000.0;
        
        // time.
        double actualFrameTime, realTime = 0;
        
        // should the game be rendered.
        boolean render;
        
        // fps
        final int FPS = 60;
        final double DESIRED_FRAME_TIME = 1.0 / FPS;
        
        // while the game is running
        while(running) {
            // calculates the elapsed time of the frame.
            // converts from nano seconds to seconds
            // by dividing by one billion.
            start = System.nanoTime() / 1_000_000_000.0;
            actualFrameTime = start - previous;
            previous = start;
            
            // the game time is updated by the elapsed frame time.
            realTime += actualFrameTime;
            
            // resets it to back to false.
            render = false;
            
            // if time surpasses desired frame time, game should update.
            while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
                realTime -= DESIRED_FRAME_TIME;
                Game.update();
                
                // if the game is updated, the game should render.
                // if the game is not updated, the game doesn't render.
                render = true;
            }
            
            if(render)
                Game.render();
            // sleep if game should not render.
            // reduces cpu usage by a lot.
            else
                try {
                    // sleep for one millisecond.
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
package userInterface.containers;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

// the JFrame that the game will reside in.
public final class BB_Window {
    private JFrame window;
    private Canvas canvas;
    private Dimension windowDimension;
    
    // constructs the canvas, window, and buffer.
    public BB_Window(String title, int width, int height) {
        // creates dimension.
        windowDimension = new Dimension(width, height);
        
        // creates a canvas with a bunch of defaults.
        canvas = new Canvas();
        
        // sets a non-changeable size.
        canvas.setPreferredSize(windowDimension);
        canvas.setMinimumSize(windowDimension);
        canvas.setMaximumSize(windowDimension);
        
        // cannot be focused for event listeners.
        canvas.setFocusable(false);
        
        // creates window with a bunch of defaults.
        window = new JFrame();
        window.getContentPane().add(canvas);
        window.setTitle(title);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.pack();
        window.setVisible(true);
        
        // center of screen.
        window.setLocationRelativeTo(null);
        
        BufferStrategy bufferStrategy = canvas.getBufferStrategy();
        
        if(bufferStrategy == null)
            canvas.createBufferStrategy(3);
    }
    
    // returns the frame.
    public JFrame getJFrame() {
        return window;
    }
    
    // returns the window width.
    public int getWidth() {
        return windowDimension.width;
    }
    
    // returns the window height.
    public int getHeight() {
        return windowDimension.height;
    }
    
    // returns the canvas.
    public Canvas getCanvas() {
        return canvas;
    }
}
package game.room;

import java.awt.Graphics2D;

// future functionality might be added,
// which is why this class is abstract and not interface.

// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
    public abstract void init();
    public abstract void update();
    public abstract void render(Graphics2D graphics);
}
Room.java

package game.input;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

// holds information about mouse events.
// eg, presses of buttons.
public class Mouse extends MouseAdapter {
    // the position of the mouse.
    public static int x, y;
    
    // Is the mouse pressed.
    public static boolean pressed;
    
    // Is the mouse held.
    public static boolean held;
    
    // Is the mouse hovered over the window.
    public static boolean focused;
    
    // Is the mouse being dragged.
    public static boolean dragging;
    
    // no mouse wheel support.
    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {}
    
    @Override
    public void mouseDragged(MouseEvent event) {
        x = event.getX();
        y = event.getY();
        dragging = true;
    }
    
    @Override
    public void mouseMoved(MouseEvent event) {
        x = event.getX();
        y = event.getY();
    }
    
    @Override
    public void mouseEntered(MouseEvent event) {
        focused = true;
    }
    
    @Override
    public void mouseExited(MouseEvent event) {
        focused = false;
    }
    
    @Override
    public void mousePressed(MouseEvent event) {
        held = true;
    }
    
    @Override
    public void mouseReleased(MouseEvent event) {
        held = false;
        dragging = false;
        pressed = true;
    }
}
package game.input;

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

// holds information about key events.
public class Keyboard extends KeyAdapter {
    // which keys are being held down.
    private static boolean[] heldKeys;
    
    // which keys are being clicked
    private static boolean[] clickedKeys;
    
    // size of arrays.
    private final int size;
    
    public Keyboard() {
        // there are 255 valid key codes.
        // plus one for the array size.
        size = 256;
        
        clickedKeys = new boolean[size];
        heldKeys = new boolean[size];
    }
    
    // when the key is pressed.
    @Override
    public void keyPressed(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is being held.
        heldKeys[event.getKeyCode()] = true;
    }
    
    @Override
    public void keyReleased(KeyEvent event) {
        // catches out of bounds error.
        if(event.getKeyCode() > size)
            return;
        
        // key is let go.
        heldKeys[event.getKeyCode()] = false;
        
        // when key is let go, it gets interpreted as it being pressed.
        clickedKeys[event.getKeyCode()] = true;
    }
    
    // returns whether or not the key is held.
    public static boolean keyHeld(Key key) {
        if(heldKeys != null)
            return heldKeys[key.keyCode];
        return false;
    }
    
    // returns whether or not the key is clicked.
    public static boolean keyClicked(Key key) {
        if(clickedKeys != null)
            return clickedKeys[key.keyCode];
        return false;
    }
    
    // resets key input.
    public static void resetKeys() {
        if(clickedKeys != null)
            for(int i = 0; i < clickedKeys.length; i++)
                clickedKeys[i] = false;
    }
    
    public enum Key {
        // movement keys.
        LEFT(37), UP(38), RIGHT(39), DOWN(40),
        
        // x key.
        A(88),
        
        // z key.
        B(90),
        
        // enter key.
        START(10);
        
        private int keyCode;
        
        private Key(int keyCode) {
            this.keyCode = keyCode;
        }
    };
}
package game;

import java.awt.Graphics2D;

import game.input.Keyboard;
import game.input.Mouse;
import game.room.Room;
import userInterface.containers.BB_Window;

// creates a new game
public final class Game {
    // the window that the game resides in.
    private static BB_Window window;
    
    // the current room that is drawn to the window.
    private static Room room;
    
    private static GameLoop gameLoop;
    
    // game constructor cannot be called.
    private Game() {}
    
    // inits the game.
    // ie, adds input to the game (key and mouse).
    public static void init(BB_Window window) {
        if(gameLoop != null)
            return;
        
        // creates mouse and keyboard listeners.
        Mouse mouse = new Mouse();
        Keyboard keyboard = new Keyboard();
        
        // adds input listeners to the window.
        window.getJFrame().addKeyListener(keyboard);
        window.getCanvas().addMouseListener(mouse);
        window.getCanvas().addMouseMotionListener(mouse);
        
        // init game loop
        gameLoop = new GameLoop();
        
        // init window
        Game.window = window;
        
        gameLoop.start();
    }
    
    // updates the current room and resets input.
    protected static void update() {
        // if room doesn't exist, don't update it.
        if(room == null)
            return;
        
        // updates current room.
        Game.room.update();
        
        // resets mouse input.
        Mouse.pressed = false;
        
        // resets key input.
        Keyboard.resetKeys();
        
        // if a mouse or key button is clicked,
        // then it would have to be reset to false here.
    }
    
    // renders the current room.
    protected static void render() {
        // if room doesn't exist, don't render it.
        if(room == null)
            return;
        
        // creates graphics object from the window canvas.
        Graphics2D graphics = (Graphics2D) window.getCanvas().getBufferStrategy().getDrawGraphics();
        
        // creates the screen for next drawing.
        graphics.clearRect(0, 0, window.getWidth(), window.getHeight());
        
        // renders the current room.
        Game.room.render(graphics);
        
        // shows the buffer.
        window.getCanvas().getBufferStrategy().show();
        
        // removes graphics object.
        graphics.dispose();
    }
    
    // sets the current room to a new one.
    public static void setRoom(Room newRoom) {
        newRoom.init();
        Game.room = newRoom;
    }
    
    // returns the current room.
    public static Room getRoom() {
        return Game.room;
    }
    
    // returns width of window.
    public static int getWindowWidth() {
        return window.getWidth();
    }
    
    // returns height of window.
    public static int getWindowHeight() {
        return window.getHeight();
    }
    
    // stops the game loop.
    public static void stop() {
        gameLoop.stop();
    }
}
package game;

public class GameLoop implements Runnable {
    // the thread that the game runs on.
    private Thread thread;
    
    // is the game running.
    private boolean running;
    
    // starts the game loop.
    // inits the thread and calls its start method.
    public void start() {
        // you can't start the game if it is started.
        if(running)
            return;
        
        // starts the game.
        running = true;
        
        // creates thread.
        thread = new Thread(this);
        
        // starts the game.
        // ie, calls thread.run();
        thread.start();
    }
    
    // stops the game loop.
    // interrupts the thread and terminates the currently running JVM.
    public void stop() {
        // you can't end the game if it is ended.
        if(!running)
            return;
        
        // ends the game.
        running = false;
        
        // interrupts the thread.
        // ie, ends the thread.
        // this will always end the thread,
        // because running is set to false.
        thread.interrupt();
        
        // ends the program.
        System.exit(0);
    }
    
    // this is the game loop.
    @Override
    public void run() {
        // holds information about each frames elapsed time.
        double start, previous = System.nanoTime() / 1_000_000_000.0;
        
        // time.
        double actualFrameTime, realTime = 0;
        
        // should the game be rendered.
        boolean render;
        
        // fps
        final int FPS = 60;
        final double DESIRED_FRAME_TIME = 1.0 / FPS;
        
        // while the game is running
        while(running) {
            // calculates the elapsed time of the frame.
            // converts from nano seconds to seconds
            // by dividing by one billion.
            start = System.nanoTime() / 1_000_000_000.0;
            actualFrameTime = start - previous;
            previous = start;
            
            // the game time is updated by the elapsed frame time.
            realTime += actualFrameTime;
            
            // resets it to back to false.
            render = false;
            
            // if time surpasses desired frame time, game should update.
            while(realTime >= DESIRED_FRAME_TIME && realTime != 0) {
                realTime -= DESIRED_FRAME_TIME;
                Game.update();
                
                // if the game is updated, the game should render.
                // if the game is not updated, the game doesn't render.
                render = true;
            }
            
            if(render)
                Game.render();
            // sleep if game should not render.
            // reduces cpu usage by a lot.
            else
                try {
                    // sleep for one millisecond.
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}
package userInterface.containers;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;

import javax.swing.JFrame;

// the JFrame that the game will reside in.
public final class BB_Window {
    private JFrame window;
    private Canvas canvas;
    private Dimension windowDimension;
    
    // constructs the canvas, window, and buffer.
    public BB_Window(String title, int width, int height) {
        // creates dimension.
        windowDimension = new Dimension(width, height);
        
        // creates a canvas with a bunch of defaults.
        canvas = new Canvas();
        
        // sets a non-changeable size.
        canvas.setPreferredSize(windowDimension);
        canvas.setMinimumSize(windowDimension);
        canvas.setMaximumSize(windowDimension);
        
        // cannot be focused for event listeners.
        canvas.setFocusable(false);
        
        // creates window with a bunch of defaults.
        window = new JFrame();
        window.getContentPane().add(canvas);
        window.setTitle(title);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setResizable(false);
        window.pack();
        window.setVisible(true);
        
        // center of screen.
        window.setLocationRelativeTo(null);
        
        BufferStrategy bufferStrategy = canvas.getBufferStrategy();
        
        if(bufferStrategy == null)
            canvas.createBufferStrategy(3);
    }
    
    // returns the frame.
    public JFrame getJFrame() {
        return window;
    }
    
    // returns the window width.
    public int getWidth() {
        return windowDimension.width;
    }
    
    // returns the window height.
    public int getHeight() {
        return windowDimension.height;
    }
    
    // returns the canvas.
    public Canvas getCanvas() {
        return canvas;
    }
}
package game.room;

import java.awt.Graphics2D;

// future functionality might be added,
// which is why this class is abstract and not interface.

// represents a room/location in your Game
// eg, a town, a house, a forest, and a cave are all examples of rooms.
public abstract class Room {
    public abstract void init();
    public abstract void update();
    public abstract void render(Graphics2D graphics);
}
我觉得只有这些文件才能理解我的游戏库的功能

然而,我注意到,每当我测试我的游戏库时,都会有一个非常明显的口吃,每隔几秒钟就会发生一次,持续几秒钟。这很烦人。然而,更令人恼火的是,这种块状/滞后的运动在我的电脑上比在其他电脑上更明显。我的电脑发生了什么事情?我该如何解决这个问题?下面是我的游戏库工作原理的一个示例

Game.setRoom(new Room() {
    private int x, y;
    
    @Override
    public void init() {
        x = 0;
        y = 0;
    }
    
    @Override
    public void update() {
        x++;
        y++;
    }
    
    @Override
    public void render(Graphics2D graphics) {
        graphics.fillRect(x, y, 100, 100);
    }});

Game.init(new BB_Window("Test", 640, 640));
这个示例程序绘制了一个在屏幕上沿对角线向下移动的矩形。 然而,有时,矩形似乎“跳过”像素,并且移动得比它应该移动的更多。 我试着记录我的屏幕来准确地显示正在发生的事情,但由于某种原因,口吃没有出现在视频中

我尝试通过执行以下操作来启用硬件加速

System.setProperty("sun.java2d.opengl", "true");
但那没用

我的电脑一点也不坏,那么为什么游戏在其他电脑上运行比在我的电脑上更流畅呢

我该怎么做才能在我的游戏库中修复这个问题


提前感谢您。

您正在使用第三方课程,因此我们无法进行测试。我注意到,每当我测试我的游戏库时,都会有一个非常明显的口吃,每隔几秒钟就会发生一次,持续几秒钟。-在这个工作示例中,我没有注意到任何问题:我注意到每当我测试我的游戏库时,都会有一个非常明显的口吃,每隔几秒钟就会发生一次,持续几秒钟。很抱歉,我将添加它。现在你应该能够在你的机器上测试它
Thread.sleep(1)← 这就是为什么。你占用了你的CPU。是的,睡眠(1)总比不睡眠好,但你仍然经常荒谬地运行游戏循环。绘图的帧速率不是唯一重要的帧速率;你真的需要多久重复一次游戏循环?提高游戏状态的频率超过每秒20次有什么好处吗?有人会注意到你的游戏是否需要0.05秒来响应输入吗?1)我在一个文件中给了你一个例子,你可以下载并测试。我不打算抄6门课。如果你想让我们帮你把事情弄简单。2) 我的链接的重点是让您查看代码,了解它是如何工作的,然后进行更改。3) 不要使用魔法数字。所有枚举的值都是幻数。使用API提供的字段,例如KeyEvent.VK_LEFT。4) 您应该使用
键绑定
,而不是KeyListener来处理键盘事件。5) 使用
摆动计时器
,而不是Thread.sleep()来安排动画。您使用的是第三方类,因此我们无法进行测试。我注意到,每当我测试我的游戏库时,都会有一个非常明显的口吃,每隔几秒钟就会发生一次,持续几秒钟。-在这个工作示例中,我没有注意到任何问题:我注意到每当我测试我的游戏库时,都会有一个非常明显的口吃,每隔几秒钟就会发生一次,持续几秒钟。很抱歉,我将添加它。现在你应该能够在你的机器上测试它
Thread.sleep(1)← 这就是为什么。你占用了你的CPU。是的,睡眠(1)总比不睡眠好,但你仍然经常荒谬地运行游戏循环。绘图的帧速率不是唯一重要的帧速率;你真的需要多久重复一次游戏循环?提高游戏状态的频率超过每秒20次有什么好处吗?有人会注意到你的游戏是否需要0.05秒来响应输入吗?1)我在一个文件中给了你一个例子,你可以下载并测试。我不打算抄6门课。如果你想让我们帮你把事情弄简单。2) 我的链接的重点是让您查看代码,了解它是如何工作的,然后进行更改。3) 不要使用魔法数字。所有枚举的值都是幻数。使用API提供的字段,例如KeyEvent.VK_LEFT。4) 您应该使用
键绑定
,而不是KeyListener来处理键盘事件。5) 使用
摆动计时器
,而不是Thread.sleep()来安排动画。