手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏17

2022-01-09  本文已影响0人  __豆约翰__

这节比较有趣,我们来实现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()方法是自动追踪的核心算法,原理如下图所示:

31aaa47bd98c24184a056865d2256e1.png

如果您迷路了,请参考完整源码:

项目源码

项目源码

上一篇下一篇

猜你喜欢

热点阅读