Skip to content

Latest commit

 

History

History
176 lines (127 loc) · 6.42 KB

5-4.md

File metadata and controls

176 lines (127 loc) · 6.42 KB

5-4 药水效果

Bukkit 中所有的药水效果都通过 PotionEffect 进行描述。

使用原版药水效果

要使用一个已经存在的药水效果,我们只需要实例化 PotionEffect 并进行应用即可。

下面演示如何给一名玩家「迅捷 II」效果,首先创建药水效果的实例:

PotionEffect pe = new PotionEffect(PotionEffectType.SPEED, 100, 1);

其中,所有的药水效果种类都定义在 PotionEffectType 类中。可以通过 JavaDocs 查找可能的值。

我们来看看构造方法的签名:

public PotionEffect(
    @NotNull PotionEffectType type,
    int duration,
    int amplifier,
    boolean ambient, // 可选
    boolean particles, // 可选
    boolean icon // 可选
)

六个参数分别是:

  • 药水类型,只能使用 PotionEffectType 中的静态成员变量
  • 持续时间,单位刻
  • 倍率,对于有等级的效果(如「力量」),该数字比等级小 1,对于没有等级的效果,设置为 0
  • 是否进行渲染,可选,如果为 true 将产生更多的粒子,如果不填,默认为 true
  • 是否具有粒子,可选,似乎会影响客户端的渲染,具体作用尚不明确
  • 是否具有图标,可选,似乎会影响客户端在背包界面是否显示该效果,具体作用尚不明确

一般而言,填写三个参数就足够了。

要使用这个药水效果,只需要在合适的时机进行应用:

pe.apply(Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG")));

药水效果实际上不仅能用于玩家,还能用于任何 LivingEntity 的实例。

自定义药水效果

Bukkit 没有提供自定义药水效果的方法,但我们可以自己创建。

下面演示如何创建「EEE」效果,该效果在玩家获取 10 秒之后发送大量的字母「e」。(致敬咏士)

首先,由于我们要创建的是药水效果,因此需要创建一个类来描述它。

public class EEEEffect extends PotionEffect {
    public EEEEffect() {
        super(PotionEffectType.BAD_OMEN, 100, 0);
    }
}

super 指的是「使用父类的构造方法」,也就是「采用传统的方法」。

这里的 PotionEffectType 是药水类型(主要决定图标),插件无法修改(Bukkit 写死在代码里面了),因此只能选择一个已有的。这里我们选择的是「不祥之兆」。

持续时间和等级无所谓,因为我们不会用到它,随便传两个值就可以了。

下面是重中之重!

要实现我们自己的效果,需要重写 apply 方法。

示例如下:

public class EEEEffect extends PotionEffect {
    public EEEEffect() {
        super(PotionEffectType.BAD_OMEN, 100, 1);
    }
    
    @Override
    public boolean apply(LivingEntity entity) {
        if (entity instanceof Player) {
            entity.sendMessage("您即将受到 EEE 效果的影响!");
            // 计划任务,从此开始
            new BukkitRunnable() {
                @Override
                public void run() {
                    for (int i = 1; i <= 10; i++) {
                        entity.sendMessage("eeeeeeeeeeeeeeee(后略)");
                        // 发送消息
                    }
                }
            }.runTaskLaterAsynchronously(<插件主类名>.instance, 200);
            // 到此结束
            return true; // 可以被添加
        }
        return false; // 不可被添加
    }
}

基本上只需要注意三个点:

  • 如果这个效果成功被添加,返回 true,否则返回 false,这似乎会影响到 Bukkit 的游戏判断,因此请如实返回
  • apply 方法只会在药水生效的瞬间被调用一次,如果要像「力量」那样持续生效,有几个办法:
    • 创建一个 List<UUID> 记录有这个效果的实体,并通过 Bukkit 的计划任务在一定时间后移除,然后监听事件,通过查询这个 List 对实体的行为进行相应的修改
    • 将数据通过 NBT 绑定到实体上,并通过 Bukkit 的计划任务在一定时间后移除,然后监听事件,通过查询 NBT 对实体的行为进行相应的修改
  • 一定要记得加 @Override

那什么是 Bukkit 的计划任务呢?

Bukkit 计划任务用于「在一段时间后执行某个操作」,我们在 4-2 和 AC-1-1 中见到过它的「异步执行」版本。计划任务的写法和异步执行非常相似:

new BukkitRunnable() {
    @Override
    public void run() {
        // 要做之事……
    }
}.runTaskLaterAsynchronously(<插件主类名>.instance, 200); // 200 是要推迟的时间,单位刻

这样就不难解释我们上面的效果了,我们让 Bukkit 向玩家发送许多「e」,并将这个操作推迟了 10 秒(200 刻)。

好啦!这样药水效果就创建完了,不需要注册!

将这个效果直接应用给玩家:

new EEEEffect().apply(Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG")));

将效果与药水绑定

现在重新看看 3-2 中的内容,是不是恍然大悟了?

其实,创建一瓶「咏 e」药水也不难嘛……唰唰唰就写出来了:

ItemStack ePotion = new ItemStack(Material.SPLASH_POTION);
// 喷溅型咏 E 药水,Minecraft 会自动判断受影响的实体,想想就很好玩啊!
PotionMeta pm = (PotionMeta) myPotion.getItemMeta();
pm.setColor(new Color(225, 0, 0)); // 危险的红色
pm.setBasePotionData(new PotionData(PotionType.WATER));
// 不需要任何预设效果,使用 WATER,请区分 PotionType 和 PotionEffectType!
pm.addCustomEffect(new EEEEffect()); // 加入我们自定义的药水效果
pm.setDisplayName("喷溅的咏 e 药水");
pm.setLore(Collections.singletonList(ChatColor.GRAY + "eee……eeee?"));
// 灰色的介绍
ePotion.setItemMeta(pm);

Collections.singletonList 创建一个单项只读列表。

对于药水究竟怎么「喷溅」,「喷溅」到谁身上,那是 Bukkit 来决定的啦~

现在 ePotion 就是一个「喷溅的咏 e 药水」啦!想怎么使用就由你决定啦~

例如,将它给予一个玩家:

Objects.requireNonNull(Bukkit.getPlayer("ThatRarityEG"))
    .getInventory()
    .addItem(ePotion);

将它对着自己丢出来试试吧!

效果大概是这样的(1.16.5 原版,资源包是 Love-And-Tolerance):

RESULT

EEE