《Java 2D游戏编程入门》—— 8.2 创建一个原型小行星

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

8.2 创建一个原型小行星

PrototypeAsteroid类位于javagames.prototype包中,它表示一个穿越太空的陨石。在创建的时候,使用了一个随机的速率和旋转。Java的随机数生成器只能返回0到1之间的浮点数,因此,要创建在任意范围内分布的随机数,需要一些额外的步骤。例如,要返回-3到7之间的随机数,应按照如下步骤进行。

  • 1.用最大值减去最小值,计算随机数之间的差距。
  • 2.生成从0到1的一个随机浮点数。
  • 3.将随机数乘以差距值。
  • 4.通过加上最小值来迁移范围。

这些步骤听起来有些令人混淆,实际上并非如此。

private float getRandomFloat( float min, float max ) {
  float rand = new Random().nextFloat();
  return rand * (max - min) + min;
}```
要得到一个随机的整数,也可以采用相同的步骤。由于随机数生成器返回范围从0到计数值减去1的一个数字,因此该方法需要略作调整。

private float getRandomRadians( int minDegree, int maxDegree ) {
  int rand = new Random().nextInt( maxDegree - minDegree + 1 );
  return (float)Math.toRadians( rand + minDegree );
}`
getRandomRotationDelta()方法返回了(5,45)到(–5,–45)之间的一个角度(弧度表示),如图8.8所示。

4c7bd601ff5cd6737101359bae3cf35b59492624
private float getRandomRotationDelta() {
  float radians = getRandomRadians( 5, 45 );
  return new Random().nextBoolean()? radians : -radians;
}```
还可以使用setter和getter方法来访问小行星的某些属性。

public void setPolygon( Vector2f[] polygon );
public void setPosition( Vector2f position );
public Vector2f getPosition();
public void setSize( PrototypeAsteroid.Size size );
public PrototypeAster.Size getSize()`
大小是一个枚举类型的值:

public class PrototypeAsteroid {
  public enum Size {
    Large,
    Medium,
    Small;
  }
  //...
}```
update()方法负责调整小行星的位置和旋转。注意,除了调整位置和旋转,PolygonWrapper类用来折返多边形的位置。

draw()方法负责用给定的视口矩阵和Graphics对象绘制多边形。要绘制填充的多边形,需要给Utility类添加两个方法:

package javagames.util;
import java.awt.*;
import java.util.List;

public class Utility {
  // ... Other methods left out
  // ... New methods are below
  public static void fillPolygon( Graphics2D g, Vector2f[] polygon ) {
    Polygon p = new Polygon();
    for( Vector2f v : polygon ) {
      p.addPoint( (int)v.x, (int)v.y );
    }
    g.fill( p );
  }
  public static void fillPolygon( Graphics2D g, List polygon ) {
    Polygon p = new Polygon();
    for( Vector2f v : polygon ) {
      p.addPoint( (int)v.x, (int)v.y );
    }
    g.fill( p );
  }
}`
pointInPolygon()方法和前面所讨论的方法相同。contains()方法接受一个点,如果PolygonWrapper所复制的任何多边形包含该点的话,它返回true。注意,PrototypeAsteroid中没有实际的模型代码。那是编辑器和工厂的工作,我们将在后面介绍。

package javagames.prototype;
import java.awt.*;
import java.util.*;
import javagames.util.*;

public class PrototypeAsteroid {
  public enum Size {
    Large,
    Medium,
    Small;
  }
  private PolygonWrapper wrapper;
  private Size size;
  private float rotation;
  private float rotationDelta;
  private Vector2f[] polygon;
  private Vector2f position;
  private Vector2f velocity;
  private ArrayList<Vector2f[]> renderList;
  public PrototypeAsteroid( PolygonWrapper wrapper ) {
    this.wrapper = wrapper;
    renderList = new ArrayList<Vector2f[]>();
    velocity = getRandomVelocity();
    rotationDelta = getRandomRotationDelta();
  }
  private Vector2f getRandomVelocity() {
    float angle = getRandomRadians( 0, 360 );
    float radius = getRandomFloat( 0.06f, 0.3f );
    return Vector2f.polar( angle, radius );
  }
  private float getRandomRadians( int minDegree, int maxDegree ) {
    int rand = new Random().nextInt( maxDegree - minDegree + 1 );
    return (float)Math.toRadians( rand + minDegree );
  }
  private float getRandomRotationDelta() {
    float radians = getRandomRadians( 5, 45 );
    return new Random().nextBoolean() ? radians : -radians;
  }
  private float getRandomFloat( float min, float max ) {
    float rand = new Random().nextFloat();
    return rand * (max - min) + min;
  }
  public void setPolygon( Vector2f[] polygon ) {
    this.polygon = polygon;
  }
  public void setPosition( Vector2f position ) {
    this.position = position;
  }
  public Vector2f getPosition() {
    return position;
  }
  public void setSize( Size size ) {
    this.size = size;
  }
  public Size getSize() {
    return size;
  }
  public void update( float time ) {
    position = position.add( velocity.mul( time ) );
    position = wrapper.wrapPosition( position );
    rotation += rotationDelta * time;
    renderList.clear();
    Vector2f[] world = transformPolygon();
    renderList.add( world );
    wrapper.wrapPolygon( world, renderList );
  }
  private Vector2f[] transformPolygon() {
    Matrix3x3f mat = Matrix3x3f.rotate( rotation );
    mat = mat.mul( Matrix3x3f.translate( position ) );
    return transform( polygon, mat );
  }
  private Vector2f[] transform( Vector2f[] poly, Matrix3x3f mat ) {
    Vector2f[] copy = new Vector2f[ poly.length ];
    for( int i = 0; i < poly.length; ++i ) {
      copy[i] = mat.mul( poly[i] );
    }
    return copy;
  }
  public void draw( Graphics2D g, Matrix3x3f view ) {
    for( Vector2f[] poly : renderList ) {
      for( int i = 0; i < poly.length; ++i ) {
        poly[i] = view.mul( poly[i] );
      }
      g.setColor( Color.LIGHT_GRAY );
      Utility.fillPolygon( g, poly );
      g.setColor( Color.BLACK );
      Utility.drawPolygon( g, poly );
    }
  }
  public boolean contains( Vector2f point ) {
    for( Vector2f[] polygon : renderList ) {
      if( pointInPolygon( point, polygon ) ) {
        return true;
      }
    }
    return false;
  }
  private boolean pointInPolygon( Vector2f point, Vector2f[] polygon ) {
    boolean inside = false;
    Vector2f start = polygon[ polygon.length - 1 ];
    boolean startAbove = start.y >= point.y;
    for( int i = 0; i < polygon.length; ++i ) {
      Vector2f end = polygon[i];
      boolean endAbove = end.y >= point.y;
      if( startAbove != endAbove ) {
        float m = (end.y - start.y) / (end.x - start.x);
        float x = start.x + (point.y - start.y) / m;
        if( x >= point.x ) {
          inside = !inside;
        }
      }
      startAbove = endAbove;
      start = end;
    }
    return inside;
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值