@thewhateverapp/tile-sdk 0.15.3 → 0.15.4

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.
Files changed (51) hide show
  1. package/dist/excalibur/index.d.ts +48 -0
  2. package/dist/excalibur/index.d.ts.map +1 -0
  3. package/dist/excalibur/index.js +51 -0
  4. package/dist/react/ExcaliburGame.d.ts +109 -0
  5. package/dist/react/ExcaliburGame.d.ts.map +1 -0
  6. package/dist/react/ExcaliburGame.js +215 -0
  7. package/dist/react/index.js +3 -3
  8. package/dist/scene/index.d.ts +3 -41
  9. package/dist/scene/index.d.ts.map +1 -1
  10. package/dist/scene/index.js +1 -49
  11. package/dist/spec/schema.d.ts +12 -12
  12. package/package.json +7 -7
  13. package/dist/pixi/index.d.ts +0 -43
  14. package/dist/pixi/index.d.ts.map +0 -1
  15. package/dist/pixi/index.js +0 -46
  16. package/dist/react/PixiGame.d.ts +0 -138
  17. package/dist/react/PixiGame.d.ts.map +0 -1
  18. package/dist/react/PixiGame.js +0 -237
  19. package/dist/scene/SceneContext.d.ts +0 -173
  20. package/dist/scene/SceneContext.d.ts.map +0 -1
  21. package/dist/scene/SceneContext.js +0 -89
  22. package/dist/scene/SceneFromJson.d.ts +0 -34
  23. package/dist/scene/SceneFromJson.d.ts.map +0 -1
  24. package/dist/scene/SceneFromJson.js +0 -97
  25. package/dist/scene/SceneRenderer.d.ts +0 -29
  26. package/dist/scene/SceneRenderer.d.ts.map +0 -1
  27. package/dist/scene/SceneRenderer.js +0 -312
  28. package/dist/scene/camera/CameraController.d.ts +0 -6
  29. package/dist/scene/camera/CameraController.d.ts.map +0 -1
  30. package/dist/scene/camera/CameraController.js +0 -90
  31. package/dist/scene/components/ComponentRunner.d.ts +0 -22
  32. package/dist/scene/components/ComponentRunner.d.ts.map +0 -1
  33. package/dist/scene/components/ComponentRunner.js +0 -210
  34. package/dist/scene/effects/GlowFilter.d.ts +0 -38
  35. package/dist/scene/effects/GlowFilter.d.ts.map +0 -1
  36. package/dist/scene/effects/GlowFilter.js +0 -40
  37. package/dist/scene/effects/ParticleSystem.d.ts +0 -52
  38. package/dist/scene/effects/ParticleSystem.d.ts.map +0 -1
  39. package/dist/scene/effects/ParticleSystem.js +0 -107
  40. package/dist/scene/entities/EntityGraphics.d.ts +0 -26
  41. package/dist/scene/entities/EntityGraphics.d.ts.map +0 -1
  42. package/dist/scene/entities/EntityGraphics.js +0 -226
  43. package/dist/scene/input/InputManager.d.ts +0 -18
  44. package/dist/scene/input/InputManager.d.ts.map +0 -1
  45. package/dist/scene/input/InputManager.js +0 -86
  46. package/dist/scene/physics/PhysicsEngine.d.ts +0 -15
  47. package/dist/scene/physics/PhysicsEngine.d.ts.map +0 -1
  48. package/dist/scene/physics/PhysicsEngine.js +0 -260
  49. package/dist/scene/timeline/TimelineExecutor.d.ts +0 -6
  50. package/dist/scene/timeline/TimelineExecutor.d.ts.map +0 -1
  51. package/dist/scene/timeline/TimelineExecutor.js +0 -241
