@thewhateverapp/tile-sdk 0.14.5 → 0.14.7
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/scene/SceneContext.d.ts +6 -0
- package/dist/scene/SceneContext.d.ts.map +1 -1
- package/dist/scene/SceneContext.js +3 -0
- package/dist/scene/SceneRenderer.d.ts.map +1 -1
- package/dist/scene/SceneRenderer.js +14 -4
- package/dist/scene/camera/CameraController.d.ts.map +1 -1
- package/dist/scene/camera/CameraController.js +7 -1
- package/dist/scene/components/ComponentRunner.d.ts.map +1 -1
- package/dist/scene/components/ComponentRunner.js +16 -5
- package/dist/scene/physics/PhysicsEngine.d.ts.map +1 -1
- package/dist/scene/physics/PhysicsEngine.js +12 -4
- package/dist/scene/timeline/TimelineExecutor.d.ts.map +1 -1
- package/dist/scene/timeline/TimelineExecutor.js +6 -1
- package/package.json +1 -1
|
@@ -35,6 +35,8 @@ export interface EntityState {
|
|
|
35
35
|
* Player-specific state for dash games
|
|
36
36
|
*/
|
|
37
37
|
export interface PlayerState {
|
|
38
|
+
/** Has the game started (waiting for first jump) */
|
|
39
|
+
started: boolean;
|
|
38
40
|
/** Is player on ground */
|
|
39
41
|
grounded: boolean;
|
|
40
42
|
/** Is player dead */
|
|
@@ -54,6 +56,10 @@ export interface PlayerState {
|
|
|
54
56
|
deaths: number;
|
|
55
57
|
/** Level complete */
|
|
56
58
|
complete: boolean;
|
|
59
|
+
/** Invincibility frames (prevents instant re-death after respawn) */
|
|
60
|
+
invincible: boolean;
|
|
61
|
+
/** Invincibility time remaining in ms */
|
|
62
|
+
invincibilityTimeRemaining: number;
|
|
57
63
|
}
|
|
58
64
|
/**
|
|
59
65
|
* Camera state
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneContext.d.ts","sourceRoot":"","sources":["../../src/scene/SceneContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAqC,KAAK,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,kCAAkC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,0BAA0B;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,qBAAqB;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SceneContext.d.ts","sourceRoot":"","sources":["../../src/scene/SceneContext.tsx"],"names":[],"mappings":"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"}
|
|
@@ -39,6 +39,7 @@ export function createEntityState(entity) {
|
|
|
39
39
|
*/
|
|
40
40
|
export function createPlayerState() {
|
|
41
41
|
return {
|
|
42
|
+
started: false,
|
|
42
43
|
grounded: false,
|
|
43
44
|
dead: false,
|
|
44
45
|
jumpCount: 0,
|
|
@@ -49,6 +50,8 @@ export function createPlayerState() {
|
|
|
49
50
|
speedMultiplier: 1,
|
|
50
51
|
deaths: 0,
|
|
51
52
|
complete: false,
|
|
53
|
+
invincible: false,
|
|
54
|
+
invincibilityTimeRemaining: 0,
|
|
52
55
|
};
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneRenderer.d.ts","sourceRoot":"","sources":["../../src/scene/SceneRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,2BAA2B,CAAC;AAqDrE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,IAAI,EAAE,WAAW,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,kCAAkC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EAAE,SAAS,EACf,OAAO,EACP,MAAc,EACd,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,EACnB,KAAa,GACd,EAAE,kBAAkB,qBA0CpB;
|
|
1
|
+
{"version":3,"file":"SceneRenderer.d.ts","sourceRoot":"","sources":["../../src/scene/SceneRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAU,MAAM,2BAA2B,CAAC;AAqDrE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,oCAAoC;IACpC,IAAI,EAAE,WAAW,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,kCAAkC;IAClC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EAAE,SAAS,EACf,OAAO,EACP,MAAc,EACd,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,WAAW,EACnB,KAAa,GACd,EAAE,kBAAkB,qBA0CpB;AA8PD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -131,6 +131,9 @@ function SceneContent({ spec, onEvent, paused, width, height, debug, }) {
|
|
|
131
131
|
player.dead = false;
|
|
132
132
|
player.jumpCount = 0;
|
|
133
133
|
player.gravityDir = 1;
|
|
134
|
+
// Grant 1 second of invincibility to prevent instant re-death
|
|
135
|
+
player.invincible = true;
|
|
136
|
+
player.invincibilityTimeRemaining = 1000;
|
|
134
137
|
// Find player entity and reset position
|
|
135
138
|
for (const [, state] of entitiesRef.current) {
|
|
136
139
|
if (state.entity.tags?.includes('player')) {
|
|
@@ -203,10 +206,17 @@ function SceneContent({ spec, onEvent, paused, width, height, debug, }) {
|
|
|
203
206
|
useGameLoop((delta) => {
|
|
204
207
|
if (paused)
|
|
205
208
|
return;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
const playerState = playerRef.current;
|
|
210
|
+
// Update timeline elapsed time (only when game has started)
|
|
211
|
+
if (playerState.started) {
|
|
212
|
+
// Adjust start time on first frame after starting
|
|
213
|
+
if (timelineRef.current.elapsedMs === 0) {
|
|
214
|
+
startTimeRef.current = Date.now();
|
|
215
|
+
}
|
|
216
|
+
const now = Date.now();
|
|
217
|
+
timelineRef.current.elapsedMs = now - startTimeRef.current;
|
|
218
|
+
timelineRef.current.currentBeat = (timelineRef.current.elapsedMs / 1000) * (bpm / 60);
|
|
219
|
+
}
|
|
210
220
|
}, !paused);
|
|
211
221
|
// Render entities grouped by layer
|
|
212
222
|
const renderLayers = useMemo(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CameraController.d.ts","sourceRoot":"","sources":["../../../src/scene/camera/CameraController.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"CameraController.d.ts","sourceRoot":"","sources":["../../../src/scene/camera/CameraController.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,QA6Ff"}
|
|
@@ -20,7 +20,13 @@ export function useCameraController(context, width, height) {
|
|
|
20
20
|
break;
|
|
21
21
|
}
|
|
22
22
|
case 'scroll': {
|
|
23
|
-
// Auto-scroll camera
|
|
23
|
+
// Auto-scroll camera (only when game has started)
|
|
24
|
+
if (!playerState.started) {
|
|
25
|
+
// Initialize camera position when not started
|
|
26
|
+
cameraState.x = cameraConfig?.initialX ?? width / 2;
|
|
27
|
+
cameraState.y = cameraConfig?.initialY ?? height / 2;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
24
30
|
const scrollSpeed = (cameraConfig?.scrollSpeed ?? 320) * playerState.speedMultiplier;
|
|
25
31
|
const direction = cameraConfig?.scrollDirection ?? 'right';
|
|
26
32
|
switch (direction) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComponentRunner.d.ts","sourceRoot":"","sources":["../../../src/scene/components/ComponentRunner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAazE;;GAEG;AACH,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,KAAK,gBAAgB,GAAG,CACtB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;AAcV;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,QAkB5D;
|
|
1
|
+
{"version":3,"file":"ComponentRunner.d.ts","sourceRoot":"","sources":["../../../src/scene/components/ComponentRunner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAazE;;GAEG;AACH,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,KAAK,gBAAgB,GAAG,CACtB,KAAK,EAAE,WAAW,EAClB,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,KACV,IAAI,CAAC;AAcV;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,QAkB5D;AA4ND;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,QAExE"}
|
|
@@ -125,6 +125,21 @@ function handleFollow(state, component, context, delta) {
|
|
|
125
125
|
function handleDashPlayer(state, component, context, delta) {
|
|
126
126
|
const { player, camera, emitEvent, respawnPlayer } = context;
|
|
127
127
|
const playerState = player.current;
|
|
128
|
+
// Handle jump input (check before started check so we can start the game)
|
|
129
|
+
const jumpPressed = isJumpPressed(context);
|
|
130
|
+
const wasJumpPressed = state.componentState.wasJumpPressed ?? false;
|
|
131
|
+
const justPressed = jumpPressed && !wasJumpPressed;
|
|
132
|
+
state.componentState.wasJumpPressed = jumpPressed;
|
|
133
|
+
// Start the game on first jump
|
|
134
|
+
if (!playerState.started && justPressed) {
|
|
135
|
+
playerState.started = true;
|
|
136
|
+
emitEvent('game.started');
|
|
137
|
+
return; // Don't process jump on the start frame
|
|
138
|
+
}
|
|
139
|
+
// Don't run game logic until started
|
|
140
|
+
if (!playerState.started) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
128
143
|
// Handle death
|
|
129
144
|
if (playerState.dead) {
|
|
130
145
|
// Wait a moment then respawn
|
|
@@ -138,11 +153,7 @@ function handleDashPlayer(state, component, context, delta) {
|
|
|
138
153
|
}
|
|
139
154
|
return;
|
|
140
155
|
}
|
|
141
|
-
// Handle jump
|
|
142
|
-
const jumpPressed = isJumpPressed(context);
|
|
143
|
-
const wasJumpPressed = state.componentState.wasJumpPressed ?? false;
|
|
144
|
-
const justPressed = jumpPressed && !wasJumpPressed;
|
|
145
|
-
state.componentState.wasJumpPressed = jumpPressed;
|
|
156
|
+
// Handle jump (only after game started)
|
|
146
157
|
if (justPressed) {
|
|
147
158
|
// Check if touching an orb
|
|
148
159
|
if (playerState.touchingOrb) {
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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"}
|
|
@@ -114,6 +114,14 @@ export function usePhysicsEngine(context, width, height) {
|
|
|
114
114
|
if (!engine)
|
|
115
115
|
return;
|
|
116
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
|
+
}
|
|
117
125
|
// Update gravity direction for player
|
|
118
126
|
engine.gravity.y = (gravity / 1000) * playerState.gravityDir;
|
|
119
127
|
// Step physics (delta is ~1 at 60fps, so we use 16.67ms per frame)
|
|
@@ -137,9 +145,9 @@ export function usePhysicsEngine(context, width, height) {
|
|
|
137
145
|
// Simple ground check - if velocity.y is very small and we're not in the air
|
|
138
146
|
playerState.grounded = Math.abs(body.velocity.y) < 0.5;
|
|
139
147
|
}
|
|
140
|
-
// Check for death (fell off screen) - only if height is valid
|
|
148
|
+
// Check for death (fell off screen) - only if height is valid and not invincible
|
|
141
149
|
if (playerEntity && height > 0 && playerEntity.y > height + 200) {
|
|
142
|
-
if (!playerState.dead) {
|
|
150
|
+
if (!playerState.dead && !playerState.invincible) {
|
|
143
151
|
playerState.dead = true;
|
|
144
152
|
playerState.deaths++;
|
|
145
153
|
emitEvent('player.death', { cause: 'fall', deaths: playerState.deaths });
|
|
@@ -161,9 +169,9 @@ function handleCollision(entityA, entityB, context) {
|
|
|
161
169
|
const playerEntity = isPlayerA ? entityA : entityB;
|
|
162
170
|
const otherEntity = isPlayerA ? entityB : entityA;
|
|
163
171
|
const otherTags = otherEntity.entity.tags ?? [];
|
|
164
|
-
// Check for hazard collision
|
|
172
|
+
// Check for hazard collision (only if not invincible)
|
|
165
173
|
if (otherTags.includes('hazard') || hasComponent(otherEntity, 'KillOnTouch')) {
|
|
166
|
-
if (!playerState.dead) {
|
|
174
|
+
if (!playerState.dead && !playerState.invincible) {
|
|
167
175
|
playerState.dead = true;
|
|
168
176
|
playerState.deaths++;
|
|
169
177
|
emitEvent('player.death', { cause: 'hazard', deaths: playerState.deaths });
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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"}
|
|
@@ -5,12 +5,17 @@ import { getEasing } from '@thewhateverapp/scene-sdk';
|
|
|
5
5
|
* Hook to execute timeline events
|
|
6
6
|
*/
|
|
7
7
|
export function useTimelineExecutor(context) {
|
|
8
|
-
const { spec, timeline, entities, camera, emitEvent, spawnEntity, bpm } = context;
|
|
8
|
+
const { spec, timeline, entities, camera, emitEvent, spawnEntity, bpm, player } = context;
|
|
9
9
|
const timelineEvents = spec.timeline ?? [];
|
|
10
10
|
useGameLoop((delta) => {
|
|
11
11
|
const state = timeline.current;
|
|
12
|
+
const playerState = player.current;
|
|
12
13
|
const elapsedMs = state.elapsedMs;
|
|
13
14
|
const currentBeat = state.currentBeat;
|
|
15
|
+
// Don't process timeline until game has started
|
|
16
|
+
if (!playerState.started) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
14
19
|
// Process pending timeline events
|
|
15
20
|
while (state.nextEventIndex < timelineEvents.length) {
|
|
16
21
|
const event = timelineEvents[state.nextEventIndex];
|