本節書摘來異步社群《java 2d遊戲程式設計入門》一書中的第8章,第8.7節,作者:【美】timothy wright(萊特),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
原型遊戲如圖8.12所示,位于javagames.prototype包中,它使用了我們目前為止所見過的所有技術。盡管這隻是一個原型,并且目前還沒有成為一款完整的遊戲,但我已經展示了足夠的工具來讓一些功能奏效。如果要等到最後再制作一款遊戲,可能需要等太長的時間。

該原型遊戲使用了我們在本章前面所介紹的如下的類。
polygonwrapper
prototypeship
prototypeasteroid
prototypeasteroidfactory
prototypebullet
當你在本章末尾嘗試編譯和運作代碼之前,確定已經建立了這些類。
initialize()方法為原型建立了所有這些對象,包括建立了一些星星作為背景。如下的代碼建立了星星,并且建立了顔色的一個數組。color類接受3個值:red、blue和green,這3個值在0到1之間。将每種顔色值設定為相同的值,将會産生灰色的陰影。本書稍後會詳細介紹顔色,但現在,隻要使用java語言所提供的java.awt.color類就行了。
// prototypegame.java
private vector2f getasteroidstartposition() {
float angle = (float)math.toradians( rand.nextint( 360 ) );
float minimum = appworldwidth / 4.0f;
float extra = rand.nextfloat() * minimum;
float radius = minimum + extra;
return vector2f.polar( angle, radius );
}<code>`</code>
前面的代碼在圓圈中放置了新的多邊形,該圓圈是螢幕的四分之一大,如圖8.13所示。
這會防止這種現象發生:新産生的小行星出現于飛船的頂部,玩家還沒來得及開火,就碰到它并爆炸了。這是遊戲程式員所面對的各種挑戰的一個很好的例子。隻有在原型遊戲開始運作時,這個問題才會變得明顯。不管遊戲多麼簡單,總是會有奇怪的問題需要解決。
processinput()方法使用向左鍵和向右鍵來旋轉飛船,向上鍵會激活加速動作,空格鍵會發射子彈,escape鍵會重新産生小行星。
當子彈擊中小行星時,不僅小行星會從渲染清單中删除,而且如果小行星不是太小的話,它會分裂成兩塊更小的小行星。
updateship()方法檢查碰撞。如果飛船被擊中,會設定毀滅标志。盡管在真實的遊戲中,當飛船被擊中時,遊戲會重新啟動,但我們還沒有介紹玩家生命或遊戲結束狀态的概念,是以,目前當飛船被擊中時,将其繪制為紅色。
render()方法繪制星星、所有的小行星、子彈、飛船以及常用的幀速率和指令。還有一些新的代碼,它們會開啟抗鋸齒功能,以使線條繪制得更為平滑。第10章将會介紹抗鋸齒。
package javagames.prototype;
import java.awt.*;
import java.awt.event.keyevent;
import java.util.*;
import javagames.prototype.prototypeasteroid.size;
import javagames.util.*;
public class prototypegame extends simpleframework {
private static final int star_count = 1500;
private prototypeship ship;
private polygonwrapper wrapper;
private prototypeasteroidfactory factory;
private arraylist bullets;
private arraylist asteroids;
private random rand;
private vector2f[] stars;
private color[] colors;
public prototypegame() {
appborderscale = 0.9f;
appwidth = 640;
appheight = 640;
appmaintainratio = true;
appsleep = 1l;
apptitle = "prototype game";
}
@override
protected void initialize() {
super.initialize();
// create game objects
rand = new random();
bullets = new arraylist();
asteroids = new arraylist();
wrapper = new polygonwrapper( appworldwidth, appworldheight );
ship = new prototypeship( wrapper );
factory = new prototypeasteroidfactory( wrapper );
createstars();
createasteroids();
// this creates the random stars for the background
private void createstars() {
stars = new vector2f[ star_count ];
colors = new color[ star_count ];
for( int i = 0; i < stars.length; ++i ) {
float x = rand.nextfloat() * 2.0f - 1.0f;
float y = rand.nextfloat() * 2.0f - 1.0f;
stars[i] = new vector2f( x, y );
float color = rand.nextfloat();
colors[i] = new color( color, color, color );
}
// create the random asteroids
private void createasteroids() {
asteroids.clear();
for( int i = 0; i < 4; ++i ) {
vector2f position = getasteroidstartposition();
asteroids.add( factory.createlargeasteroid( position ) );
// create random position for an asteroid
private vector2f getasteroidstartposition() {
float angle = (float)math.toradians( rand.nextint( 360 ) );
float minimum = appworldwidth / 4.0f;
float extra = rand.nextfloat() * minimum;
float radius = minimum + extra;
return vector2f.polar( angle, radius );
protected void processinput( float delta ) {
super.processinput( delta );
// fly the ship
if( keyboard.keydown( keyevent.vk_left ) ) {
ship.rotateleft( delta );
if( keyboard.keydown( keyevent.vk_right ) ) {
ship.rotateright( delta );
if( keyboard.keydownonce( keyevent.vk_space ) ) {
bullets.add( ship.launchbullet() );
if( keyboard.keydownonce( keyevent.vk_escape ) ) {
createasteroids();
ship.setthrusting( keyboard.keydown( keyevent.vk_up ) );
protected void updateobjects( float delta ) {
super.updateobjects( delta );
updateasteroids( delta );
updatebullets( delta );
updateship( delta );
private void updateasteroids( float delta ) {
for( prototypeasteroid asteroid : asteroids ) {
asteroid.update( delta );
private void updatebullets( float delta ) {
arraylist copy =
new arraylist( bullets );
for( prototypebullet bullet : copy ) {
updatebullet( delta, bullet );
// check for bullet collisions
private void updatebullet( float delta, prototypebullet bullet ) {
bullet.update( delta );
if( wrapper.hasleftworld( bullet.getposition() ) ) {
bullets.remove( bullet );
} else {
arraylist ast =
new arraylist( asteroids );
for( prototypeasteroid asteroid : ast ) {
if( asteroid.contains( bullet.getposition() ) ) {
bullets.remove( bullet );
asteroids.remove( asteroid );
spawnbabies( asteroid );
}
}
// create smaller asteroids when one is broken apart
private void spawnbabies( prototypeasteroid asteroid ) {
if( asteroid.getsize() == size.large ) {
asteroids.add(
factory.createmediumasteroid( asteroid.getposition() ) );
if( asteroid.getsize() == size.medium ) {
factory.createsmallasteroid( asteroid.getposition() ) );
// update the ship object
private void updateship( float delta ) {
ship.update( delta );
boolean ishit = false;
if( ship.istouching( asteroid ) ) {
ishit = true;
ship.setdamaged( ishit );
protected void render( graphics g ) {
// render instructions
super.render( g );
g.drawstring( "rotate: left/right arrow", 20, 35 );
g.drawstring( "thrust: up arrow", 20, 50 );
g.drawstring( "fire: space bar", 20, 65 );
g.drawstring( "press esc to respawn", 20, 80 );
graphics2d g2d = (graphics2d)g;
g2d.setrenderinghint(
renderinghints.key_antialiasing,
renderinghints.value_antialias_on
);
// draw game objects
matrix3x3f view = getviewporttransform();
drawstars( g2d, view );
drawasteroids( g2d, view );
drawbullets( g2d, view );
drawship( g2d, view );
private void drawstars( graphics2d g, matrix3x3f view ) {
g.setcolor( colors[i] );
vector2f screen = view.mul( stars[i] );
g.fillrect( (int)screen.x, (int)screen.y, 1, 1 );
private void drawship( graphics2d g, matrix3x3f view ) {
ship.draw( g, view );
private void drawasteroids( graphics2d g, matrix3x3f view ) {
asteroid.draw( g, view );
private void drawbullets( graphics2d g, matrix3x3f view ) {
for( prototypebullet b : bullets ) {
b.draw( g, view );
public static void main( string[] args ) {
launchapp( new prototypegame() );