• [ << ]
  • [ 0 ]
  • [ 1 ]
  • [ 2 ]
  • [ >> ]
May '09
30
Deze 'game loop' is goed te implementeren met de standaardbibliotheek, bijvoorbeeld zoals geëllustreerd in de volgende code dat een vierkant de muis laat volgen over het scherm:

ClassicGameLoop.java
                      
public class ClassicGameLoop extends JFrame {

private int mx, my;
private int bx, by;
 
public ClassicGameLoop() {
	setSize(512, 512);
	setDefaultCloseOperation(
		JFrame.EXIT_ON_CLOSE
		);
	setVisible(true);
	this.addMouseMotionListener(
		new MouseMotionAdapter() {
			public void mouseMoved(MouseEvent e) {
				// Store location of mouse.
				mx = e.getX();
				my = e.getY();
		}
	});
}

public void paint(Graphics g) {
	// Redraw the Screen
	g.fillRect(0, 0, getWidth(), getHeight());
	g.setColor(Color.WHITE);
	g.translate(bx, by);
	g.fillRect(0, 0, 3, 3);
}

public void run() throws Exception {
	while (true) {
		// Signal refresh to event queue.
		repaint();			
		// Update model
		if (bx > mx) bx--; else bx++; 
		if (by > my) by--; else by++;
		// Wait a bit.
		Thread.sleep(10L);
	}
}

public static void main(String[] args) throws Exception {
	new ClassicGameLoop().run();
}

}

                      
De code werkt als volgt: In de main methode wordt een nieuwe instantie gemaakt van ClassicGameLoop, wat een venster is op het scherm. In de constructor wordt het venster zichtbaar gezet nadat de grootte en het standaard sluit gedrag is ingesteld. Vervolgens wordt een MouseMotionListener gebruikt om bij iedere muisbeweging de nieuwe positie van de muis door te krijgen. Wanneer het ClassicGameLoop venster is geconstrueerd wordt de run() methode uitgevoerd die de eigenlijke implementatie van de 'game loop' bevat. Als eerste wordt op asynchrone wijze gevraagd om het scherm te verversen, wat na verloop van tijd resulteert in een aanroep van de paint(..) methode. Vervolgens wordt het spel model bijgewerkt en na een korte pauze begint de cyclus overnieuw.

Een nadeel van het asynchrone updaten van het scherm via de repaint() methode is dat deze nog wel eens wil hikken. Dit komt omdat het achterliggend mechanisme probeert zo efficiënt mogelijk om te gaan met scherm verversingen en daarom er nog wel eens één of meerdere wil overslaan. Dit mechanisme is bedoeld voor gewone gebruikerinterfaces en niet voor spellen. Een oplossing hiervoor is om het heft in eigen hand te nemen en actief te gaan renderen. Dit is eenvoudig te doen door gebruik te maken van het BufferStrategy object dat in ieder venster zit ingebouwd. Door het in de constructor te initialiseren met createBufferStrategy(2) en vervolgens de 'game loop' aan te passen wordt de ClassicGameLoop een ActiveGameLoop:

ActiveGameLoop.java
                      
public void run() throws Exception {
	while (true) {
		Graphics g = this.getBufferStrategy()
			.getDrawGraphics();
		// Render
		paint(g);
		// Show
		this.getBufferStrategy().show();
		// Update model
		if (bx > mx) bx--; else bx++;
		if (by > my) by--; else by++;
		// Wait a bit
		Thread.sleep(10L);
	}
}

                      
Nu dat het scherm actief ververst wordt en daardoor geen hikken kunnen optreden is er nog een ander gemeen detail. De duur van 1 iteratie van de game loop is afhankelijk van de snelheid van de hardware. Door nu de ingebouwde vertraging van 10ms aan te passen naar een dynamische vertraging die compenseert voor de duur van het renderen en het updaten van het model kan ook dit probleem opgelost worden. System.currentTimeMillis() en System.nanoTime() maken dit mogelijk.

Andere belangrijke onderdelen van een spel zijn muziek en geluidseffecten. Hiervoor heeft Java ook een standaard api, de javax.sound api. Helaas zit ondersteuning voor het mp3 of ogg formaat er niet standaard in, maar door gebruik te maken van 3rd party uitbreidingen via de Service Provider Interface (SPI) zijn deze eenvoudig en transparant (geen extra code, enkel een jar file) toe te voegen aan het spel. Javazoom.net heeft bijvoorbeeld een mooie LGPL mp3 en ogg vorbis library.
  • [ << ]
  • [ 0 ]
  • [ 1 ]
  • [ 2 ]
  • [ >> ]