本节书摘来异步社区《Java 2D游戏编程入门》一书中的第8章,第8.7节,作者:【美】Timothy Wright(莱特),更多章节内容可以访问云栖社区“异步社区”公众号查看。
原型游戏如图8.12所示,位于javagames.prototype包中,它使用了我们目前为止所见过的所有技术。尽管这只是一个原型,并且目前还没有成为一款完整的游戏,但我已经展示了足够的工具来让一些功能奏效。如果要等到最后再制作一款游戏,可能需要等太长的时间。
该原型游戏使用了我们在本章前面所介绍的如下的类。
PolygonWrapperPrototypeShipPrototypeAsteroidPrototypeAsteroidFactoryPrototypeBullet当你在本章末尾尝试编译和运行代码之前,确保已经创建了这些类。
initialize()方法为原型创建了所有这些对象,包括创建了一些星星作为背景。如下的代码创建了星星,并且创建了颜色的一个数组。Color类接受3个值:red、blue和green,这3个值在0到1之间。将每种颜色值设置为相同的值,将会产生灰色的阴影。本书稍后会详细介绍颜色,但现在,只要使用Java语言所提供的java.awt.Color类就行了。
// PrototypeGame.java 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 ); } }``` 当创建小行星的时候,注意getAsteroidStartPosition()方法。和产生各种大小的随机小行星的示例不同,这个方法只创建一个较大的随机小行星,并且使用如下代码将其放置到一个圆圈中,以使得它们不会在飞船之上产生。// PrototypeGame.javaprivate 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 );}`前面的代码在圆圈中放置了新的多边形,该圆圈是屏幕的四分之一大,如图8.13所示。
这会防止这种现象发生:新产生的小行星出现于飞船的顶部,玩家还没来得及开火,就碰到它并爆炸了。这是游戏程序员所面对的各种挑战的一个很好的例子。只有在原型游戏开始运行时,这个问题才会变得明显。不管游戏多么简单,总是会有奇怪的问题需要解决。
processInput()方法使用向左键和向右键来旋转飞船,向上键会激活加速动作,空格键会发射子弹,Escape键会重新产生小行星。
当子弹击中小行星时,不仅小行星会从渲染列表中删除,而且如果小行星不是太小的话,它会分裂成两块更小的小行星。
updateShip()方法检查碰撞。如果飞船被击中,会设置毁灭标志。尽管在真实的游戏中,当飞船被击中时,游戏会重新启动,但我们还没有介绍玩家生命或游戏结束状态的概念,因此,目前当飞船被击中时,将其绘制为红色。
render()方法绘制星星、所有的小行星、子弹、飞船以及常用的帧速率和指令。还有一些新的代码,它们会开启抗锯齿功能,以使线条绘制得更为平滑。第10章将会介绍抗锯齿。
Graphics2D g2d = (Graphics2D)g; g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );``` drawStars()、drawShip()、drawAsteroids()和drawBullets()方法负责绘制原型中的各种物体。PrototypeGame的代码如下所示: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 ); } @Override 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 ) ); } @Override 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() ) ); asteroids.add( factory.createMediumAsteroid( asteroid.getPosition() ) ); } if( asteroid.getSize() == Size.Medium ) { asteroids.add( factory.createSmallAsteroid( asteroid.getPosition() ) ); asteroids.add( factory.createSmallAsteroid( asteroid.getPosition() ) ); } } // update the ship object private void updateShip( float delta ) { ship.update( delta ); boolean isHit = false; for( PrototypeAsteroid asteroid : asteroids ) { if( ship.isTouching( asteroid ) ) { isHit = true; } } ship.setDamaged( isHit ); } @Override 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 ) { for( int i = 0; i < stars.length; ++i ) { 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 ) { for( PrototypeAsteroid asteroid : asteroids ) { 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() ); }}`
相关资源:Java 2D游戏编程入门_PDF电子书下载 高清 带索引书签目录