基于A*图节点的Processing游戏:玩家移动状态检测问题求助
解决思路与代码修改
作为编程新手,你当前遇到的核心问题是Player类的移动逻辑用while循环导致瞬间完成移动,以及没有把路径节点和到达检测逻辑结合起来。下面是一步步的实操方案:
1. 修复Player的平滑移动逻辑
你现在drawPlayer()里的while (dir.mag() > 1.0)会让玩家瞬间跳到目标节点,这不仅看不到移动过程,还逼得你用时间延迟模拟"到达"。我们改成逐帧移动,贴合Processing的动画机制:
void drawPlayer() { fill(circleColour); circle(xPos,yPos,35); float speed = 5.0; // 调整这个值控制移动速度,不用100这么大,否则还是太快 PVector dir = new PVector(xTar - xPos, yTar - yPos); // 把while改成if,每帧只移动一小步 if (dir.mag() > 1.0) { dir.normalize(); dir.mult(speed); // 直接用speed控制每帧移动距离,更直观 xPos += dir.x; yPos += dir.y; isPlayerStopped = false; } else { // 到达目标,校准位置到节点坐标(避免微小误差) xPos = xTar; yPos = yTar; isPlayerStopped = true; } }
2. 让Player管理完整路径,跟踪当前节点
我们需要让Player知道整条路径的节点,以及当前走到了哪一步。修改Player类,添加路径跟踪的变量和方法:
class Player { int lastHitting; int side; float xPos; float yPos; float xTar; float yTar; color circleColour = color(255,0,0); boolean isPlayerStopped; // 新增:跟踪路径节点和当前索引 GraphNode[] pathNodes; int currentPathIndex; Player(int lastHitting, int side) { this.lastHitting = lastHitting; this.side = side; if (this.side == 0) { circleColour = color(0,0,255); xPos = 180; yPos = 900; } else if (this.side == 1) { circleColour = color(255,0,0); xPos = 990; yPos = 125; } // 初始化路径索引 currentPathIndex = 0; isPlayerStopped = true; } // 新增:设置完整路径 void setPath(GraphNode[] path) { this.pathNodes = path; if (path != null && path.length > 0) { // 设置第一个目标节点(如果路径不为空) currentPathIndex = 0; setTargetPosition(pathNodes[currentPathIndex].xf(), pathNodes[currentPathIndex].yf()); isPlayerStopped = false; } } // 新增:切换到下一个路径节点 boolean goToNextNode() { if (pathNodes == null || currentPathIndex >= pathNodes.length - 1) { // 已经到达最后一个节点,没有下一个了 return false; } currentPathIndex++; GraphNode nextNode = pathNodes[currentPathIndex]; setTargetPosition(nextNode.xf(), nextNode.yf()); isPlayerStopped = false; return true; } // 新增:获取当前所在节点的ID int getCurrentNodeId() { if (pathNodes != null && currentPathIndex < pathNodes.length) { return pathNodes[currentPathIndex].id(); } return -1; // 表示没有路径或未到达任何节点 } // 保留你原有的movementCheck、getXPos、getYPos方法 boolean movementCheck() { return isPlayerStopped; } float getXPos() { return xPos; } float getYPos() { return yPos; } void setTargetPosition(float targetX, float targetY) { xTar = targetX; yTar = targetY; } }
3. 调整主程序逻辑,去掉时间延迟,监听到达事件
在setup()里直接把A*生成的route传给Player,不用单独存xPos/yPos:
void setup() { // ... 保留你原有的其他代码 ... midBlue = new Player(lastHittingBlue, blueSide); midRed = new Player(lastHittingRed, redSide); // 给蓝色玩家设置路径 midBlue.setPath(route); }
然后修改draw()函数,去掉runtime延迟,改为检测玩家是否到达当前节点:
void draw() { background(0); text((float)millis()/1000, 10,height/6); text(start/1000, 10,height/3); runtime = millis() - start; text(runtime/1000, 10,height/2); drawGraph(); drawPath(); // 检测蓝色玩家是否到达当前节点 if (midBlue.movementCheck()) { // 到达节点,打印当前节点ID int currentNodeId = midBlue.getCurrentNodeId(); println("蓝色玩家到达节点: " + currentNodeId); // 尝试切换到下一个节点 boolean hasNext = midBlue.goToNextNode(); if (!hasNext) { println("蓝色玩家已到达最终目标!"); // 可以在这里添加到达终点后的逻辑,比如等待用户输入新目标 } } midBlue.drawPlayer(); midRed.drawPlayer(); // 红色玩家的逻辑可以参照蓝色玩家处理 text( "x: " + mouseX + " y: " + mouseY, mouseX + 2, mouseY ); }
4. 优化路径绘制逻辑(可选)
你当前的drawPath()里while (firstRun)会重复添加节点,其实直接用route数组绘制即可:
void drawPath() { if (route == null || route.length < 2) return; strokeWeight(10); stroke(200, 255, 200, 160); for (int i = 1; i < route.length; i++) { GraphNode from = route[i-1]; GraphNode to = route[i]; line(from.xf(), from.yf(), to.xf(), to.yf()); } // 统计路径长度只需要一次 if (nodeCount == true) { count = route.length; nodeCount = false; } }
关键说明
- 为什么把while改成if?因为Processing的
draw()是逐帧循环调用的(默认60帧/秒),每帧移动一小步才能实现平滑动画,同时不会阻塞程序。 - 让Player管理路径节点,能直接获取节点ID,不需要单独存坐标,逻辑更清晰。
- 用
dir.mag() < 1.0做到达检测是合理的,当玩家和目标的距离小于1像素时,我们认为已经到达,再校准位置到节点坐标,避免微小误差。
这样修改后,你的玩家会平滑地沿路径逐节点移动,到达每个节点时都会打印当前节点ID,自动切换下一个节点,直到到达终点,完全不需要时间延迟啦!
内容的提问来源于stack exchange,提问作者Xarigizel
相关产品推荐
相关产品推荐

