@caperjs/plugin-crunch 0.7.0 → 0.7.2

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/lib/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const version = "0.7.0";
1
+ export declare const version = "0.7.2";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -8,10 +8,11 @@
8
8
  "@caperjs/core",
9
9
  "caper"
10
10
  ],
11
- "version": "0.7.0",
11
+ "version": "0.7.2",
12
12
  "files": [
13
13
  "lib",
14
- "src"
14
+ "src",
15
+ "!src/**/*.test.ts"
15
16
  ],
16
17
  "main": "lib/caper-plugin-crunch.mjs",
17
18
  "types": "lib/index.d.ts",
@@ -24,19 +25,20 @@
24
25
  "sideEffects": false,
25
26
  "scripts": {
26
27
  "build": "pnpm run generate-version && vite build",
27
- "test": "echo \"Error: no test specified\" && exit 1",
28
+ "test": "vitest run",
28
29
  "generate-version": "node generateVersion.mjs"
29
30
  },
30
31
  "author": "",
31
32
  "license": "MIT",
32
33
  "devDependencies": {
33
- "@caperjs/core": "^0.7.0",
34
+ "@caperjs/core": "^0.7.2",
34
35
  "vite": "^8.0.7",
35
- "vite-plugin-dts": "^4.5.3"
36
+ "vite-plugin-dts": "^4.5.3",
37
+ "vitest": "^3"
36
38
  },
37
39
  "peerDependencies": {
38
- "@caperjs/core": "^0.7.0",
40
+ "@caperjs/core": "^0.7.2",
39
41
  "gsap": "^3.15.0",
40
- "pixi.js": "8.20.0"
42
+ "pixi.js": "8.22.0"
41
43
  }
42
44
  }
package/src/Sensor.ts CHANGED
@@ -216,6 +216,7 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
216
216
  this._xRemainder -= move;
217
217
  const sign = Math.sign(move);
218
218
  let remaining = Math.abs(move);
219
+ const candidates = this.getOverlapCandidates(move, 0);
219
220
  while (remaining > 0) {
220
221
  const step = sign;
221
222
  const nextX = this.x + step;
@@ -233,7 +234,7 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
233
234
  this._x = nextX;
234
235
  remaining--;
235
236
  this.updateView();
236
- this.checkActorOverlaps();
237
+ this.checkActorOverlaps(candidates);
237
238
  } else {
238
239
  // Stop horizontal movement when hitting a solid
239
240
  this.velocity.x = 0;
@@ -261,6 +262,7 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
261
262
  const sign = Math.sign(move);
262
263
 
263
264
  let remaining = Math.abs(move);
265
+ const candidates = this.getOverlapCandidates(0, move);
264
266
  while (remaining > 0) {
265
267
  const step = sign;
266
268
  const nextY = this.y + step;
@@ -281,7 +283,7 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
281
283
  this._y = nextY;
282
284
  remaining--;
283
285
  this.updateView();
284
- this.checkActorOverlaps();
286
+ this.checkActorOverlaps(candidates);
285
287
  } else {
286
288
  // Stop vertical movement when landing on a solid
287
289
  this.velocity.y = 0;
@@ -309,6 +311,13 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
309
311
  this.velocity.y += this.system.gravity * deltaTime;
310
312
  }
311
313
 
314
+ // Clamp velocity, as Actor does. Without it a sensor with nothing beneath it
315
+ // accelerates forever, and every extra pixel per frame is another pass through
316
+ // the move loops below.
317
+ const maxVelocity = this.system.maxVelocity;
318
+ this.velocity.x = Math.min(Math.max(this.velocity.x, -maxVelocity), maxVelocity);
319
+ this.velocity.y = Math.min(Math.max(this.velocity.y, -maxVelocity), maxVelocity);
320
+
312
321
  // Move
313
322
  if (this.velocity.x !== 0) {
314
323
  this.moveX(this.velocity.x * deltaTime);
@@ -318,12 +327,35 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
318
327
  }
319
328
  }
320
329
 
330
+ /**
331
+ * The only actors a move of (dx, dy) pixels can start or stop overlapping: those
332
+ * touching the area swept by the move, plus the ones overlapping right now (they
333
+ * may be left behind). Built once per move so the per-pixel loop scans a handful
334
+ * of actors instead of rebuilding and walking the whole list for every pixel.
335
+ */
336
+ private getOverlapCandidates(dx: number, dy: number): Set<Actor> {
337
+ const candidates = new Set<Actor>(this.overlappingActors);
338
+ const left = Math.min(this.x, this.x + dx);
339
+ const top = Math.min(this.y, this.y + dy);
340
+ const right = Math.max(this.x, this.x + dx) + this.width;
341
+ const bottom = Math.max(this.y, this.y + dy) + this.height;
342
+
343
+ for (const actor of this.system.getActorsByType(this.collidableTypes)) {
344
+ if (actor.x < right && actor.x + actor.width > left && actor.y < bottom && actor.y + actor.height > top) {
345
+ candidates.add(actor);
346
+ }
347
+ }
348
+ return candidates;
349
+ }
350
+
321
351
  /**
322
352
  * Checks for overlapping actors and triggers callbacks.
323
353
  *
354
+ * @param candidates - Restrict the scan to these actors (see getOverlapCandidates).
355
+ * Omit for a full scan of every actor of the collidable types.
324
356
  * @returns Set of current overlaps
325
357
  */
326
- public checkActorOverlaps(): Set<SensorOverlap> {
358
+ public checkActorOverlaps(candidates?: Iterable<Actor>): Set<SensorOverlap> {
327
359
  // Skip if sensor has no collision mask or is inactive
328
360
  if (this.collisionMask === 0 || !this.active) {
329
361
  return new Set();
@@ -340,7 +372,7 @@ export class Sensor<D extends EntityData = EntityData> extends Entity<D> {
340
372
  const sensorMask = this.collisionMask;
341
373
 
342
374
  // Get actors by type, but only process those that could be nearby
343
- const nearbyActors = this.system.getActorsByType(this.collidableTypes);
375
+ const nearbyActors = candidates ?? this.system.getActorsByType(this.collidableTypes);
344
376
 
345
377
  for (const actor of nearbyActors) {
346
378
  // Skip inactive actors
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.7.0';
1
+ export const version = '0.7.2';