@thewhateverapp/tile-sdk 0.14.4 → 0.14.6
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 +4 -0
- package/dist/scene/SceneContext.d.ts.map +1 -1
- package/dist/scene/SceneContext.js +2 -0
- package/dist/scene/SceneRenderer.d.ts.map +1 -1
- package/dist/scene/SceneRenderer.js +16 -3
- package/dist/scene/physics/PhysicsEngine.d.ts.map +1 -1
- package/dist/scene/physics/PhysicsEngine.js +13 -5
- package/package.json +1 -1
|
@@ -54,6 +54,10 @@ export interface PlayerState {
|
|
|
54
54
|
deaths: number;
|
|
55
55
|
/** Level complete */
|
|
56
56
|
complete: boolean;
|
|
57
|
+
/** Invincibility frames (prevents instant re-death after respawn) */
|
|
58
|
+
invincible: boolean;
|
|
59
|
+
/** Invincibility time remaining in ms */
|
|
60
|
+
invincibilityTimeRemaining: number;
|
|
57
61
|
}
|
|
58
62
|
/**
|
|
59
63
|
* 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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SceneRenderer.d.ts","sourceRoot":"","sources":["../../src/scene/SceneRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA4D,MAAM,OAAO,CAAC;
|
|
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;AAqPD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import React, { useEffect, useRef, useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import Matter from 'matter-js';
|
|
3
4
|
import { compileScene } from '@thewhateverapp/scene-sdk';
|
|
4
5
|
import { PixiGame, useGameLoop, Container } from '../pixi/index.js';
|
|
5
6
|
import { SceneContext, createEntityState, createPlayerState, createCameraState, createInputState, createTimelineState, } from './SceneContext.js';
|
|
@@ -10,6 +11,7 @@ import { useComponentRunner } from './components/ComponentRunner.js';
|
|
|
10
11
|
import { useTimelineExecutor } from './timeline/TimelineExecutor.js';
|
|
11
12
|
import { useCameraController } from './camera/CameraController.js';
|
|
12
13
|
import { TILE_WIDTH, TILE_HEIGHT } from '../react/PixiGame.js';
|
|
14
|
+
const { Body } = Matter;
|
|
13
15
|
/**
|
|
14
16
|
* Hook to track container size using ResizeObserver
|
|
15
17
|
*/
|
|
@@ -129,19 +131,30 @@ function SceneContent({ spec, onEvent, paused, width, height, debug, }) {
|
|
|
129
131
|
player.dead = false;
|
|
130
132
|
player.jumpCount = 0;
|
|
131
133
|
player.gravityDir = 1;
|
|
134
|
+
// Grant 1 second of invincibility to prevent instant re-death
|
|
135
|
+
player.invincible = true;
|
|
136
|
+
player.invincibilityTimeRemaining = 1000;
|
|
132
137
|
// Find player entity and reset position
|
|
133
138
|
for (const [, state] of entitiesRef.current) {
|
|
134
139
|
if (state.entity.tags?.includes('player')) {
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
const respawnX = player.checkpointX ?? state.entity.transform.x;
|
|
141
|
+
const respawnY = player.checkpointY ?? state.entity.transform.y;
|
|
142
|
+
state.x = respawnX;
|
|
143
|
+
state.y = respawnY;
|
|
137
144
|
state.velocityX = 0;
|
|
138
145
|
state.velocityY = 0;
|
|
139
146
|
state.rotation = 0;
|
|
147
|
+
// Update physics body if it exists
|
|
148
|
+
if (state.body) {
|
|
149
|
+
Body.setPosition(state.body, { x: respawnX, y: respawnY });
|
|
150
|
+
Body.setVelocity(state.body, { x: 0, y: 0 });
|
|
151
|
+
Body.setAngle(state.body, 0);
|
|
152
|
+
}
|
|
140
153
|
break;
|
|
141
154
|
}
|
|
142
155
|
}
|
|
143
156
|
emitEvent('player.respawn', { x: player.checkpointX, y: player.checkpointY });
|
|
144
|
-
}, [
|
|
157
|
+
}, [emitEvent]);
|
|
145
158
|
// Build context value
|
|
146
159
|
const contextValue = useMemo(() => ({
|
|
147
160
|
spec,
|
|
@@ -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)
|
|
141
|
-
if (playerEntity && playerEntity.y > height +
|
|
142
|
-
if (!playerState.dead) {
|
|
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) {
|
|
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 });
|