Hi, I was looking at the game loop tutorial and put it in a simple tile map based demo. I noticed that it consumes around 30% of the CPU. Is this value expected? Minecraft consumes exactly the same in my machine, but the game is much heavier. Just wondering if I could optimize my cpu consuption. Here is the code if anyone want to try, can run in window mode or applet.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
public class TileMap1 extends Applet implements Runnable {
private static final int SCREEN_WIDTH = 8 * 32;
private static final int SCREEN_HEIGHT = 7 * 32;
private boolean isApplet;
private Thread gameThread;
private int fps;
private BufferedImage tiles;
private Image offImage;
private int[][] myMap = { { 1, 1, 1, 1, 1, 1, 1, 1 }, //
{ 1, 0, 0, 0, 0, 0, 0, 1 }, //
{ 1, 0, 1, 0, 0, 0, 0, 1 }, //
{ 1, 0, 0, 0, 0, 1, 0, 1 }, //
{ 1, 0, 0, 0, 0, 0, 0, 2 }, //
{ 1, 1, 1, 1, 1, 1, 1, 1 } };
private int[][] myMap2 = { { 1, 1, 1, 1, 1, 1, 1, 1 }, //
{ 1, 0, 0, 0, 0, 0, 0, 1 }, //
{ 1, 0, 1, 0, 0, 0, 0, 1 }, //
{ 1, 0, 0, 0, 0, 1, 0, 1 }, //
{ 3, 0, 0, 0, 0, 0, 0, 1 }, //
{ 1, 1, 1, 1, 1, 1, 1, 1 } };
private int[][] currentMap;
private Sprite hero;
private boolean[] controls = new boolean[5];
public TileMap1() {
this.hero = new Sprite(2, 1);
this.isApplet = true;
this.currentMap = this.myMap;
super.enableEvents(KeyEvent.KEY_EVENT_MASK);
}
public void init() {
this.offImage = super.createImage(SCREEN_WIDTH, SCREEN_HEIGHT);
try {
URL url = this.getClass().getClassLoader().getResource("tiles.png");
this.tiles = ImageIO.read(url);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
public void start() {
if (this.gameThread == null) {
this.gameThread = new Thread(this);
}
this.gameThread.start();
}
public void stop() {
this.gameThread = null;
}
public void paint(Graphics g) {
this.render(this.offImage.getGraphics());
g.drawImage(this.offImage, 0, 0, 640, 480, null);
}
private void render(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// Draws our map.
int mapWidth = this.currentMap[0].length;
int mapHeight = this.currentMap.length;
for (int i = 0; i < mapWidth; i++) {
for (int j = 0; j < mapHeight; j++) {
int frame = this.currentMap[j][i];
g.drawImage(this.tiles.getSubimage(frame * 32, 0, 32, 32),
i * 32, j * 32, null);
}
}
hero.render(g);
g.setColor(Color.red);
g.drawString("FPS:" + this.fps, 10, 10);
}
public void run() {
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
long lastFpsTime = 0;
int fps = 0;
while (true) {
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double) OPTIMAL_TIME);
// update the frame counter
lastFpsTime += updateLength;
fps++;
// System.out.println(lastFpsTime);
// update our FPS counter if a second has passed since
// we last recorded
if (lastFpsTime >= 1000000000) {
// System.out.println("(FPS: " + fps + ")");
this.fps = fps;
lastFpsTime = 0;
fps = 0;
}
this.logic();
this.paint(this.getGraphics());
Toolkit.getDefaultToolkit().sync();
try {
Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
} catch (Exception e) {
}
}
}
private void checkDoor(int j, int i) {
if (this.currentMap[j][i] == 2) {
this.currentMap = myMap2;
hero.x = 1 * 32 + 6;
} else if (this.currentMap[j][i] == 3) {
this.currentMap = myMap;
hero.x = 6 * 32 + 6;
}
}
private void logic() {
int dx = 0;
int dy = 0;
if (this.controls[0]) {
dx = -1;
} else if (this.controls[1]) {
dx = 1;
} else if (this.controls[2]) {
dy = -1;
} else if (this.controls[3]) {
dy = 1;
}
hero.move(dx, dy);
}
protected void processKeyEvent(KeyEvent e) {
int[] keys = new int[] { KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT,
KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_SPACE };
for (int i = 0; i < keys.length; i++) {
if (e.getKeyCode() == keys[i]) {
this.controls[i] = e.getID() == KeyEvent.KEY_PRESSED;
}
}
if (e.getKeyCode() == KeyEvent.VK_ESCAPE && !this.isApplet) {
System.exit(0);
}
}
public void buildFrame() {
Frame f = new Frame("Tile Based Maps Tutorial");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(640, 480);
f.setResizable(false);
Dimension dimension = getToolkit().getScreenSize();
Rectangle rectangle = f.getBounds();
f.setLocation((dimension.width - rectangle.width) / 2,
(dimension.height - rectangle.height) / 2);
f.add(this);
f.setVisible(true);
this.isApplet = false;
this.init();
this.start();
}
public static void main(String[] args) {
TileMap1 g = new TileMap1();
g.buildFrame();
}
class Sprite {
int x;
int y;
int dx;
int dy;
Sprite(int px, int py) {
x = px * 32 + 6;
y = py * 32 + 6;
}
void move(int pDx, int pDy) {
dx = pDx;
dy = pDy;
if (pDy != 0) {
if (canMove(x, y + dy)) {
checkDoor((int) Math.floor(y / 32),
(int) Math.floor(x / 32));
y += dy;
}
}
if (pDx != 0) {
if (canMove(x + dx, y)) {
checkDoor((int) Math.floor(y / 32),
(int) Math.floor(x / 32));
x += dx;
}
}
}
boolean canMove(int x, int y) {
int downY = (int) Math.floor((y + 20) / 32);
int upY = (int) Math.floor(y / 32);
int leftX = (int) Math.floor(x / 32);
int rightX = (int) Math.floor((x + 20) / 32);
if (dy == -1) {
return (!isSolid(upY, leftX) && !isSolid(upY, rightX));
} else if (dy == 1) {
return (!isSolid(downY, leftX) && !isSolid(downY, rightX));
}
if (dx == -1) {
return (!isSolid(downY, leftX) && !isSolid(upY, leftX));
} else if (dx == 1) {
return (!isSolid(upY, rightX) && !isSolid(downY, rightX));
}
return false;
}
private boolean isSolid(int j, int i) {
return (currentMap[j][i] == 1);
}
void render(Graphics g) {
// Body
g.setColor(Color.YELLOW);
g.fillOval(x, y, 20, 20);
g.setColor(Color.BLACK);
g.drawOval(x, y, 20, 20);
// Eyes
g.setColor(Color.WHITE);
g.fillOval(x + 2, y + 5, 8, 10);
g.fillOval(x + 10, y + 5, 8, 10);
g.setColor(Color.BLACK);
g.drawOval(x + 2, y + 5, 8, 10);
g.drawOval(x + 10, y + 5, 8, 10);
g.fillOval(x + 4 + (dx * 2), y + 8 + (dy * 2), 4, 4);
g.fillOval(x + 12 + (dx * 2), y + 8 + (dy * 2), 4, 4);
}
}
}