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

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

8.7 编写原型游戏

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

20765ff4c59ca5899cb50dd0396c2754a4d31336

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

  • PolygonWrapper
  • PrototypeShip
  • PrototypeAsteroid
  • PrototypeAsteroidFactory
  • PrototypeBullet

当你在本章末尾尝试编译和运行代码之前,确保已经创建了这些类。

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.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 );
}`
前面的代码在圆圈中放置了新的多边形,该圆圈是屏幕的四分之一大,如图8.13所示。

036c14119a901bbef04e11d5f25c08cd99410ba5

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

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() );
  }
}`

中文名: Java2游戏编程 名: Java 2 Game Programming 作者: Thomas Petchel译者: 晏利斌 孙淑敏 邵荣 资源格式: PDF 版本: 扫描版 出版社: 清华大学出版社书号: 7302112932发行时间: 2005年08月 地区: 大陆 语言: 简体中文 简介: 内容介绍:   你经常看到有人在玩手机游戏吧,那些手机游戏基本上是用Java编写的。Java已经成熟了,它现在是一种开发能够多种平台上运行的中小型游戏的很好方式。本书将向读者展示用Java语言和它的类库创建2D游戏,所涉及的主题包括高速性能、双缓冲图像、动画、声音、媒体控制、I/O和网络支持等。将带领大家一步一步学习编写Java游戏,最终打造属于自己的Java游戏。 目录: 第1篇 步入Java丛林:从Java2 API开始 第1章 Java2软件开发工具包 1.1 Java简史 1.2 为什么在游戏中使用Java 1.3 为Java准备系统 1.3.1 安装Java SDK 1.3.2 编译和运行Java程序 1.3.3 使用命令行 1.3.4 使用集成开发环境(IDE) 1.3.5 关于Java2文档的说明 1.4 总结 第2章 预备:学习Java2 API 2.1 Game Over! 程序 2.1.1 import语句 2.1.2 给Java代码加注释 2.1.3 Java类声明 2.1.4 Java方法声明 2.1.5 Java中的代码块 2.1.6 Java程序组成部分的关键点回顾 2.2 比特和字节:始的Java类型 2.2.1 基本的整数类型 2.2.2 浮点类型 2.2.3 Char类型 2.2.4 布尔型 2.2.5 String类型 2.2.6 强制转换变量类型 2.2.7 Java数据类型、数组和标识符需要记忆的要点 2.3 Java中的运算符 2.3.1 赋值运算符 2.3.2 比较运算符 2.3.3 算术运算符 2.3.4 自增和自减运算符 2.3.5 更多的整数运算符 2.3.6 使用点运算符 2.3.7 instanceof运算符 2.3.8 优先级顺序 2.3.9 关于运算符的记忆要点 2.4 条件语句 2.4.1 switch语句 2.4.2 Java中的循环语句 2.4.3 用break、continue和return提前退出循环 2.5 处理运行时异常 2.5.1 使用try和catch块 2.5.2 使用throws子句 2.5.3 关于流程控制语句的记忆要点 2.6 总结 2.7 练习 第3章 带有类的语言:Java面向对象程序设计 3.1 设计一个Java类 3.2 方法的魔法 3.3 关于方法的更多话题 3.3.1 构造函数方法 3.3.2 访问方法 3.3.3 类方法 3.3.4 “其他”方法 3.4 继承 3.5 抽象类 3.6 类修饰符 3.7 接口 3.8 快捷地创建类 3.9 包 3.10 总结 3.11 练习 第4章 Java API为你服务:常用Java类 4.1 java.lang包 4.1.1 java.lang.Object 4.1.2 java.lang.String 4.1.3 java.lang.StringBuffer 4.1.4 封装类 4.1.5 java.lang.Math 4.1.6 java.lang.System 4.1.7 java.lang.Cloneable 4.1.8 java.lang.Thread 4.2 java.io包 4.3 java.util包 4.3.1 java.util.StringTokenizer 4.3.2 java.util.Random 4.3.3 Java2集合框架 4.4 总结 4.5 练习 第2篇 Java 2-D图像开发和抽象Window工具包 第5章 Applet基础 5.1 什么是Java applet 5.2 Applet和Application的比较 5.3 Applet的组成和生命周期 5.4 一个Applet例子 5.5 运行Java Applets 5.6 通用AWT组件 5.6.1 按钮 5.6.2 单选按钮(Radio Button) 5.6.3 作出重要选择 5.6.4 循环播放声音文件 5.6.5 文本域 5.6.6 标签 5.7 布局管理 5.7.1 FlowLayout类 5.7.2 GridLayout类 5.7.3 BorderLayout类 5.7.4 CardLayout类 5.8 容器(Container) 5.9 创建自定义组件 5.10 一个完整的例子 5.11 总结 5.12 练习 第6章 监听用户 6.1 EventLi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值