与飞行有关的MoveControl

本文把这类飞行生物使用的MoveControl称为飞行类MoveControl

这一部分我们来看3个较泛用或简单的飞行类MoveControl的代码,来简单了解一下飞行类MoveControl的功能和组成部分,然后对比下这些飞行类MoveControl的区别。

首先看比较泛用的FlyingMoveControl

FlyingMoveControl中的tick方法:

if (operation == MoveControl.Operation.MOVE_TO) {
    operation = MoveControl.Operation.WAIT;
    mob.setNoGravity(true);
    double dx = wantedX - mob.getX();
    double dy = wantedY - mob.getY();
    double dz = wantedZ - mob.getZ();
    double distSqr = dx * dx + dy * dy + dz * dz;

    // 目标位置与当前位置相同
    if (distSqr < (double) 2.5000003E-7F) {
        mob.setYya(0);
        mob.setZza(0);
        return;
    }

    // 水平朝向(yRot) & 速度调整
    // 以90°的最大速度水平旋转向目标位置
    // 此处的反正切函数得到的度数是与x轴正方向(东)的夹角,而我们需要与z轴正方向(南)的夹角,所以要减去90°
    // 
    // 因为-atan2(a, b) = atan2(b, a) - 90°,所以也可以写成下面的语句
    // float newYRot = (float) -(Mth.atan2(dx, dz) * 180 / Math.PI);
    float newYRot = (float) (Mth.atan2(dz, dx) * 180 / Math.PI - 90);
    mob.setYRot(rotlerp(mob.getYRot(), newYRot, 90));
    float speed;
    if (mob.onGround()) {
        speed = (float) (speedModifier * mob.getAttributeValue(Attributes.MOVEMENT_SPEED));
    } else {
        speed = (float) (speedModifier * mob.getAttributeValue(Attributes.FLYING_SPEED));
    }
    mob.setSpeed(speed);

    // 垂直朝向(xRot) & 速度调整
    double horizontalDist = Math.sqrt(dx * dx + dz * dz);
    if (Math.abs(dy) > (double) 1.0E-5F || Math.abs(horizontalDist) > (double) 1.0E-5F) {
        // 注意“抬头”时xRot为负
        float newXRot = (float) -(Mth.atan2(dy, horizontalDist) * (180 / Math.PI));
        mob.setXRot(rotlerp(mob.getXRot(), newXRot, maxTurn));
        mob.setYya(dy > 0 ? speed : -speed);
    }
} else {
    // 自然降落
    if (!hoversInPlace) {
        mob.setNoGravity(false);
    }
    mob.setYya(0);
    mob.setZza(0);
}

以下是该MoveControl的核心特点:

  • 同时调整水平和垂直朝向
  • 不飞行时自然降落(可选)
  • 飞行速度与实体属性的值有关

接下来是VexMoveControl中的tick方法,VexMoveControl是恼鬼特有的MoveControl

if (operation == MoveControl.Operation.MOVE_TO) {
    Vec3 vecToWanted = new Vec3(wantedX - getX(), wantedY - getY(), wantedZ - getZ());
    double len = vecToWanted.length();
    if (len < getBoundingBox().getSize()) {
        // 缓缓停下
        operation = MoveControl.Operation.WAIT;
        setDeltaMovement(getDeltaMovement().scale(0.5));
    } else {
        setDeltaMovement(getDeltaMovement().add(vecToWanted.scale(speedModifier * 0.05 / len)));

        if (getTarget() == null) {
            Vec3 deltaMovement = getDeltaMovement();
            setYRot((float) (-Mth.atan2(deltaMovement.x, deltaMovement.z) * 180 / Math.PI));
            yBodyRot = getYRot();
        } else {
            double dx = getTarget().getX() - getX();
            double dz = getTarget().getZ() - getZ();
            // 与FlyingMoveControl中不同,此处的反正切函数得到的度数是z轴正方向(南)的夹角,但是还要取相反数
            // 举个例子,当dx和dz都大于0时,应该面向东南方向,若原本面向正南(yRot=0),此时应逆时针旋转
            // 上方的if中根据移动方向自我调整朝向的代码同理
            setYRot((float) (-Mth.atan2(dx, dz) * 180 / Math.PI));
            yBodyRot = getYRot();
        }
    }
}

以下是该MoveControl的核心特点:

  • 只调整水平朝向
  • 不飞行时不降落
  • 飞行速度与实体属性的值无关

不难发现,不同的点在于恼鬼始终保持着漂浮状态而不会自然下落,而且只会根据移动方向调整自身的水平朝向。

然后是GhastMoveControl中的tick方法,GhastMoveControl是恶魂特有的MoveControl

if (operation == MoveControl.Operation.MOVE_TO) {
    if (floatDuration-- <= 0) {
        floatDuration += ghast.getRandom().nextInt(5) + 2;
        Vec3 vecToWanted = new Vec3(wantedX - ghast.getX(), wantedY - ghast.getY(), wantedZ - ghast.getZ());
        double len  = vecToWanted.length();
        vecToWanted = vecToWanted.normalize();
        if (canReach(vecToWanted, Mth.ceil(len))) {
            ghast.setDeltaMovement(ghast.getDeltaMovement().add(vecToWanted.scale(0.1)));
        } else {
            operation = MoveControl.Operation.WAIT;
        }
    }
}

以下是该MoveControl的核心特点:

  • 不调整朝向(恶魂的朝向在其AI中调整而不在此处调整)
  • 不飞行时不降落
  • 飞行速度与实体属性的值无关

恶魂的移动则简单很多,只会间歇性漂移。其朝向和是否正在看向其攻击目标有关,而且要分类讨论,这也许是代码中把恶魂的朝向用单独的GhastLookGoal来控制的原因。

通过对比这3个MoveControl,我们也可以得知缓慢效果影响不了飞行速度,而且很难统一改变所有飞行生物的飞行速度的原因。原版MC的代码还是太难以评价了。

据此可以总结出MoveControl一般会具备的功能:

  1. 改变实体的移动方向(通过改变deltaMovement实现)
  2. 改变实体的朝向,包括水平朝向(yRot)和垂直朝向(xRot

飞行的友好生物(鹦鹉、蜜蜂、悦灵等)一般使用FlyingMoveControl,而飞行的怪物移动方式较为复杂,因此一般使用自定义的飞行类MoveControl

results matching ""

    No results matching ""

    results matching ""

      No results matching ""