SST-CTF/snake

View on GitHub
org.sstctf.snake_game/src/org/sstctf/snake_game/Game.java

Summary

Maintainability
A
25 mins
Test Coverage
package org.sstctf.snake_game;

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

/**
 * The main class of the snake_game package.
 * It is a canvas that can be added to a frame.
 * It is creates a thread on start that executes the
 * game loop.
 * The class controls the rendering and updating of all
 * game objects.
 * 
 * @author Andrew Quach
 * @author Stanislav Lyakhov
 *
 * @version 1.0.0
 */
public class Game extends Canvas implements Runnable {

    private static final long serialVersionUID = -4394636783234289567L;

    public static final int WIDTH = 640, HEIGHT = 640; 
    public static final int SCALE = 16;
    public static final String NAME = "SNAKE";

    private Thread thread;
    private volatile boolean running = false;
    private Handler handler;
    private HUD hud;
    private DeathScreen deathScreen;

    public static State gameState = State.GAME;

    /**
     * Creates new handler, hud, and deathScreen objects.
     * Sets boundaries and repaint options for canvas.
     * Adds the key listener from KeyInput class.
     * Creates the main window.
     * Adds the main game objects.
     */
    public Game() {
        // New handler, hud, and death screen objects
        handler = new Handler();
        hud = new HUD(handler);
        deathScreen = new DeathScreen(hud);
        // Set canvas options
        setIgnoreRepaint(true);
        setBounds(0, 0, WIDTH, HEIGHT+100);
        // Add key listener
        this.addKeyListener(new KeyInput(handler));
        // Create new window
        new Window(WIDTH, HEIGHT, NAME, this);
        // Add main game objects
        handler.addObject(new Board(0, 0));
        handler.addObject(new Snake(1, 1, handler, this));
        handler.addObject(new Pellet(5, 5, handler));
    }

    /**
     * Delegates onDeath actions to deathScreen object.
     */
    public void onDeath() {
        deathScreen.onDeath();
    }

    /**
     * Create a new thread, start it, and set
     * the running state to true.
     */
    public synchronized void start() {
        thread = new Thread(this);
        thread.start();
        running = true;
    }

    /**
     * Set the running state to false to
     * stop the thread.
     */
    public synchronized void stop() {
        running = false;
    }

    /**
     * Override of run() in runnable that executes on thread start.
     * Requests the window focus on start.
     * Main game loop that executes tick() every 15 seconds.
     * Continuously renders by calling render() while game is running. 
     */
    @Override
    public void run() {
        this.requestFocus();

        long lastTime = System.nanoTime();
        double amountOfTicks = 15.0;
        // Amount of times our ticks go into 1 second
        double ns = 1000000000 / amountOfTicks;
        double delta = 0.0;

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

            // While one tick of time has passed
            while (delta >= 1) {
                // Run tick() every tick
                tick();
                delta--;
            }
            // Render everything if game is still running
            if (running) render();
        }

        stop();
    }

    /**
     * Call the tick methods of handler and hud
     * while the game state is GAME.
     */
    private void tick() {
        if (gameState == State.GAME) {
            handler.tick();
            hud.tick();
        } 
    }

    /**
     * Render method that controls all rendering in the game.
     * Uses a bufferstrategy to prevent unnecessary flickering.
     * Controls which classes gets to render depending on game state.
     */
    private void render() {
        // Get a buffer strategy from canvas if it exists
        BufferStrategy bs = this.getBufferStrategy();
        // Else create a buffer strategy
        if (bs == null) {
            // Triple buffering
            this.createBufferStrategy(3);
            return;
        }
        // Create graphics object from buffer strategy
        Graphics g = bs.getDrawGraphics();

        // Render handler and hud if the state is GAME
        if (gameState == State.GAME) {
            handler.render(g);
            hud.render(g);
        // Render deathScreen is the state is DEATH
        } else if (gameState == State.DEATH) {
            deathScreen.render(g);
        }

        g.dispose();
        // Display the buffer
        bs.show();
    }

    /**
     * Main method responsible of creating the game object.
     */
    public static void main(String[] args) {
        new Game();
    }
}