载入中...
搜索中...
未找到
CardTypes.cpp
浏览该文件的文档.
1#include "card/CardTypes.h"
2
3#include "graphics/Graphics.h"
4
5#include <algorithm>
6#include <random>
7
8namespace eve::card {
9
11 switch (state) {
12 case CardState::Deck: return "deck";
13 case CardState::Hand: return "hand";
14 case CardState::Hovered: return "hovered";
15 case CardState::Dragging: return "dragging";
16 case CardState::Returning: return "returning";
17 case CardState::Played: return "played";
18 case CardState::Discarded: return "discarded";
19 case CardState::Disabled: return "disabled";
20 }
21 return "unknown";
22}
23
24// ---------------------------------------------------------------------------
25// 工具
26// ---------------------------------------------------------------------------
27
28namespace {
29
30struct RenderTransform {
31 float cx = 0.f;
32 float cy = 0.f;
33 float degrees = 0.f;
34 bool active = false;
35};
36
37RenderTransform gRenderTransform;
38
39glm::vec2 transformedCenter(float x, float y, float w, float h) {
40 glm::vec2 center{x + w * 0.5f, y + h * 0.5f};
41 if (!gRenderTransform.active || std::abs(gRenderTransform.degrees) < 0.001f) return center;
42 const float rad = gRenderTransform.degrees * 3.14159265358979323846f / 180.f;
43 const float c = std::cos(rad);
44 const float s = std::sin(rad);
45 const float dx = center.x - gRenderTransform.cx;
46 const float dy = center.y - gRenderTransform.cy;
47 return {gRenderTransform.cx + dx * c - dy * s, gRenderTransform.cy + dx * s + dy * c};
48}
49
50float clampf(float v, float lo, float hi) { return v < lo ? lo : (v > hi ? hi : v); }
51float lerpf(float a, float b, float t) { return a + (b - a) * t; }
52
53// 帧率无关的插值系数:k 是 60fps 下的每帧系数,换算到实际 dt。
54float frameRateK(float k, float dt) {
55 if (dt <= 0.f) return k;
56 const float u = 1.f - k;
57 const float n = dt * 60.f;
58 const int whole = static_cast<int>(n);
59 const float frac = n - static_cast<float>(whole);
60 float r = 1.f;
61 for (int i = 0; i < whole; ++i) r *= u;
62 r *= (1.f + frac * (u - 1.f));
63 return 1.f - r;
64}
65
66void drawSolid(graphics::Graphics *gfx, float x, float y, float w, float h, float angle,
67 const glm::vec4 &color) {
68 if (!gRenderTransform.active || std::abs(angle) < 0.001f)
69 gfx->drawSolidRect(x, y, w, h, color);
70 else {
71 const glm::vec2 center = transformedCenter(x, y, w, h);
72 gfx->drawSolidRectRotated(center.x, center.y, w, h, angle, color);
73 }
74}
75
76void drawTexture(graphics::Graphics *gfx, graphics::Texture *texture, float x, float y, float w, float h,
77 float angle, const glm::vec4 &color) {
78 if (!gRenderTransform.active || std::abs(angle) < 0.001f) {
79 gfx->drawTexturedRect(texture, x, y, w, h, color);
80 } else {
81 const glm::vec2 center = transformedCenter(x, y, w, h);
82 gfx->drawTexturedRectShaderUVRotated(texture, nullptr, center.x, center.y, w, h,
83 angle, 0.f, 0.f, 1.f, 1.f, color);
84 }
85}
86
87void drawGem(graphics::Graphics *gfx, float x, float y, float size, float angle,
88 const glm::vec3 &rgb, float a) {
89 drawSolid(gfx, x, y, size, size, angle, glm::vec4(0.15f, 0.13f, 0.10f, a));
90 const float p = size * 0.20f;
91 drawSolid(gfx, x + p, y + p, size - p * 2.f, size - p * 2.f, angle, glm::vec4(rgb, a));
92}
93
94} // namespace
95
96// ---------------------------------------------------------------------------
97// CardData
98// ---------------------------------------------------------------------------
99
101 CardData *c = CardData::create();
102 c->identity();
103 c->stats();
104 c->visual();
105 c->layout();
106 c->state();
107 return c;
108}
109
110bool CardData::hit(float px, float py) {
111 const auto *L = layout().operator->();
112 if (L->w <= 0.f || L->h <= 0.f) return false;
113 const float cw = L->w * L->scale;
114 const float ch = L->h * L->scale;
115 return px >= L->x - cw * 0.5f && px <= L->x + cw * 0.5f && py >= L->y - ch * 0.5f &&
116 py <= L->y + ch * 0.5f;
117}
118
119std::string CardData::describe() {
120 const auto *I = identity().operator->();
121 const auto *S = stats().operator->();
122 if (I->kind == "spell") return I->name + "(法术 · 费用 " + std::to_string(S->cost) + ")";
123 return I->name + "(" + std::to_string(S->attack) + "/" + std::to_string(S->health) + " · 费用 " +
124 std::to_string(S->cost) + ")";
125}
126
127// ---------------------------------------------------------------------------
128// Deck
129// ---------------------------------------------------------------------------
130
132 Deck *d = Deck::create();
133 d->membership();
134 return d;
135}
136
138 auto &cards = membership()->cards;
139 if (cards.empty()) return nullptr;
140 CardData *top = cards.back();
141 cards.pop_back();
142 return top;
143}
144
146 auto &cards = membership()->cards;
147 return cards.empty() ? nullptr : cards.back();
148}
149
150CardData *Deck::get(int index) {
151 auto &cards = membership()->cards;
152 if (index < 0 || static_cast<size_t>(index) >= cards.size()) return nullptr;
153 return cards[static_cast<size_t>(index)];
154}
155
157 static thread_local std::mt19937 rng(std::random_device{}());
158 std::shuffle(membership()->cards.begin(), membership()->cards.end(), rng);
159}
160
161// ---------------------------------------------------------------------------
162// Zone
163// ---------------------------------------------------------------------------
164
166 Zone *z = Zone::create();
167 z->rect();
168 z->filter();
169 return z;
170}
171
172bool Zone::contains(float px, float py) {
173 const auto *R = rect().operator->();
174 return px >= R->x && px <= R->x + R->w && py >= R->y && py <= R->y + R->h;
175}
176
178 const auto *R = rect().operator->();
179 if (!R->enabled || !card) return false;
180 const auto &kinds = filter()->acceptKinds;
181 if (kinds.empty()) return true;
182 const std::string &kind = card->identity()->kind;
183 for (const auto &k : kinds)
184 if (k == kind) return true;
185 return false;
186}
187
188void Zone::render(graphics::Graphics *gfx, bool showLabel) {
189 auto *R = rect().operator->();
190 gfx->drawSolidRect(R->x, R->y, R->w, R->h, glm::vec4(R->color, R->alpha));
191 if (showLabel && gfx->getFont() && !R->label.empty()) {
192 const glm::vec4 tint(clampf(R->color.r * 0.9f + 0.3f, 0.f, 1.f),
193 clampf(R->color.g * 0.9f + 0.3f, 0.f, 1.f),
194 clampf(R->color.b * 0.9f + 0.3f, 0.f, 1.f), 1.f);
195 printCentered(gfx, R->label, R->x + R->w * 0.5f, R->y + R->h * 0.5f, 0.9f, tint);
196 }
197}
198
199// ---------------------------------------------------------------------------
200// 渲染辅助
201// ---------------------------------------------------------------------------
202
203void printCentered(graphics::Graphics *gfx, const std::string &text, float cx, float cy, float scale,
204 const glm::vec4 &color) {
205 auto *font = gfx->getFont();
206 if (!font) return;
207 const float tw = font->getWidth(text) * scale;
208 const float th = font->getHeight() * scale;
209 // print 的 y 是基线;基线位于字形中心略下方
210 gfx->print(text, cx - tw * 0.5f, cy - th * 0.35f, color, scale);
211}
212
213void renderCardBack(graphics::Graphics *gfx, float x, float y, float w, float h, float angle, float a) {
214 const RenderTransform previous = gRenderTransform;
215 gRenderTransform = {x + w * 0.5f, y + h * 0.5f, angle, true};
216 drawSolid(gfx, x, y, w, h, angle, glm::vec4(0.06f, 0.06f, 0.10f, a));
217 const float i1 = w * 0.05f;
218 drawSolid(gfx, x + i1, y + i1, w - i1 * 2.f, h - i1 * 2.f, angle,
219 glm::vec4(0.30f, 0.17f, 0.45f, a));
220 const float i2 = w * 0.10f;
221 drawSolid(gfx, x + i2, y + i2, w - i2 * 2.f, h - i2 * 2.f, angle,
222 glm::vec4(0.11f, 0.08f, 0.22f, a));
223 if (gfx->getFont())
224 printCentered(gfx, "?", x + w * 0.5f, y + h * 0.5f, 1.2f * (w / 110.f),
225 glm::vec4(0.9f, 0.85f, 0.95f, a));
226 gRenderTransform = previous;
227}
228
229void renderCard(graphics::Graphics *gfx, const CardData &cardRef, const LayoutConfig &cfg, bool back) {
230 (void)cfg;
231 CardData &card = const_cast<CardData &>(cardRef);
232 const auto *L = card.layout().operator->();
233 const auto *V = card.visual().operator->();
234 const auto *I = card.identity().operator->();
235 const auto *S = card.stats().operator->();
236
237 const float w = L->w * L->scale;
238 const float h = L->h * L->scale;
239 const float x = L->x - w * 0.5f;
240 const float y = L->y - h * 0.5f;
241 const float a = L->alpha;
242
243 const RenderTransform previous = gRenderTransform;
244 gRenderTransform = {L->x, L->y, L->angle, true};
245
246 if (back || !V->faceUp) {
247 renderCardBack(gfx, x, y, w, h, L->angle, a);
248 gRenderTransform = previous;
249 return;
250 }
251
252 // 外框
253 drawSolid(gfx, x, y, w, h, L->angle, glm::vec4(0.07f, 0.07f, 0.09f, a));
254 const float inset = w * 0.035f;
255 const float ix = x + inset;
256 const float iy = y + inset;
257 const float iw = w - inset * 2.f;
258 const float ih = h - inset * 2.f;
259
260 // 卡面底色
261 drawSolid(gfx, ix, iy, iw, ih, L->angle, glm::vec4(V->tint, a));
262
263 // 头部色带
264 const float headerH = ih * 0.16f;
265 drawSolid(gfx, ix, iy, iw, headerH, L->angle,
266 glm::vec4(V->tint.r * 0.82f, V->tint.g * 0.82f, V->tint.b * 0.82f, a));
267
268 // 卡图区域
269 const float artY = iy + headerH;
270 const float artH = ih * 0.34f;
271 if (V->texture) {
272 drawTexture(gfx, V->texture, ix + 2.f, artY + 2.f, iw - 4.f, artH - 4.f, L->angle,
273 glm::vec4(1.f, 1.f, 1.f, a));
274 } else {
275 drawSolid(gfx, ix + 2.f, artY + 2.f, iw - 4.f, artH - 4.f, L->angle,
276 glm::vec4(V->tint.r * 0.55f, V->tint.g * 0.55f, V->tint.b * 0.55f, a));
277 }
278
279 // 描述文字区
280 const float bodyY = artY + artH;
281 const float bodyH = iy + ih - bodyY;
282 drawSolid(gfx, ix, bodyY, iw, bodyH, L->angle, glm::vec4(0.96f, 0.94f, 0.90f, a));
283 drawSolid(gfx, ix + iw * 0.12f, bodyY + bodyH * 0.5f - 1.f, iw * 0.76f, 2.f, L->angle,
284 glm::vec4(0.45f, 0.42f, 0.38f, a));
285
286 // 数值宝石
287 const float gem = w * 0.13f;
288 drawGem(gfx, x + inset, iy, gem, L->angle, glm::vec3(1.00f, 0.78f, 0.25f), a); // 费用(金)
289 if (I->kind != "spell") {
290 drawGem(gfx, x + inset, iy + ih - gem, gem, L->angle, glm::vec3(0.92f, 0.38f, 0.22f), a); // 攻击(橙)
291 drawGem(gfx, x + iw - inset - gem, iy + ih - gem, gem, L->angle, glm::vec3(0.30f, 0.78f, 0.42f), a); // 生命(绿)
292 }
293
294 // 文字(可选:需 gfx 已 setFont)
295 auto *font = gfx->getFont();
296 if (font) {
297 const float ts = 1.f * (w / 110.f);
298 printCentered(gfx, std::to_string(S->cost), x + inset + gem * 0.5f, iy + gem * 0.55f, ts,
299 glm::vec4(0.12f, 0.08f, 0.05f, a));
300 if (I->kind != "spell") {
301 printCentered(gfx, std::to_string(S->attack), x + inset + gem * 0.5f, iy + ih - gem * 0.45f,
302 ts, glm::vec4(0.10f, 0.05f, 0.05f, a));
303 printCentered(gfx, std::to_string(S->health), x + iw - inset - gem * 0.5f,
304 iy + ih - gem * 0.45f, ts, glm::vec4(0.05f, 0.10f, 0.05f, a));
305 }
306 printCentered(gfx, I->name, x + w * 0.5f, iy + headerH * 0.5f, ts * 0.8f,
307 glm::vec4(0.10f, 0.08f, 0.06f, a));
308 }
309 gRenderTransform = previous;
310}
311
312// ---------------------------------------------------------------------------
313// Hand
314// ---------------------------------------------------------------------------
315
317 Hand *h = Hand::create();
318 h->meta();
319 h->membership();
320 h->drag();
321 return h;
322}
323
325 membership()->cards.push_back(c);
326 if (c) {
327 auto *md = meta().operator->();
328 c->state()->phase = c->visual()->disabled ? CardState::Disabled : CardState::Hand;
329 c->layout()->w = md->config ? md->config->cardW : 110.f;
330 c->layout()->h = md->config ? md->config->cardH : 150.f;
331 c->layout()->scale = 0.01f; // 从 0 生长出牌动画
332 c->layout()->alpha = (c->visual()->disabled && md->config) ? md->config->disabledAlpha : 1.f;
333 }
334}
335
337 auto &cards = membership()->cards;
338 for (size_t i = 0; i < cards.size(); ++i) {
339 if (cards[i] == c) {
340 cards.erase(cards.begin() + static_cast<ptrdiff_t>(i));
341 return true;
342 }
343 }
344 return false;
345}
346
348 membership()->cards.clear();
349 auto *d = drag().operator->();
350 d->card = nullptr;
351 d->press = nullptr;
352}
353
354CardData *Hand::get(int index) {
355 auto &cards = membership()->cards;
356 if (index < 0 || static_cast<size_t>(index) >= cards.size()) return nullptr;
357 return cards[static_cast<size_t>(index)];
358}
359
360CardData *Hand::find(const std::string &id) {
361 for (auto *c : membership()->cards)
362 if (c && c->identity()->id == id) return c;
363 return nullptr;
364}
365
366CardData *Hand::pick(float px, float py) {
367 auto &cards = membership()->cards;
368 for (auto it = cards.rbegin(); it != cards.rend(); ++it) {
369 if (*it && (*it)->hit(px, py)) return *it;
370 }
371 return nullptr;
372}
373
374void Hand::slotTransform(int i, int n, float &ox, float &oy, float &angle) {
375 const LayoutConfig cfg = meta()->config ? *meta()->config : LayoutConfig();
376 const float totalW = static_cast<float>(n) * cfg.cardW + static_cast<float>(n - 1) * cfg.spacing;
377 const float left = cfg.handX - totalW * 0.5f;
378 ox = left + static_cast<float>(i) * (cfg.cardW + cfg.spacing) + cfg.cardW * 0.5f;
379 const float t = (n > 1) ? static_cast<float>(i) / static_cast<float>(n - 1) : 0.5f;
380 const float d = 2.f * t - 1.f;
381 oy = cfg.handY - cfg.arcHeight * (d * d);
382 angle = cfg.rotationAngle * d;
383}
384
385void Hand::update(float dt, float mx, float my, bool down, const std::vector<Zone *> &zones,
386 std::vector<CardEvent> &out) {
387 auto *md = meta().operator->();
388 auto *d = drag().operator->();
389 auto &cards = membership()->cards;
390 const LayoutConfig cfg = md->config ? *md->config : LayoutConfig();
391 const int n = static_cast<int>(cards.size());
392
393 // 1) 布局 + 悬浮
394 for (int i = 0; i < n; ++i) {
395 CardData *card = cards[static_cast<size_t>(i)];
396 if (!card || card == d->card) continue;
397
398 float sx = 0.f, sy = 0.f, sa = 0.f;
399 slotTransform(i, n, sx, sy, sa);
400
401 bool hover = false;
402 if (d->card == nullptr) hover = (card == pick(mx, my));
403 auto *st = card->state().operator->();
404 auto *vis = card->visual().operator->();
405 auto *lay = card->layout().operator->();
406 st->hovered = hover;
407 if (vis->disabled) st->phase = CardState::Disabled;
408 else if (st->dragging) st->phase = CardState::Dragging;
409 else if (hover) st->phase = CardState::Hovered;
410 else if (st->phase != CardState::Returning) st->phase = CardState::Hand;
411
412 float targetScale = 1.f;
413 float targetY = sy;
414 float targetAngle = sa;
415 if (hover) {
416 targetY = sy - cfg.hoverLift;
417 targetScale = cfg.hoverScale;
418 if (cfg.hoverRotation) targetAngle = 0.f;
419 }
420 float k = frameRateK(hover ? cfg.hoverSpeed : cfg.motionSpeed, dt);
421 lay->x = lerpf(lay->x, sx, k);
422 lay->y = lerpf(lay->y, targetY, k);
423 lay->scale = lerpf(lay->scale, targetScale, k);
424 lay->angle = lerpf(lay->angle, targetAngle, k);
425 lay->alpha = lerpf(lay->alpha, vis->disabled ? cfg.disabledAlpha : 1.f, k);
426 }
427
428 // 2) 拖拽状态机
429 const bool press = down && !d->wasDown;
430 const bool release = !down && d->wasDown;
431 d->wasDown = down;
432
433 if (press && md->interactive) {
434 d->press = pick(mx, my);
435 if (d->press && d->press->visual()->disabled) d->press = nullptr;
436 d->pressX = mx;
437 d->pressY = my;
438 }
439
440 if (down && d->press && !d->card) {
441 const float dx = mx - d->pressX;
442 const float dy = my - d->pressY;
443 if (dx * dx + dy * dy > cfg.dragThreshold) {
444 d->card = d->press;
445 d->card->state()->dragging = true;
446 d->card->state()->phase = CardState::Dragging;
447 d->ox = mx - d->card->layout()->x;
448 d->oy = my - d->card->layout()->y;
449 }
450 }
451
452 if (d->card && down) {
453 auto *lay = d->card->layout().operator->();
454 lay->x = mx - d->ox;
455 lay->y = my - d->oy;
456 lay->scale = cfg.hoverScale;
457 lay->angle = 0.f;
458 lay->alpha = 1.f;
459 }
460
461 if (release) {
462 if (d->card) {
463 d->card->state()->dragging = false;
464 d->card->state()->phase = CardState::Returning;
465 CardData *dropped = d->card;
466 d->card = nullptr; // 归位;若已从手牌移除则自然消失
467 for (Zone *z : zones) {
468 if (z && z->contains(mx, my)) {
469 const std::string cardId = dropped ? dropped->identity()->id : "";
470 if (z->accepts(dropped)) {
471 out.push_back(CardEvent{"drop", md->owner, z->rect()->id, cardId, ""});
472 } else {
473 out.push_back(CardEvent{"dropRejected", md->owner, z->rect()->id, cardId,
474 "kind_not_allowed"});
475 }
476 break;
477 }
478 }
479 } else if (d->press) {
480 out.push_back(CardEvent{"click", md->owner, "", d->press->identity()->id, ""});
481 }
482 d->press = nullptr;
483 }
484}
485
487 auto *md = meta().operator->();
488 const LayoutConfig cfg = md->config ? *md->config : LayoutConfig();
489 const bool back = md->faceDown && !md->peek;
490 const CardData *dragCard = drag()->card;
491 for (auto *c : membership()->cards) {
492 if (c && c != dragCard) renderCard(gfx, *c, cfg, back);
493 }
494 if (dragCard) renderCard(gfx, *dragCard, cfg, back);
495}
496
497} // namespace eve::card
bool active
Definition CardTypes.cpp:34
float cx
Definition CardTypes.cpp:31
float cy
Definition CardTypes.cpp:32
float degrees
Definition CardTypes.cpp:33
Tok kind
std::string layout
std::string id
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
uint32_t i1
Definition Grass.cpp:62
uint32_t i2
Definition Grass.cpp:62
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
std::vector< Colorf > px
JobSystemThreadPool::State * state
uint32_t a
uint32_t b
uint32_t c
glm::vec4 p[6]
std::string filter
int d
int v
image::ImageData::Colorf color
float scale
Definition TreeMesh.cpp:122
uint32_t s
Definition Weather.cpp:28
单张卡牌:ECS 实体,数据拆成 Identity / Stats / Visual / Layout / State。
Definition CardTypes.h:84
static CardData * createCard()
创建并触摸全部组件。
bool hit(float px, float py)
以当前中心 + 缩放判断点是否命中。
std::string describe()
卡牌描述字符串(调试用)。
牌库(栈顶在末尾)。
Definition CardTypes.h:142
CardData * get(int index)
CardData * peek()
查看栈顶卡牌(不弹出)。
void shuffle()
洗牌。
CardData * draw()
弹出栈顶卡牌(末尾);空牌库返回 nullptr。
static Deck * createDeck()
创建并触摸 Membership。
手牌:扇形布局 + 悬浮 + 拖拽 + 落区判定 + 渲染。
Definition CardTypes.h:223
void slotTransform(int i, int n, float &ox, float &oy, float &angle)
第 i 张(共 n 张)的扇形目标位置(牌中心)。
void release() override
Definition CardTypes.h:227
CardData * get(int index)
static Hand * createHand()
创建并触摸全部组件。
bool removeCard(CardData *c)
CardData * pick(float px, float py)
命中检测:返回 (px,py) 处最上层卡牌。
void addCard(CardData *c)
手牌增删与查询。
void render(graphics::Graphics *gfx)
绘制整手牌。
void update(float dt, float mx, float my, bool down, const std::vector< Zone * > &zones, std::vector< CardEvent > &out)
每帧推进:布局 + 悬浮 + 拖拽状态机,产出事件到 out。
CardData * find(const std::string &id)
落牌区(手牌区 / 出牌区 / 弃牌区),用于拖放命中判定。
Definition CardTypes.h:175
void render(graphics::Graphics *gfx, bool showLabel)
绘制落牌区。
static Zone * createZone()
创建并触摸组件。
bool accepts(CardData *card)
该区域是否接受这张卡。
bool contains(float px, float py)
点是否落在区域内。
float getWidth(const std::string &text) const
Pixel width of text (UTF-8), including kerning; delegates to FontData.
Definition Font.cpp:176
virtual void print(const std::string &text, float x, float y, const Color &color=Color(1.f, 1.f, 1.f, 1.f), float scale=1.f)
Draws UTF-8 text with the current font (see setFont), baseline-aligned so that (x,...
Definition Graphics.cpp:936
Font * getFont() const
Definition Graphics.h:691
virtual void drawSolidRect(float x, float y, float w, float h, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Internal immediate-mode helper used by RenderSystem / Batcher.
float lerpf(float a, float b, float t)
Definition AnimMath.h:35
float clampf(float v, float lo, float hi)
Definition AnimMath.h:31
void renderCardBack(graphics::Graphics *gfx, float x, float y, float w, float h, float angle, float a)
绘制牌背。
CardState
单张卡牌的运行时状态。
Definition CardTypes.h:25
const char * cardStateName(CardState state)
状态枚举的字符串名(用于脚本/调试)。
Definition CardTypes.cpp:10
void printCentered(graphics::Graphics *gfx, const std::string &text, float cx, float cy, float scale, const glm::vec4 &color)
渲染辅助(也供 Zone / Deck 复用)。
void renderCard(graphics::Graphics *gfx, const CardData &cardRef, const LayoutConfig &cfg, bool back)
绘制单张卡牌(正面或牌背)。
一次交互事件。
Definition CardTypes.h:210
UiCard 风格的布局配置(脚本可实时修改,对应 UiCard 的 Configs 面板)。
Definition CardTypes.h:40
float cardW
卡牌宽/高(像素)。
Definition CardTypes.h:42
bool hoverRotation
悬浮时是否恢复为水平。
Definition CardTypes.h:54
float arcHeight
扇形弧度(两端上翘高度)。
Definition CardTypes.h:50
float disabledAlpha
禁用牌透明度。
Definition CardTypes.h:62
float handX
手牌扇形中心 X / 基准高度 Y。
Definition CardTypes.h:47
float motionSpeed
通用归位运动速度。
Definition CardTypes.h:60
float spacing
手牌水平间距。
Definition CardTypes.h:45
float hoverScale
悬浮缩放/上移像素/运动速度。
Definition CardTypes.h:56
float rotationAngle
手牌两端最大旋转角(度)。
Definition CardTypes.h:52
float dragThreshold
拖拽触发距离(像素)。
Definition CardTypes.h:69