星际争霸2的PYSC2环境你知道吗?能否介绍一下屏幕坐标

创建于:2025年5月28日

使用 O3 回答 Chat01

问题

星际争霸2的PYSC2环境你知道吗?能否介绍一下屏幕坐标

思考

Explaining screen coordinates in PySC2

In the PySC2 environment, screen coordinates are tied to the feature layers representation, where the default size (height, width) is 84x84, with coordinates indexed as [y][x], starting from the top-left (0,0). There are multiple coordinate spaces like screen, minimap, camera, and world, each with different purposes. The screen view is camera-centered over part of the map. Additionally, spatial resolution can be adjusted via AgentInterfaceFormat Dimensions, and it’s essential to consider how functions like move_screen or attack_screen expect coordinates.

Explaining coordinates in PySC2

In PySC2, there are two main coordinate spaces: screen (camera view) and minimap (full map). Both start at (0,0) at the top-left. For observations, feature arrays have the shape (channels, height, width) or as plain [height, width] arrays, using [y][x] to refer to pixel coordinates. In action functions (e.g., Move_screen), coordinates should be in (x, y) order. Screen resolution is default 84x84, but can be configured. Increased resolution changes the coordinate range, and screen coordinates shift when the camera moves.

Thought for 2m 16s

回答

下面把 PySC2 里最常用、也最容易弄混的 Screen 坐标系 讲清楚──读完你就能判断「这一对 (x, y) 到底该怎么写、范围是多少、跟摄像机/小地图是什么关系」。


1. 坐标原点与方向

空间原点x 轴y 轴典型分辨率
Screen(屏幕)左上角 (0, 0)向右增大向下增大84 × 84(默认,可自定义)
Minimap(小地图)左上角 (0, 0)向右增大向下增大64 × 64(默认,可自定义)

官方文档强调:观测里的坐标是 (y, x);动作里的坐标必须写成 (x, y),两者顺序相反。


2. 为什么会有 (y, x)(x, y) 的差别?

  • 观测 (Observation)
    obs.observation.feature_screen[...] 等数组下标是 行先列后 的 NumPy 风格:
    python
    value = feature_screen[y][x] # y 是行,x 是列
  • 动作 (Action)
    actions.FunctionCall.Move_screen("now", [x, y]) 里的参数按游戏 UI 的习惯写,横坐标在前。

很多 bug 都源于忘记对调这两个数。社区教程和 StackOverflow 也一直在提醒这一点。


3. 数值范围与分辨率

python
from 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), )
  • 这里把 screen 分辨率设成 96,所以合法坐标是 0 ≤ x ≤ 95, 0 ≤ y ≤ 95
  • minimap 改成 72 后,对应坐标范围就变成 0–71。
  • 如果你用默认的 84×84/64×64,就把上面的最大值改成 83 / 63 即可。

4. 摄像机与世界坐标的关系

  • Screen 坐标是「相机视窗内的像素」——当相机移动时,同一单位在 Screen 上的坐标会改变。
  • 想获取单位在当前 Screen 里的位置,最简单的办法是可选 use_feature_units=True,然后读取
    python
    for u in obs.observation.feature_units: print(u.x, u.y) # 这对 (x, y) 已经是屏幕坐标,范围同 screen 分辨率
  • 如果你在 Raw API 模式下用 unit.x, unit.y,它们是 地图原坐标(world coordinate),范围与地图大小(32–256)相关,需要对照相机中心自行换算。

5. 典型代码片段:把观测里的点喂给动作

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” 的报错。


6. 常见坑 & 小贴士

  1. 坐标超界
    提前检查 0 &le; x < screen_width,否则环境会抛 ValueError
  2. step_mul 与 APM
    坐标系跟 step_mul 无关,但步长太大时你的相机可能早就移动了,导致坐标失效。
  3. 升级分辨率就要同步调整 CNN
    把 84→128 后,卷积网络的输入尺寸也要跟着改,否则 shape 不匹配。
  4. Debug
    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呢?

思考

