/* * Copyright (C) 2014, David Verhaak * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package edu.atlas.games; import java.awt.KeyboardFocusManager; import java.util.logging.Level; import java.util.logging.Logger; import edu.atlas.games.content.Content; import edu.atlas.games.graphics.SpriteBatch; import edu.atlas.games.graphics.Texture2D; import edu.atlas.games.input.Keyboard; import edu.atlas.games.input.KeyboardState; import edu.atlas.games.input.Keys; /** * Handles the main of the Game. * @author David Verhaak <david@forcez.nl> * @since 0.1 */ public class Game implements Runnable { public static final ThreadGroup THREAD_GROUP = new ThreadGroup("atlas-games"); private static final Logger LOG = Logger.getLogger(Game.class.getName()); private final int TARGET_FPS = 60; private final long OPTIMAL_TIME = 1000 / TARGET_FPS; private final int MAX_FRAME_SKIPS = 5; private long timeStarted; private int framesSkipped; private long timeDifference; private long sleepTime; private boolean running; private Window window; private SpriteBatch spriteBatch; private Texture2D texture; /** * Constructs the Game by creating a <code>Window</code>, * constructing the <code>SpriteBatch</code> and adding the KeyEventDispatcher. * @since 0.1 */ public Game() { window = new Window(this); spriteBatch = new SpriteBatch(this); KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new Keyboard()); } /** * Runs the main game loop which calls <code>initialize</code> and <code>loadContent</code> * on start and calling <code>update</code> and <code>draw</code> every frame. * @since 0.1 */ @Override public void run() { initialize(); loadContent(); window.setVisible(true); running = true; while (running) { timeStarted = System.currentTimeMillis(); framesSkipped = 0; update(); window.getCanvas().display(); timeDifference = System.currentTimeMillis() - timeStarted; sleepTime = OPTIMAL_TIME - timeDifference; if (sleepTime > 0) { try { Thread.sleep(sleepTime); } catch (InterruptedException exception) { LOG.log(Level.SEVERE, null, exception); shutdown(); } } while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) { update(); sleepTime += OPTIMAL_TIME; framesSkipped++; } } shutdown(); } /** * Initializes the Game. * This method is automatically called when the game is started. * @since 0.1 */ public void initialize() { LOG.log(Level.INFO, "Initialize"); for (GameComponent component : Components.getGameComponents()) { component.initialize(); } } /** * Loads the content of the Game. * This method is automatically called when the game is started. * @since 0.1 */ public void loadContent() { LOG.log(Level.INFO, "LoadContent"); texture = Content.load(Texture2D.class, "content/images/umbrellas.png"); for (DrawableGameComponent component : Components.getDrawableGameComponents()) { component.loadContent(); } } /** * Updates the Game. * This method is automatically called once every frame. * @since 0.1 */ public void update() { KeyboardState keyboard = Keyboard.getState(); if (keyboard.isKeyDown(Keys.ESCAPE)) { this.shutdown(); } for (GameComponent component : Components.getGameComponents()) { if (component.isEnabled()) { component.update(); } } } /** * Draws the Game. * This method is automatically called once every frame. * @since 0.1 */ public void draw() { spriteBatch.draw(texture, new Vector2(300, 300)); for (DrawableGameComponent component : Components.getDrawableGameComponents()) { if (component.isVisible()) { component.draw(spriteBatch); } } } /** * Shuts the Game down. * This method is automatically called when the Window closes. * @since 0.1 */ public void shutdown() { LOG.log(Level.INFO, "Shutdown"); running = false; System.exit(0); } /** * Gets the current instance of the <code>Window</code> class. * @return The current instance of the <code>Window</code> class. * @since 0.1 */ public Window getWindow() { return window; } /** * Checks if the main game loop is running or not. * @return The current state of the main game loop. * @since 0.1 */ public boolean isRunning() { return running; } }