《Java 2D游戏编程入门》—— 8.7 编写原型游戏

    xiaoxiao2024-04-06  122

    本节书摘来异步社区《Java 2D游戏编程入门》一书中的第8章,第8.7节,作者:【美】Timothy Wright(莱特),更多章节内容可以访问云栖社区“异步社区”公众号查看。

    8.7 编写原型游戏

    原型游戏如图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电子书下载 高清 带索引书签目录
    最新回复(0)