GMS2中Q-learning AI的QTable索引越界问题求助
GMS2 Q-learning AI 索引越界问题修复
问题核心错误分析
- 状态表示无效:原
getCurrentState()返回字符串格式的坐标组合(如"100_200"),直接作为ds_grid索引时,GMS2会将其强制转换为无效数字(如0或NaN),导致索引越界。 - 动作类型不统一:探索模式返回字符串动作(
"up"等),而QTable选择动作时返回数字索引,后续更新QTable时误用了无关的id_action变量,而非实际执行的动作索引。 - 索引范围判断逻辑失效:用字符串类型的
currentState直接与数字比较,无法正确校验索引有效性。
具体修复步骤
1. 重构状态表示(转换为唯一整数索引)
将世界坐标映射为网格单元的唯一整数索引,确保索引在QTable的有效范围内:
// 修改Step事件中的getCurrentState函数 function getCurrentState() { // 自定义网格单元尺寸(需与游戏场景匹配,比如你的移动速度spd或格子大小) var gridCellSize = spd; // 将世界坐标转换为网格单元坐标 var gridX = floor(x / gridCellSize); var gridY = floor(y / gridCellSize); // 转换为唯一整数索引(假设游戏网格总列数为10,可根据实际调整) var gridTotalCols = 10; return gridY * gridTotalCols + gridX; }
注:需根据游戏实际网格尺寸调整gridTotalCols,确保所有可能的状态索引落在0到QTableWidth-1之间。
2. 统一动作的数字索引
将所有动作改为数字索引表示,避免字符串与数字混用:
修改动作选择逻辑
#region randomizar ou andar com base em aprendizado if random(1) < explorationRate { // 探索模式:随机选择0-3的动作索引(0=上,1=下,2=左,3=右) action = irandom(3); } else { var bestActionIndex = 0; var bestActionValue = QTable[# currentState, 0]; // 仅遍历4种动作(无需遍历QTableHeight的100个无效项) for (var i = 1; i < 4; i++) { var value = QTable[# currentState, i]; if (value > bestActionValue) { bestActionValue = value; bestActionIndex = i; } } action = bestActionIndex; } #endregion
修改动作执行逻辑
#region açoes switch (action) { case 0: // 上 y -= spd; break; case 1: // 下 y += spd; break; case 2: // 左 x -= spd; break; case 3: // 右 x += spd; break; } #endregion
3. 修复QTable更新的索引逻辑
删除无关的id_action变量,使用实际执行的action作为索引,并修正范围判断:
newState = getCurrentState(); // 校验索引有效性(状态索引在QTable宽度内,动作索引为0-3) if (currentState >= 0 && currentState < QTableWidth && action >= 0 && action < 4) { var currentQValue = QTable[# currentState, action]; // 获取新状态下的最大Q值 var maxFutureQValue = QTable[# newState, 0]; for (var i = 1; i < 4; i++) { if (QTable[# newState, i] > maxFutureQValue) { maxFutureQValue = QTable[# newState, i]; } } // 标准Q-learning更新公式 QTable[# currentState, action] = currentQValue + learningRate * (reward + discountFactor * maxFutureQValue - currentQValue); } else { show_debug_message("索引越界:状态=" + string(currentState) + ",动作=" + string(action)); }
4. 调整QTable尺寸优化内存
因为只有4种动作,将QTableHeight改为4即可:
// 修改Create事件中的QTable初始化 QTableWidth = 100; // 根据实际状态总数调整(如网格单元总数量) QTableHeight = 4; // 固定为4,对应4种动作 QTable = ds_grid_create(QTableWidth, QTableHeight); ds_grid_set_all(QTable, 0); // 初始化所有Q值为0
额外优化建议
- 每次触发奖励/惩罚后重置
reward,避免累积影响后续更新:
if place_meeting(x, y, obj_objetivo) { reward = 10; // 改为赋值而非累加 x = iniX; y = iniY; } else if place_meeting(x, y, obj_Obstaculo) { reward = -10; // 改为赋值而非累加 x = iniX; y = iniY; } else { reward = -0.1; // 增加每步小惩罚,鼓励AI尽快到达目标 }
内容的提问来源于stack exchange,提问作者DAriousda
相关产品推荐
相关产品推荐

