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

    xiaoxiao2024-04-18  113

    本节书摘来异步社区《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所示。

    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)