Libgdx中Actor动作的暂停与续播实现问题
解决Libgdx中Actor动作暂停/继续后速度异常的问题
哈哈,这个坑我当初刚用Libgdx的时候也踩过!你遇到的核心问题其实很好理解:Libgdx内置的像MoveToAction这类动作,是基于总时长来计算移动速度的。当你中途暂停动作(比如直接清除动作),再次启动时如果还是用原来的总时长,但此时Actor已经走了一段路,剩余位移要在更短的时间内完成,速度自然就飙上去了。
下面给你两种最实用的解决思路,都是我实际项目里用过的:
方法一:用Libgdx内置的暂停/恢复API
Libgdx的Action类本身就提供了pause()和resume()方法,不需要自己折腾进度计算,关键是要保留住原来的动作实例,不要随便清除。
代码示例
// 先定义成员变量存住动作和状态 private Actor myMovingActor; private MoveToAction moveAction; private boolean isActionActive = false; // 初始化环节 myMovingActor = new Actor(); // 创建动作并设置目标和总时长 moveAction = new MoveToAction(); moveAction.setPosition(600, 400); // 目标坐标 moveAction.setDuration(3f); // 总时长3秒 // 按钮点击事件处理 startPauseBtn.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { if (isActionActive) { // 暂停动作 moveAction.pause(); } else { // 如果动作还没加到Actor上,先加进去 if (!myMovingActor.getActions().contains(moveAction, true)) { myMovingActor.addAction(moveAction); } // 恢复动作执行 moveAction.resume(); } isActionActive = !isActionActive; } });
注意点
- 不要调用
myMovingActor.clearActions(),否则动作会被移除,下次只能重新创建,进度就丢了 - 如果动作已经执行完毕(比如Actor到了目标位置),需要重新创建一个新的
MoveToAction再启动
方法二:手动记录进度,自定义动作逻辑
如果内置的暂停恢复满足不了你的需求(比如要做更复杂的动作控制),可以手动记录动作的执行进度,每次恢复时基于剩余位移和剩余时间重新计算速度。
代码示例
// 成员变量记录关键信息 private Actor myActor; private Vector2 targetPos; // 目标位置 private float totalDuration; // 总时长 private float elapsedTime = 0f; // 已经消耗的时间 private boolean isMoving = false; // 按钮点击事件 controlBtn.addListener(new ClickListener() { @Override public void clicked(InputEvent event, float x, float y) { if (!isMoving) { // 第一次启动时初始化目标和时长 if (targetPos == null) { targetPos = new Vector2(500, 300); totalDuration = 2f; } isMoving = true; // 添加自定义动作处理移动 myActor.addAction(new Action() { @Override public boolean act(float delta) { if (!isMoving) { // 暂停时只累加已消耗时间,不移动 elapsedTime += delta; return false; // 保持动作在列表中,不标记完成 } float progress = elapsedTime / totalDuration; if (progress >= 1f) { // 动作完成,重置状态 myActor.setPosition(targetPos.x, targetPos.y); isMoving = false; elapsedTime = 0f; targetPos = null; return true; // 标记动作完成,从列表移除 } // 计算当前帧应该移动的距离(保持原速度) Vector2 currentPos = myActor.getPosition(new Vector2()); float remainingTime = totalDuration - elapsedTime; Vector2 moveDelta = targetPos.cpy().sub(currentPos).scl(delta / remainingTime); myActor.moveBy(moveDelta.x, moveDelta.y); elapsedTime += delta; return false; } }); } else { // 暂停动作 isMoving = false; } } });
这种方式的好处是完全可控,不管是暂停、恢复还是中途修改目标位置,都能轻松调整,适合复杂的交互场景。
内容的提问来源于stack exchange,提问作者hello123
相关产品推荐
相关产品推荐

