@almadar/ui 5.49.1 → 5.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +519 -215
- package/dist/avl/index.js +521 -217
- package/dist/components/game/molecules/three/index.cjs +251 -3
- package/dist/components/game/molecules/three/index.js +253 -5
- package/dist/components/game/molecules/useUnitSpriteAtlas.d.ts +30 -0
- package/dist/components/game/organisms/types/isometric.d.ts +4 -0
- package/dist/components/game/organisms/types/spriteAnimation.d.ts +24 -0
- package/dist/components/game/organisms/utils/spriteAnimation.d.ts +29 -1
- package/dist/components/index.cjs +377 -141
- package/dist/components/index.js +378 -140
- package/dist/providers/index.cjs +289 -28
- package/dist/providers/index.js +290 -29
- package/dist/runtime/index.cjs +519 -215
- package/dist/runtime/index.js +521 -217
- package/package.json +1 -1
package/dist/components/index.js
CHANGED
|
@@ -42,12 +42,12 @@ import { DndContext, useSensors, useSensor, PointerSensor, KeyboardSensor, useDr
|
|
|
42
42
|
import { useSortable, arrayMove, sortableKeyboardCoordinates, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
43
43
|
import { CSS } from '@dnd-kit/utilities';
|
|
44
44
|
import { useNodeId, ReactFlowProvider, Handle, Position } from '@xyflow/react';
|
|
45
|
-
import * as
|
|
45
|
+
import * as THREE3 from 'three';
|
|
46
46
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
47
47
|
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
|
|
48
48
|
import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
49
|
-
import { Canvas, useThree } from '@react-three/fiber';
|
|
50
|
-
import { Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
49
|
+
import { Canvas, useLoader, useFrame, useThree } from '@react-three/fiber';
|
|
50
|
+
import { Billboard, Grid as Grid$1, OrbitControls } from '@react-three/drei';
|
|
51
51
|
import { getPatternDefinition as getPatternDefinition$1, getComponentForPattern as getComponentForPattern$1 } from '@almadar/patterns';
|
|
52
52
|
|
|
53
53
|
var __defProp = Object.defineProperty;
|
|
@@ -9373,6 +9373,291 @@ var init_useCamera = __esm({
|
|
|
9373
9373
|
}
|
|
9374
9374
|
});
|
|
9375
9375
|
|
|
9376
|
+
// components/game/organisms/utils/spriteSheetConstants.ts
|
|
9377
|
+
var SHEET_COLUMNS, SPRITE_SHEET_LAYOUT;
|
|
9378
|
+
var init_spriteSheetConstants = __esm({
|
|
9379
|
+
"components/game/organisms/utils/spriteSheetConstants.ts"() {
|
|
9380
|
+
SHEET_COLUMNS = 8;
|
|
9381
|
+
SPRITE_SHEET_LAYOUT = {
|
|
9382
|
+
idle: { row: 0, frames: 4, frameRate: 6, loop: true },
|
|
9383
|
+
walk: { row: 1, frames: 8, frameRate: 10, loop: true },
|
|
9384
|
+
attack: { row: 2, frames: 6, frameRate: 12, loop: false },
|
|
9385
|
+
hit: { row: 3, frames: 3, frameRate: 8, loop: false },
|
|
9386
|
+
death: { row: 4, frames: 6, frameRate: 8, loop: false }
|
|
9387
|
+
};
|
|
9388
|
+
}
|
|
9389
|
+
});
|
|
9390
|
+
|
|
9391
|
+
// components/game/organisms/utils/spriteAnimation.ts
|
|
9392
|
+
function inferDirection(dx, dy) {
|
|
9393
|
+
if (dx === 0 && dy === 0) return "se";
|
|
9394
|
+
if (dx >= 0 && dy >= 0) return "se";
|
|
9395
|
+
if (dx <= 0 && dy >= 0) return "sw";
|
|
9396
|
+
if (dx >= 0 && dy <= 0) return "ne";
|
|
9397
|
+
return "nw";
|
|
9398
|
+
}
|
|
9399
|
+
function resolveSheetDirection(facing) {
|
|
9400
|
+
switch (facing) {
|
|
9401
|
+
case "se":
|
|
9402
|
+
return { sheetDir: "se", flipX: false };
|
|
9403
|
+
case "sw":
|
|
9404
|
+
return { sheetDir: "sw", flipX: false };
|
|
9405
|
+
case "ne":
|
|
9406
|
+
return { sheetDir: "sw", flipX: true };
|
|
9407
|
+
case "nw":
|
|
9408
|
+
return { sheetDir: "se", flipX: true };
|
|
9409
|
+
}
|
|
9410
|
+
}
|
|
9411
|
+
function frameRect(frame, row, columns, frameWidth, frameHeight) {
|
|
9412
|
+
return {
|
|
9413
|
+
sx: frame % columns * frameWidth,
|
|
9414
|
+
sy: row * frameHeight,
|
|
9415
|
+
sw: frameWidth,
|
|
9416
|
+
sh: frameHeight
|
|
9417
|
+
};
|
|
9418
|
+
}
|
|
9419
|
+
function getCurrentFrameFromDef(def, elapsed) {
|
|
9420
|
+
const frameDuration = 1e3 / def.frameRate;
|
|
9421
|
+
const totalDuration = def.frames * frameDuration;
|
|
9422
|
+
if (def.loop) {
|
|
9423
|
+
const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
|
|
9424
|
+
return { frame: frame2, finished: false };
|
|
9425
|
+
}
|
|
9426
|
+
if (elapsed >= totalDuration) {
|
|
9427
|
+
return { frame: def.frames - 1, finished: true };
|
|
9428
|
+
}
|
|
9429
|
+
const frame = Math.floor(elapsed / frameDuration);
|
|
9430
|
+
return { frame, finished: false };
|
|
9431
|
+
}
|
|
9432
|
+
function getCurrentFrame(animName, elapsed) {
|
|
9433
|
+
return getCurrentFrameFromDef(SPRITE_SHEET_LAYOUT[animName], elapsed);
|
|
9434
|
+
}
|
|
9435
|
+
function resolveFrame(sheetUrls, frameDims, animState) {
|
|
9436
|
+
if (!sheetUrls) return null;
|
|
9437
|
+
const { sheetDir, flipX } = resolveSheetDirection(animState.direction);
|
|
9438
|
+
const sheetUrl = sheetUrls[sheetDir];
|
|
9439
|
+
if (!sheetUrl) return null;
|
|
9440
|
+
const def = SPRITE_SHEET_LAYOUT[animState.animation];
|
|
9441
|
+
const { frame } = getCurrentFrame(animState.animation, animState.elapsed);
|
|
9442
|
+
const rect = frameRect(frame, def.row, def.frames, frameDims.width, frameDims.height);
|
|
9443
|
+
return {
|
|
9444
|
+
sheetUrl,
|
|
9445
|
+
sx: rect.sx,
|
|
9446
|
+
sy: rect.sy,
|
|
9447
|
+
sw: rect.sw,
|
|
9448
|
+
sh: rect.sh,
|
|
9449
|
+
flipX
|
|
9450
|
+
};
|
|
9451
|
+
}
|
|
9452
|
+
function createUnitAnimationState(unitId) {
|
|
9453
|
+
return {
|
|
9454
|
+
unitId,
|
|
9455
|
+
animation: "idle",
|
|
9456
|
+
direction: "se",
|
|
9457
|
+
frame: 0,
|
|
9458
|
+
elapsed: 0,
|
|
9459
|
+
queuedAnimation: null,
|
|
9460
|
+
finished: false
|
|
9461
|
+
};
|
|
9462
|
+
}
|
|
9463
|
+
function transitionAnimation(state, newAnim, direction) {
|
|
9464
|
+
if (state.animation === "death" && state.finished) return state;
|
|
9465
|
+
if (state.animation === newAnim && SPRITE_SHEET_LAYOUT[newAnim].loop) {
|
|
9466
|
+
return direction ? { ...state, direction } : state;
|
|
9467
|
+
}
|
|
9468
|
+
return {
|
|
9469
|
+
...state,
|
|
9470
|
+
animation: newAnim,
|
|
9471
|
+
direction: direction ?? state.direction,
|
|
9472
|
+
frame: 0,
|
|
9473
|
+
elapsed: 0,
|
|
9474
|
+
queuedAnimation: null,
|
|
9475
|
+
finished: false
|
|
9476
|
+
};
|
|
9477
|
+
}
|
|
9478
|
+
function tickAnimationState(state, deltaMs) {
|
|
9479
|
+
const newElapsed = state.elapsed + deltaMs;
|
|
9480
|
+
const { frame, finished } = getCurrentFrame(state.animation, newElapsed);
|
|
9481
|
+
const def = SPRITE_SHEET_LAYOUT[state.animation];
|
|
9482
|
+
if (finished && !def.loop && !state.finished) {
|
|
9483
|
+
if (state.animation === "death") {
|
|
9484
|
+
return { ...state, elapsed: newElapsed, frame, finished: true };
|
|
9485
|
+
}
|
|
9486
|
+
const nextAnim = state.queuedAnimation ?? "idle";
|
|
9487
|
+
return {
|
|
9488
|
+
...state,
|
|
9489
|
+
animation: nextAnim,
|
|
9490
|
+
elapsed: 0,
|
|
9491
|
+
frame: 0,
|
|
9492
|
+
queuedAnimation: null,
|
|
9493
|
+
finished: false
|
|
9494
|
+
};
|
|
9495
|
+
}
|
|
9496
|
+
return { ...state, elapsed: newElapsed, frame, finished };
|
|
9497
|
+
}
|
|
9498
|
+
var init_spriteAnimation = __esm({
|
|
9499
|
+
"components/game/organisms/utils/spriteAnimation.ts"() {
|
|
9500
|
+
init_spriteSheetConstants();
|
|
9501
|
+
}
|
|
9502
|
+
});
|
|
9503
|
+
function unitAtlasUrl(unit) {
|
|
9504
|
+
if (unit.spriteSheet) return unit.spriteSheet;
|
|
9505
|
+
const sprite = unit.sprite;
|
|
9506
|
+
if (!sprite) return null;
|
|
9507
|
+
const match = /^(.*-sprite-sheet)(?:-(?:se|sw))?(?:-v\d+)?\.png$/.exec(sprite);
|
|
9508
|
+
if (!match) return null;
|
|
9509
|
+
return `${match[1]}.json`;
|
|
9510
|
+
}
|
|
9511
|
+
function resolveSheetUrl(atlasUrl, relativeSheetPath) {
|
|
9512
|
+
try {
|
|
9513
|
+
return new URL(relativeSheetPath, atlasUrl).toString();
|
|
9514
|
+
} catch {
|
|
9515
|
+
const base = atlasUrl.slice(0, atlasUrl.lastIndexOf("/") + 1);
|
|
9516
|
+
return `${base}${relativeSheetPath.replace(/^\.\//, "")}`;
|
|
9517
|
+
}
|
|
9518
|
+
}
|
|
9519
|
+
function useUnitSpriteAtlas(units) {
|
|
9520
|
+
const atlasCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
9521
|
+
const loadingRef = useRef(/* @__PURE__ */ new Set());
|
|
9522
|
+
const [pendingCount, setPendingCount] = useState(0);
|
|
9523
|
+
const [, forceTick] = useState(0);
|
|
9524
|
+
const animStatesRef = useRef(/* @__PURE__ */ new Map());
|
|
9525
|
+
const lastTickRef = useRef(0);
|
|
9526
|
+
const rafRef = useRef(0);
|
|
9527
|
+
const atlasUrls = useMemo(() => {
|
|
9528
|
+
const set = /* @__PURE__ */ new Set();
|
|
9529
|
+
for (const unit of units) {
|
|
9530
|
+
const url = unitAtlasUrl(unit);
|
|
9531
|
+
if (url) set.add(url);
|
|
9532
|
+
}
|
|
9533
|
+
return [...set];
|
|
9534
|
+
}, [units]);
|
|
9535
|
+
useEffect(() => {
|
|
9536
|
+
const cache = atlasCacheRef.current;
|
|
9537
|
+
const loading = loadingRef.current;
|
|
9538
|
+
const toLoad = atlasUrls.filter((url) => !cache.has(url) && !loading.has(url));
|
|
9539
|
+
if (toLoad.length === 0) return;
|
|
9540
|
+
let cancelled = false;
|
|
9541
|
+
setPendingCount((prev) => prev + toLoad.length);
|
|
9542
|
+
for (const url of toLoad) {
|
|
9543
|
+
loading.add(url);
|
|
9544
|
+
fetch(url).then((res) => res.ok ? res.json() : Promise.reject(new Error(String(res.status)))).then((atlas) => {
|
|
9545
|
+
if (cancelled) return;
|
|
9546
|
+
cache.set(url, atlas);
|
|
9547
|
+
}).catch(() => {
|
|
9548
|
+
}).finally(() => {
|
|
9549
|
+
if (cancelled) return;
|
|
9550
|
+
loading.delete(url);
|
|
9551
|
+
setPendingCount((prev) => Math.max(0, prev - 1));
|
|
9552
|
+
forceTick((n) => n + 1);
|
|
9553
|
+
});
|
|
9554
|
+
}
|
|
9555
|
+
return () => {
|
|
9556
|
+
cancelled = true;
|
|
9557
|
+
};
|
|
9558
|
+
}, [atlasUrls]);
|
|
9559
|
+
const sheetUrls = useMemo(() => {
|
|
9560
|
+
const urls = /* @__PURE__ */ new Set();
|
|
9561
|
+
for (const unit of units) {
|
|
9562
|
+
const atlasUrl = unitAtlasUrl(unit);
|
|
9563
|
+
if (!atlasUrl) continue;
|
|
9564
|
+
const atlas = atlasCacheRef.current.get(atlasUrl);
|
|
9565
|
+
if (!atlas) continue;
|
|
9566
|
+
for (const rel of Object.values(atlas.sheets)) {
|
|
9567
|
+
if (rel) urls.add(resolveSheetUrl(atlasUrl, rel));
|
|
9568
|
+
}
|
|
9569
|
+
}
|
|
9570
|
+
return [...urls];
|
|
9571
|
+
}, [units, pendingCount]);
|
|
9572
|
+
useEffect(() => {
|
|
9573
|
+
const hasAtlasUnits = units.some((u) => unitAtlasUrl(u) !== null);
|
|
9574
|
+
if (!hasAtlasUnits) return;
|
|
9575
|
+
let running = true;
|
|
9576
|
+
const tick = (ts) => {
|
|
9577
|
+
if (!running) return;
|
|
9578
|
+
const last = lastTickRef.current || ts;
|
|
9579
|
+
const delta = ts - last;
|
|
9580
|
+
lastTickRef.current = ts;
|
|
9581
|
+
const states = animStatesRef.current;
|
|
9582
|
+
const currentIds = /* @__PURE__ */ new Set();
|
|
9583
|
+
for (const unit of units) {
|
|
9584
|
+
if (unitAtlasUrl(unit) === null) continue;
|
|
9585
|
+
currentIds.add(unit.id);
|
|
9586
|
+
let state = states.get(unit.id);
|
|
9587
|
+
if (!state) {
|
|
9588
|
+
state = { animation: "idle", direction: "se", elapsed: 0, walkHold: 0, prev: null };
|
|
9589
|
+
states.set(unit.id, state);
|
|
9590
|
+
}
|
|
9591
|
+
const posX = unit.position?.x ?? unit.x ?? 0;
|
|
9592
|
+
const posY = unit.position?.y ?? unit.y ?? 0;
|
|
9593
|
+
if (state.prev) {
|
|
9594
|
+
const dx = posX - state.prev.x;
|
|
9595
|
+
const dy = posY - state.prev.y;
|
|
9596
|
+
if (dx !== 0 || dy !== 0) {
|
|
9597
|
+
state.animation = "walk";
|
|
9598
|
+
state.direction = inferDirection(dx, dy);
|
|
9599
|
+
state.walkHold = WALK_HOLD_MS;
|
|
9600
|
+
} else if (state.animation === "walk") {
|
|
9601
|
+
state.walkHold -= delta;
|
|
9602
|
+
if (state.walkHold <= 0) state.animation = "idle";
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
state.prev = { x: posX, y: posY };
|
|
9606
|
+
state.elapsed += delta;
|
|
9607
|
+
}
|
|
9608
|
+
for (const id of states.keys()) {
|
|
9609
|
+
if (!currentIds.has(id)) states.delete(id);
|
|
9610
|
+
}
|
|
9611
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
9612
|
+
};
|
|
9613
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
9614
|
+
return () => {
|
|
9615
|
+
running = false;
|
|
9616
|
+
cancelAnimationFrame(rafRef.current);
|
|
9617
|
+
lastTickRef.current = 0;
|
|
9618
|
+
};
|
|
9619
|
+
}, [units]);
|
|
9620
|
+
const resolveUnitFrame = useCallback((unitId) => {
|
|
9621
|
+
const unit = units.find((u) => u.id === unitId);
|
|
9622
|
+
if (!unit) return null;
|
|
9623
|
+
const atlasUrl = unitAtlasUrl(unit);
|
|
9624
|
+
if (!atlasUrl) return null;
|
|
9625
|
+
const atlas = atlasCacheRef.current.get(atlasUrl);
|
|
9626
|
+
if (!atlas) return null;
|
|
9627
|
+
const state = animStatesRef.current.get(unitId);
|
|
9628
|
+
const animation = state?.animation ?? "idle";
|
|
9629
|
+
const direction = state?.direction ?? "se";
|
|
9630
|
+
const elapsed = state?.elapsed ?? 0;
|
|
9631
|
+
const def = atlas.animations[animation] ?? atlas.animations.idle;
|
|
9632
|
+
if (!def) return null;
|
|
9633
|
+
const { sheetDir, flipX } = resolveSheetDirection(direction);
|
|
9634
|
+
const rel = atlas.sheets[sheetDir] ?? atlas.sheets.se ?? atlas.sheets.sw;
|
|
9635
|
+
if (!rel) return null;
|
|
9636
|
+
const sheetUrl = resolveSheetUrl(atlasUrl, rel);
|
|
9637
|
+
const isIdle = animation === "idle";
|
|
9638
|
+
const frame = isIdle ? 0 : getCurrentFrameFromDef(def, elapsed).frame;
|
|
9639
|
+
const rect = frameRect(frame, def.row, atlas.columns, atlas.frameWidth, atlas.frameHeight);
|
|
9640
|
+
return {
|
|
9641
|
+
sheetUrl,
|
|
9642
|
+
sx: rect.sx,
|
|
9643
|
+
sy: rect.sy,
|
|
9644
|
+
sw: rect.sw,
|
|
9645
|
+
sh: rect.sh,
|
|
9646
|
+
flipX,
|
|
9647
|
+
applyBreathing: isIdle
|
|
9648
|
+
};
|
|
9649
|
+
}, [units]);
|
|
9650
|
+
return { sheetUrls, resolveUnitFrame, pendingCount };
|
|
9651
|
+
}
|
|
9652
|
+
var WALK_HOLD_MS;
|
|
9653
|
+
var init_useUnitSpriteAtlas = __esm({
|
|
9654
|
+
"components/game/molecules/useUnitSpriteAtlas.ts"() {
|
|
9655
|
+
"use client";
|
|
9656
|
+
init_spriteAnimation();
|
|
9657
|
+
WALK_HOLD_MS = 600;
|
|
9658
|
+
}
|
|
9659
|
+
});
|
|
9660
|
+
|
|
9376
9661
|
// components/game/organisms/utils/isometric.ts
|
|
9377
9662
|
function isoToScreen(tileX, tileY, scale, baseOffsetX) {
|
|
9378
9663
|
const scaledTileWidth = TILE_WIDTH * scale;
|
|
@@ -9486,6 +9771,10 @@ function IsometricCanvas({
|
|
|
9486
9771
|
() => unitsProp.map((u) => u.position ? u : { ...u, position: { x: u.x ?? 0, y: u.y ?? 0 } }),
|
|
9487
9772
|
[unitsProp]
|
|
9488
9773
|
);
|
|
9774
|
+
const { sheetUrls: atlasSheetUrls, resolveUnitFrame: resolveUnitFrameInternal, pendingCount: atlasPending } = useUnitSpriteAtlas(units);
|
|
9775
|
+
const resolveFrameForUnit = useCallback((unitId) => {
|
|
9776
|
+
return resolveUnitFrame?.(unitId) ?? resolveUnitFrameInternal(unitId);
|
|
9777
|
+
}, [resolveUnitFrame, resolveUnitFrameInternal]);
|
|
9489
9778
|
const features = useMemo(
|
|
9490
9779
|
() => featuresProp.map((f3) => {
|
|
9491
9780
|
if (f3.type) return f3;
|
|
@@ -9569,9 +9858,10 @@ function IsometricCanvas({
|
|
|
9569
9858
|
}
|
|
9570
9859
|
}
|
|
9571
9860
|
if (effectSpriteUrls) urls.push(...effectSpriteUrls);
|
|
9861
|
+
if (atlasSheetUrls.length) urls.push(...atlasSheetUrls);
|
|
9572
9862
|
if (backgroundImage) urls.push(backgroundImage);
|
|
9573
9863
|
return [...new Set(urls.filter(Boolean))];
|
|
9574
|
-
}, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, backgroundImage, assetManifest, resolveManifestUrl]);
|
|
9864
|
+
}, [sortedTiles, features, units, getTerrainSprite, getFeatureSprite, getUnitSprite, effectSpriteUrls, atlasSheetUrls, backgroundImage, assetManifest, resolveManifestUrl]);
|
|
9575
9865
|
const { getImage, pendingCount } = useImageCache(spriteUrls);
|
|
9576
9866
|
useEffect(() => {
|
|
9577
9867
|
if (typeof window === "undefined") return;
|
|
@@ -9859,7 +10149,7 @@ function IsometricCanvas({
|
|
|
9859
10149
|
ctx.lineWidth = 3;
|
|
9860
10150
|
ctx.stroke();
|
|
9861
10151
|
}
|
|
9862
|
-
const frame =
|
|
10152
|
+
const frame = resolveFrameForUnit(unit.id);
|
|
9863
10153
|
const frameImg = frame ? getImage(frame.sheetUrl) : null;
|
|
9864
10154
|
if (frame && frameImg) {
|
|
9865
10155
|
const frameAr = frame.sw / frame.sh;
|
|
@@ -9969,7 +10259,7 @@ function IsometricCanvas({
|
|
|
9969
10259
|
resolveTerrainSpriteUrl,
|
|
9970
10260
|
resolveFeatureSpriteUrl,
|
|
9971
10261
|
resolveUnitSpriteUrl,
|
|
9972
|
-
|
|
10262
|
+
resolveFrameForUnit,
|
|
9973
10263
|
getImage,
|
|
9974
10264
|
gridWidth,
|
|
9975
10265
|
gridHeight,
|
|
@@ -10001,7 +10291,7 @@ function IsometricCanvas({
|
|
|
10001
10291
|
};
|
|
10002
10292
|
}, [selectedUnitId, units, scale, baseOffsetX, scaledTileWidth, scaledDiamondTopY, scaledFloorHeight, viewportSize, targetCameraRef]);
|
|
10003
10293
|
useEffect(() => {
|
|
10004
|
-
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0;
|
|
10294
|
+
const hasAnimations = units.length > 0 || validMoves.length > 0 || attackTargets.length > 0 || selectedUnitId != null || targetCameraRef.current != null || hasActiveEffects2 || pendingCount > 0 || atlasPending > 0;
|
|
10005
10295
|
draw(animTimeRef.current);
|
|
10006
10296
|
if (!hasAnimations) return;
|
|
10007
10297
|
let running = true;
|
|
@@ -10017,7 +10307,7 @@ function IsometricCanvas({
|
|
|
10017
10307
|
running = false;
|
|
10018
10308
|
cancelAnimationFrame(rafIdRef.current);
|
|
10019
10309
|
};
|
|
10020
|
-
}, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, lerpToTarget, targetCameraRef]);
|
|
10310
|
+
}, [draw, units.length, validMoves.length, attackTargets.length, selectedUnitId, hasActiveEffects2, pendingCount, atlasPending, lerpToTarget, targetCameraRef]);
|
|
10021
10311
|
const handleMouseMoveWithCamera = useCallback((e) => {
|
|
10022
10312
|
if (enableCamera) {
|
|
10023
10313
|
const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
|
|
@@ -10162,6 +10452,7 @@ var init_IsometricCanvas = __esm({
|
|
|
10162
10452
|
init_ErrorState();
|
|
10163
10453
|
init_useImageCache();
|
|
10164
10454
|
init_useCamera();
|
|
10455
|
+
init_useUnitSpriteAtlas();
|
|
10165
10456
|
init_verificationRegistry();
|
|
10166
10457
|
init_isometric();
|
|
10167
10458
|
IsometricCanvas.displayName = "IsometricCanvas";
|
|
@@ -29532,13 +29823,13 @@ var init_MapView = __esm({
|
|
|
29532
29823
|
shadowSize: [41, 41]
|
|
29533
29824
|
});
|
|
29534
29825
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
29535
|
-
const { useEffect:
|
|
29826
|
+
const { useEffect: useEffect80, useRef: useRef78, useCallback: useCallback120, useState: useState110 } = React76__default;
|
|
29536
29827
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
29537
29828
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
29538
29829
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
29539
29830
|
const map = useMap();
|
|
29540
|
-
const prevRef =
|
|
29541
|
-
|
|
29831
|
+
const prevRef = useRef78({ centerLat, centerLng, zoom });
|
|
29832
|
+
useEffect80(() => {
|
|
29542
29833
|
const prev = prevRef.current;
|
|
29543
29834
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
29544
29835
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -29549,7 +29840,7 @@ var init_MapView = __esm({
|
|
|
29549
29840
|
}
|
|
29550
29841
|
function MapClickHandler({ onMapClick }) {
|
|
29551
29842
|
const map = useMap();
|
|
29552
|
-
|
|
29843
|
+
useEffect80(() => {
|
|
29553
29844
|
if (!onMapClick) return;
|
|
29554
29845
|
const handler = (e) => {
|
|
29555
29846
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -29577,8 +29868,8 @@ var init_MapView = __esm({
|
|
|
29577
29868
|
showAttribution = true
|
|
29578
29869
|
}) {
|
|
29579
29870
|
const eventBus = useEventBus3();
|
|
29580
|
-
const [clickedPosition, setClickedPosition] =
|
|
29581
|
-
const handleMapClick =
|
|
29871
|
+
const [clickedPosition, setClickedPosition] = useState110(null);
|
|
29872
|
+
const handleMapClick = useCallback120((lat, lng) => {
|
|
29582
29873
|
if (showClickedPin) {
|
|
29583
29874
|
setClickedPosition({ lat, lng });
|
|
29584
29875
|
}
|
|
@@ -29587,7 +29878,7 @@ var init_MapView = __esm({
|
|
|
29587
29878
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29588
29879
|
}
|
|
29589
29880
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29590
|
-
const handleMarkerClick =
|
|
29881
|
+
const handleMarkerClick = useCallback120((marker) => {
|
|
29591
29882
|
onMarkerClick?.(marker);
|
|
29592
29883
|
if (markerClickEvent) {
|
|
29593
29884
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -41632,7 +41923,7 @@ var init_AssetLoader = __esm({
|
|
|
41632
41923
|
__publicField(this, "textureCache");
|
|
41633
41924
|
__publicField(this, "loadingPromises");
|
|
41634
41925
|
this.objLoader = new OBJLoader();
|
|
41635
|
-
this.textureLoader = new
|
|
41926
|
+
this.textureLoader = new THREE3.TextureLoader();
|
|
41636
41927
|
this.modelCache = /* @__PURE__ */ new Map();
|
|
41637
41928
|
this.textureCache = /* @__PURE__ */ new Map();
|
|
41638
41929
|
this.loadingPromises = /* @__PURE__ */ new Map();
|
|
@@ -41706,7 +41997,7 @@ var init_AssetLoader = __esm({
|
|
|
41706
41997
|
return this.loadingPromises.get(`texture:${url}`);
|
|
41707
41998
|
}
|
|
41708
41999
|
const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
|
|
41709
|
-
texture.colorSpace =
|
|
42000
|
+
texture.colorSpace = THREE3.SRGBColorSpace;
|
|
41710
42001
|
this.textureCache.set(url, texture);
|
|
41711
42002
|
this.loadingPromises.delete(`texture:${url}`);
|
|
41712
42003
|
return texture;
|
|
@@ -41780,7 +42071,7 @@ var init_AssetLoader = __esm({
|
|
|
41780
42071
|
});
|
|
41781
42072
|
this.modelCache.forEach((model) => {
|
|
41782
42073
|
model.scene.traverse((child) => {
|
|
41783
|
-
if (child instanceof
|
|
42074
|
+
if (child instanceof THREE3.Mesh) {
|
|
41784
42075
|
child.geometry.dispose();
|
|
41785
42076
|
if (Array.isArray(child.material)) {
|
|
41786
42077
|
child.material.forEach((m) => m.dispose());
|
|
@@ -42336,7 +42627,7 @@ function ModelLoader({
|
|
|
42336
42627
|
if (!loadedModel) return null;
|
|
42337
42628
|
const cloned = loadedModel.clone();
|
|
42338
42629
|
cloned.traverse((child) => {
|
|
42339
|
-
if (child instanceof
|
|
42630
|
+
if (child instanceof THREE3.Mesh) {
|
|
42340
42631
|
child.castShadow = castShadow;
|
|
42341
42632
|
child.receiveShadow = receiveShadow;
|
|
42342
42633
|
}
|
|
@@ -42450,6 +42741,47 @@ function CameraController({
|
|
|
42450
42741
|
}, [camera.position, onCameraChange]);
|
|
42451
42742
|
return null;
|
|
42452
42743
|
}
|
|
42744
|
+
function UnitSpriteBillboard({
|
|
42745
|
+
sheetUrl,
|
|
42746
|
+
resolveFrame: resolveFrame2,
|
|
42747
|
+
height = 1.2
|
|
42748
|
+
}) {
|
|
42749
|
+
const texture = useLoader(THREE3.TextureLoader, sheetUrl);
|
|
42750
|
+
const meshRef = useRef(null);
|
|
42751
|
+
const matRef = useRef(null);
|
|
42752
|
+
const [aspect, setAspect] = useState(1);
|
|
42753
|
+
useFrame(() => {
|
|
42754
|
+
const frame = resolveFrame2();
|
|
42755
|
+
if (!frame || !texture.image) return;
|
|
42756
|
+
const imgW = texture.image.width;
|
|
42757
|
+
const imgH = texture.image.height;
|
|
42758
|
+
if (!imgW || !imgH) return;
|
|
42759
|
+
texture.repeat.set((frame.flipX ? -1 : 1) * (frame.sw / imgW), frame.sh / imgH);
|
|
42760
|
+
texture.offset.set(
|
|
42761
|
+
frame.flipX ? (frame.sx + frame.sw) / imgW : frame.sx / imgW,
|
|
42762
|
+
1 - (frame.sy + frame.sh) / imgH
|
|
42763
|
+
);
|
|
42764
|
+
texture.magFilter = THREE3.NearestFilter;
|
|
42765
|
+
texture.minFilter = THREE3.NearestFilter;
|
|
42766
|
+
texture.needsUpdate = true;
|
|
42767
|
+
const nextAspect = frame.sw / frame.sh;
|
|
42768
|
+
if (Math.abs(nextAspect - aspect) > 1e-3) setAspect(nextAspect);
|
|
42769
|
+
if (matRef.current) matRef.current.needsUpdate = true;
|
|
42770
|
+
});
|
|
42771
|
+
return /* @__PURE__ */ jsxs("mesh", { ref: meshRef, position: [0, height / 2, 0], children: [
|
|
42772
|
+
/* @__PURE__ */ jsx("planeGeometry", { args: [height * aspect, height] }),
|
|
42773
|
+
/* @__PURE__ */ jsx(
|
|
42774
|
+
"meshBasicMaterial",
|
|
42775
|
+
{
|
|
42776
|
+
ref: matRef,
|
|
42777
|
+
map: texture,
|
|
42778
|
+
transparent: true,
|
|
42779
|
+
alphaTest: 0.1,
|
|
42780
|
+
side: THREE3.DoubleSide
|
|
42781
|
+
}
|
|
42782
|
+
)
|
|
42783
|
+
] });
|
|
42784
|
+
}
|
|
42453
42785
|
var DEFAULT_GRID_CONFIG, GameCanvas3D;
|
|
42454
42786
|
var init_GameCanvas3D2 = __esm({
|
|
42455
42787
|
"components/game/molecules/GameCanvas3D.tsx"() {
|
|
@@ -42460,6 +42792,7 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42460
42792
|
init_Canvas3DLoadingState2();
|
|
42461
42793
|
init_Canvas3DErrorBoundary2();
|
|
42462
42794
|
init_ModelLoader();
|
|
42795
|
+
init_useUnitSpriteAtlas();
|
|
42463
42796
|
init_cn();
|
|
42464
42797
|
init_GameCanvas3D();
|
|
42465
42798
|
DEFAULT_GRID_CONFIG = {
|
|
@@ -42516,8 +42849,10 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42516
42849
|
const controlsRef = useRef(null);
|
|
42517
42850
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
42518
42851
|
const [internalError, setInternalError] = useState(null);
|
|
42852
|
+
const { sheetUrls: atlasSheetUrls, resolveUnitFrame } = useUnitSpriteAtlas(units);
|
|
42853
|
+
const preloadUrls = useMemo(() => [...preloadAssets, ...atlasSheetUrls], [preloadAssets, atlasSheetUrls]);
|
|
42519
42854
|
const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
|
|
42520
|
-
preloadUrls
|
|
42855
|
+
preloadUrls,
|
|
42521
42856
|
loader: customAssetLoader
|
|
42522
42857
|
});
|
|
42523
42858
|
const eventHandlers = useGameCanvas3DEvents({
|
|
@@ -42576,7 +42911,7 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42576
42911
|
getCameraPosition: () => {
|
|
42577
42912
|
if (controlsRef.current) {
|
|
42578
42913
|
const pos = controlsRef.current.object.position;
|
|
42579
|
-
return new
|
|
42914
|
+
return new THREE3.Vector3(pos.x, pos.y, pos.z);
|
|
42580
42915
|
}
|
|
42581
42916
|
return null;
|
|
42582
42917
|
},
|
|
@@ -42728,6 +43063,8 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42728
43063
|
({ unit, position }) => {
|
|
42729
43064
|
const isSelected = selectedUnitId === unit.id;
|
|
42730
43065
|
const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
|
|
43066
|
+
const hasAtlas = unitAtlasUrl(unit) !== null;
|
|
43067
|
+
const initialFrame = hasAtlas ? resolveUnitFrame(unit.id) : null;
|
|
42731
43068
|
return /* @__PURE__ */ jsxs(
|
|
42732
43069
|
"group",
|
|
42733
43070
|
{
|
|
@@ -42739,7 +43076,16 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42739
43076
|
/* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
|
|
42740
43077
|
/* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
|
|
42741
43078
|
] }),
|
|
42742
|
-
|
|
43079
|
+
hasAtlas && initialFrame ? (
|
|
43080
|
+
/* Animated sprite-sheet billboard — single cropped frame, by state */
|
|
43081
|
+
/* @__PURE__ */ jsx(Billboard, { children: /* @__PURE__ */ jsx(
|
|
43082
|
+
UnitSpriteBillboard,
|
|
43083
|
+
{
|
|
43084
|
+
sheetUrl: initialFrame.sheetUrl,
|
|
43085
|
+
resolveFrame: () => resolveUnitFrame(unit.id)
|
|
43086
|
+
}
|
|
43087
|
+
) })
|
|
43088
|
+
) : unit.modelUrl ? (
|
|
42743
43089
|
/* GLB unit model (box fallback while loading / on error) */
|
|
42744
43090
|
/* @__PURE__ */ jsx(
|
|
42745
43091
|
ModelLoader,
|
|
@@ -42793,7 +43139,7 @@ var init_GameCanvas3D2 = __esm({
|
|
|
42793
43139
|
}
|
|
42794
43140
|
);
|
|
42795
43141
|
},
|
|
42796
|
-
[selectedUnitId, handleUnitClick]
|
|
43142
|
+
[selectedUnitId, handleUnitClick, resolveUnitFrame]
|
|
42797
43143
|
);
|
|
42798
43144
|
const DefaultFeatureRenderer = useCallback(
|
|
42799
43145
|
({
|
|
@@ -48497,12 +48843,8 @@ function Sprite({
|
|
|
48497
48843
|
}) {
|
|
48498
48844
|
const eventBus = useEventBus();
|
|
48499
48845
|
const sourcePosition = useMemo(() => {
|
|
48500
|
-
const
|
|
48501
|
-
|
|
48502
|
-
return {
|
|
48503
|
-
x: frameX * frameWidth,
|
|
48504
|
-
y: frameY * frameHeight
|
|
48505
|
-
};
|
|
48846
|
+
const { sx, sy } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
|
|
48847
|
+
return { x: sx, y: sy };
|
|
48506
48848
|
}, [frame, columns, frameWidth, frameHeight]);
|
|
48507
48849
|
const transform = useMemo(() => {
|
|
48508
48850
|
const transforms = [
|
|
@@ -48560,8 +48902,7 @@ function drawSprite(ctx, image, props) {
|
|
|
48560
48902
|
opacity = 1,
|
|
48561
48903
|
columns = 16
|
|
48562
48904
|
} = props;
|
|
48563
|
-
const sourceX = frame
|
|
48564
|
-
const sourceY = Math.floor(frame / columns) * frameHeight;
|
|
48905
|
+
const { sx: sourceX, sy: sourceY } = frameRect(frame, Math.floor(frame / columns), columns, frameWidth, frameHeight);
|
|
48565
48906
|
ctx.save();
|
|
48566
48907
|
ctx.globalAlpha = opacity;
|
|
48567
48908
|
ctx.translate(x + frameWidth / 2, y + frameHeight / 2);
|
|
@@ -48586,6 +48927,7 @@ var init_Sprite = __esm({
|
|
|
48586
48927
|
"components/game/atoms/Sprite.tsx"() {
|
|
48587
48928
|
"use client";
|
|
48588
48929
|
init_useEventBus();
|
|
48930
|
+
init_spriteAnimation();
|
|
48589
48931
|
}
|
|
48590
48932
|
});
|
|
48591
48933
|
var StatCard;
|
|
@@ -52593,121 +52935,15 @@ init_useGameAudio();
|
|
|
52593
52935
|
init_useImageCache();
|
|
52594
52936
|
init_useCamera();
|
|
52595
52937
|
|
|
52596
|
-
// components/game/organisms/utils/spriteSheetConstants.ts
|
|
52597
|
-
var SHEET_COLUMNS = 8;
|
|
52598
|
-
var SPRITE_SHEET_LAYOUT = {
|
|
52599
|
-
idle: { row: 0, frames: 4, frameRate: 6, loop: true },
|
|
52600
|
-
walk: { row: 1, frames: 8, frameRate: 10, loop: true },
|
|
52601
|
-
attack: { row: 2, frames: 6, frameRate: 12, loop: false },
|
|
52602
|
-
hit: { row: 3, frames: 3, frameRate: 8, loop: false },
|
|
52603
|
-
death: { row: 4, frames: 6, frameRate: 8, loop: false }
|
|
52604
|
-
};
|
|
52605
|
-
|
|
52606
|
-
// components/game/organisms/utils/spriteAnimation.ts
|
|
52607
|
-
function inferDirection(dx, dy) {
|
|
52608
|
-
if (dx === 0 && dy === 0) return "se";
|
|
52609
|
-
if (dx >= 0 && dy >= 0) return "se";
|
|
52610
|
-
if (dx <= 0 && dy >= 0) return "sw";
|
|
52611
|
-
if (dx >= 0 && dy <= 0) return "ne";
|
|
52612
|
-
return "nw";
|
|
52613
|
-
}
|
|
52614
|
-
function resolveSheetDirection(facing) {
|
|
52615
|
-
switch (facing) {
|
|
52616
|
-
case "se":
|
|
52617
|
-
return { sheetDir: "se", flipX: false };
|
|
52618
|
-
case "sw":
|
|
52619
|
-
return { sheetDir: "sw", flipX: false };
|
|
52620
|
-
case "ne":
|
|
52621
|
-
return { sheetDir: "sw", flipX: true };
|
|
52622
|
-
case "nw":
|
|
52623
|
-
return { sheetDir: "se", flipX: true };
|
|
52624
|
-
}
|
|
52625
|
-
}
|
|
52626
|
-
function getCurrentFrame(animName, elapsed) {
|
|
52627
|
-
const def = SPRITE_SHEET_LAYOUT[animName];
|
|
52628
|
-
const frameDuration = 1e3 / def.frameRate;
|
|
52629
|
-
const totalDuration = def.frames * frameDuration;
|
|
52630
|
-
if (def.loop) {
|
|
52631
|
-
const frame2 = Math.floor(elapsed % totalDuration / frameDuration);
|
|
52632
|
-
return { frame: frame2, finished: false };
|
|
52633
|
-
}
|
|
52634
|
-
if (elapsed >= totalDuration) {
|
|
52635
|
-
return { frame: def.frames - 1, finished: true };
|
|
52636
|
-
}
|
|
52637
|
-
const frame = Math.floor(elapsed / frameDuration);
|
|
52638
|
-
return { frame, finished: false };
|
|
52639
|
-
}
|
|
52640
|
-
function resolveFrame(sheetUrls, frameDims, animState) {
|
|
52641
|
-
if (!sheetUrls) return null;
|
|
52642
|
-
const { sheetDir, flipX } = resolveSheetDirection(animState.direction);
|
|
52643
|
-
const sheetUrl = sheetUrls[sheetDir];
|
|
52644
|
-
if (!sheetUrl) return null;
|
|
52645
|
-
const def = SPRITE_SHEET_LAYOUT[animState.animation];
|
|
52646
|
-
const { frame } = getCurrentFrame(animState.animation, animState.elapsed);
|
|
52647
|
-
return {
|
|
52648
|
-
sheetUrl,
|
|
52649
|
-
sx: frame * frameDims.width,
|
|
52650
|
-
sy: def.row * frameDims.height,
|
|
52651
|
-
sw: frameDims.width,
|
|
52652
|
-
sh: frameDims.height,
|
|
52653
|
-
flipX
|
|
52654
|
-
};
|
|
52655
|
-
}
|
|
52656
|
-
function createUnitAnimationState(unitId) {
|
|
52657
|
-
return {
|
|
52658
|
-
unitId,
|
|
52659
|
-
animation: "idle",
|
|
52660
|
-
direction: "se",
|
|
52661
|
-
frame: 0,
|
|
52662
|
-
elapsed: 0,
|
|
52663
|
-
queuedAnimation: null,
|
|
52664
|
-
finished: false
|
|
52665
|
-
};
|
|
52666
|
-
}
|
|
52667
|
-
function transitionAnimation(state, newAnim, direction) {
|
|
52668
|
-
if (state.animation === "death" && state.finished) return state;
|
|
52669
|
-
if (state.animation === newAnim && SPRITE_SHEET_LAYOUT[newAnim].loop) {
|
|
52670
|
-
return direction ? { ...state, direction } : state;
|
|
52671
|
-
}
|
|
52672
|
-
return {
|
|
52673
|
-
...state,
|
|
52674
|
-
animation: newAnim,
|
|
52675
|
-
direction: direction ?? state.direction,
|
|
52676
|
-
frame: 0,
|
|
52677
|
-
elapsed: 0,
|
|
52678
|
-
queuedAnimation: null,
|
|
52679
|
-
finished: false
|
|
52680
|
-
};
|
|
52681
|
-
}
|
|
52682
|
-
function tickAnimationState(state, deltaMs) {
|
|
52683
|
-
const newElapsed = state.elapsed + deltaMs;
|
|
52684
|
-
const { frame, finished } = getCurrentFrame(state.animation, newElapsed);
|
|
52685
|
-
const def = SPRITE_SHEET_LAYOUT[state.animation];
|
|
52686
|
-
if (finished && !def.loop && !state.finished) {
|
|
52687
|
-
if (state.animation === "death") {
|
|
52688
|
-
return { ...state, elapsed: newElapsed, frame, finished: true };
|
|
52689
|
-
}
|
|
52690
|
-
const nextAnim = state.queuedAnimation ?? "idle";
|
|
52691
|
-
return {
|
|
52692
|
-
...state,
|
|
52693
|
-
animation: nextAnim,
|
|
52694
|
-
elapsed: 0,
|
|
52695
|
-
frame: 0,
|
|
52696
|
-
queuedAnimation: null,
|
|
52697
|
-
finished: false
|
|
52698
|
-
};
|
|
52699
|
-
}
|
|
52700
|
-
return { ...state, elapsed: newElapsed, frame, finished };
|
|
52701
|
-
}
|
|
52702
|
-
|
|
52703
52938
|
// components/game/organisms/hooks/useSpriteAnimations.ts
|
|
52939
|
+
init_spriteAnimation();
|
|
52704
52940
|
function useSpriteAnimations(getSheetUrls, getFrameDims, options = {}) {
|
|
52705
52941
|
const speed = options.speed ?? 1;
|
|
52706
52942
|
const animStatesRef = useRef(/* @__PURE__ */ new Map());
|
|
52707
52943
|
const prevPositionsRef = useRef(/* @__PURE__ */ new Map());
|
|
52708
52944
|
const unitDataRef = useRef(/* @__PURE__ */ new Map());
|
|
52709
52945
|
const walkHoldRef = useRef(/* @__PURE__ */ new Map());
|
|
52710
|
-
const
|
|
52946
|
+
const WALK_HOLD_MS2 = 600;
|
|
52711
52947
|
const syncUnits = useCallback((units, deltaMs) => {
|
|
52712
52948
|
const scaledDelta = deltaMs * speed;
|
|
52713
52949
|
const states = animStatesRef.current;
|
|
@@ -52733,7 +52969,7 @@ function useSpriteAnimations(getSheetUrls, getFrameDims, options = {}) {
|
|
|
52733
52969
|
const dir = inferDirection(dx, dy);
|
|
52734
52970
|
if (state.animation !== "attack" && state.animation !== "hit" && state.animation !== "death") {
|
|
52735
52971
|
state = transitionAnimation(state, "walk", dir);
|
|
52736
|
-
walkHold.set(unit.id,
|
|
52972
|
+
walkHold.set(unit.id, WALK_HOLD_MS2);
|
|
52737
52973
|
}
|
|
52738
52974
|
} else if (state.animation === "walk") {
|
|
52739
52975
|
const remaining = (walkHold.get(unit.id) ?? 0) - scaledDelta;
|
|
@@ -53066,6 +53302,8 @@ function usePhysics2D(options = {}) {
|
|
|
53066
53302
|
|
|
53067
53303
|
// components/game/organisms/index.ts
|
|
53068
53304
|
init_isometric();
|
|
53305
|
+
init_spriteAnimation();
|
|
53306
|
+
init_spriteSheetConstants();
|
|
53069
53307
|
init_BattleBoard();
|
|
53070
53308
|
init_UncontrolledBattleBoard();
|
|
53071
53309
|
init_useBattleState();
|