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

本节书摘来异步社区《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.java
protected 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() );
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值