@@ -1,226 +0,0 @@
1
- 'use client';
2
- /**
3
- * EntityGraphics - Imperative pixi.js graphics creation for entities
4
- *
5
- * This module creates and updates pixi objects directly without React reconciler.
6
- */
7
- import * as PIXI from 'pixi.js';
8
- /**
9
- * Parse hex color string to number
10
- */
11
- function parseColor(color) {
12
- return parseInt(color.replace('#', ''), 16);
13
- }
14
- /**
15
- * Create pixi graphics for an entity
16
- */
17
- export function createEntityGraphics(state, debug = false) {
18
- const container = new PIXI.Container();
19
- let graphics = null;
20
- let text = null;
21
- let sprite = null;
22
- let debugGraphics = null;
23
- const { entity } = state;
24
- const kind = entity.kind;
25
- // Parse colors
26
- const fillColor = parseColor(state.fill ?? entity.render?.fill ?? '#ffffff');
27
- const strokeColor = entity.render?.stroke ? parseColor(entity.render.stroke) : undefined;
28
- const strokeWidth = entity.render?.strokeWidth ?? 0;
29
- switch (kind) {
30
- case 'rect': {
31
- const geom = entity.geom;
32
- graphics = new PIXI.Graphics();
33
- drawRect(graphics, geom, fillColor, strokeColor, strokeWidth);
34
- container.addChild(graphics);
35
- if (debug) {
36
- debugGraphics = new PIXI.Graphics();
37
- drawDebugBounds(debugGraphics, geom);
38
- container.addChild(debugGraphics);
39
- }
40
- break;
41
- }
42
- case 'circle': {
43
- const geom = entity.geom;
44
- graphics = new PIXI.Graphics();
45
- drawCircle(graphics, geom, fillColor, strokeColor, strokeWidth);
46
- container.addChild(graphics);
47
- break;
48
- }
49
- case 'poly': {
50
- const geom = entity.geom;
51
- graphics = new PIXI.Graphics();
52
- drawPoly(graphics, geom, fillColor, strokeColor, strokeWidth);
53
- container.addChild(graphics);
54
- break;
55
- }
56
- case 'line': {
57
- const geom = entity.geom;
58
- graphics = new PIXI.Graphics();
59
- drawLine(graphics, geom, strokeColor ?? fillColor);
60
- container.addChild(graphics);
61
- break;
62
- }
63
- case 'text': {
64
- const geom = entity.geom;
65
- text = createTextElement(geom, fillColor);
66
- container.addChild(text);
67
- break;
68
- }
69
- case 'sprite': {
70
- const geom = entity.geom;
71
- // For now, draw a placeholder since we don't have texture loading
72
- graphics = new PIXI.Graphics();
73
- drawSpritePlaceholder(graphics, geom);
74
- container.addChild(graphics);
75
- break;
76
- }
77
- case 'emitter': {
78
- const geom = entity.geom;
79
- graphics = new PIXI.Graphics();
80
- drawEmitterMarker(graphics, fillColor);
81
- container.addChild(graphics);
82
- break;
83
- }
84
- case 'group':
85
- // Groups are just containers
86
- break;
87
- default:
88
- console.warn(`Unknown entity kind: ${kind}`);
89
- }
90
- // Set initial position
91
- container.x = state.x;
92
- container.y = state.y;
93
- container.rotation = state.rotation;
94
- container.scale.set(state.scaleX, state.scaleY);
95
- container.alpha = state.alpha;
96
- return { container, graphics, text, sprite, debugGraphics };
97
- }
98
- /**
99
- * Update entity graphics position and state
100
- */
101
- export function updateEntityGraphics(entityGraphics, state) {
102
- const { container, graphics } = entityGraphics;
103
- // Update transform
104
- container.x = state.x;
105
- container.y = state.y;
106
- container.rotation = state.rotation;
107
- container.scale.set(state.scaleX, state.scaleY);
108
- container.alpha = state.alpha;
109
- // If fill color changed, redraw (for dynamic color changes)
110
- if (graphics && state.entity.kind === 'rect') {
111
- const geom = state.entity.geom;
112
- const fillColor = parseColor(state.fill ?? state.entity.render?.fill ?? '#ffffff');
113
- const strokeColor = state.entity.render?.stroke ? parseColor(state.entity.render.stroke) : undefined;
114
- const strokeWidth = state.entity.render?.strokeWidth ?? 0;
115
- graphics.clear();
116
- drawRect(graphics, geom, fillColor, strokeColor, strokeWidth);
117
- }
118
- }
119
- /**
120
- * Draw a rectangle
121
- */
122
- function drawRect(g, geom, fillColor, strokeColor, strokeWidth = 0) {
123
- if (strokeColor !== undefined && strokeWidth > 0) {
124
- g.lineStyle(strokeWidth, strokeColor);
125
- }
126
- g.beginFill(fillColor);
127
- const anchorX = geom.w / 2;
128
- const anchorY = geom.h / 2;
129
- if (geom.cornerRadius && geom.cornerRadius > 0) {
130
- g.drawRoundedRect(-anchorX, -anchorY, geom.w, geom.h, geom.cornerRadius);
131
- }
132
- else {
133
- g.drawRect(-anchorX, -anchorY, geom.w, geom.h);
134
- }
135
- g.endFill();
136
- }
137
- /**
138
- * Draw a circle
139
- */
140
- function drawCircle(g, geom, fillColor, strokeColor, strokeWidth = 0) {
141
- if (strokeColor !== undefined && strokeWidth > 0) {
142
- g.lineStyle(strokeWidth, strokeColor);
143
- }
144
- g.beginFill(fillColor);
145
- g.drawCircle(0, 0, geom.r);
146
- g.endFill();
147
- }
148
- /**
149
- * Draw a polygon
150
- */
151
- function drawPoly(g, geom, fillColor, strokeColor, strokeWidth = 0) {
152
- if (strokeColor !== undefined && strokeWidth > 0) {
153
- g.lineStyle(strokeWidth, strokeColor);
154
- }
155
- g.beginFill(fillColor);
156
- const points = geom.points;
157
- if (points.length < 3)
158
- return;
159
- g.moveTo(points[0][0], points[0][1]);
160
- for (let i = 1; i < points.length; i++) {
161
- g.lineTo(points[i][0], points[i][1]);
162
- }
163
- g.closePath();
164
- g.endFill();
165
- }
166
- /**
167
- * Draw a line
168
- */
169
- function drawLine(g, geom, strokeColor) {
170
- g.lineStyle(geom.lineWidth ?? 2, strokeColor);
171
- const points = geom.points;
172
- if (points.length < 2)
173
- return;
174
- g.moveTo(points[0][0], points[0][1]);
175
- for (let i = 1; i < points.length; i++) {
176
- g.lineTo(points[i][0], points[i][1]);
177
- }
178
- }
179
- /**
180
- * Create a text element
181
- */
182
- function createTextElement(geom, fillColor) {
183
- const style = new PIXI.TextStyle({
184
- fontFamily: geom.fontFamily ?? 'Arial',
185
- fontSize: geom.fontSize ?? 16,
186
- fontWeight: (geom.fontWeight ?? 'normal'),
187
- fill: fillColor,
188
- align: (geom.align ?? 'center'),
189
- });
190
- const text = new PIXI.Text(geom.text, style);
191
- text.anchor.set(0.5, 0.5);
192
- return text;
193
- }
194
- /**
195
- * Draw sprite placeholder (for missing sprites)
196
- */
197
- function drawSpritePlaceholder(g, geom) {
198
- const w = geom.w ?? 32;
199
- const h = geom.h ?? 32;
200
- g.beginFill(0x888888);
201
- g.drawRect(-w / 2, -h / 2, w, h);
202
- g.endFill();
203
- // Draw X to indicate missing sprite
204
- g.lineStyle(2, 0xff0000);
205
- g.moveTo(-w / 2, -h / 2);
206
- g.lineTo(w / 2, h / 2);
207
- g.moveTo(w / 2, -h / 2);
208
- g.lineTo(-w / 2, h / 2);
209
- }
210
- /**
211
- * Draw emitter marker
212
- */
213
- function drawEmitterMarker(g, fillColor) {
214
- g.beginFill(fillColor, 0.3);
215
- g.drawCircle(0, 0, 10);
216
- g.endFill();
217
- g.lineStyle(1, fillColor);
218
- g.drawCircle(0, 0, 15);
219
- }
220
- /**
221
- * Draw debug bounds
222
- */
223
- function drawDebugBounds(g, geom) {
224
- g.lineStyle(1, 0x00ff00, 0.5);
225
- g.drawRect(-geom.w / 2, -geom.h / 2, geom.w, geom.h);
226
- }
@@ -1,18 +0,0 @@
1
- import type { SceneContextValue } from '../SceneContext.js';
2
- /**
3
- * Hook to manage keyboard and touch input
4
- */
5
- export declare function useInputManager(context: SceneContextValue): void;
6
- /**
7
- * Check if jump is currently pressed
8
- */
9
- export declare function isJumpPressed(context: SceneContextValue): boolean;
10
- /**
11
- * Check if a specific key is pressed
12
- */
13
- export declare function isKeyPressed(context: SceneContextValue, key: string): boolean;
14
- /**
15
- * Check if touch/click is active
16
- */
17
- export declare function isTouching(context: SceneContextValue): boolean;
18
- //# sourceMappingURL=InputManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"InputManager.d.ts","sourceRoot":"","sources":["../../../src/scene/input/InputManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,QA2EzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAEjE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE7E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAE9D"}
@@ -1,86 +0,0 @@
1
- 'use client';
2
- import { useEffect } from 'react';
3
- /**
4
- * Hook to manage keyboard and touch input
5
- */
6
- export function useInputManager(context) {
7
- const { input } = context;
8
- useEffect(() => {
9
- const inputState = input.current;
10
- // Keyboard event handlers
11
- const handleKeyDown = (e) => {
12
- const key = e.key;
13
- const code = e.code;
14
- // Track all keys
15
- inputState.keys[key] = true;
16
- inputState.keys[code] = true;
17
- // Jump keys: Space, ArrowUp, W
18
- if (key === ' ' || key === 'ArrowUp' || key === 'w' || key === 'W') {
19
- inputState.jumpPressed = true;
20
- }
21
- };
22
- const handleKeyUp = (e) => {
23
- const key = e.key;
24
- const code = e.code;
25
- // Track all keys
26
- inputState.keys[key] = false;
27
- inputState.keys[code] = false;
28
- // Jump keys: Space, ArrowUp, W
29
- if (key === ' ' || key === 'ArrowUp' || key === 'w' || key === 'W') {
30
- inputState.jumpPressed = false;
31
- }
32
- };
33
- // Touch event handlers
34
- const handleTouchStart = (e) => {
35
- inputState.touching = true;
36
- inputState.jumpPressed = true;
37
- };
38
- const handleTouchEnd = (e) => {
39
- inputState.touching = false;
40
- inputState.jumpPressed = false;
41
- };
42
- // Mouse event handlers (for desktop click)
43
- const handleMouseDown = (e) => {
44
- inputState.touching = true;
45
- inputState.jumpPressed = true;
46
- };
47
- const handleMouseUp = (e) => {
48
- inputState.touching = false;
49
- inputState.jumpPressed = false;
50
- };
51
- // Add event listeners
52
- window.addEventListener('keydown', handleKeyDown);
53
- window.addEventListener('keyup', handleKeyUp);
54
- window.addEventListener('touchstart', handleTouchStart, { passive: true });
55
- window.addEventListener('touchend', handleTouchEnd, { passive: true });
56
- window.addEventListener('mousedown', handleMouseDown);
57
- window.addEventListener('mouseup', handleMouseUp);
58
- // Cleanup
59
- return () => {
60
- window.removeEventListener('keydown', handleKeyDown);
61
- window.removeEventListener('keyup', handleKeyUp);
62
- window.removeEventListener('touchstart', handleTouchStart);
63
- window.removeEventListener('touchend', handleTouchEnd);
64
- window.removeEventListener('mousedown', handleMouseDown);
65
- window.removeEventListener('mouseup', handleMouseUp);
66
- };
67
- }, [input]);
68
- }
69
- /**
70
- * Check if jump is currently pressed
71
- */
72
- export function isJumpPressed(context) {
73
- return context.input.current.jumpPressed;
74
- }
75
- /**
76
- * Check if a specific key is pressed
77
- */
78
- export function isKeyPressed(context, key) {
79
- return context.input.current.keys[key] ?? false;
80
- }
81
- /**
82
- * Check if touch/click is active
83
- */
84
- export function isTouching(context) {
85
- return context.input.current.touching;
86
- }
@@ -1,15 +0,0 @@
1
- import Matter from 'matter-js';
2
- import type { SceneContextValue } from '../SceneContext.js';
3
- /**
4
- * Hook to initialize and run the physics engine
5
- */
6
- export declare function usePhysicsEngine(context: SceneContextValue, width: number, height: number): void;
7
- /**
8
- * Apply impulse to a body
9
- */
10
- export declare function applyImpulse(body: Matter.Body, impulseX: number, impulseY: number): void;
11
- /**
12
- * Set velocity on a body
13
- */
14
- export declare function setVelocity(body: Matter.Body, velocityX: number, velocityY: number): void;
15
- //# sourceMappingURL=PhysicsEngine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PhysicsEngine.d.ts","sourceRoot":"","sources":["../../../src/scene/physics/PhysicsEngine.tsx"],"names":[],"mappings":"AAGA,OAAO,MAAM,MAAM,WAAW,CAAC;AAC/B,OAAO,KAAK,EAAE,iBAAiB,EAAe,MAAM,oBAAoB,CAAC;AAqEzE;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,QA+Gf;AA2GD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,QAMjB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,CAAC,IAAI,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,QAGlB"}
@@ -1,260 +0,0 @@
1
- 'use client';
2
- import { useEffect, useRef } from 'react';
3
- import Matter from 'matter-js';
4
- import { useGameLoop } from '../../pixi/index.js';
5
- const { Engine, World, Bodies, Body, Events } = Matter;
6
- /**
7
- * Creates a Matter.js body from an entity state
8
- */
9
- function createBody(state, worldGravity) {
10
- const { entity } = state;
11
- const bodyConfig = entity.body;
12
- // No physics body
13
- if (!bodyConfig || bodyConfig.type === 'none') {
14
- return null;
15
- }
16
- const transform = entity.transform;
17
- const x = transform.x;
18
- const y = transform.y;
19
- const rotation = (transform.rotation ?? 0) * (Math.PI / 180);
20
- // Common body options
21
- const options = {
22
- isStatic: bodyConfig.isStatic ?? false,
23
- isSensor: bodyConfig.type === 'sensor',
24
- restitution: bodyConfig.restitution ?? 0,
25
- friction: bodyConfig.friction ?? 0.1,
26
- frictionAir: 0.01,
27
- angle: rotation,
28
- label: entity.id,
29
- collisionFilter: {
30
- category: bodyConfig.category ?? 0x0001,
31
- mask: bodyConfig.mask ?? 0xFFFF,
32
- },
33
- };
34
- let body = null;
35
- // Create body based on shape
36
- switch (bodyConfig.shape) {
37
- case 'rect': {
38
- const geom = entity.geom;
39
- body = Bodies.rectangle(x, y, geom.w, geom.h, options);
40
- break;
41
- }
42
- case 'circle': {
43
- const geom = entity.geom;
44
- body = Bodies.circle(x, y, geom.r, options);
45
- break;
46
- }
47
- case 'poly': {
48
- const geom = entity.geom;
49
- // Convert points to Matter.js format
50
- const vertices = geom.points.map(([px, py]) => ({ x: px, y: py }));
51
- body = Bodies.fromVertices(x, y, [vertices], options);
52
- break;
53
- }
54
- default:
55
- console.warn(`Unknown body shape: ${bodyConfig.shape}`);
56
- return null;
57
- }
58
- return body;
59
- }
60
- /**
61
- * Hook to initialize and run the physics engine
62
- */
63
- export function usePhysicsEngine(context, width, height) {
64
- const { spec, entities, player, engine: engineRef, emitEvent } = context;
65
- const bodiesMapRef = useRef(new Map());
66
- // Get gravity from spec
67
- const gravity = spec.world?.gravity ?? 2600;
68
- // Initialize engine
69
- useEffect(() => {
70
- // Create engine with gravity
71
- const engine = Engine.create({
72
- gravity: {
73
- x: 0,
74
- y: gravity / 1000, // Matter.js uses different scale
75
- scale: 0.001,
76
- },
77
- });
78
- engineRef.current = engine;
79
- // Create bodies for all entities
80
- const bodiesMap = new Map();
81
- const bodiesToAdd = [];
82
- for (const [id, state] of entities.current) {
83
- const body = createBody(state, gravity);
84
- if (body) {
85
- bodiesMap.set(id, body);
86
- bodiesToAdd.push(body);
87
- state.body = body;
88
- }
89
- }
90
- // Add all bodies to world
91
- World.add(engine.world, bodiesToAdd);
92
- bodiesMapRef.current = bodiesMap;
93
- // Set up collision events
94
- Events.on(engine, 'collisionStart', (event) => {
95
- for (const pair of event.pairs) {
96
- const entityA = entities.current.get(pair.bodyA.label);
97
- const entityB = entities.current.get(pair.bodyB.label);
98
- if (entityA && entityB) {
99
- handleCollision(entityA, entityB, context);
100
- }
101
- }
102
- });
103
- // Cleanup
104
- return () => {
105
- Events.off(engine, 'collisionStart');
106
- World.clear(engine.world, false);
107
- Engine.clear(engine);
108
- engineRef.current = null;
109
- };
110
- }, [spec, gravity, engineRef, entities]);
111
- // Physics update loop
112
- useGameLoop((delta) => {
113
- const engine = engineRef.current;
114
- if (!engine)
115
- return;
116
- const playerState = player.current;
117
- // Update invincibility timer
118
- if (playerState.invincible && playerState.invincibilityTimeRemaining > 0) {
119
- playerState.invincibilityTimeRemaining -= 16.67 * delta;
120
- if (playerState.invincibilityTimeRemaining <= 0) {
121
- playerState.invincible = false;
122
- playerState.invincibilityTimeRemaining = 0;
123
- }
124
- }
125
- // Update gravity direction for player
126
- engine.gravity.y = (gravity / 1000) * playerState.gravityDir;
127
- // Step physics (delta is ~1 at 60fps, so we use 16.67ms per frame)
128
- Engine.update(engine, 16.67 * delta);
129
- // Sync entity positions from physics bodies
130
- for (const [id, body] of bodiesMapRef.current) {
131
- const state = entities.current.get(id);
132
- if (!state || state.destroyed)
133
- continue;
134
- // Update entity position from body
135
- state.x = body.position.x;
136
- state.y = body.position.y;
137
- state.rotation = body.angle;
138
- state.velocityX = body.velocity.x;
139
- state.velocityY = body.velocity.y;
140
- }
141
- // Check if player is grounded
142
- const playerEntity = findPlayerEntity(entities.current);
143
- if (playerEntity?.body) {
144
- const body = playerEntity.body;
145
- // Simple ground check - if velocity.y is very small and we're not in the air
146
- playerState.grounded = Math.abs(body.velocity.y) < 0.5;
147
- }
148
- // Check for death (fell off screen) - only if height is valid and not invincible
149
- if (playerEntity && height > 0 && playerEntity.y > height + 200) {
150
- if (!playerState.dead && !playerState.invincible) {
151
- playerState.dead = true;
152
- playerState.deaths++;
153
- emitEvent('player.death', { cause: 'fall', deaths: playerState.deaths });
154
- }
155
- }
156
- });
157
- }
158
- /**
159
- * Handle collision between two entities
160
- */
161
- function handleCollision(entityA, entityB, context) {
162
- const { player, emitEvent } = context;
163
- const playerState = player.current;
164
- // Check if either entity is the player
165
- const isPlayerA = entityA.entity.tags?.includes('player');
166
- const isPlayerB = entityB.entity.tags?.includes('player');
167
- if (!isPlayerA && !isPlayerB)
168
- return;
169
- const playerEntity = isPlayerA ? entityA : entityB;
170
- const otherEntity = isPlayerA ? entityB : entityA;
171
- const otherTags = otherEntity.entity.tags ?? [];
172
- // Check for hazard collision (only if not invincible)
173
- if (otherTags.includes('hazard') || hasComponent(otherEntity, 'KillOnTouch')) {
174
- if (!playerState.dead && !playerState.invincible) {
175
- playerState.dead = true;
176
- playerState.deaths++;
177
- emitEvent('player.death', { cause: 'hazard', deaths: playerState.deaths });
178
- }
179
- return;
180
- }
181
- // Check for checkpoint collision
182
- if (otherTags.includes('checkpoint') || hasComponent(otherEntity, 'Checkpoint')) {
183
- playerState.checkpointX = otherEntity.x;
184
- playerState.checkpointY = otherEntity.y;
185
- emitEvent('checkpoint.reached', { x: otherEntity.x, y: otherEntity.y });
186
- return;
187
- }
188
- // Check for finish line collision
189
- if (otherTags.includes('finish') || hasComponent(otherEntity, 'FinishLine')) {
190
- if (!playerState.complete) {
191
- playerState.complete = true;
192
- emitEvent('level.complete', { deaths: playerState.deaths });
193
- }
194
- return;
195
- }
196
- // Check for jump orb collision
197
- if (otherTags.includes('orb') || hasComponent(otherEntity, 'JumpOrb')) {
198
- playerState.touchingOrb = otherEntity.entity.id;
199
- return;
200
- }
201
- // Check for speed portal collision
202
- if (hasComponent(otherEntity, 'SpeedPortal')) {
203
- const component = getComponent(otherEntity, 'SpeedPortal');
204
- const params = component?.params;
205
- if (params?.speed) {
206
- playerState.speedMultiplier = params.speed / 320; // Base speed
207
- emitEvent('speed.changed', { speed: params.speed });
208
- }
209
- return;
210
- }
211
- // Check for gravity portal collision
212
- if (hasComponent(otherEntity, 'GravityPortal')) {
213
- playerState.gravityDir *= -1;
214
- emitEvent('gravity.flipped', { direction: playerState.gravityDir });
215
- return;
216
- }
217
- // Ground collision - reset jump count
218
- if (otherEntity.entity.body?.isStatic && !otherEntity.entity.body?.type) {
219
- playerState.grounded = true;
220
- playerState.jumpCount = 0;
221
- }
222
- }
223
- /**
224
- * Find the player entity
225
- */
226
- function findPlayerEntity(entities) {
227
- for (const [, state] of entities) {
228
- if (state.entity.tags?.includes('player')) {
229
- return state;
230
- }
231
- }
232
- return null;
233
- }
234
- /**
235
- * Check if entity has a component
236
- */
237
- function hasComponent(state, type) {
238
- return state.entity.components?.some((c) => c.type === type) ?? false;
239
- }
240
- /**
241
- * Get a component from an entity
242
- */
243
- function getComponent(state, type) {
244
- return state.entity.components?.find((c) => c.type === type);
245
- }
246
- /**
247
- * Apply impulse to a body
248
- */
249
- export function applyImpulse(body, impulseX, impulseY) {
250
- Body.applyForce(body, body.position, {
251
- x: impulseX * 0.001,
252
- y: impulseY * 0.001,
253
- });
254
- }
255
- /**
256
- * Set velocity on a body
257
- */
258
- export function setVelocity(body, velocityX, velocityY) {
259
- Body.setVelocity(body, { x: velocityX, y: velocityY });
260
- }
@@ -1,6 +0,0 @@
1
- import type { SceneContextValue } from '../SceneContext.js';
2
- /**
3
- * Hook to execute timeline events
4
- */
5
- export declare function useTimelineExecutor(context: SceneContextValue): void;
6
- //# sourceMappingURL=TimelineExecutor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"TimelineExecutor.d.ts","sourceRoot":"","sources":["../../../src/scene/timeline/TimelineExecutor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAe,MAAM,oBAAoB,CAAC;AAIzE;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,QA4C7D"}