《Java 2D游戏编程入门》—— 8.4 用原型小行星工厂生产小行星

8.4 用原型小行星工厂生产小行星

位于javagames.prototype包中的PrototypeAsteroidFactory,包含了3个大的、3个中型的和3个小的小行星,它们都是使用编辑器并粘贴到代码中设计的。给定一个位置,这3个方法生成一个随机数来选择所返回的小行星:

createLargeAsteroid( Vector2f position )
createMediumAsteroid( Vector2f position )
createSmallAsteroid( Vector2f position )```
第一个方法mirror(),用来沿着x轴和y轴翻转模型,以便模型有多个独特的版本。

// PrototypeAsteroidFactory.java
private Vector2f[] mirror( Vector2f[] polygon ) {
  Vector2f[] mirror = new Vector2f[ polygon.length ];
  float x = rand.nextBoolean() ? 1.0f : -1.0f;
  float y = rand.nextBoolean() ? 1.0f : -1.0f;
    Matrix3x3f mat = Matrix3x3f.scale( x, y );
    for( int i = 0; i < polygon.length; ++i ) {
    mirror[i] = mat.mul( polygon[i] );
  }
  return mirror;
}`
就像在执行视口矩阵乘法的时候使用矩阵来翻转y轴一样,通过乘以-1来翻转x或y轴的值,以缩放模型。

package javagames.prototype;
import java.util.Random;
import javagames.prototype.PrototypeAsteroid.Size;
import javagames.util.Matrix3x3f;
import javagames.util.Vector2f;

