如何修改NES版《超级马里奥兄弟》1-1关卡寄存器指定马里奥起始位置?
解决gym-super-mario-bros里马里奥起始位置被重置的问题
为啥改了RAM还是回到初始位置
直接修改0x6d(页面寄存器)和0x86(页面内X偏移)会被游戏的关卡初始化逻辑覆盖——环境执行reset()时,游戏会从ROM的关卡数据中读取默认起始位置,自动覆盖你修改的寄存器值。另外,仅修改_x_position函数只是调整了位置的读取逻辑,并没有真正改变游戏内的初始状态。
具体解决办法
1. 选对修改RAM的时机
不要在环境初始化前修改RAM,等reset()完成后立刻写入目标寄存器值:
import gym_super_mario_bros from nes_py.wrappers import JoypadSpace from gym_super_mario_bros.actions import SIMPLE_MOVEMENT env = gym_super_mario_bros.make('SuperMarioBros-v0') env = JoypadSpace(env, SIMPLE_MOVEMENT) # 先完成环境重置 obs = env.reset() # 写入目标位置的RAM值(示例:绝对X坐标设为0x200) env.unwrapped.ram[0x6D] = 0x2 # 设置页面寄存器 env.unwrapped.ram[0x86] = 0x00 # 设置页面内X偏移 # 同步修改绝对位置寄存器,避免游戏逻辑冲突 env.unwrapped.ram[0x0710] = 0x200
2. 修改环境初始化逻辑(永久生效)
如果需要每次重置环境都直接加载自定义起始位置,修改smb_env.py中的_reset方法,在游戏初始化完成后添加RAM写入代码:
# 在smb_env.py的_reset方法末尾添加以下内容 # 自定义起始位置:页面0x2,偏移0x00 self.ram[0x6D] = 0x2 self.ram[0x86] = 0x00 self.ram[0x0710] = 0x200
注意:修改库文件后,需确保Python能加载到修改后的版本,可选择重新安装库或调整文件路径。
3. 确保位置读取逻辑正确
修改_x_position函数时,要保证它能正确计算马里奥的绝对位置:
def _x_position(self) -> int: # 绝对X坐标 = 页面值 * 256 + 页面内偏移 return (self.ram[0x6D] << 8) + self.ram[0x86]
避免仅读取单一寄存器导致位置显示错误。
额外提醒
- 确认RAM地址匹配:不同ROM版本(如美版、日版)的RAM映射可能存在差异,要与你使用的游戏版本对应。
- 选择合法位置:若设置的位置超出当前关卡的可加载区域,游戏可能会强制将马里奥拉回合法坐标,需选择关卡内的有效位置。
内容的提问来源于stack exchange,提问作者Edoardo Fazzari
相关产品推荐
相关产品推荐

