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

    xiaoxiao2024-04-03  121

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

    8.6 原型Ship类

    PrototypeShip代码位于javagames.prototype包中,这也是一目了然的。构造方法为移动飞船设置了一些常量,并且直接编码了模型的点。还有set()和get()方法用于销毁状态、角度、加速等,还有一些方法能够向左或向右旋转飞船。

    launchBullet()方法返回一个新的PrototypeBullet对象,该对象转换为飞船的突起部分。

    // PrototypeShip.java public PrototypeBullet launchBullet() {   Vector2f bulletPos = position.add( Vector2f.polar( angle, 0.0325f ) );   return new PrototypeBullet( bulletPos, angle ); }``` isTouching()方法检查渲染列表中的每一艘飞船与给定的小行星物体之间的碰撞。最酷的部分是updatePosition()方法,它使得飞船来回飞行。首先,要更新速度:

    V__1=V__0+at

    加速度在setThrusting()方法中设置。如果飞船没有向前移动,那么加速度为0并且速度保持不变。注意,新的加速度向量使用当前的角度,这会慢慢改变飞船航行的方向。

    Vector2f accel = Vector2f.polar(angle, curAcc);`接下来,新的速度保持在最大值之下。如果没有执行这一步,飞船会持续加速并且最终会比子弹移动得还要快。注意这里使用了最小值,因此当最大速度不再比实际速度小的时候,最大速度为1.0并且保持不变。只有在最大速度小于实际值的时候,速度才会受到有效的限制。

    float maxSpeed = Math.min( maxVelocity / velocity.len(), 1.0f ); velocity = velocity.mul( maxSpeed );``` 接下来,应用了摩擦力。即便太空中没有摩擦力,我还是想给飞船添加摩擦力,以便它最终能够减速。如果飞船没有加速,摩擦力将会使其慢下来。

    float slowDown = 1.0f - friction * time;velocity = velocity.mul( slowDown );`最后,更新位置,然后折返。

    position = position.add( velocity.mul( time ) ); position = wrapper.wrapPosition( position ); PrototypeShip代码如下所示: package javagames.prototype; import java.awt.*; import java.util.ArrayList; import javagames.util.*; public class PrototypeShip {   private float angle;   private float acceleration;   private float friction;   private float maxVelocity;   private float rotationDelta;   private float curAcc;   private Vector2f position;   private Vector2f velocity;   private PolygonWrapper wrapper;   private boolean damaged;   private Vector2f[] polyman;   private ArrayList<Vector2f[]> renderList;   public PrototypeShip( PolygonWrapper wrapper ) {     this.wrapper = wrapper;     friction = 0.25f;     rotationDelta = (float)Math.toRadians( 180.0 );     acceleration = 1.0f;     maxVelocity = 0.5f;     velocity = new Vector2f();     position = new Vector2f();     polyman = new Vector2f[] {       new Vector2f( 0.0325f, 0.0f ),       new Vector2f( -0.0325f, -0.0325f ),       new Vector2f( 0.0f, 0.0f ),       new Vector2f( -0.0325f, 0.0325f ),     };     renderList = new ArrayList<Vector2f[]>();   }   public void setDamaged( boolean damaged ) {     this.damaged = damaged;   }   public boolean isDamaged() {     return damaged;   }   public void rotateLeft( float delta ) {     angle += rotationDelta * delta;   }   public void rotateRight( float delta ) {     angle -= rotationDelta * delta;   }   public void setThrusting( boolean thrusting ) {     curAcc = thrusting ? acceleration : 0.0f;   }   public void setAngle( float angle ) {     this.angle = angle;   }   public PrototypeBullet launchBullet() {     Vector2f bulletPos = position.add( Vector2f.polar( angle, 0.0325f ) );     return new PrototypeBullet( bulletPos, angle );   }   public void update( float time ) {     updatePosition( time );     renderList.clear();     Vector2f[] world = transformPolygon();     renderList.add( world );     wrapper.wrapPolygon( world, renderList );   }   private Vector2f[] transformPolygon() {     Matrix3x3f mat = Matrix3x3f.rotate( angle );     mat = mat.mul( Matrix3x3f.translate( position ) );     return transform( polyman, mat );   }   private void updatePosition( float time ) {     Vector2f accel = Vector2f.polar( angle, curAcc );     velocity = velocity.add( accel.mul( time ) );     float maxSpeed = Math.min( maxVelocity / velocity.len(), 1.0f );     velocity = velocity.mul( maxSpeed );     float slowDown = 1.0f - friction * time;     velocity = velocity.mul( slowDown );     position = position.add( velocity.mul( time ) );     position = wrapper.wrapPosition( position );   }   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 ) {     g.setColor( new Color( 50, 50, 50 ) );     for( Vector2f[] poly : renderList ) {       for( int i = 0; i < poly.length; ++i ) {         poly[i] = view.mul( poly[i] );       }       g.setColor( Color.DARK_GRAY );       Utility.fillPolygon( g, poly );        g.setColor( isDamaged() ? Color.RED : Color.GREEN );       Utility.drawPolygon( g, poly );     }   }   public boolean isTouching( PrototypeAsteroid asteroid ) {     for( Vector2f[] poly : renderList ) {       for( Vector2f v : poly ) {         if( asteroid.contains( v ) ) {           return true;         }       }     }     return false;   } }``` FlyingShipExample位于javagames.prototype包中,如图8.11所示,它使用飞船和子弹代码来测试飞船在屏幕上的来回飞行。向左箭头和向右箭头会旋转飞船,向上箭头使飞船向前移动,而空格键发射子弹。 <div style="text-align: center"><img src="https://yqfile.alicdn.com/7bceaa8fb0150027f1a3aa9d8a5f74f2e46f3043.png" width="" height=""> </div> 注意updateObject()方法中Java的魔力。如果在遍历子弹的集合时试图移除子弹,那么,该列表将会抛出一个ConcurrentModificationException。生成该列表的一个副本并且将其从最初的列表中移除,这样就不会抛出异常。

    // FlyingShipExample.javaprotected void updateObjects( float delta ) {  super.updateObjects( delta );  ship.update( delta );  ArrayList copy =    new ArrayList( bullets );  for( PrototypeBullet bullet : copy ) {    bullet.update( delta );    if( wrapper.hasLeftWorld( bullet.getPosition() ) ) {      bullets.remove( bullet );    }  }}`FlyingShipExample如下所示:

    package javagames.prototype; import java.awt.*; import java.awt.event.KeyEvent; import java.util.ArrayList; import javagames.util.*; public class FlyingShipExample extends SimpleFramework {   private PrototypeShip ship;   private PolygonWrapper wrapper;   private ArrayList<PrototypeBullet> bullets;   public FlyingShipExample() {     appBorderScale = 0.9f;     appWidth = 640;     appHeight = 640;     appMaintainRatio = true;     appSleep = 1L;     appTitle = "Flying Ship Example";   }   @Override   protected void initialize() {     super.initialize();     bullets = new ArrayList<PrototypeBullet>();     wrapper = new PolygonWrapper( appWorldWidth, appWorldHeight );     ship = new PrototypeShip( wrapper );   }   @Override   protected void processInput( float delta ) {     super.processInput( delta );     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() );     }     ship.setThrusting( keyboard.keyDown( KeyEvent.VK_UP ) );   }   @Override   protected void updateObjects( float delta ) {     super.updateObjects( delta );     ship.update( delta );     ArrayList<PrototypeBullet> copy =       new ArrayList<PrototypeBullet>( bullets );     for( PrototypeBullet bullet : copy ) {       bullet.update( delta );       if( wrapper.hasLeftWorld( bullet.getPosition() ) ) {         bullets.remove( bullet );       }     }   }   @Override   protected void render( Graphics g ) {     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 );     Matrix3x3f view = getViewportTransform();     ship.draw( (Graphics2D)g, view );     for( PrototypeBullet b : bullets ) {       b.draw( (Graphics2D)g, view );     }   }   public static void main( String[] args ) {     launchApp( new FlyingShipExample() );   }
    最新回复(0)