forked from Windsland52/ArknightsAutoOperator
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmap_picker.py
More file actions
165 lines (139 loc) · 6.01 KB
/
Copy pathmap_picker.py
File metadata and controls
165 lines (139 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"""地图选点弹窗(QGraphicsView 棋盘网格)。
点关卡 → 选中格子 → 生成棋盘记号(如 D2)→ 确认回填到编辑面板。
区分可部署/不可部署(buildableType: 0=不可, 1=地面, 2=高台)。
tiles[r] 中 r=0 是玩家视角最上行(行号最大),r=height-1 是最下行(行号1)。
QGraphicsScene y 向下,故 y = r*cell:r 小(行号大、玩家上方)→画面上方。
棋盘记号由 tile_position_to_str 算(行号 = height - r)。
"""
from __future__ import annotations
from typing import Any
from PySide6.QtCore import Signal
from PySide6.QtGui import QBrush, QColor, QFont, QMouseEvent, QPainter, QPen
from PySide6.QtWidgets import (
QDialog,
QGraphicsRectItem,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QLabel,
QPushButton,
QVBoxLayout,
QWidget,
)
from aao.core.geometry.convert_pos import tile_position_to_str
from aao.core.geometry.map_loader import load_map
_CELL = 40
_COLORS = {
"forbidden": QColor("#3a3a3a"),
"wall": QColor("#6d4c41"),
"road": QColor("#5a8f3a"),
"hole": QColor("#222"),
"start": QColor("#c62828"),
"end": QColor("#1565c0"),
}
class _MapGrid(QGraphicsView):
"""关卡棋盘网格。"""
picked = Signal(str) # 棋盘记号,如 "D2"
def __init__(self, map_data: dict[str, Any]):
super().__init__()
self._map_data = map_data
self._height = map_data["height"]
self._width = map_data["width"]
self._tiles = map_data["tiles"]
self._selected: tuple[int, int] | None = None # (col, row)
self._cell_items: dict[tuple[int, int], QGraphicsRectItem] = {}
self.setRenderHint(QPainter.RenderHint.Antialiasing)
self.setFixedSize(self._width * _CELL + 4, self._height * _CELL + 4)
scene = QGraphicsScene(self)
self.setScene(scene)
for r in range(self._height):
for c in range(self._width):
tile = self._tiles[r][c]
key = (tile.get("tileKey") or "").replace("tile_", "")
base = _COLORS.get(key, QColor("#777"))
# 不可部署加深
if tile.get("buildableType", 0) == 0 and key not in ("start", "end"):
base = base.darker(150)
# tiles[r] 中 r=0 是玩家视角最上行(行号最大),r=height-1 是最下行(行号1)。
# QScene y 向下,故 y = r*cell(r 小=行号大=玩家上方→画面上方)。
x = c * _CELL
y = r * _CELL
rect = QGraphicsRectItem(x, y, _CELL, _CELL)
rect.setBrush(QBrush(base))
rect.setPen(QPen(QColor("#000"), 1))
# 记号标签
label = scene.addText(
tile_position_to_str(c, r, self._height), QFont("Consolas", 7)
)
label.setPos(x + 2, y + 2)
label.setDefaultTextColor(QColor("#eee"))
scene.addItem(rect)
self._cell_items[(c, r)] = rect
scene.setSceneRect(0, 0, self._width * _CELL, self._height * _CELL)
def mousePressEvent(self, event: QMouseEvent) -> None:
item = self.itemAt(event.pos())
# 找到对应 rect
for (c, r), rect in self._cell_items.items():
if rect is item or (isinstance(item, QGraphicsRectItem) and item is rect):
self._select(c, r)
return
# 点击的可能是被 label 覆盖,回退:按坐标算
sp = self.mapToScene(event.pos())
c = int(sp.x() // _CELL)
r = int(sp.y() // _CELL) # y=r*cell 渲染,故 r=y
if 0 <= c < self._width and 0 <= r < self._height:
self._select(c, r)
super().mousePressEvent(event)
def _select(self, c: int, r: int) -> None:
# 允许选任意格子(含不可部署区,装置/技能目标可能在不可部署格上)
# 清旧高亮
if self._selected is not None:
old = self._cell_items.get(self._selected)
if old is not None:
old.setPen(QPen(QColor("#000"), 1))
self._selected = (c, r)
self._cell_items[(c, r)].setPen(QPen(QColor("#fff"), 3))
self.picked.emit(tile_position_to_str(c, r, self._height))
def selected_pos(self) -> str | None:
if self._selected is None:
return None
c, r = self._selected
return tile_position_to_str(c, r, self._height)
class MapPickerDialog(QDialog):
"""地图选点对话框。返回选中棋盘记号(或空)。"""
def __init__(self, map_code: str, parent: QWidget | None = None):
super().__init__(parent)
self.setWindowTitle(f"地图选点 - {map_code}")
self._result_pos: str | None = None
layout = QVBoxLayout(self)
map_data = load_map(map_code)
if map_data is None:
layout.addWidget(QLabel(f"无法加载关卡 {map_code} 的地图数据"))
self._grid = None
else:
self._grid = _MapGrid(map_data)
layout.addWidget(self._grid)
hint = QLabel("点击可部署格(绿=地面, 棕=高台)选中")
layout.addWidget(hint)
btn_row = QHBoxLayout()
self.lbl_sel = QLabel("选中: —")
btn_row.addWidget(self.lbl_sel)
btn_row.addStretch()
self.btn_ok = QPushButton("确定")
self.btn_cancel = QPushButton("取消")
self.btn_ok.setEnabled(False)
btn_row.addWidget(self.btn_ok)
btn_row.addWidget(self.btn_cancel)
layout.addLayout(btn_row)
if self._grid is not None:
self._grid.picked.connect(self._on_picked)
self.btn_ok.clicked.connect(self._on_ok)
self.btn_cancel.clicked.connect(self.reject)
def _on_picked(self, pos: str) -> None:
self._result_pos = pos
self.lbl_sel.setText(f"选中: {pos}")
self.btn_ok.setEnabled(True)
def _on_ok(self) -> None:
self.accept()
def selected_pos(self) -> str | None:
return self._result_pos