public class PrototypeAsteroidFactory {
private static final Vector2f[][] LARGE = {
  { // Large 0
    new Vector2f(-0.029733956f, 0.283255100f),
    new Vector2f(-0.183098610f, 0.111111104f),
    new Vector2f(-0.230046930f,-0.057902932f),
    new Vector2f(-0.092331770f,-0.139280080f),
    new Vector2f( 0.117370844f,-0.142410040f),
    new Vector2f( 0.161189320f,-0.048513293f),
    new Vector2f( 0.151799680f, 0.067292630f),
    new Vector2f( 0.195618150f, 0.129890440f),
    new Vector2f( 0.017214417f, 0.158059480f),
  }, { // Large 1
    new Vector2f(-0.001763641f, 0.325800420f),
    new Vector2f(-0.082892360f, 0.220339000f),
    new Vector2f(-0.227513200f, 0.065913380f),
    new Vector2f(-0.206349200f,-0.141242860f),
    new Vector2f(-0.061728360f,-0.080979230f),
    new Vector2f( 0.061728418f,-0.167608260f),
    new Vector2f( 0.192239940f,-0.092278720f),
    new Vector2f( 0.167548480f, 0.126177010f),
    new Vector2f( 0.107583820f, 0.269303200f),
  }, { // Large 2
    new Vector2f( 0.176838760f,-0.107981205f),
    new Vector2f(-0.070422530f,-0.076682330f),
    new Vector2f(-0.220657290f,-0.123630640f),
    new Vector2f(-0.273865400f, 0.048513293f),
    new Vector2f(-0.186228510f, 0.086071970f),
    new Vector2f(-0.214397490f, 0.223787190f),
    new Vector2f(-0.026604056f, 0.148669780f),
    new Vector2f( 0.104851365f, 0.220657290f),
    new Vector2f( 0.211267590f, 0.032863855f),
  },
};
private static final Vector2f[][] MEDIUM = {
  { // Medium 0
    new Vector2f(-0.045383394f, 0.186228510f),
    new Vector2f(-0.167449180f, 0.123630700f),
    new Vector2f(-0.067292630f, 0.039123654f),
    new Vector2f(-0.107981205f,-0.073552370f),
    new Vector2f( 0.057902932f,-0.073552370f),
    new Vector2f( 0.133020280f, 0.098591566f),
  }, { // Medium 1
    new Vector2f(-0.023474216f, 0.189358350f),
    new Vector2f(-0.107981205f, 0.107981205f),
    new Vector2f(-0.129890440f,-0.098591566f),
    new Vector2f( 0.020344257f,-0.120500800f),
    new Vector2f( 0.139280080f,-0.001564979f),
    new Vector2f( 0.076682330f, 0.092331770f),
    new Vector2f(-0.007824719f, 0.095461670f),
  }, { // Medium 2
    new Vector2f(-0.064162790f, 0.158059480f),
    new Vector2f(-0.173708920f, 0.126760600f),
    new Vector2f(-0.142410040f, 0.023474216f),
    new Vector2f(-0.039123654f, 0.029733956f),
    new Vector2f( 0.010954618f,-0.035993695f),
    new Vector2f( 0.117370844f, 0.023474216f),
    new Vector2f( 0.117370844f, 0.120500800f),
    new Vector2f(-0.001564979f, 0.092331770f),
  },
};
private static final Vector2f[][] SMALL = {
  { // Small 0
    new Vector2f(-0.048513293f, 0.057902990f),
    new Vector2f(-0.073552430f,-0.042253494f),
    new Vector2f( 0.004694819f,-0.035993695f),
    new Vector2f( 0.042253494f, 0.026604056f),
    new Vector2f(-0.001564979f, 0.082942130f),
  }, { // Small 1
    new Vector2f( 0.067292690f, 0.007824719f),
    new Vector2f(-0.029733956f,-0.076682330f),
    new Vector2f(-0.067292630f,-0.042253494f),
    new Vector2f(-0.061032890f, 0.082942130f),
    new Vector2f( 0.032863855f, 0.111111104f),
  }, { // Small 2
    new Vector2f(-0.007824719f, 0.089201870f),
    new Vector2f(-0.114241004f, 0.001564979f),
    new Vector2f(-0.004694819f,-0.067292690f),
    new Vector2f( 0.039123654f,-0.039123654f),
    new Vector2f(-0.014084518f, 0.020344317f),
  },
};
private PolygonWrapper wrapper;
private Random rand;
public PrototypeAsteroidFactory( PolygonWrapper wrapper ) {
  this.wrapper = wrapper;
  this.rand = new Random();
}

public PrototypeAsteroid createLargeAsteroid( Vector2f position ) {
  PrototypeAsteroid asteroid = new PrototypeAsteroid( wrapper );
  asteroid.setPosition( position );
  asteroid.setPolygon( getRandomAsteroid( LARGE ) );
  asteroid.setSize( Size.Large );
  return asteroid;
}
public PrototypeAsteroid createMediumAsteroid( Vector2f position ) {
  PrototypeAsteroid asteroid = new PrototypeAsteroid( wrapper );
  asteroid.setPosition( position );
  asteroid.setPolygon( getRandomAsteroid( MEDIUM ) );
  asteroid.setSize( Size.Medium );
  return asteroid;
}
public PrototypeAsteroid createSmallAsteroid( Vector2f position ) {
  PrototypeAsteroid asteroid = new PrototypeAsteroid( wrapper );
  asteroid.setPosition( position );
  asteroid.setPolygon( getRandomAsteroid( SMALL ) );
  asteroid.setSize( Size.Small );
  return asteroid;
}
private Vector2f[] getRandomAsteroid( Vector2f[][] asteroids ) {
  return mirror( asteroids[ rand.nextInt( asteroids.length ) ] );
}
private Vector2f[] mirror( Vector2f[] polygon ) {
  Vector2f[] mirror = new Vector2f[ polygon.length ];
  float x = rand.nextBoolean() ? 1.0f : -1.0f;
  float y = rand.nextBoolean() ? 1.0f : -1.0f;
  Matrix3x3f mat = Matrix3x3f.scale( x, y );
  for( int i = 0; i < polygon.length; ++i ) {
    mirror[i] = mat.mul( polygon[i] );
  }
  return mirror;
  }
}```
RandomAsteroidExample位于javagames.prototype包中,如图8.10所示,它使用PolygonWrapper、PrototypeAsteroid和PrototypeAsteroid Factory,来生成在屏幕上随机飞来飞去的陨石。
<div style="text-align: center"><img src="https://yqfile.alicdn.com/b714c45b53653458cc5392685ac60b1e1273e94d.png" width="" height="">
</div>

getRandomAsteroid()方法创建了一个随机的位置,然后选择一个随机的大小:small、medium或large。记住,工厂的每一个方法都从3种不同的多边形模型中针对每个大小选取一个模型,并且为每个模型生成4个镜像的版本。每个多边形有4个镜像,每个大小有3个形状,共有3种不同的大小,因此,共有36种不同的模型。

还应该注意,由于PrototypeAsteroid使用了新的Utility.fillPolygon()方法,Graphics对象强制转型为一个Graphics2D对象。

// RandomAsteroidExample.java
protected void render( Graphics g ) {
  super.render( g );
  g.drawString( "Press ESC to respawn", 20, 35 );
  Matrix3x3f view = getViewportTransform();
  for( PrototypeAsteroid asteroid : asteroids ) {
    asteroid.draw( (Graphics2D)g, view );
  }
}
RandomAsteroidExample代码如下所示:

package javagames.prototype;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.*;
import javagames.prototype.PrototypeAsteroid.Size;
import javagames.util.*;

public class RandomAsteroidExample extends SimpleFramework {
  private PrototypeAsteroidFactory factory;
  private ArrayList asteroids;
  private Random rand;
  public RandomAsteroidExample() {
    appBorderScale = 0.9f;
    appWidth = 640;
    appHeight = 640;
    appMaintainRatio = true;
    appSleep = 1L;
    appTitle = "Random Asteroids";
    appBackground = Color.WHITE;
    appFPSColor = Color.BLACK;
  }
  @Override
  protected void initialize() {
    super.initialize();
    rand = new Random();
    asteroids = new ArrayList();
    PolygonWrapper wrapper =
      new PolygonWrapper( appWorldWidth, appWorldHeight );
    factory = new PrototypeAsteroidFactory( wrapper );
    createAsteroids();
  }
  private void createAsteroids() {
    asteroids.clear();
    for( int i = 0; i < 42; ++i ) {
      asteroids.add( getRandomAsteroid() );
    }
  }
  private PrototypeAsteroid getRandomAsteroid() {
    float x = rand.nextFloat() * 2.0f - 1.0f;
    float y = rand.nextFloat() * 2.0f - 1.0f;
    Vector2f position = new Vector2f( x, y );
    Size[] sizes = Size.values();
    Size randomSize = sizes[ rand.nextInt( sizes.length ) ];
    switch( randomSize ) {
      case Small: return factory.createSmallAsteroid( position );
      case Medium: return factory.createMediumAsteroid( position );
      case Large:
      default: return factory.createLargeAsteroid( position );
    }
  }
  @Override
  protected void processInput( float delta ) {
    super.processInput( delta );
    if( keyboard.keyDownOnce( KeyEvent.VK_ESCAPE ) ) {
      createAsteroids();
    }
  }
  @Override
  protected void updateObjects( float delta ) {
    super.updateObjects( delta );
    for( PrototypeAsteroid asteroid : asteroids ) {
      asteroid.update( delta );
    }
  }
  @Override
  protected void render( Graphics g ) {
    super.render( g );
    g.drawString( "Press ESC to respawn", 20, 35 );
    Matrix3x3f view = getViewportTransform();
    for( PrototypeAsteroid asteroid : asteroids ) {
      asteroid.draw( (Graphics2D)g, view );
    }
  }
  public static void main( String[] args ) {
    launchApp( new RandomAsteroidExample() );
  }
}`

