星际争霸2的PYSC2环境你知道吗?能否介绍一下屏幕坐标
创建于:2025年5月28日
创建于:2025年5月28日
星际争霸2的PYSC2环境你知道吗?能否介绍一下屏幕坐标
下面把 PySC2 里最常用、也最容易弄混的 Screen 坐标系 讲清楚──读完你就能判断「这一对 (x, y) 到底该怎么写、范围是多少、跟摄像机/小地图是什么关系」。
空间 | 原点 | x 轴 | y 轴 | 典型分辨率 |
---|---|---|---|---|
Screen(屏幕) | 左上角 (0, 0) | 向右增大 | 向下增大 | 84 × 84(默认,可自定义) |
Minimap(小地图) | 左上角 (0, 0) | 向右增大 | 向下增大 | 64 × 64(默认,可自定义) |
官方文档强调:观测里的坐标是 (y, x);动作里的坐标必须写成 (x, y),两者顺序相反。
(y, x)
↔ (x, y)
的差别?obs.observation.feature_screen[...]
等数组下标是 行先列后 的 NumPy 风格:
pythonvalue = feature_screen[y][x] # y 是行,x 是列
actions.FunctionCall.Move_screen("now", [x, y])
里的参数按游戏 UI 的习惯写,横坐标在前。很多 bug 都源于忘记对调这两个数。社区教程和 StackOverflow 也一直在提醒这一点。
pythonfrom pysc2.env import sc2_env from pysc2.lib import features env = sc2_env.SC2Env( map_name="Simple64", agent_interface_format=features.AgentInterfaceFormat( feature_dimensions=features.Dimensions(screen=96, minimap=72), use_feature_units=True), )
0 ≤ x ≤ 95, 0 ≤ y ≤ 95
。use_feature_units=True
,然后读取
pythonfor u in obs.observation.feature_units: print(u.x, u.y) # 这对 (x, y) 已经是屏幕坐标,范围同 screen 分辨率
unit.x
, unit.y
,它们是 地图原坐标(world coordinate),范围与地图大小(32–256)相关,需要对照相机中心自行换算。python# 找到未被占用的矿区 (PLAYER_NEUTRAL) 的像素集合 y, x = (obs.observation["feature_screen"][features.SCREEN_FEATURES.player_relative.index] == features.PlayerRelative.NEUTRAL).nonzero() # 取像素平均位置,注意先 x 后 y target = [int(x.mean()), int(y.mean())] act = actions.FUNCTIONS.Move_screen("now", target)
如果直接把 [y.mean(), x.mean()]
传进去,会收到 “invalid action arguments” 的报错。
0 ≤ x < screen_width
,否则环境会抛 ValueError
。step_mul
无关,但步长太大时你的相机可能早就移动了,导致坐标失效。visualize=True
或把 screen
渲染成图像,直接在窗口里看坐标是最快的排错手段。观测用
(y, x)
,动作用(x, y)
;原点左上,坐标随分辨率而定,随摄像机一起移动。
掌握这条规则,你在 PySC2 写任何空间动作时就不会再「点不到」啦!
{"2": "Game Info:\n\tTime: 0:03\n\nTeam Colossus-1 Info:\n\tTeam minimap position: [31, 35]\n\tControlled Team Units:\n\t\tUnit: Colossus Tag: 0x100040001 ScreenPos: [66, 76] Health: 350(100 %) Weapon Cooldown Time: 0.59s\n\tNearby Ally Units:\n\t\tUnit: Colossus Tag: 0x100000001 ScreenPos: [63, 60] Health: 350(100 %)\n\tNearby Enemy Units:\n\t\tUnit: Zergling Tag: 0x100a00001 ScreenPos: [118, 83] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100dc0001 ScreenPos: [10, 79] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100a40001 ScreenPos: [3, 80] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100240001 ScreenPos: [6, 79] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100400001 ScreenPos: [119, 77] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100680001 ScreenPos: [6, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x1004c0001 ScreenPos: [110, 82] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100e40001 ScreenPos: [123, 66] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d80001 ScreenPos: [5, 65] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100e80001 ScreenPos: [4, 77] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100800001 ScreenPos: [114, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100740001 ScreenPos: [125, 74] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x100900001 ScreenPos: [127, 79] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d00001 ScreenPos: [15, 91] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100980001 ScreenPos: [8, 76] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100f00001 ScreenPos: [89, 88] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100600001 ScreenPos: [108, 78] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100180001 ScreenPos: [8, 84] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100340001 ScreenPos: [104, 76] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x101040001 ScreenPos: [12, 81] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d40001 ScreenPos: [98, 91] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x100c80001 ScreenPos: [121, 89] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100280001 ScreenPos: [2, 84] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x1007c0001 ScreenPos: [109, 89] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100840001 ScreenPos: [52, 76] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x100640001 ScreenPos: [1, 74] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100ec0001 ScreenPos: [41, 85] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100c00001 ScreenPos: [101, 94] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100ac0001 ScreenPos: [124, 82] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100580001 ScreenPos: [11, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100e00001 ScreenPos: [94, 91] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100bc0001 ScreenPos: [102, 91] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x100480001 ScreenPos: [21, 86] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100500001 ScreenPos: [106, 91] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x1001c0001 ScreenPos: [93, 79] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100300001 ScreenPos: [105, 79] Health: 21(60 %)\n\t\tUnit: Zergling Tag: 0x100440001 ScreenPos: [53, 79] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x100f40001 ScreenPos: [114, 83] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x1009c0001 ScreenPos: [124, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100700001 ScreenPos: [123, 77] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100cc0001 ScreenPos: [127, 67] Health: 35(100 %)\n\nTeam Colossus-2 Info:\n\tTeam minimap position: [31, 35]\n\tControlled Team Units:\n\t\tUnit: Colossus Tag: 0x100000001 ScreenPos: [63, 61] Health: 350(100 %) Weapon Cooldown Time: 0.45s\n\tNearby Ally Units:\n\t\tUnit: Colossus Tag: 0x100040001 ScreenPos: [66, 76] Health: 350(100 %)\n\tNearby Enemy Units:\n\t\tUnit: Zergling Tag: 0x100cc0001 ScreenPos: [126, 66] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x1009c0001 ScreenPos: [125, 86] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100f40001 ScreenPos: [114, 83] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100440001 ScreenPos: [54, 79] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x100bc0001 ScreenPos: [101, 91] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x100e00001 ScreenPos: [93, 91] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100580001 ScreenPos: [12, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100640001 ScreenPos: [1, 73] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100840001 ScreenPos: [53, 76] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x100280001 ScreenPos: [2, 85] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100c80001 ScreenPos: [121, 88] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100340001 ScreenPos: [103, 76] Health: 20(57 %)\n\t\tUnit: Zergling Tag: 0x100980001 ScreenPos: [8, 76] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d00001 ScreenPos: [16, 91] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100740001 ScreenPos: [125, 74] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x100e80001 ScreenPos: [4, 77] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d80001 ScreenPos: [6, 65] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100e40001 ScreenPos: [122, 66] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100240001 ScreenPos: [6, 80] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100a40001 ScreenPos: [2, 80] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100a00001 ScreenPos: [117, 83] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100dc0001 ScreenPos: [9, 78] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100400001 ScreenPos: [120, 77] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100680001 ScreenPos: [6, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x1004c0001 ScreenPos: [109, 81] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100800001 ScreenPos: [113, 87] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100f00001 ScreenPos: [88, 88] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100600001 ScreenPos: [107, 78] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100180001 ScreenPos: [9, 84] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x101040001 ScreenPos: [12, 81] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100d40001 ScreenPos: [97, 91] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x1007c0001 ScreenPos: [108, 88] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100ec0001 ScreenPos: [42, 84] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100c00001 ScreenPos: [100, 94] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100ac0001 ScreenPos: [124, 81] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x101000001 ScreenPos: [1, 65] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100480001 ScreenPos: [21, 86] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100500001 ScreenPos: [106, 92] Health: 5(14 %)\n\t\tUnit: Zergling Tag: 0x1001c0001 ScreenPos: [92, 79] Health: 35(100 %)\n\t\tUnit: Zergling Tag: 0x100300001 ScreenPos: [104, 79] Health: 21(60 %)\n\t\tUnit: Zergling Tag: 0x100700001 ScreenPos: [124, 77] Health: 35(100 %)\n\nRelevant Knowledge:\n\tProtoss.Colossus\n\t\tThe large quad-legged vehicle fires lasers in a splash pattern well-suited to destroying swarms of weaker units. This unit can also traverse differences in terrain height due to its long legs, and will appear to step over ledges and other obstacles due to the inverse kinematics system.\n\t\tUnit properties: ['ground', 'air', 'armored', 'massive', 'mechanical']\n\t\tWeapon info: Attack Range 7, target: ['ground'], anti: ['light'], DPS(damage per second) 13, DPS-anti 20\n\t\tunit abilities:\n\tZerg.Zergling\n\t\tFast but weak melee attacker ideal for swarming attacks in large numbers.\n\t\tUnit properties: ['ground', 'light', 'biological']\n\t\tWeapon info: Attack Range 1, target: ['ground'], DPS(damage per second) 10\n\nValid Actions:\n\tTeam Colossus-1 Valid Actions:\n\t\t<Attack_Unit(tag)>\n\t\t<Move_Screen(screen)>\n\tTeam Colossus-2 Valid Actions:\n\t\t<Attack_Unit(tag)>\n\t\t<Move_Screen(screen)>\n\nAction Args: \n\t(1) tag: tag refers to a hexadecimal number, shape as 0x000000000.\n\t(2) screen: screen refers to a screen coordinate, shape as [x, y], where x and y range from 0 to 128.\n\t(3) minimap: minimap refers to a minimap coordinate, shape as [x, y], where x and y range from 0 to 64.\nFor example, when you want to use an action like <Action_Name(tag, screen)>, you should output like <Action_Name(0x100580001, [37, 55])>; when you want to use an action like <Action_Name(screen)>, you should output like <Action_Name([66, 78])>. What's more, You need to see clearly whether an action is using screen coordinates or minimap coordinates, If an action name as XXXX_Screen, it uses screen coordinate; if an action name as XXXX_Minimap, it uses minimap coordinate.\n\nGive each team no more than 3 actions, among which activity release should usually before move and attack.\nNow, start generating your analysis and actions:"}
就比方这一条信息,屏幕坐标怎么超过了84呢?
84×84
只是 PySC2 的默认 screen 分辨率,并不是硬性上限。出现 118 , 127
这些数,一般有两种情况:
可能原因 | 现象 | 说明 |
---|---|---|
你把 feature layer 分辨率调大了 | feature_dimensions=Dimensions(screen=128, …) | PySC2 会把 screen 坐标拉伸到 0–127。很多基于 gym-sc2 的示例(特别是对战环境而不是官方 mini-game)都会把 screen 设成 128×128 ,方便卷积网络输入成 2 的幂次。 |
你看的是 Raw API 的“世界坐标” | .observation.raw_units[i].x / .y 或第三方库打印成 ScreenPos [...] | Raw 坐标直接给出单位在 整张地图(tile 尺寸)里的位置,不受相机和 feature layer 分辨率限制。常见天梯地图的可玩区域正好是 128×128 tile,所以最大值就是 127。 |
在你发的日志里还能看到环境自己写了一句:
screen refers to a screen coordinate, shape as [x, y], where x and y range from 0 to 128
也就是说,这个自定义环境 已经把合法范围声明成 0-128。所以:
pythonenv = sc2_env.SC2Env( ..., agent_interface_format=features.AgentInterfaceFormat( feature_dimensions=features.Dimensions(screen=84, minimap=64), use_feature_units=True # 如果只想要屏幕坐标,别开 raw ) )
0 ≤ x, y < 128
。关键点
- screen 坐标范围 = 你在
Dimensions(screen=…)
里设的值减 1。- Raw 坐标完全独立,跟地图大小相关(64 / 96 / 128 / 160…)。
- 一定要先弄清你拿到的到底是哪种坐标,再做界限检查或转换。
from llm_pysc2.agents.configs.llm_smac import *
from llm_pysc2.agents import MainAgent, LLMAgent
import os
class MainAgentLLMSmac(MainAgent):
def init(self):
config = ConfigSmac_2c()
super(MainAgentLLMSmac, self).init(config, LLMAgent)
def step(self, obs):
return super().step(obs)
if name == "main":
os.system(f"python -m pysc2.bin.agent --map 2c_vs_64zg --agent_race protoss --parallel 1 "
f"--agent llm_pysc2.bin.llm_smac.2c_vs_64zg.MainAgentLLMSmac")
这样启动的会如何影响分辨率呢?
结论先行
你贴的 os.system("python -m pysc2.bin.agent …")
这一行 并不会 主动修改 feature-layer 分辨率;
由于没传任何 --feature_screen_size / --feature_minimap_size
之类的 flag,PySC2 会退回到默认值——screen 84 × 84,minimap 64 × 64,所以动作参数的合法区间是 [0, 83]
/ [0, 63]
GitHub
那么你日志里为什么能看到 118, 127
这样的坐标?
LLM-PySC2 的 SMAC 适配层把 Raw API 的世界坐标 直接打印成了 ScreenPos:
,这些坐标反映的是地图网格(2c_vs_64zg 的可玩区域正好是 128 × 128),和 feature-layer 分辨率是两码事。
如果你真的想把 Move/Attack_Screen 之类动作的合法范围扩成 0–127
,有两种办法:
做法 | 影响 | 适用场景 |
---|---|---|
在命令行里显式加<br>--feature_screen_size 128 --feature_minimap_size 128 | PySC2 会把 feature 层重采样成 128×128;动作坐标也随之放宽 | 纯文本观察就够用、只想把坐标对齐到 128 时 |
把脚本里的 enable_image_rgb = True 或 enable_image_feature = True | 脚本会自动追加<br>--feature_screen_size 256 … (见 256 flag) | 想顺便要 RGB / feature map 图像,或者干脆用 256 输入给 CNN |
例子(128):
bashpython -m pysc2.bin.agent \ --map 2c_vs_64zg \ --agent_race protoss \ --parallel 1 \ --feature_screen_size 128 --feature_minimap_size 128 \ --agent llm_pysc2.bin.llm_smac.2c_vs_64zg.MainAgentLLMSmac
如果你保留默认 84×84,但仍拿到 Raw
坐标当作目标点,只需在发动作前做一次简单的 缩放 / clamp(常用做法是把 raw x,y 各乘以 screen/128
再取整)。
--feature_screen_size
决定,默认 N = 84。ValueError: Argument is out of range
.只要记住 “打印给你看的不一定就是能直接丢进动作里的” 就不会被坐标混淆坑到。
screen [0, 84)
参数说明 GitHub