载入中...
搜索中...
未找到
DualGrid.cpp
浏览该文件的文档.
1#include "map/DualGrid.h"
3
4namespace eve::map {
5namespace {
6
7// SpriteCook / common dual-grid 4×4 sheet: index by 4-bit corner mask.
8// mask 0 → empty; other values map to atlas local ids 0..15.
9constexpr std::array<int, 16> kDefaultFrameByMask = {
10 -1, 15, 8, 9, 0, 11, 14, 7, 13, 4, 1, 10, 3, 2, 5, 6,
11};
12
13int resolveFirstGid(TileLayer *display, int firstDisplayGid) {
14 if (firstDisplayGid > 0) return firstDisplayGid;
15 const int ts = display->getTilesetFirstGid();
16 return ts > 0 ? ts : 1;
17}
18
19float staggerPitchY(const TileLayer::Config &cfg) {
20 const bool hex = cfg.orientation == MapOrientation::Hexagonal && cfg.hexSideLength > 0.f;
21 return hex ? (cfg.tileH + cfg.hexSideLength) * 0.5f : cfg.tileH * 0.5f;
22}
23
24float staggerPitchX(const TileLayer::Config &cfg) {
25 const bool hex = cfg.orientation == MapOrientation::Hexagonal && cfg.hexSideLength > 0.f;
26 return hex ? (cfg.tileW + cfg.hexSideLength) * 0.5f : cfg.tileW * 0.5f;
27}
28
29} // namespace
30
31const std::array<int, 16> &dualGridDefaultFrameTable() { return kDefaultFrameByMask; }
32
33int dualGridDefaultFrame(int mask) {
34 if (mask < 0 || mask > 15) return -1;
35 return kDefaultFrameByMask[size_t(mask)];
36}
37
38void dualGridHalfOffset(const TileLayer::Config &cfg, float &offX, float &offY) {
39 switch (cfg.orientation) {
41 // tileToWorld(tx-0.5, ty-0.5) with same iso formula ⇒ origin (ox, oy - th/2).
42 offX = 0.f;
43 offY = -cfg.tileH * 0.5f;
44 break;
47 if (cfg.staggerAxis == StaggerAxis::Y) {
48 offX = -cfg.tileW * 0.5f;
49 offY = -staggerPitchY(cfg) * 0.5f;
50 } else {
51 offX = -staggerPitchX(cfg) * 0.5f;
52 offY = -cfg.tileH * 0.5f;
53 }
54 break;
56 default:
57 offX = -cfg.tileW * 0.5f;
58 offY = -cfg.tileH * 0.5f;
59 break;
60 }
61}
62
63bool dualGridLogicFilled(TileLayer &logic, int tx, int ty, int filledGid) {
64 auto cfg = logic.config();
65 if (tx < 0 || ty < 0 || tx >= cfg->mapW || ty >= cfg->mapH) return false;
66 const int gid = int(tileGid(uint32_t(logic.getTile(tx, ty))));
67 if (gid == 0) return false;
68 if (filledGid == 0) return true;
69 return gid == filledGid;
70}
71
72int dualGridMaskAt(TileLayer &logic, int dx, int dy, int filledGid) {
73 const bool tl = dualGridLogicFilled(logic, dx - 1, dy - 1, filledGid);
74 const bool tr = dualGridLogicFilled(logic, dx, dy - 1, filledGid);
75 const bool bl = dualGridLogicFilled(logic, dx - 1, dy, filledGid);
76 const bool br = dualGridLogicFilled(logic, dx, dy, filledGid);
77 return dualGridMaskFromCorners(tl, tr, bl, br);
78}
79
80bool resolveDualGrid(TileLayer *logic, TileLayer *display, const DualGridOptions &opts,
81 std::string *error) {
82 if (!logic || !display) {
83 if (error) *error = "resolveDualGrid: logic and display layers required";
84 return false;
85 }
86 if (logic == display) {
87 if (error) *error = "resolveDualGrid: logic and display must be different layers";
88 return false;
89 }
90
91 const int logicW = logic->getMapWidth();
92 const int logicH = logic->getMapHeight();
93 if (logicW <= 0 || logicH <= 0) {
94 if (error) *error = "resolveDualGrid: logic layer has empty size";
95 return false;
96 }
97
98 const float tileW = logic->getTileWidth();
99 const float tileH = logic->getTileHeight();
100 display->setTileSize(tileW, tileH);
101 display->resize(logicW + 1, logicH + 1);
102
103 auto lc = logic->config();
104 auto dc = display->config();
105 dc->orientation = lc->orientation;
106 dc->staggerAxis = lc->staggerAxis;
107 dc->staggerIndex = lc->staggerIndex;
108 dc->hexSideLength = lc->hexSideLength;
109
110 if (opts.applyHalfOffset) {
111 float offX = 0.f, offY = 0.f;
112 dualGridHalfOffset(*lc, offX, offY);
113 display->setOrigin(logic->getX() + offX, logic->getY() + offY);
114 } else {
115 display->setOrigin(logic->getX(), logic->getY());
116 }
117
118 // Keep draw bookkeeping in sync when display is freshly created.
119 display->setLayer(logic->getLayer());
120 display->setCamera(logic->draw()->camera);
121 display->setCanvas(logic->draw()->canvas);
122
123 const int firstGid = resolveFirstGid(display, opts.firstDisplayGid);
124 const int filledGid = opts.filledGid;
125
126 for (int dy = 0; dy < logicH + 1; ++dy) {
127 for (int dx = 0; dx < logicW + 1; ++dx) {
128 const int mask = dualGridMaskAt(*logic, dx, dy, filledGid);
129 int frame = -1;
130 if (opts.useDefaultFrameTable) {
131 frame = dualGridDefaultFrame(mask);
132 } else if (mask != 0) {
133 frame = mask;
134 }
135 const int gid = (frame < 0) ? 0 : firstGid + frame;
136 display->setTile(dx, dy, gid);
137 }
138 }
139
140 if (opts.hideLogic) logic->setVisible(false);
141 display->setVisible(true);
142
143 if (error) error->clear();
144 return true;
145}
146
147bool resolveDualGrid(TileLayer *logic, TileLayer *display, std::string *error) {
148 return resolveDualGrid(logic, display, DualGridOptions{}, error);
149}
150
151} // namespace eve::map
std::string error
float tr
int firstGid
int tileW
int tileH
ECS tile layer entity. Script mutates tile GIDs / tileset / draw; TileRenderSystem batch-draws atlas ...
Definition TileLayer.h:30
float getTileWidth()
Tile size in pixels.
Definition TileLayer.cpp:35
void setOrigin(float x, float y)
World origin of the layer (pixels).
Definition TileLayer.cpp:25
void setTile(int tx, int ty, int gid)
Tile GID access; 0 = empty.
Definition TileLayer.cpp:52
void resize(int mapW, int mapH)
Resizes the tile grid (existing GIDs preserved where possible).
Definition TileLayer.cpp:44
void setLayer(int layer)
Draw order layer / visibility / tint.
Definition TileLayer.cpp:99
void setCamera(graphics::Camera2D *camera)
Definition TileLayer.cpp:97
int getTile(int tx, int ty)
Definition TileLayer.cpp:58
void setTileSize(float tileW, float tileH)
Definition TileLayer.cpp:38
void setCanvas(graphics::Canvas *canvas)
Draw target canvas / camera.
Definition TileLayer.cpp:96
void setVisible(bool visible)
int getMapWidth()
Map dimensions in tiles.
Definition TileLayer.cpp:33
放置世界:格子占用(多通道)+ 地形语义 + 已放置建筑实例。 行为由 PlacementSystem 提供;本类暴露便于脚本绑定的薄封装方法。 坐标换算统一走 eve::grid(支持 rectang...
int dualGridMaskAt(TileLayer &logic, int dx, int dy, int filledGid)
4-bit corner mask for display cell (dx,dy) on a (logicW+1)×(logicH+1) grid. Samples logic (dx-1,...
Definition DualGrid.cpp:72
bool dualGridLogicFilled(TileLayer &logic, int tx, int ty, int filledGid)
Whether logic cell (tx,ty) is filled under options. Out of bounds → false.
Definition DualGrid.cpp:63
int dualGridDefaultFrame(int mask)
Default 4x4 atlas frame index for mask 0..15. -1 means draw nothing. Matches the SpriteCook / common ...
Definition DualGrid.cpp:33
int dualGridMaskFromCorners(bool tl, bool tr, bool bl, bool br)
Pack four corner occupancy bits: TL=1, TR=2, BL=4, BR=8.
Definition DualGrid.h:48
uint32_t tileGid(uint32_t raw)
Strip Tiled flip / rotate flags; keep low 28 bits.
Definition TileLayer.h:161
void dualGridHalfOffset(const TileLayer::Config &cfg, float &offX, float &offY)
Half-step origin delta for the display layer (added to logic origin). Orthogonal: (-tileW/2,...
Definition DualGrid.cpp:38
bool resolveDualGrid(TileLayer *logic, TileLayer *display, const DualGridOptions &opts, std::string *error)
Resolve logic → display dual-grid tiles. Resizes display to (logicW+1)×(logicH+1),...
Definition DualGrid.cpp:80
const std::array< int, 16 > & dualGridDefaultFrameTable()
Copy of the default frame table (16 entries).
Definition DualGrid.cpp:31
Dual-grid autotile (Oskar Stålberg style).
Definition DualGrid.h:28
bool hideLogic
Hide the logic layer after resolve (logic stays for gameplay queries).
Definition DualGrid.h:39
int filledGid
0 = any non-zero logic GID counts as filled; else only this GID.
Definition DualGrid.h:30
bool applyHalfOffset
Apply projection-correct half-step origin offset on the display layer.
Definition DualGrid.h:37
int firstDisplayGid
GID of atlas local id 0 on the display tileset. 0 = use display->getTilesetFirstGid() (fallback 1).
Definition DualGrid.h:35
bool useDefaultFrameTable
When true, use the default SpriteCook-style 4x4 atlas frame table. When false, GID = firstDisplayGid ...
Definition DualGrid.h:44
MapOrientation orientation
Definition TileLayer.h:43