@sadhaka/loom-engine 0.10.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/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/animation/animation-clip.d.ts +12 -0
- package/dist/animation/animation-clip.d.ts.map +1 -0
- package/dist/animation/animation-clip.js +85 -0
- package/dist/animation/animation-clip.js.map +1 -0
- package/dist/animation/animation-state-pool.d.ts +25 -0
- package/dist/animation/animation-state-pool.d.ts.map +1 -0
- package/dist/animation/animation-state-pool.js +113 -0
- package/dist/animation/animation-state-pool.js.map +1 -0
- package/dist/asset/sprite-sheet-loader.d.ts +41 -0
- package/dist/asset/sprite-sheet-loader.d.ts.map +1 -0
- package/dist/asset/sprite-sheet-loader.js +313 -0
- package/dist/asset/sprite-sheet-loader.js.map +1 -0
- package/dist/audio/audio-bus.d.ts +43 -0
- package/dist/audio/audio-bus.d.ts.map +1 -0
- package/dist/audio/audio-bus.js +258 -0
- package/dist/audio/audio-bus.js.map +1 -0
- package/dist/combat/mob-catalog.d.ts +29 -0
- package/dist/combat/mob-catalog.d.ts.map +1 -0
- package/dist/combat/mob-catalog.js +104 -0
- package/dist/combat/mob-catalog.js.map +1 -0
- package/dist/components/health.d.ts +28 -0
- package/dist/components/health.d.ts.map +1 -0
- package/dist/components/health.js +150 -0
- package/dist/components/health.js.map +1 -0
- package/dist/components/interactable.d.ts +30 -0
- package/dist/components/interactable.d.ts.map +1 -0
- package/dist/components/interactable.js +94 -0
- package/dist/components/interactable.js.map +1 -0
- package/dist/components/particle-emitter.d.ts +62 -0
- package/dist/components/particle-emitter.d.ts.map +1 -0
- package/dist/components/particle-emitter.js +193 -0
- package/dist/components/particle-emitter.js.map +1 -0
- package/dist/components/pursue.d.ts +23 -0
- package/dist/components/pursue.d.ts.map +1 -0
- package/dist/components/pursue.js +96 -0
- package/dist/components/pursue.js.map +1 -0
- package/dist/components/ranged-attack.d.ts +44 -0
- package/dist/components/ranged-attack.d.ts.map +1 -0
- package/dist/components/ranged-attack.js +120 -0
- package/dist/components/ranged-attack.js.map +1 -0
- package/dist/components/sprite.d.ts +27 -0
- package/dist/components/sprite.d.ts.map +1 -0
- package/dist/components/sprite.js +122 -0
- package/dist/components/sprite.js.map +1 -0
- package/dist/components/transform.d.ts +30 -0
- package/dist/components/transform.d.ts.map +1 -0
- package/dist/components/transform.js +150 -0
- package/dist/components/transform.js.map +1 -0
- package/dist/director/director-bridge.d.ts +22 -0
- package/dist/director/director-bridge.d.ts.map +1 -0
- package/dist/director/director-bridge.js +23 -0
- package/dist/director/director-bridge.js.map +1 -0
- package/dist/director/director-encounter-system.d.ts +21 -0
- package/dist/director/director-encounter-system.d.ts.map +1 -0
- package/dist/director/director-encounter-system.js +128 -0
- package/dist/director/director-encounter-system.js.map +1 -0
- package/dist/director/director-system.d.ts +19 -0
- package/dist/director/director-system.d.ts.map +1 -0
- package/dist/director/director-system.js +179 -0
- package/dist/director/director-system.js.map +1 -0
- package/dist/director/event-envelope.d.ts +144 -0
- package/dist/director/event-envelope.d.ts.map +1 -0
- package/dist/director/event-envelope.js +108 -0
- package/dist/director/event-envelope.js.map +1 -0
- package/dist/director/knot-context-resource.d.ts +25 -0
- package/dist/director/knot-context-resource.d.ts.map +1 -0
- package/dist/director/knot-context-resource.js +152 -0
- package/dist/director/knot-context-resource.js.map +1 -0
- package/dist/director/mock-director-bridge.d.ts +18 -0
- package/dist/director/mock-director-bridge.d.ts.map +1 -0
- package/dist/director/mock-director-bridge.js +75 -0
- package/dist/director/mock-director-bridge.js.map +1 -0
- package/dist/director/snapshot-recovery.d.ts +37 -0
- package/dist/director/snapshot-recovery.d.ts.map +1 -0
- package/dist/director/snapshot-recovery.js +180 -0
- package/dist/director/snapshot-recovery.js.map +1 -0
- package/dist/director/sse-director-bridge.d.ts +42 -0
- package/dist/director/sse-director-bridge.d.ts.map +1 -0
- package/dist/director/sse-director-bridge.js +280 -0
- package/dist/director/sse-director-bridge.js.map +1 -0
- package/dist/engine.d.ts +25 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +166 -0
- package/dist/engine.js.map +1 -0
- package/dist/entity.d.ts +17 -0
- package/dist/entity.d.ts.map +1 -0
- package/dist/entity.js +77 -0
- package/dist/entity.js.map +1 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -0
- package/dist/input/input-manager.d.ts +91 -0
- package/dist/input/input-manager.d.ts.map +1 -0
- package/dist/input/input-manager.js +349 -0
- package/dist/input/input-manager.js.map +1 -0
- package/dist/input/tap-to-walk.d.ts +27 -0
- package/dist/input/tap-to-walk.d.ts.map +1 -0
- package/dist/input/tap-to-walk.js +118 -0
- package/dist/input/tap-to-walk.js.map +1 -0
- package/dist/input/virtual-dpad.d.ts +34 -0
- package/dist/input/virtual-dpad.d.ts.map +1 -0
- package/dist/input/virtual-dpad.js +267 -0
- package/dist/input/virtual-dpad.js.map +1 -0
- package/dist/renderer/camera.d.ts +26 -0
- package/dist/renderer/camera.d.ts.map +1 -0
- package/dist/renderer/camera.js +39 -0
- package/dist/renderer/camera.js.map +1 -0
- package/dist/renderer/canvas2d-device.d.ts +26 -0
- package/dist/renderer/canvas2d-device.d.ts.map +1 -0
- package/dist/renderer/canvas2d-device.js +252 -0
- package/dist/renderer/canvas2d-device.js.map +1 -0
- package/dist/renderer/graphics-device.d.ts +36 -0
- package/dist/renderer/graphics-device.d.ts.map +1 -0
- package/dist/renderer/graphics-device.js +12 -0
- package/dist/renderer/graphics-device.js.map +1 -0
- package/dist/renderer/iso-projection.d.ts +11 -0
- package/dist/renderer/iso-projection.d.ts.map +1 -0
- package/dist/renderer/iso-projection.js +59 -0
- package/dist/renderer/iso-projection.js.map +1 -0
- package/dist/resources.d.ts +28 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +53 -0
- package/dist/resources.js.map +1 -0
- package/dist/system.d.ts +14 -0
- package/dist/system.d.ts.map +1 -0
- package/dist/system.js +25 -0
- package/dist/system.js.map +1 -0
- package/dist/systems/animation-system.d.ts +8 -0
- package/dist/systems/animation-system.d.ts.map +1 -0
- package/dist/systems/animation-system.js +77 -0
- package/dist/systems/animation-system.js.map +1 -0
- package/dist/systems/attack-system.d.ts +17 -0
- package/dist/systems/attack-system.d.ts.map +1 -0
- package/dist/systems/attack-system.js +94 -0
- package/dist/systems/attack-system.js.map +1 -0
- package/dist/systems/damage-system.d.ts +18 -0
- package/dist/systems/damage-system.d.ts.map +1 -0
- package/dist/systems/damage-system.js +77 -0
- package/dist/systems/damage-system.js.map +1 -0
- package/dist/systems/input-system.d.ts +7 -0
- package/dist/systems/input-system.d.ts.map +1 -0
- package/dist/systems/input-system.js +27 -0
- package/dist/systems/input-system.js.map +1 -0
- package/dist/systems/interaction-system.d.ts +23 -0
- package/dist/systems/interaction-system.d.ts.map +1 -0
- package/dist/systems/interaction-system.js +120 -0
- package/dist/systems/interaction-system.js.map +1 -0
- package/dist/systems/particle-emitter-system.d.ts +8 -0
- package/dist/systems/particle-emitter-system.d.ts.map +1 -0
- package/dist/systems/particle-emitter-system.js +161 -0
- package/dist/systems/particle-emitter-system.js.map +1 -0
- package/dist/systems/particle-render-system.d.ts +7 -0
- package/dist/systems/particle-render-system.d.ts.map +1 -0
- package/dist/systems/particle-render-system.js +53 -0
- package/dist/systems/particle-render-system.js.map +1 -0
- package/dist/systems/particle-simulation-system.d.ts +8 -0
- package/dist/systems/particle-simulation-system.d.ts.map +1 -0
- package/dist/systems/particle-simulation-system.js +45 -0
- package/dist/systems/particle-simulation-system.js.map +1 -0
- package/dist/systems/projectile-render-system.d.ts +7 -0
- package/dist/systems/projectile-render-system.d.ts.map +1 -0
- package/dist/systems/projectile-render-system.js +35 -0
- package/dist/systems/projectile-render-system.js.map +1 -0
- package/dist/systems/projectile-system.d.ts +7 -0
- package/dist/systems/projectile-system.d.ts.map +1 -0
- package/dist/systems/projectile-system.js +114 -0
- package/dist/systems/projectile-system.js.map +1 -0
- package/dist/systems/pursue-system.d.ts +7 -0
- package/dist/systems/pursue-system.d.ts.map +1 -0
- package/dist/systems/pursue-system.js +83 -0
- package/dist/systems/pursue-system.js.map +1 -0
- package/dist/systems/ranged-attack-system.d.ts +7 -0
- package/dist/systems/ranged-attack-system.d.ts.map +1 -0
- package/dist/systems/ranged-attack-system.js +98 -0
- package/dist/systems/ranged-attack-system.js.map +1 -0
- package/dist/systems/sprite-render-system.d.ts +9 -0
- package/dist/systems/sprite-render-system.d.ts.map +1 -0
- package/dist/systems/sprite-render-system.js +108 -0
- package/dist/systems/sprite-render-system.js.map +1 -0
- package/dist/systems/veil-budget-system.d.ts +7 -0
- package/dist/systems/veil-budget-system.d.ts.map +1 -0
- package/dist/systems/veil-budget-system.js +37 -0
- package/dist/systems/veil-budget-system.js.map +1 -0
- package/dist/util/color.d.ts +19 -0
- package/dist/util/color.d.ts.map +1 -0
- package/dist/util/color.js +45 -0
- package/dist/util/color.js.map +1 -0
- package/dist/util/math.d.ts +26 -0
- package/dist/util/math.d.ts.map +1 -0
- package/dist/util/math.js +47 -0
- package/dist/util/math.js.map +1 -0
- package/dist/util/typed-arrays.d.ts +7 -0
- package/dist/util/typed-arrays.d.ts.map +1 -0
- package/dist/util/typed-arrays.js +42 -0
- package/dist/util/typed-arrays.js.map +1 -0
- package/dist/vfx/particle-pool.d.ts +61 -0
- package/dist/vfx/particle-pool.d.ts.map +1 -0
- package/dist/vfx/particle-pool.js +204 -0
- package/dist/vfx/particle-pool.js.map +1 -0
- package/dist/vfx/projectile-pool.d.ts +56 -0
- package/dist/vfx/projectile-pool.d.ts.map +1 -0
- package/dist/vfx/projectile-pool.js +157 -0
- package/dist/vfx/projectile-pool.js.map +1 -0
- package/dist/world.d.ts +23 -0
- package/dist/world.d.ts.map +1 -0
- package/dist/world.js +101 -0
- package/dist/world.js.map +1 -0
- package/dist/zone/zone-catalog.d.ts +17 -0
- package/dist/zone/zone-catalog.d.ts.map +1 -0
- package/dist/zone/zone-catalog.js +116 -0
- package/dist/zone/zone-catalog.js.map +1 -0
- package/dist/zone/zone-state.d.ts +18 -0
- package/dist/zone/zone-state.d.ts.map +1 -0
- package/dist/zone/zone-state.js +52 -0
- package/dist/zone/zone-state.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// ProjectileSystem - simulates in-flight projectiles + applies hit
|
|
2
|
+
// damage when a projectile contacts a HealthPool entity.
|
|
3
|
+
//
|
|
4
|
+
// Pipeline per tick:
|
|
5
|
+
// 1. For each live projectile:
|
|
6
|
+
// - Decrease life by dt; kill if life <= 0
|
|
7
|
+
// - If homing + target alive: re-aim velocity toward target
|
|
8
|
+
// - Integrate position by velocity * dt
|
|
9
|
+
// - Spatial query: any alive Health-bearing entity within hit
|
|
10
|
+
// radius (size/2 in world units, plus a small fudge)?
|
|
11
|
+
// - On hit: apply damage to target; kill projectile unless
|
|
12
|
+
// PIERCE flag is set
|
|
13
|
+
//
|
|
14
|
+
// Runs in PHASE_PHYSICS, alongside ParticleSimulationSystem. The
|
|
15
|
+
// hit query is O(projectiles * targets); for typical Survivor loads
|
|
16
|
+
// (under 50 of each) that's fine. Phase 8+ may add a spatial hash
|
|
17
|
+
// if profile shows the inner loop dominates.
|
|
18
|
+
import { POOL_PROJECTILE, PROJECTILE_FLAG_ALIVE, PROJECTILE_FLAG_HOMING, PROJECTILE_FLAG_PIERCE } from '../vfx/projectile-pool.js';
|
|
19
|
+
import { POOL_HEALTH } from '../components/health.js';
|
|
20
|
+
import { POOL_TRANSFORM } from '../world.js';
|
|
21
|
+
import { makeEntity } from '../entity.js';
|
|
22
|
+
export class ProjectileSystem {
|
|
23
|
+
name = 'projectile';
|
|
24
|
+
update(world, dt) {
|
|
25
|
+
const pool = world.getPool(POOL_PROJECTILE);
|
|
26
|
+
if (!pool)
|
|
27
|
+
return;
|
|
28
|
+
const transforms = world.getPool(POOL_TRANSFORM);
|
|
29
|
+
const health = world.getPool(POOL_HEALTH);
|
|
30
|
+
if (!transforms || !health)
|
|
31
|
+
return;
|
|
32
|
+
const hwm = pool.getHighWaterMark();
|
|
33
|
+
if (hwm === 0)
|
|
34
|
+
return;
|
|
35
|
+
const now = typeof performance !== 'undefined' ? performance.now() : 0;
|
|
36
|
+
for (let i = 0; i < hwm; i++) {
|
|
37
|
+
const f = pool.flags[i] ?? 0;
|
|
38
|
+
if ((f & PROJECTILE_FLAG_ALIVE) === 0)
|
|
39
|
+
continue;
|
|
40
|
+
// Life decay.
|
|
41
|
+
const remaining = (pool.life[i] ?? 0) - dt;
|
|
42
|
+
if (remaining <= 0) {
|
|
43
|
+
pool.kill(i);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
pool.life[i] = remaining;
|
|
47
|
+
// Homing: re-aim velocity toward target each tick.
|
|
48
|
+
if ((f & PROJECTILE_FLAG_HOMING) !== 0) {
|
|
49
|
+
const targetIdx = pool.targetIndex[i] ?? -1;
|
|
50
|
+
if (targetIdx >= 0) {
|
|
51
|
+
const target = makeEntity(targetIdx, 0);
|
|
52
|
+
if (health.isAlive(target)) {
|
|
53
|
+
const tx = transforms.x[targetIdx] ?? 0;
|
|
54
|
+
const ty = transforms.y[targetIdx] ?? 0;
|
|
55
|
+
const tz = transforms.z[targetIdx] ?? 0;
|
|
56
|
+
const dx = tx - (pool.x[i] ?? 0);
|
|
57
|
+
const dy = ty - (pool.y[i] ?? 0);
|
|
58
|
+
const dz = tz - (pool.z[i] ?? 0);
|
|
59
|
+
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
60
|
+
if (dist > 1e-6) {
|
|
61
|
+
const speed = Math.sqrt((pool.vx[i] ?? 0) ** 2 +
|
|
62
|
+
(pool.vy[i] ?? 0) ** 2 +
|
|
63
|
+
(pool.vz[i] ?? 0) ** 2);
|
|
64
|
+
pool.vx[i] = (dx / dist) * speed;
|
|
65
|
+
pool.vy[i] = (dy / dist) * speed;
|
|
66
|
+
pool.vz[i] = (dz / dist) * speed;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Integrate position.
|
|
72
|
+
pool.x[i] = (pool.x[i] ?? 0) + (pool.vx[i] ?? 0) * dt;
|
|
73
|
+
pool.y[i] = (pool.y[i] ?? 0) + (pool.vy[i] ?? 0) * dt;
|
|
74
|
+
pool.z[i] = (pool.z[i] ?? 0) + (pool.vz[i] ?? 0) * dt;
|
|
75
|
+
// Hit detection: scan HealthPool for alive entities within
|
|
76
|
+
// hit radius. Skip the projectile's owner.
|
|
77
|
+
const px = pool.x[i] ?? 0;
|
|
78
|
+
const py = pool.y[i] ?? 0;
|
|
79
|
+
const owner = pool.ownerIndex[i] ?? -1;
|
|
80
|
+
const hitRadius = (pool.size[i] ?? 4) * 0.05; // size pixels -> world units, approx
|
|
81
|
+
const hitRadiusSq = hitRadius * hitRadius;
|
|
82
|
+
const targetHwm = health.getHighWaterMark();
|
|
83
|
+
let hitIdx = -1;
|
|
84
|
+
for (let j = 1; j < targetHwm; j++) {
|
|
85
|
+
if (j === owner)
|
|
86
|
+
continue;
|
|
87
|
+
const target = makeEntity(j, 0);
|
|
88
|
+
if (!health.isAlive(target))
|
|
89
|
+
continue;
|
|
90
|
+
const tx = transforms.x[j] ?? 0;
|
|
91
|
+
const ty = transforms.y[j] ?? 0;
|
|
92
|
+
const dx = tx - px;
|
|
93
|
+
const dy = ty - py;
|
|
94
|
+
// Use a slightly larger hit radius for tile-space contact -
|
|
95
|
+
// 0.5 world units is roughly half a tile and matches the
|
|
96
|
+
// existing PursueSystem stopDistance defaults.
|
|
97
|
+
const contactSq = 0.5 * 0.5;
|
|
98
|
+
const distSq = dx * dx + dy * dy;
|
|
99
|
+
if (distSq < Math.max(hitRadiusSq, contactSq)) {
|
|
100
|
+
hitIdx = j;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (hitIdx >= 0) {
|
|
105
|
+
const target = makeEntity(hitIdx, 0);
|
|
106
|
+
health.applyDamage(target, pool.damage[i] ?? 0, now);
|
|
107
|
+
if ((f & PROJECTILE_FLAG_PIERCE) === 0) {
|
|
108
|
+
pool.kill(i);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=projectile-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectile-system.js","sourceRoot":"","sources":["../../src/systems/projectile-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pursue-system.d.ts","sourceRoot":"","sources":["../../src/systems/pursue-system.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAOzC,qBAAa,YAAa,YAAW,MAAM;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAY;IAEjC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;CAmEvC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// PursueSystem - per-tick enemy AI advance.
|
|
2
|
+
//
|
|
3
|
+
// For each entity with a PursueComponent + Transform, walks the
|
|
4
|
+
// entity toward its target's Transform at the configured speed.
|
|
5
|
+
// When in stop-distance, stops moving and (if contactDamage > 0
|
|
6
|
+
// and cooldown elapsed) applies contact damage to the target.
|
|
7
|
+
//
|
|
8
|
+
// Runs in PHASE_LOGIC, after the input-driven systems (camera,
|
|
9
|
+
// click) so target positions are settled, before DamageSystem
|
|
10
|
+
// (PHASE_LOGIC later in the registration order) so the damage
|
|
11
|
+
// applied this tick is reflected in the cleanup pass.
|
|
12
|
+
import { POOL_TRANSFORM } from '../world.js';
|
|
13
|
+
import { POOL_PURSUE, PURSUE_FLAG_ACTIVE } from '../components/pursue.js';
|
|
14
|
+
import { POOL_HEALTH } from '../components/health.js';
|
|
15
|
+
import { makeEntity } from '../entity.js';
|
|
16
|
+
export class PursueSystem {
|
|
17
|
+
name = 'pursue';
|
|
18
|
+
update(world, dt) {
|
|
19
|
+
const transforms = world.getPool(POOL_TRANSFORM);
|
|
20
|
+
const pursuit = world.getPool(POOL_PURSUE);
|
|
21
|
+
if (!transforms || !pursuit)
|
|
22
|
+
return;
|
|
23
|
+
const health = world.getPool(POOL_HEALTH);
|
|
24
|
+
const hwm = pursuit.getHighWaterMark();
|
|
25
|
+
const now = typeof performance !== 'undefined' ? performance.now() : 0;
|
|
26
|
+
for (let i = 1; i < hwm; i++) {
|
|
27
|
+
const f = pursuit.flags[i] ?? 0;
|
|
28
|
+
if ((f & PURSUE_FLAG_ACTIVE) === 0)
|
|
29
|
+
continue;
|
|
30
|
+
// Skip dead pursuers.
|
|
31
|
+
if (health) {
|
|
32
|
+
const e = makeEntity(i, 0);
|
|
33
|
+
if (health.isDead(e)) {
|
|
34
|
+
pursuit.flags[i] = 0;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const targetIdx = pursuit.targetIndex[i] ?? -1;
|
|
39
|
+
if (targetIdx < 0)
|
|
40
|
+
continue;
|
|
41
|
+
// If the target is dead, stop pursuing.
|
|
42
|
+
if (health && health.isDead(makeEntity(targetIdx, 0))) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const myX = transforms.x[i] ?? 0;
|
|
46
|
+
const myY = transforms.y[i] ?? 0;
|
|
47
|
+
const tx = transforms.x[targetIdx] ?? 0;
|
|
48
|
+
const ty = transforms.y[targetIdx] ?? 0;
|
|
49
|
+
const dx = tx - myX;
|
|
50
|
+
const dy = ty - myY;
|
|
51
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
52
|
+
const stopDist = pursuit.stopDistance[i] ?? 0;
|
|
53
|
+
if (dist > stopDist) {
|
|
54
|
+
// Walk toward target. Normalize delta + step by speed * dt.
|
|
55
|
+
const speed = pursuit.speed[i] ?? 0;
|
|
56
|
+
const step = speed * dt;
|
|
57
|
+
const nx = dist > 0 ? dx / dist : 0;
|
|
58
|
+
const ny = dist > 0 ? dy / dist : 0;
|
|
59
|
+
// Don't overshoot.
|
|
60
|
+
const moveX = step >= dist ? dx : nx * step;
|
|
61
|
+
const moveY = step >= dist ? dy : ny * step;
|
|
62
|
+
const e = makeEntity(i, 0);
|
|
63
|
+
transforms.setPosition(e, myX + moveX, myY + moveY, transforms.z[i] ?? 0);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// In contact range. Apply contact damage if cooldown elapsed.
|
|
67
|
+
const damage = pursuit.contactDamage[i] ?? 0;
|
|
68
|
+
if (damage > 0 && health) {
|
|
69
|
+
const lastHit = pursuit.lastHitMs[i] ?? -1;
|
|
70
|
+
const cooldown = pursuit.contactCooldownMs[i] ?? 1000;
|
|
71
|
+
if (lastHit < 0 || now - lastHit >= cooldown) {
|
|
72
|
+
const target = makeEntity(targetIdx, 0);
|
|
73
|
+
const applied = health.applyDamage(target, damage, now);
|
|
74
|
+
if (applied > 0) {
|
|
75
|
+
pursuit.lastHitMs[i] = now;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=pursue-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pursue-system.js","sourceRoot":"","sources":["../../src/systems/pursue-system.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,EAAE;AACF,gEAAgE;AAChE,gEAAgE;AAChE,gEAAgE;AAChE,8DAA8D;AAC9D,EAAE;AACF,+DAA+D;AAC/D,8DAA8D;AAC9D,8DAA8D;AAC9D,sDAAsD;AAItD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAc,WAAW,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AACtF,OAAO,EAAc,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,OAAO,YAAY;IACd,IAAI,GAAW,QAAQ,CAAC;IAEjC,MAAM,CAAC,KAAY,EAAE,EAAU;QAC7B,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAgB,cAAc,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAa,WAAW,CAAC,CAAC;QACvD,IAAI,CAAC,UAAU,IAAI,CAAC,OAAO;YAAE,OAAO;QACpC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAa,WAAW,CAAC,CAAC;QAEtD,MAAM,GAAG,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,OAAO,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC;gBAAE,SAAS;YAE7C,sBAAsB;YACtB,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3B,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrB,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;YACH,CAAC;YAED,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/C,IAAI,SAAS,GAAG,CAAC;gBAAE,SAAS;YAC5B,wCAAwC;YACxC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACtD,SAAS;YACX,CAAC;YAED,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAExC,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;YACpB,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAE9C,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;gBACpB,4DAA4D;gBAC5D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBACpC,MAAM,IAAI,GAAG,KAAK,GAAG,EAAE,CAAC;gBACxB,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpC,MAAM,EAAE,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpC,mBAAmB;gBACnB,MAAM,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;gBAC5C,MAAM,KAAK,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC;gBAC5C,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC3B,UAAU,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,GAAG,KAAK,EAAE,GAAG,GAAG,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5E,CAAC;iBAAM,CAAC;gBACN,8DAA8D;gBAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;gBAC7C,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,EAAE,CAAC;oBACzB,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;oBACtD,IAAI,OAAO,GAAG,CAAC,IAAI,GAAG,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC;wBAC7C,MAAM,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;wBACxC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;wBACxD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;4BAChB,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;wBAC7B,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
export declare class RangedAttackSystem implements System {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
update(world: World, _dt: number): void;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=ranged-attack-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranged-attack-system.d.ts","sourceRoot":"","sources":["../../src/systems/ranged-attack-system.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAazC,qBAAa,kBAAmB,YAAW,MAAM;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAmB;IAExC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CA6ExC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// RangedAttackSystem - per-tick ranged-attack scheduler.
|
|
2
|
+
//
|
|
3
|
+
// For each active RangedAttackPool entry:
|
|
4
|
+
// 1. Read the firing entity's transform + the target's transform
|
|
5
|
+
// 2. If target alive AND distance is in [minRange, range] AND
|
|
6
|
+
// cooldown elapsed: spawn a projectile aimed at the target
|
|
7
|
+
// with the configured params
|
|
8
|
+
// 3. Otherwise no-op for this tick
|
|
9
|
+
//
|
|
10
|
+
// Runs in PHASE_LOGIC, after PursueSystem (so positions are up to
|
|
11
|
+
// date) and before DamageSystem cleanup. Spawns projectiles into
|
|
12
|
+
// the shared ProjectilePool which ProjectileSystem (PHASE_PHYSICS)
|
|
13
|
+
// will then advance + collide.
|
|
14
|
+
import { POOL_TRANSFORM } from '../world.js';
|
|
15
|
+
import { POOL_RANGED, RANGED_FLAG_ACTIVE, RANGED_FLAG_HOMING, } from '../components/ranged-attack.js';
|
|
16
|
+
import { POOL_PROJECTILE } from '../vfx/projectile-pool.js';
|
|
17
|
+
import { POOL_HEALTH } from '../components/health.js';
|
|
18
|
+
import { makeEntity } from '../entity.js';
|
|
19
|
+
export class RangedAttackSystem {
|
|
20
|
+
name = 'ranged-attack';
|
|
21
|
+
update(world, _dt) {
|
|
22
|
+
const ranged = world.getPool(POOL_RANGED);
|
|
23
|
+
if (!ranged)
|
|
24
|
+
return;
|
|
25
|
+
const transforms = world.getPool(POOL_TRANSFORM);
|
|
26
|
+
const projectiles = world.getPool(POOL_PROJECTILE);
|
|
27
|
+
const health = world.getPool(POOL_HEALTH);
|
|
28
|
+
if (!transforms || !projectiles || !health)
|
|
29
|
+
return;
|
|
30
|
+
const hwm = ranged.getHighWaterMark();
|
|
31
|
+
const now = typeof performance !== 'undefined' ? performance.now() : 0;
|
|
32
|
+
for (let i = 1; i < hwm; i++) {
|
|
33
|
+
const f = ranged.flags[i] ?? 0;
|
|
34
|
+
if ((f & RANGED_FLAG_ACTIVE) === 0)
|
|
35
|
+
continue;
|
|
36
|
+
// Skip dead firers.
|
|
37
|
+
const firer = makeEntity(i, 0);
|
|
38
|
+
if (!health.isAlive(firer)) {
|
|
39
|
+
ranged.flags[i] = 0;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const targetIdx = ranged.targetIndex[i] ?? -1;
|
|
43
|
+
if (targetIdx < 0)
|
|
44
|
+
continue;
|
|
45
|
+
const target = makeEntity(targetIdx, 0);
|
|
46
|
+
if (!health.isAlive(target))
|
|
47
|
+
continue;
|
|
48
|
+
// Cooldown gate.
|
|
49
|
+
const cooldown = ranged.cooldownMs[i] ?? 1000;
|
|
50
|
+
const lastFire = ranged.lastFireMs[i] ?? -1;
|
|
51
|
+
if (lastFire >= 0 && now - lastFire < cooldown)
|
|
52
|
+
continue;
|
|
53
|
+
// Range check.
|
|
54
|
+
const myX = transforms.x[i] ?? 0;
|
|
55
|
+
const myY = transforms.y[i] ?? 0;
|
|
56
|
+
const tx = transforms.x[targetIdx] ?? 0;
|
|
57
|
+
const ty = transforms.y[targetIdx] ?? 0;
|
|
58
|
+
const dx = tx - myX;
|
|
59
|
+
const dy = ty - myY;
|
|
60
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
61
|
+
const range = ranged.range[i] ?? 0;
|
|
62
|
+
const minRange = ranged.minRange[i] ?? 0;
|
|
63
|
+
if (dist > range || dist < minRange)
|
|
64
|
+
continue;
|
|
65
|
+
// Fire. Velocity = direction normalized * projectileSpeed.
|
|
66
|
+
const speed = ranged.projectileSpeed[i] ?? 1;
|
|
67
|
+
const norm = dist > 1e-6 ? 1 / dist : 0;
|
|
68
|
+
const vx = dx * norm * speed;
|
|
69
|
+
const vy = dy * norm * speed;
|
|
70
|
+
const homing = (f & RANGED_FLAG_HOMING) !== 0;
|
|
71
|
+
const slot = projectiles.spawn({
|
|
72
|
+
x: myX,
|
|
73
|
+
y: myY,
|
|
74
|
+
z: transforms.z[i] ?? 0.5,
|
|
75
|
+
vx,
|
|
76
|
+
vy,
|
|
77
|
+
vz: 0,
|
|
78
|
+
life: ranged.projectileLife[i] ?? 2.0,
|
|
79
|
+
damage: ranged.damage[i] ?? 1,
|
|
80
|
+
ownerIndex: i,
|
|
81
|
+
targetIndex: homing ? targetIdx : -1,
|
|
82
|
+
size: ranged.projectileSize[i] ?? 5,
|
|
83
|
+
color: {
|
|
84
|
+
r: ranged.r[i] ?? 1,
|
|
85
|
+
g: ranged.g[i] ?? 1,
|
|
86
|
+
b: ranged.b[i] ?? 1,
|
|
87
|
+
a: ranged.a[i] ?? 1,
|
|
88
|
+
},
|
|
89
|
+
homing,
|
|
90
|
+
pierce: false,
|
|
91
|
+
});
|
|
92
|
+
if (slot >= 0) {
|
|
93
|
+
ranged.lastFireMs[i] = now;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=ranged-attack-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranged-attack-system.js","sourceRoot":"","sources":["../../src/systems/ranged-attack-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
export declare class SpriteRenderSystem implements System {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
private sortBuffer;
|
|
6
|
+
private scratchTint;
|
|
7
|
+
update(world: World, _dt: number): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=sprite-render-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite-render-system.d.ts","sourceRoot":"","sources":["../../src/systems/sprite-render-system.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAgBzC,qBAAa,kBAAmB,YAAW,MAAM;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAmB;IAIxC,OAAO,CAAC,UAAU,CAAmB;IAOrC,OAAO,CAAC,WAAW,CAEjB;IAEF,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CA0ExC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// SpriteRenderSystem - iterates entities with both Transform and
|
|
2
|
+
// Sprite components and submits drawSprite calls to the device.
|
|
3
|
+
//
|
|
4
|
+
// This is the first real ECS system in the engine. Everything in
|
|
5
|
+
// the demo that previously called device.drawSprite directly now
|
|
6
|
+
// goes through here.
|
|
7
|
+
//
|
|
8
|
+
// v1 sort: simple back-to-front by iso depth key (x + y), with
|
|
9
|
+
// per-frame allocation of a sort buffer. Phase 2 keeps this naive;
|
|
10
|
+
// optimization (radix sort, persistent buffer) deferred to Phase 4
|
|
11
|
+
// when the VFX framework adds many additive sprites that will
|
|
12
|
+
// expose any sort cost.
|
|
13
|
+
import { POOL_TRANSFORM, POOL_SPRITE } from '../world.js';
|
|
14
|
+
import { TRANSFORM_FLAG_VISIBLE } from '../components/transform.js';
|
|
15
|
+
import { SPRITE_FLAG_ACTIVE, SPRITE_FLAG_TINTED } from '../components/sprite.js';
|
|
16
|
+
import { RESOURCE_DEVICE, RESOURCE_CAMERA, } from '../resources.js';
|
|
17
|
+
export class SpriteRenderSystem {
|
|
18
|
+
name = 'sprite-render';
|
|
19
|
+
// Persistent sort buffer to avoid per-frame allocation. Resized
|
|
20
|
+
// when entity count grows past it.
|
|
21
|
+
sortBuffer = [];
|
|
22
|
+
// Scratch tint object reused across all tinted-sprite draws this
|
|
23
|
+
// frame. Phase 9.1: replaces a per-tinted-sprite allocation with
|
|
24
|
+
// one mutate-and-pass. drawSprite reads ColorRGBA fields by name
|
|
25
|
+
// and does not retain the reference past the call, so reuse is
|
|
26
|
+
// safe and avoids ~N tint-object allocations per frame.
|
|
27
|
+
scratchTint = {
|
|
28
|
+
r: 1, g: 1, b: 1, a: 1,
|
|
29
|
+
};
|
|
30
|
+
update(world, _dt) {
|
|
31
|
+
const transforms = world.getPool(POOL_TRANSFORM);
|
|
32
|
+
const sprites = world.getPool(POOL_SPRITE);
|
|
33
|
+
const device = world.resources.get(RESOURCE_DEVICE);
|
|
34
|
+
const camera = world.resources.get(RESOURCE_CAMERA);
|
|
35
|
+
if (!transforms || !sprites || !device || !camera)
|
|
36
|
+
return;
|
|
37
|
+
device.setCamera(camera);
|
|
38
|
+
const hwm = Math.min(transforms.getHighWaterMark(), sprites.getHighWaterMark());
|
|
39
|
+
// Build the sort list - one entry per active sprite with a
|
|
40
|
+
// visible transform. Reuse the buffer; grow only when needed.
|
|
41
|
+
let count = 0;
|
|
42
|
+
while (this.sortBuffer.length < hwm) {
|
|
43
|
+
this.sortBuffer.push({ index: 0, depth: 0 });
|
|
44
|
+
}
|
|
45
|
+
for (let i = 1; i < hwm; i++) { // index 0 is NULL_ENTITY, skip
|
|
46
|
+
const tFlags = transforms.flags[i] ?? 0;
|
|
47
|
+
const sFlags = sprites.flags[i] ?? 0;
|
|
48
|
+
if ((tFlags & TRANSFORM_FLAG_VISIBLE) === 0)
|
|
49
|
+
continue;
|
|
50
|
+
if ((sFlags & SPRITE_FLAG_ACTIVE) === 0)
|
|
51
|
+
continue;
|
|
52
|
+
const x = transforms.x[i] ?? 0;
|
|
53
|
+
const y = transforms.y[i] ?? 0;
|
|
54
|
+
const z = transforms.z[i] ?? 0;
|
|
55
|
+
const entry = this.sortBuffer[count];
|
|
56
|
+
if (!entry)
|
|
57
|
+
continue;
|
|
58
|
+
entry.index = i;
|
|
59
|
+
// Iso depth key: (x + y) * 1000 + z. Larger = drawn later.
|
|
60
|
+
entry.depth = (x + y) * 1000 + z;
|
|
61
|
+
count++;
|
|
62
|
+
}
|
|
63
|
+
// Insertion sort. For small N (typical Phase 2 demo: dozens of
|
|
64
|
+
// entities), this beats Array.prototype.sort's overhead. When N
|
|
65
|
+
// grows, we'll swap in a radix sort.
|
|
66
|
+
for (let i = 1; i < count; i++) {
|
|
67
|
+
const key = this.sortBuffer[i];
|
|
68
|
+
if (!key)
|
|
69
|
+
continue;
|
|
70
|
+
let j = i - 1;
|
|
71
|
+
while (j >= 0) {
|
|
72
|
+
const prev = this.sortBuffer[j];
|
|
73
|
+
if (!prev || prev.depth <= key.depth)
|
|
74
|
+
break;
|
|
75
|
+
this.sortBuffer[j + 1] = prev;
|
|
76
|
+
j--;
|
|
77
|
+
}
|
|
78
|
+
this.sortBuffer[j + 1] = key;
|
|
79
|
+
}
|
|
80
|
+
// Submit in sort order.
|
|
81
|
+
for (let k = 0; k < count; k++) {
|
|
82
|
+
const entry = this.sortBuffer[k];
|
|
83
|
+
if (!entry)
|
|
84
|
+
continue;
|
|
85
|
+
const i = entry.index;
|
|
86
|
+
const atlas = sprites.atlas[i] ?? -1;
|
|
87
|
+
if (atlas < 0)
|
|
88
|
+
continue;
|
|
89
|
+
const frame = sprites.frame[i] ?? 0;
|
|
90
|
+
const x = transforms.x[i] ?? 0;
|
|
91
|
+
const y = transforms.y[i] ?? 0;
|
|
92
|
+
const z = transforms.z[i] ?? 0;
|
|
93
|
+
const sFlags = sprites.flags[i] ?? 0;
|
|
94
|
+
if ((sFlags & SPRITE_FLAG_TINTED) !== 0) {
|
|
95
|
+
const tint = this.scratchTint;
|
|
96
|
+
tint.r = sprites.tintR[i] ?? 1;
|
|
97
|
+
tint.g = sprites.tintG[i] ?? 1;
|
|
98
|
+
tint.b = sprites.tintB[i] ?? 1;
|
|
99
|
+
tint.a = sprites.tintA[i] ?? 1;
|
|
100
|
+
device.drawSprite(x, y, z, atlas, frame, tint);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
device.drawSprite(x, y, z, atlas, frame);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=sprite-render-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprite-render-system.js","sourceRoot":"","sources":["../../src/systems/sprite-render-system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { System } from '../system.js';
|
|
2
|
+
import type { World } from '../world.js';
|
|
3
|
+
export declare class VeilBudgetSystem implements System {
|
|
4
|
+
readonly name: string;
|
|
5
|
+
update(world: World, _dt: number): void;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=veil-budget-system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"veil-budget-system.d.ts","sourceRoot":"","sources":["../../src/systems/veil-budget-system.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AASzC,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAiB;IAEtC,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;CAYxC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// VeilBudgetSystem - reads the VeilBudgetResource each tick and
|
|
2
|
+
// propagates its values into the engine subsystems that gate on it.
|
|
3
|
+
//
|
|
4
|
+
// Phase 5 wiring:
|
|
5
|
+
// audioBudget -> AudioBus.setAudioBudget(budget)
|
|
6
|
+
// particleBudget -> ParticlePool.setMaxParticles(budget)
|
|
7
|
+
//
|
|
8
|
+
// This is the cheap-but-explicit propagation step. Subsystems could
|
|
9
|
+
// subscribe to budget changes directly, but a polling system is
|
|
10
|
+
// simpler and runs in O(1) since the bus / pool ignore set-same.
|
|
11
|
+
//
|
|
12
|
+
// Runs in PHASE_INPUT immediately after InputSystem, so by the time
|
|
13
|
+
// gameplay logic / particle emit / audio play* calls happen later in
|
|
14
|
+
// the tick, gates are current.
|
|
15
|
+
//
|
|
16
|
+
// The Director-bridge in Phase 6 mutates budget values directly on
|
|
17
|
+
// the resource; this system is what makes those mutations visible to
|
|
18
|
+
// audio + VFX.
|
|
19
|
+
import { RESOURCE_VEIL_BUDGET, } from '../resources.js';
|
|
20
|
+
import { RESOURCE_AUDIO_BUS } from '../audio/audio-bus.js';
|
|
21
|
+
import { POOL_PARTICLE } from './particle-simulation-system.js';
|
|
22
|
+
export class VeilBudgetSystem {
|
|
23
|
+
name = 'veil-budget';
|
|
24
|
+
update(world, _dt) {
|
|
25
|
+
const budget = world.resources.get(RESOURCE_VEIL_BUDGET);
|
|
26
|
+
if (!budget)
|
|
27
|
+
return;
|
|
28
|
+
const audio = world.resources.get(RESOURCE_AUDIO_BUS);
|
|
29
|
+
if (audio)
|
|
30
|
+
audio.setAudioBudget(budget.audioBudget);
|
|
31
|
+
const particles = world.getPool(POOL_PARTICLE);
|
|
32
|
+
if (particles && particles.getMaxParticles() !== budget.particleBudget) {
|
|
33
|
+
particles.setMaxParticles(budget.particleBudget);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=veil-budget-system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"veil-budget-system.js","sourceRoot":"","sources":["../../src/systems/veil-budget-system.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,oEAAoE;AACpE,EAAE;AACF,kBAAkB;AAClB,sDAAsD;AACtD,2DAA2D;AAC3D,EAAE;AACF,oEAAoE;AACpE,gEAAgE;AAChE,iEAAiE;AACjE,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,+BAA+B;AAC/B,EAAE;AACF,mEAAmE;AACnE,qEAAqE;AACrE,eAAe;AAIf,OAAO,EACL,oBAAoB,GAErB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAY,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAEhE,MAAM,OAAO,gBAAgB;IAClB,IAAI,GAAW,aAAa,CAAC;IAEtC,MAAM,CAAC,KAAY,EAAE,GAAW;QAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAqB,oBAAoB,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM;YAAE,OAAO;QAEpB,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAW,kBAAkB,CAAC,CAAC;QAChE,IAAI,KAAK;YAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEpD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAe,aAAa,CAAC,CAAC;QAC7D,IAAI,SAAS,IAAI,SAAS,CAAC,eAAe,EAAE,KAAK,MAAM,CAAC,cAAc,EAAE,CAAC;YACvE,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ColorRGBA {
|
|
2
|
+
r: number;
|
|
3
|
+
g: number;
|
|
4
|
+
b: number;
|
|
5
|
+
a: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function rgba(r: number, g: number, b: number, a: number): ColorRGBA;
|
|
8
|
+
export declare const COLOR_WHITE: Readonly<ColorRGBA>;
|
|
9
|
+
export declare const COLOR_BLACK: Readonly<ColorRGBA>;
|
|
10
|
+
export declare const COLOR_TRANSPARENT: Readonly<ColorRGBA>;
|
|
11
|
+
export declare const COLOR_KNOT_STR: Readonly<ColorRGBA>;
|
|
12
|
+
export declare const COLOR_KNOT_DEX: Readonly<ColorRGBA>;
|
|
13
|
+
export declare const COLOR_KNOT_INT: Readonly<ColorRGBA>;
|
|
14
|
+
export declare const COLOR_KNOT_CENTER: Readonly<ColorRGBA>;
|
|
15
|
+
export declare function hexToRgba(hex: number, alpha?: number): ColorRGBA;
|
|
16
|
+
export declare function rgbaToHexString(c: ColorRGBA): string;
|
|
17
|
+
export declare function rgbaToCssString(c: ColorRGBA): string;
|
|
18
|
+
export declare function colorLerp(a: ColorRGBA, b: ColorRGBA, t: number, out: ColorRGBA): ColorRGBA;
|
|
19
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/util/color.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAE1E;AAED,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,SAAS,CAA6C,CAAC;AAC1F,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,SAAS,CAA6C,CAAC;AAC1F,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,SAAS,CAA6C,CAAC;AAGhG,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,SAAS,CAAsC,CAAC;AACtF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,SAAS,CAAsC,CAAC;AACtF,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,SAAS,CAAsC,CAAC;AACtF,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,SAAS,CAAsC,CAAC;AAEzF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,SAAS,CAOnE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAKpD;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAKpD;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,SAAS,CAM1F"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Color types and helpers for the Loom Engine.
|
|
2
|
+
//
|
|
3
|
+
// Two representations:
|
|
4
|
+
// - ColorRGBA: 4 floats in [0,1]. Used in tints, gradients, blending.
|
|
5
|
+
// - Hex24: a packed 0xRRGGBB integer. Used in atlas tints and palette
|
|
6
|
+
// storage where memory matters.
|
|
7
|
+
export function rgba(r, g, b, a) {
|
|
8
|
+
return { r, g, b, a };
|
|
9
|
+
}
|
|
10
|
+
export const COLOR_WHITE = Object.freeze({ r: 1, g: 1, b: 1, a: 1 });
|
|
11
|
+
export const COLOR_BLACK = Object.freeze({ r: 0, g: 0, b: 0, a: 1 });
|
|
12
|
+
export const COLOR_TRANSPARENT = Object.freeze({ r: 0, g: 0, b: 0, a: 0 });
|
|
13
|
+
// Knot palette per LOOM-CLASS-SYSTEM-SPEC Section 4.
|
|
14
|
+
export const COLOR_KNOT_STR = Object.freeze(hexToRgba(0xb04a24));
|
|
15
|
+
export const COLOR_KNOT_DEX = Object.freeze(hexToRgba(0x5ac9d6));
|
|
16
|
+
export const COLOR_KNOT_INT = Object.freeze(hexToRgba(0x9b5de5));
|
|
17
|
+
export const COLOR_KNOT_CENTER = Object.freeze(hexToRgba(0xffd86a));
|
|
18
|
+
export function hexToRgba(hex, alpha = 1) {
|
|
19
|
+
return {
|
|
20
|
+
r: ((hex >> 16) & 0xff) / 255,
|
|
21
|
+
g: ((hex >> 8) & 0xff) / 255,
|
|
22
|
+
b: (hex & 0xff) / 255,
|
|
23
|
+
a: alpha,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function rgbaToHexString(c) {
|
|
27
|
+
const r = Math.round(c.r * 255) & 0xff;
|
|
28
|
+
const g = Math.round(c.g * 255) & 0xff;
|
|
29
|
+
const b = Math.round(c.b * 255) & 0xff;
|
|
30
|
+
return '#' + r.toString(16).padStart(2, '0') + g.toString(16).padStart(2, '0') + b.toString(16).padStart(2, '0');
|
|
31
|
+
}
|
|
32
|
+
export function rgbaToCssString(c) {
|
|
33
|
+
const r = Math.round(c.r * 255) & 0xff;
|
|
34
|
+
const g = Math.round(c.g * 255) & 0xff;
|
|
35
|
+
const b = Math.round(c.b * 255) & 0xff;
|
|
36
|
+
return 'rgba(' + r + ',' + g + ',' + b + ',' + c.a.toFixed(3) + ')';
|
|
37
|
+
}
|
|
38
|
+
export function colorLerp(a, b, t, out) {
|
|
39
|
+
out.r = a.r + (b.r - a.r) * t;
|
|
40
|
+
out.g = a.g + (b.g - a.g) * t;
|
|
41
|
+
out.b = a.b + (b.b - a.b) * t;
|
|
42
|
+
out.a = a.a + (b.a - a.a) * t;
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/util/color.ts"],"names":[],"mappings":"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"}
|