You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bukkit开发:如何创建带AI、移动到指定位置后无操作的NPC

Bukkit实现仅定向移动的AI NPC方案

核心逻辑是生成带寻路能力的生物实体,屏蔽所有原生无关AI行为,仅触发定向寻路,到达目标点后清空寻路路径、固定实体状态即可,不需要引入第三方NPC插件也能实现。

1. 生成基础NPC实体

选择自带原生寻路能力的Creature类型实体(比如村民、僵尸、流浪者这类,不要选盔甲架、掉落物这类无移动能力的实体),生成后添加专属标签方便后续识别,避免和原生生物混淆。

// 替换成你需要的NPC生成位置
Location spawnLocation = new Location(目标世界, 生成X, 生成Y, 生成Z);
// 这里以村民为例,可替换为其他Creature子类对应的EntityType
Creature moveNpc = (Creature) spawnLocation.getWorld().spawnEntity(spawnLocation, EntityType.VILLAGER);
// 添加专属识别标签
moveNpc.addScoreboardTag("single_move_npc");
// 可选:设置NPC名称
moveNpc.setCustomName("指引村民");
moveNpc.setCustomNameVisible(true);

2. 屏蔽原生多余AI行为

不要直接调用setAI(false),该方法会完全关闭实体寻路能力,导致后续移动逻辑失效。优先通过事件拦截所有和定向移动无关的行为:

  • 拦截NPC锁定实体、攻击、闲逛的目标事件
  • 拦截NPC受到的所有伤害,避免被攻击、爆炸击飞偏离路径
  • 拦截NPC的自然消失逻辑,防止距离玩家过远被服务端清除
// 把这些监听器注册到你的插件中即可
@EventHandler
public void onNpcTarget(EntityTargetEvent event) {
    if (event.getEntity().getScoreboardTags().contains("single_move_npc")) {
        event.setCancelled(true);
    }
}

@EventHandler
public void onNpcDamage(EntityDamageEvent event) {
    if (event.getEntity().getScoreboardTags().contains("single_move_npc")) {
        event.setCancelled(true);
    }
}

@EventHandler
public void onNpcDespawn(EntityUnleashEvent event) {
    if (event.getEntity().getScoreboardTags().contains("single_move_npc")) {
        event.setCancelled(true);
    }
}

如果对性能要求更高,可以通过NMS清除实体原生的所有PathfinderGoal,仅保留移动相关的底层寻路逻辑,适配对应服务端版本即可。

3. 触发定向寻路

调用实体自带的寻路接口,设置目标位置和移动速度即可让NPC自动通过原生寻路绕开障碍移动到目标点:

// 替换成你需要NPC到达的目标位置
Location targetLocation = new Location(目标世界, 目标X, 目标Y, 目标Z);
// 移动速度建议设置在0.2-0.4区间,对应普通生物的步行速度,可根据需求调整
double moveSpeed = 0.3;
// 启动寻路
moveNpc.getPathfinder().moveTo(targetLocation, moveSpeed);

4. 到达目标后的静止处理

添加定时检测任务,判断NPC是否到达目标位置,到达后立即清空寻路,避免NPC继续闲逛或者偏移位置:

// 启动主线程定时检测,每2游戏tick(约100毫秒)检测一次
BukkitTask moveCheckTask = Bukkit.getScheduler().runTaskTimer(你的插件实例, () -> {
    // 实体失效时直接取消任务,避免空指针报错
    if (moveNpc.isDead() || !moveNpc.isValid()) {
        this.cancel();
        return;
    }
    Location npcCurrentLoc = moveNpc.getLocation();
    // 计算和目标点的水平距离平方(开平方运算耗性能,直接用平方值判断)
    double horizontalDistanceSq = Math.pow(npcCurrentLoc.getX() - targetLocation.getX(), 2)
            + Math.pow(npcCurrentLoc.getZ() - targetLocation.getZ(), 2);
    // 水平距离小于0.5格时判定为到达目标点
    if (horizontalDistanceSq < 0.25) {
        // 清空所有寻路路径
        moveNpc.getPathfinder().stopPathfinding();
        // 可选:关闭碰撞,避免被其他实体、水流推离位置
        moveNpc.setCollidable(false);
        // 不需要浮空就保留重力,需要完全固定位置可设置setGravity(false)
        // 取消检测任务
        this.cancel();
    }
}, 0L, 2L);

注意事项

  • 目标位置必须处于已加载区块内,跨长距离移动时建议逐段设置路径点,提前加载对应区块,否则寻路会直接失效
  • 不要高频重复调用moveTo方法,会导致服务端寻路计算压力过大,出现NPC卡顿、抽搐的问题
  • 如果需要NPC上下楼梯、跨越台阶,目标点的Y轴坐标尽量和路径终点的地面高度对齐,避免出现NPC卡墙、跳不动的问题

内容的提问来源于stack exchange,提问作者Silvan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:24:14