这节比较有趣,我们来实现Enemy自动追踪Player的算法,无论player走到哪里,enemy都如影随形。
这里我们主要用到了向量加减的几何意义。
向量类
Vector2d.java
package utils; public class Vector2d { public double dX; public double dY; // Constructor methods .... public Vector2d(double dXp, double dYp ) { this.dX = dXp; this.dY = dYp; } public Vector2d() { dX = dY = 0.0; } // Convert Vector2d to a string ... public String toString() { return "Vector2d(" + dX + ", " + dY + ")"; } // Compute magnitude of Vector2d .... public double length() { return Math.sqrt ( dX*dX + dY*dY ); } // Sum of two Vector2ds .... public void add( Vector2d v1 ) { this.dX += v1.dX; this.dY += v1.dY; } // Subtract Vector2d v1 from v ..... public void sub( Vector2d v1 ) { this.dX -= v1.dX; this.dY -= v1.dY; } // Scale Vector2d by a constant ... public void scale( double scaleFactor ) { this.dX *=scaleFactor; this.dY *=scaleFactor; } // Normalize a Vector2ds length.... public Vector2d normalize() { Vector2d v2 = new Vector2d(); double length = Math.sqrt( this.dX*this.dX + this.dY*this.dY ); if (length != 0) { v2.dX = this.dX/length; v2.dY = this.dY/length; } return v2; } // Dot product of two Vector2ds ..... public double dotProduct ( Vector2d v1 ) { return this.dX*v1.dX + this.dY*v1.dY; } }
修改Enemy类,添加Player类型的成员;因为我们要追踪Player,所以必须维护一个Player类型的对象,作为追踪的目标。
_isInRange()方法主要用来判断Enemy是否已经距离Player足够近了,主要是检测两者x坐标和y坐标之间的差值是否足够小。
每帧对update方法的调用中,我们都调用followPath()方法来计算新的enemy位置。
public class Enemy extends AttackAbleObject{ private Animator _animator; private Player _player; private double _speed = 1.5; public Enemy(Player players, Animator animator, int hurtx, int hurty, int hurtscale_x, int hurtscale_y , int hitoffset_x1, int hitoffset_y1, int hitoffset_x2, int hitoffset_y2){ super(animator,hurtx,hurty,hurtscale_x,hurtscale_y ,hitoffset_x1,hitoffset_y1,hitoffset_x2,hitoffset_y2); _animator = animator; _player= players; _animator.setAnimation("idle"); } @Override public void update(Graphics2D g){ _animator.show(g); followPath(); } public Transform getTransform(){ return _animator; } private boolean _isInRange(){ boolean bRet = Math.abs(getX() - _player.getX()) < 60 && Math.abs(getZ() - _player.getZ()) < Config.Z_FIGHT_DIST; return bRet; } public void followPath(){ if(!_isInRange()){ Vector2d towards = new Vector2d(_player.getX()-getX(), _player.getZ()-getZ()); Vector2d normalizedTowards = towards.normalize(); Vector2d posVector = new Vector2d(normalizedTowards.dX,normalizedTowards.dY); posVector.scale(_speed); posVector.add(new Vector2d(getX(),getZ())); setPosition(posVector.dX,posVector.dY); if((getX()-_player.getX())<0 && !getTransform().isFlippedRight()){ getTransform().flip(); } if((getX()-_player.getX())>=0 && getTransform().isFlippedRight()){ getTransform().flip(); } } } }
followPath()方法是自动追踪的核心算法,原理如下图所示:
如果您迷路了,请参考完整源码: