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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:39:30