C语言交通游戏:通用链表与结构体实现撤销功能的问题
游戏撤销功能异常的问题分析与修复
核心问题点
状态记录逻辑混乱
moveCar和movePlayer函数一开始就插入状态,无论操作是否有效(比如玩家输入无效方向、车辆无法移动时),都会向链表中添加无效状态,导致撤销时回退到错误的节点。- 游戏循环中每次先执行
moveCar再处理输入,导致车辆移动和玩家操作的状态被分开记录,撤销时无法同步回退一组完整的操作。
撤销时未同步更新地图
undoMove仅修改了全局变量(playerRow、carRow等),但没有更新map数组中对应的玩家和车辆位置,导致地图显示与实际状态不符,出现车辆重复、玩家位置未变化的视觉错误。moveCar中的地图数据污染
在车辆转向失败的分支中,直接将map[carRow][carCol]赋值为方向字符(如CAR_NORTH),但map数组应存储枚举值(CAR=2)而非字符,这会破坏地图数据结构,导致显示异常。
修复方案
1. 调整状态记录时机与逻辑
- 仅在有效操作发生前记录当前状态,避免无效操作占用链表节点。
- 调整游戏循环顺序:先处理玩家输入,再执行车辆移动,将玩家操作+对应车辆移动作为一个完整步骤,只记录一次状态。
修改main函数的循环逻辑:
while (1) { printMap(); char input = getchar(); if (input == 'q') { break; } else if (input == 'u') { undoMove(); } else { // 记录当前状态,再执行玩家移动和车辆移动 insertStart(playerRow, playerCol, carRow, carCol, carDirection); movePlayer(input); moveCar(); } if (checkWinCondition()) { printf("You Win!\n"); break; } if (checkLoseCondition()) { printf("You Lose!\n"); break; } }
同时删除movePlayer和moveCar函数开头的insertStart调用。
2. 修复undoMove函数,同步更新地图
在恢复全局变量后,需要更新map数组,确保显示与实际状态一致:
void undoMove() { if (head == NULL) { return; // Nothing to undo } // 先清除当前状态在地图中的标记 map[playerRow][playerCol] = SPACE; map[carRow][carCol] = ROAD; // 恢复之前的状态 playerRow = head->playerRow; playerCol = head->playerCol; carRow = head->carRow; carCol = head->carCol; carDirection = head->carDirection; // 在地图中标记恢复后的状态 map[playerRow][playerCol] = PLAYER; map[carRow][carCol] = CAR; // 移除已恢复的状态节点 removeStart(); }
3. 修复moveCar中的地图赋值错误
删除转向失败分支中直接修改map的代码,仅更新carDirection即可:
else { carDirection = (carDirection + 2) % 4; /* Turn around (180 degrees) if no path is found */ // 移除原有的switch赋值代码,map中保持CAR枚举值,方向由carDirection控制 }
4. 优化movePlayer的无效输入处理
避免无效输入时干扰流程,仅在输入有效时执行移动:
void movePlayer(char direction) { int newPlayerRow = playerRow; int newPlayerCol = playerCol; switch (direction) { case 'w': newPlayerRow--; break; case 's': newPlayerRow++; break; case 'a': newPlayerCol--; break; case 'd': newPlayerCol++; break; case 'q': return; default: printf("Invalid input. Use 'w' to move up, 's' to move down, 'a' to move left, 'd' to move right and 'q' to quit the game.\n"); sleep(1); return; } if (newPlayerRow >= 0 && newPlayerRow < rows && newPlayerCol >= 0 && newPlayerCol < cols && map[newPlayerRow][newPlayerCol] != CAR && map[newPlayerRow][newPlayerCol] != '*') { map[playerRow][playerCol] = SPACE; playerRow = newPlayerRow; playerCol = newPlayerCol; map[playerRow][playerCol] = PLAYER; } }
修复后的效果
- 撤销操作会同步回退玩家和车辆的状态,地图显示与实际状态一致。
- 仅记录有效操作步骤,避免无效状态占用链表空间。
- 地图数据结构不再被污染,车辆显示正常。
内容的提问来源于stack exchange,提问作者user22772211
相关产品推荐
相关产品推荐

