/**
* Handles the ticking and rendering of the game.
* The Engine stores a reference to the active state and calls
* its tick and render methods.
*
* @author John Salis
*/
package jsalis.framework;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
public class Engine implements Runnable {
public final static int GAME_SPEED = 1000 / 40; // milliseconds / FPS
public final static int COLOR_SHADES = 6;
private volatile boolean isRunning = false;
private long tickCount = 0;
private Canvas canvas = new Canvas();
private BufferedImage screen;
private Graphics2D graphics;
private int[] pixels;
private int[] colors;
private AbstractState state;
private Thread thread;
public Engine(int width, int height) {
canvas.setPreferredSize(new Dimension(width, height));
screen = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
graphics = screen.createGraphics();
pixels = ((DataBufferInt)screen.getRaster().getDataBuffer()).getData();
}
private void createColors() {
colors = new int[COLOR_SHADES * COLOR_SHADES * COLOR_SHADES];
int index = 0;
for (int r = 0; r < COLOR_SHADES; r++) {
for (int g = 0; g < COLOR_SHADES; g++) {
for (int b = 0; b < COLOR_SHADES; b++) {
int rr = r * 255 / (COLOR_SHADES - 1);
int gg = g * 255 / (COLOR_SHADES - 1);
int bb = b * 255 / (COLOR_SHADES - 1);
colors[index++] = rr << 16 | gg << 8 | bb;
}
}
}
}
public void setState(AbstractState state) {
this.state = state;
}
public long getTickCount() {
return tickCount;
}
public Canvas getCanvas() {
return canvas;
}
private void tick() {
tickCount ++;
state.tick();
for (int i = 0; i < pixels.length; i++) {
pixels[i] = (int) (i + tickCount);
}
}
private void render() {
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, screen.getWidth(), screen.getHeight());
state.render(graphics);
BufferStrategy bs = canvas.getBufferStrategy();
if (bs == null) {
canvas.createBufferStrategy(2);
return;
}
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
g.drawImage(screen, 0, 0, screen.getWidth(), screen.getHeight(), canvas);
Toolkit.getDefaultToolkit().sync();
g.dispose();
bs.show();
}
public synchronized void start() {
if (isRunning) {
return;
} else {
isRunning = true;
thread = new Thread(this);
thread.start();
}
}
public synchronized void stop() {
if (!isRunning) {
return;
} else {
isRunning = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2() {
long last, diff, sleep;
last = System.currentTimeMillis();
while (isRunning) {
tick();
render();
diff = System.currentTimeMillis() - last;
sleep = GAME_SPEED - diff;
if (sleep < 0) sleep = 2;
try {
Thread.sleep(sleep);
}
catch (InterruptedException e) {
e.printStackTrace();
}
last = System.currentTimeMillis();
}
stop();
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 40D;
int ticks = 0;
int frames = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while (isRunning) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while(delta >= 1) {
ticks ++;
tick();
delta -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
}
catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
frames ++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
System.out.println("Frames: " + frames + "\t" + "Ticks: " + ticks);
frames = 0;
ticks = 0;
}
}
}
}