LibGDX开发蛇梯棋时如何通过setPosition让Sprite缓慢移动?
问题根源
你现在看到玩家瞬间跳位,根本原因是updatePlayer(int dice)里的for循环会在同一帧内全部跑完。LibGDX的游戏循环规则是:先把当前帧的所有逻辑代码执行完,再统一渲染一次。哪怕你在循环里多次调用渲染方法,本质上一帧就把骰子对应的所有位移都算完了,自然看不到移动过程。
解决方法
别把多步移动塞在一个for循环里一次性跑完,把移动拆成多帧推进,每帧只动一点点,自然就能看到平滑的移动效果。
第一步:给玩家类加几个状态变量
不再触发移动就一次性移完,而是把移动任务存起来,交给每帧循环处理:
// 标记玩家是否正在移动中 private boolean isMoving = false; // 还剩多少步没走 private int remainingSteps = 0; // 平滑移动的速度,单位 像素/秒,自己根据手感调 private float moveSpeed = 120f; // 单步移动的起点、终点坐标,用来做平滑插值 private float startX, startY, targetX, targetY;
第二步:写移动触发的入口
掷出骰子拿到点数后,别直接跑旧的for循环,而是把移动任务登记好:
public void startMove(int dice) { // 点数校验,正在移动的时候不接新的移动指令 if (dice < 1 || dice > 6 || isMoving) return; remainingSteps = dice; isMoving = true; // 算第一步要去的位置 calculateNextStepTarget(); } // 算下一格的目标位置,替换你原来循环里的位移逻辑 private void calculateNextStepTarget() { // 把当前位置记为这一步的起点 startX = getX(); startY = getY(); float gridSize = 48; // 就是你代码里用的单格宽度48 float nextX = startX + gridSize; // 到棋盘右边界了,就换行到最左侧,往上走一格 if (nextX > GameInfo.WIDTH - 20) { targetX = 20; // 换成你棋盘最左侧的实际x坐标就行 targetY = startY + gridSize; } else { targetX = nextX; targetY = startY; } }
第三步:每帧推进移动逻辑
改原来的无参updatePlayer方法,记得要把LibGDX每帧传的deltaTime(两帧之间的间隔秒数)当参数传进来,用时间差算移动距离,不然不同帧率的设备上移动速度会不一样:
public void updatePlayer(float deltaTime) { // 没在移动的话,正常渲染就行 if (!isMoving) { drawSprite(); return; } // 算这一帧能走的距离 float frameMoveDist = moveSpeed * deltaTime; // 算当前这一步起点到终点的总距离 float totalStepDist = (float) Math.hypot(targetX - startX, targetY - startY); // 如果这一帧走的距离已经超过到终点的剩余距离,说明这一步走完了 if (frameMoveDist >= totalStepDist) { setPosition(targetX, targetY); remainingSteps--; // 还有剩的步数,就算下一格的目标 if (remainingSteps > 0) { calculateNextStepTarget(); } else { // 所有步数走完,结束移动状态 isMoving = false; } } else { // 还没到终点,按比例平滑挪过去 float progress = frameMoveDist / totalStepDist; float newX = startX + (targetX - startX) * progress; float newY = startY + (targetY - startY) * progress; setPosition(newX, newY); } // 渲染当前位置的Sprite drawSprite(); } // 把你原来的渲染逻辑封装一下 private void drawSprite() { game.getBatch().begin(); draw(game.getBatch()); game.getBatch().end(); }
几个代码里的注意点
- 原来的逻辑里每挪一点就开关一次
SpriteBatch,这完全是不必要的性能浪费。实际一帧只需要在所有渲染前开一次begin(),所有东西画完关一次end()就行,不用单个Sprite就开关一次batch。 - 想更像真实蛇梯棋的节奏,可以在单步走完之后加个0.2秒左右的停顿,等停完再走下一格,不然移动会太急。
moveSpeed的数值可以根据实际视觉效果调整,数值越大移动越快。
内容的提问来源于stack exchange,提问作者Melih
相关产品推荐
相关产品推荐

