天天看点

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

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

原型游戏如图8.12所示,位于javagames.prototype包中,它使用了我们目前为止所见过的所有技术。尽管这只是一个原型,并且目前还没有成为一款完整的游戏,但我已经展示了足够的工具来让一些功能奏效。如果要等到最后再制作一款游戏,可能需要等太长的时间。

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

该原型游戏使用了我们在本章前面所介绍的如下的类。

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所示。

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

这会防止这种现象发生:新产生的小行星出现于飞船的顶部,玩家还没来得及开火,就碰到它并爆炸了。这是游戏程序员所面对的各种挑战的一个很好的例子。只有在原型游戏开始运行时,这个问题才会变得明显。不管游戏多么简单,总是会有奇怪的问题需要解决。

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 &lt; 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 &lt; 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() );