本节书摘来异步社区《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() );