The user seems to be asking why there's a coordinate value that’s larger than the default 84 in PySC2. The reason for this is that the screen resolution can be customized in PySC2. For example, the environment could be using a 128x128 or even 160x160 resolution. Some settings, like DirtSkim macro watchers or the SC2LE mini-game variant, might also modify screen dimensions. Basically, it's likely they're working with an environment where feature_screen is set to something larger than 84, like 128.

The user’s question seems to be about why screen coordinates can exceed 84 in PySC2, and the answer lies in how the environment is set up. In PySC2, screen coordinate ranges are defined by the AgentInterfaceFormat, and if screen=128 is used, it allows the coordinates to exceed 84. This is common in certain environments like mini-games with 128 width. Also, RawUnits coordinates aren’t cropped by the camera and can exceed 84 if the full map is being used, such as in the "Hydralisk Duel" with a 128 size.

Thought for 44 seconds

回答

84&times;84 只是 PySC2 的默认 screen 分辨率,并不是硬性上限。出现 118 , 127 这些数,一般有两种情况:

可能原因现象说明
你把 feature layer 分辨率调大了feature_dimensions=Dimensions(screen=128, …)PySC2 会把 screen 坐标拉伸到 0–127。很多基于 gym-sc2 的示例(特别是对战环境而不是官方 mini-game)都会把 screen 设成 128&times;128,方便卷积网络输入成 2 的幂次。
你看的是 Raw API 的“世界坐标”.observation.raw_units[i].x / .y 或第三方库打印成 ScreenPos [...]Raw 坐标直接给出单位在 整张地图(tile 尺寸)里的位置,不受相机和 feature layer 分辨率限制。常见天梯地图的可玩区域正好是 128&times;128 tile,所以最大值就是 127。

在你发的日志里还能看到环境自己写了一句:

screen refers to a screen coordinate, shape as [x, y], where x and y range from 0 to 128

也就是说,这个自定义环境 已经把合法范围声明成 0-128。所以:

  1. 如果你确实需要 84×84 的 feature layer,就在创建环境时显式写回去:
    python
    env = sc2_env.SC2Env( ..., agent_interface_format=features.AgentInterfaceFormat( feature_dimensions=features.Dimensions(screen=84, minimap=64), use_feature_units=True # 如果只想要屏幕坐标,别开 raw ) )
  2. 如果你想继续用 128×128 的大分辨率,那就把网络输入、坐标合法性判断等代码同步改成 0 &le; x, y < 128

关键点

  • screen 坐标范围 = 你在 Dimensions(screen=…) 里设的值减 1。
  • Raw 坐标完全独立,跟地图大小相关(64 / 96 / 128 / 160…)。
  • 一定要先弄清你拿到的到底是哪种坐标,再做界限检查或转换。

问题

Copyright 2024, LLM-PySC2 Contributors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");

you may not use this file except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software

distributed under the License is distributed on an "AS-IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and

limitations under the License.

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")
这样启动的会如何影响分辨率呢?

思考

Explaining screen coordinates and flags

The Move_screen function expects screen coordinates in the range of [0, 84). I’ll reference the official doc, which confirms this. If you want a larger screen, you can enable flags for a 256 range instead. To clarify, the provided script uses the command-line interface (CLI) and defaults to the PySC2 settings—

Thought for 4m 43s

回答

结论先行

  • 你贴的 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 128PySC2 会把 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):

    bash
    python -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 再取整)。


背后逻辑一图胜千言

  1. Raw world (0-127)
    单位在地图上的“绝对”网格坐标,大小由地图决定,跟屏幕分辨率没关系。
  2. Feature screen (0-N-1)
    --feature_screen_size 决定,默认 N = 84。
  3. 动作参数检查
    PySC2 会严格校验坐标是否落在 feature screen 范围内,超界就报 ValueError: Argument is out of range.

只要记住 “打印给你看的不一定就是能直接丢进动作里的” 就不会被坐标混淆坑到。


参考

  • PySC2 官方文档示例:screen [0, 84) 参数说明 GitHub
  • LLM-PySC2 脚本在启用图像通道时自动把 screen 调到 256 
  • SMAC 场景 2c_vs_64zg 本身基于 128×128 地图网格 d4marl.readthedocs.io

分享这个问答