Bukkit Runnable使用求助:实现延迟获取玩家Y坐标差值
解决Bukkit Runnable延迟计算玩家Y坐标差的问题
我懂你现在的困扰——原代码里y1和y2是在同一帧获取的,差值自然永远是0,而且完全没用到Bukkit的任务调度来实现延迟逻辑。下面我给你一步步修改代码,同时把关键要点讲清楚:
核心问题分析
你的初始代码没有实现延迟1秒的逻辑,y1和y2是在PlayerMoveEvent触发的同一时刻获取的,所以计算出来的差值始终为0,这就是你看不到预期效果的原因。我们需要用Bukkit的Scheduler来调度一个延迟任务,在1秒后再获取玩家的Y坐标。
修改后的完整代码
import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import java.util.HashMap; import java.util.UUID; public class FlyE implements Listener { // 记录玩家上次触发任务的时间,避免PlayerMoveEvent频繁触发导致任务堆积 private final HashMap<UUID, Long> cooldown = new HashMap<>(); private final JavaPlugin plugin; // 构造方法,必须传入插件实例(Bukkit调度任务需要依赖它) public FlyE(JavaPlugin plugin) { this.plugin = plugin; } @EventHandler public void onPlayerMovement(PlayerMoveEvent e) { Player p = e.getPlayer(); UUID playerId = p.getUniqueId(); long currentTime = System.currentTimeMillis(); // 加1秒冷却,避免每秒触发几十次任务占用服务器资源 if (cooldown.containsKey(playerId) && currentTime - cooldown.get(playerId) < 1000) { return; } cooldown.put(playerId, currentTime); // 获取当前时刻的Y坐标 double y1 = p.getLocation().getY(); // 调度延迟任务:20刻 = 1秒(Bukkit默认每秒运行20游戏刻) new BukkitRunnable() { @Override public void run() { // 延迟后先检查玩家是否还在线,避免调用离线玩家方法抛出空指针异常 if (!p.isOnline()) { return; } // 获取1秒后的Y坐标 double y2 = p.getLocation().getY(); // 按你原逻辑计算差值 double yf = y1 - y2; // 广播结果,这里用玩家名字比直接输出Player对象更友好 Bukkit.broadcastMessage(p.getName() + " 的Y坐标变化量 = " + yf); } }.runTaskLater(plugin, 20L); // 第二个参数是延迟的刻数,20L对应1秒 } }
关键要点解释
- Bukkit任务调度:用
BukkitRunnable配合runTaskLater实现延迟,第二个参数是延迟的游戏刻数,Bukkit默认每秒20刻,所以20L就是1秒。注意必须传入插件实例(JavaPlugin),这是Bukkit调度任务的硬性要求。 - 玩家状态检查:延迟的1秒内玩家可能下线,所以在
run()方法里先判断p.isOnline(),避免调用离线玩家的getLocation()抛出空指针异常。 - 任务堆积防护:
PlayerMoveEvent会在玩家移动时频繁触发(甚至每秒几十次),所以加了冷却机制,用HashMap记录玩家上次触发任务的时间,确保1秒内每个玩家只触发一次任务,避免服务器资源浪费。
额外注意事项
记得在你的主插件类里注册这个监听器,比如:
public class YourPlugin extends JavaPlugin { @Override public void onEnable() { getServer().getPluginManager().registerEvents(new FlyE(this), this); } }
内容的提问来源于stack exchange,提问作者Darth
相关产品推荐
相关产品推荐

