如何实现Gravity Guys游戏中敌人延迟3秒复制玩家动作?
实现敌方延迟3秒复制玩家动作的解决方案
问题分析
你当前的代码逻辑存在核心问题:在keyPressed事件中处理敌人的延迟动作完全行不通——该事件仅在玩家按下按键时触发一次,不会持续检查时间是否达到延迟要求。敌人的动作执行逻辑必须放在游戏的持续更新循环(如每帧执行的tick方法)中,才能定时检测并执行延迟动作。
解决方案步骤
- 记录玩家的动作历史:用队列存储玩家的每一次操作及其时间戳,保证敌人能按顺序延迟执行。
- 玩家触发动作时记录到队列:修改输入处理类,仅处理玩家动作并将动作信息存入队列,不再在按键事件中处理敌人逻辑。
- 在敌人的更新逻辑中执行延迟动作:在敌人每帧更新的
tick方法中,检查动作队列,当动作的时间戳与当前时间差达到3秒时,执行对应动作。
具体代码修改
1. 定义动作存储类
用于记录玩家的动作类型和触发时间:
class PlayerAction { public String action; public long timestamp; public PlayerAction(String action, long timestamp) { this.action = action; this.timestamp = timestamp; } }
2. 在Handler中添加动作队列
import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Queue; public class Handler { public List<GameObject> object = new ArrayList<>(); // 存储玩家动作的队列 public Queue<PlayerAction> playerActions = new LinkedList<>(); }
3. 修改KeyInput类,仅处理玩家动作并记录
import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; public class KeyInput extends KeyAdapter{ Handler handler; public KeyInput(Handler handler){ this.handler=handler; } public void keyPressed(KeyEvent e){ int key=e.getKeyCode(); for(int i =0 ; i<handler.object.size(); i++){ GameObject tempObject= handler.object.get(i); if (tempObject.getId() == ObjectId.Player) { if (key == KeyEvent.VK_SPACE && ((Player) tempObject).canSwitchGravity ) { // 执行玩家的重力切换 tempObject.setGravityInverted(!tempObject.isGravityInverted()); ((Player) tempObject).canSwitchGravity = false; // 将动作记录到队列 handler.playerActions.add(new PlayerAction("switch_gravity", System.currentTimeMillis())); } } if(key== KeyEvent.VK_ESCAPE){ System.exit(1); } } } }
4. 在Enemy类的tick方法中处理延迟动作
public class Enemy extends GameObject { private Handler handler; public boolean canSwitchGravity; public Enemy(float x, float y, ObjectId id, Handler handler) { super(x, y, id); this.handler = handler; } public void tick() { // 保留原有的敌人移动、碰撞检测等逻辑... // 处理延迟动作 long currentTime = System.currentTimeMillis(); // 遍历动作队列,检查是否有达到延迟时间的动作 while (!handler.playerActions.isEmpty()) { PlayerAction action = handler.playerActions.peek(); if (currentTime - action.timestamp >= 3000) { // 延迟3秒后执行对应动作 if (action.action.equals("switch_gravity") && this.canSwitchGravity) { this.setGravityInverted(!this.isGravityInverted()); this.canSwitchGravity = false; } // 执行完成后移除该动作 handler.playerActions.poll(); } else { // 队列按时间顺序存储,前面的动作未到延迟时间,后面的无需再检查 break; } } } // 保留原有的render等方法... }
注意事项
- 线程安全:如果游戏采用多线程架构(输入线程与更新线程分离),请使用
ConcurrentLinkedQueue替代LinkedList,避免并发修改问题。 - 动作顺序:队列会按玩家操作的先后顺序存储动作,敌人会依次延迟执行,完全复刻玩家的操作节奏。
- 状态一致性:确保Enemy的
canSwitchGravity逻辑与Player完全一致(仅接触地面时为true),避免敌人在无效状态下执行动作。
内容的提问来源于stack exchange,提问作者Ste Michelini
相关产品推荐
相关产品推荐