时间: 2024-10-23 23:33:32

《Java 2D游戏编程入门》—— 8.4 用原型小行星工厂生产小行星的相关文章

《Java 2D游戏编程入门》—— 8.5 原型Bullet类

8.5 原型Bullet类 PrototypeBullet代码位于javagames.prototype包中,这是一个最简单的原型游戏源代码.除了绘制圆以便可以调整屏幕大小外,没有其他任何值得讨论的内容. package javagames.prototype; import java.awt.*; import javagames.util.*; public class PrototypeBullet { private Vector2f velocity; private Vector2f

《Java 2D游戏编程入门》—— 8.6 原型Ship类

8.6 原型Ship类 PrototypeShip代码位于javagames.prototype包中,这也是一目了然的.构造方法为移动飞船设置了一些常量,并且直接编码了模型的点.还有set()和get()方法用于销毁状态.角度.加速等,还有一些方法能够向左或向右旋转飞船. launchBullet()方法返回一个新的PrototypeBullet对象,该对象转换为飞船的突起部分. // PrototypeShip.java public PrototypeBullet launchBullet(

《Java 2D游戏编程入门》—— 导读

前言 多年前,当我第一次将软件开发作为专业工作的时候,有人请我编写一个applet.那时候,我对于Java语言知道得并不多.在整个上学期间,我很广泛地使用C++.我确实用Java编写过一些代码,但认为它太慢并且是C++的没落版. 同时,我购买和阅读了很多可以接触到的游戏编程图书.我通读了一本关于人工智能的书,其中包含很多不错的示例,但它们都是用C++和DirectX编写的.由于忙着学习Java以便在工作中使用,我认为将示例转换为由Java编写可能是学习这门语言的一种好办法. 毕竟,Java游戏编

《Java 2D游戏编程入门》—— 2.4 相对鼠标移动

2.4 相对鼠标移动 对于图2.3所示的当前的鼠标输入类来说,有一个问题.首先,它看上去似乎挺明显,但是,只有在鼠标位于窗口之中的时候,程序才接受鼠标事件.一旦鼠标离开了窗口,鼠标指针的坐标位置在应用程序中就变得不再有效.更为糟糕的是,在全屏模式中,当鼠标到达屏幕边缘的时候,它会直接停下来,而不会继续注册事件.根据应用程序的需要,可能需要相对鼠标移动.好在,更新鼠标输入类以支持相对鼠标移动并不难. RelativeMouseInput类位于javagames.util包中,构建于前面示例中的类的

《Java 2D游戏编程入门》—— 8.1 创建一个多边形包装类

8.1 创建一个多边形包装类 制作一款2D太空飞船游戏时,首先要解决的大问题是,当飞船到达屏幕边缘时,会发生什么事情.一个解决方案是,将飞船保持在屏幕的中央,而移动其周围的环境.没有对加载文件的任何支持,也没有关卡编辑器的话,要做到这点似乎有点难.另一个选择是,当飞船到达屏幕边界的时候,将其弹回.这样做似乎显得很奇怪.第三种选择是,让飞船从一端到另一端折返.让我们采用第三种方法. 还有很多方法可以解决这一问题.一种方法是,让飞船完全离开屏幕,然后让其在另一端返回,如图8.1所示. 尝试这一想法似

《Java 2D游戏编程入门》—— 1.6 修改显示模式

1.6 修改显示模式 要创建全屏的应用程序,需要修改显示模式.DisplayModeTest如图1.4所示,它使用了Swing组件.这个示例也位于javagames.render包中.如果你还没有编写过任何的Swing程序,一些代码可能会看上去很陌生.有很多相关的图书和教程可供参考,并且如果要详细介绍Swing所提供的所有功能,需要比这本书更大的篇幅. 这个示例应用程序列出了所有可用的屏幕分辨率,这允许用户在全屏模式之间来回切换,以使用任何可用的显示模式.这个示例不仅展示了使用Swing组件编程

《Java 2D游戏编程入门》—— 2.1 处理键盘输入

2.1 处理键盘输入 在大多数应用程序中,软件都不需要处理键盘事件.当某些事情发生变化的时候,由任意的组件(如文本框)来处理输入并通知软件.但是,大多数计算机游戏使用键盘不是为了录入,而是为了游戏输入.根据游戏的不同,虽然可能会有录入,但键盘按键常用做方向键和发射激光武器.很多计算机游戏具有不同的输入配置,并且有些游戏甚至允许用户根据自己的意愿来设置按键.不管游戏如何使用键盘(并且它可能采用一种全新的方式来使用键盘,监听键盘事件的常用方法都不适用于游戏循环程序设计. Swing组件允许在实现了K

《Java 2D游戏编程入门》—— 2.3 处理鼠标输入

2.3 处理鼠标输入 SimpleMouseInput类位于javagames.util包中,它和前面小节中开发的键盘输入类非常相似.处理鼠标按键的方式与处理键盘按键的方式相同.实现MouseListener接口的类包含了如下的方法: mouseClicked(MouseEvent e) mouseEntered(MouseEvent e) mouseExited(MouseEvent e) mousePressed(MouseEvent e) mouseReleased(MouseEvent

《Java 2D游戏编程入门》—— 1.7 全屏显示模式中的主动渲染

1.7 全屏显示模式中的主动渲染 位于javagames.render包中的FullScreenRenderingExample,包含了主动渲染框架和切换到全拼模式的显示模式代码:它创建了一个简单的全屏游戏框架.这个示例包含了前面各部分中展示的很多代码.此外还可以直接给JFrame设置背景颜色并且忽略重绘,以及设置setUndecorated()标志.由于在前面的示例中应用程序是从窗口模式切换到全屏模式的,因此没有设置该标志:但是当只使用全屏模式的时候,应该对JFrame进行该项设置. 保存当前