custom-pixi-particles 4.40.1 → 4.41.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.
@@ -1,47 +1,54 @@
1
1
  import Behaviour from './Behaviour';
2
2
  import Particle from '../Particle';
3
3
  import { Color, Point } from '../util';
4
+ export type TemperatureZoneShapeType = 'circle' | 'square' | 'rectangle';
5
+ export type TemperatureZone = {
6
+ center: Point;
7
+ velocity: Point;
8
+ color: Color;
9
+ shapeType?: TemperatureZoneShapeType;
10
+ radius?: number;
11
+ halfSize?: number;
12
+ halfWidth?: number;
13
+ halfHeight?: number;
14
+ };
4
15
  /**
5
16
  * TemperatureBehaviour adjusts particle velocity and color
6
17
  * based on whether they are in a hot or cold zone.
18
+ *
19
+ * Gradual color mode is designed to run after ColorBehaviour (lower priority):
20
+ * ColorBehaviour sets the natural particle color first, then this behaviour
21
+ * blends zone tint on top and eases back to the live natural color on exit.
7
22
  */
8
23
  export default class TemperatureBehaviour extends Behaviour {
9
24
  enabled: boolean;
10
25
  priority: number;
11
- zones: {
12
- center: Point;
13
- radius: number;
14
- velocity: Point;
15
- color: Color;
16
- }[];
17
- /**
18
- * Initializes the particle. This behavior does not require
19
- * per-particle initialization, but it's included for extensibility.
20
- */
26
+ zones: TemperatureZone[];
27
+ /** When true, particle color eases toward zone / outside colors instead of snapping. */
28
+ gradualColorTransition: boolean;
29
+ /** Blend speed toward the target color (higher = faster). */
30
+ colorTransitionSpeed: number;
21
31
  init(particle: Particle): void;
22
- /**
23
- * Applies temperature-based adjustments to the particle's velocity and color.
24
- */
25
- apply(particle: Particle): void;
26
- /**
27
- * Checks if a particle is within a specified zone.
28
- */
29
- isInZone(particle: Particle, center: Point, radius: number): boolean;
30
- /**
31
- * Returns the name of the behavior.
32
- */
32
+ apply(particle: Particle, deltaTime?: number): void;
33
+ private applyGradualOutsideColor;
34
+ private clearGradualColorState;
35
+ private findActiveZone;
36
+ private zoneColor;
37
+ private copyColor;
38
+ private writeColor;
39
+ private mixColors;
40
+ private stepBlendToward;
41
+ private getBlendT;
42
+ private lerp;
43
+ private matchesAnyZoneColor;
44
+ private matchesAnyZoneColorValue;
45
+ isInZone(particle: Particle, zone: TemperatureZone): boolean;
33
46
  getName(): string;
34
- /**
35
- * Returns properties for serialization or debugging.
36
- */
37
47
  getProps(): {
38
48
  enabled: boolean;
39
49
  priority: number;
40
- zones: {
41
- center: Point;
42
- radius: number;
43
- velocity: Point;
44
- color: Color;
45
- }[];
50
+ zones: TemperatureZone[];
51
+ gradualColorTransition: boolean;
52
+ colorTransitionSpeed: number;
46
53
  };
47
54
  }
@@ -3,61 +3,211 @@ import behaviourNames from './BehaviourNames';
3
3
  /**
4
4
  * TemperatureBehaviour adjusts particle velocity and color
5
5
  * based on whether they are in a hot or cold zone.
6
+ *
7
+ * Gradual color mode is designed to run after ColorBehaviour (lower priority):
8
+ * ColorBehaviour sets the natural particle color first, then this behaviour
9
+ * blends zone tint on top and eases back to the live natural color on exit.
6
10
  */
7
11
  export default class TemperatureBehaviour extends Behaviour {
8
12
  constructor() {
9
13
  super(...arguments);
10
14
  this.enabled = true;
11
- this.priority = 150;
15
+ this.priority = 50;
12
16
  this.zones = [];
17
+ /** When true, particle color eases toward zone / outside colors instead of snapping. */
18
+ this.gradualColorTransition = false;
19
+ /** Blend speed toward the target color (higher = faster). */
20
+ this.colorTransitionSpeed = 6;
13
21
  }
14
- /**
15
- * Initializes the particle. This behavior does not require
16
- * per-particle initialization, but it's included for extensibility.
17
- */
18
22
  init(particle) {
19
- // Optionally, initialize particle-specific data here
23
+ const p = particle;
24
+ p._temperatureInZone = false;
25
+ p._temperatureTransitioningOut = false;
26
+ p._temperatureBlend = 0;
27
+ p._temperatureOutsideColor = null;
28
+ p._temperatureLastZoneColor = null;
20
29
  }
21
- /**
22
- * Applies temperature-based adjustments to the particle's velocity and color.
23
- */
24
- apply(particle) {
30
+ apply(particle, deltaTime = 1 / 60) {
31
+ var _a, _b, _c;
25
32
  if (!this.enabled || !this.zones || !this.zones.length)
26
33
  return;
27
- // Check if the particle is in any hot zone
34
+ const p = particle;
35
+ const activeZone = this.findActiveZone(particle);
36
+ const naturalColor = this.copyColor(particle);
37
+ const wasInZone = p._temperatureInZone === true;
38
+ if (!activeZone) {
39
+ if (this.gradualColorTransition) {
40
+ if (wasInZone) {
41
+ p._temperatureTransitioningOut = true;
42
+ }
43
+ this.applyGradualOutsideColor(particle, p, naturalColor, deltaTime);
44
+ }
45
+ else if (wasInZone && p._temperatureOutsideColor && this.matchesAnyZoneColor(particle)) {
46
+ this.writeColor(particle, p._temperatureOutsideColor);
47
+ }
48
+ else if (!wasInZone) {
49
+ p._temperatureOutsideColor = naturalColor;
50
+ }
51
+ p._temperatureInZone = false;
52
+ if (!this.gradualColorTransition) {
53
+ this.clearGradualColorState(particle, p);
54
+ }
55
+ return;
56
+ }
57
+ if (this.gradualColorTransition) {
58
+ p._temperatureTransitioningOut = false;
59
+ if (!wasInZone || !p._temperatureOutsideColor) {
60
+ p._temperatureOutsideColor = naturalColor;
61
+ }
62
+ if (!wasInZone && ((_a = p._temperatureBlend) !== null && _a !== void 0 ? _a : 0) <= 0) {
63
+ p._temperatureBlend = 0;
64
+ }
65
+ }
66
+ else if (!wasInZone) {
67
+ p._temperatureOutsideColor = naturalColor;
68
+ }
69
+ particle.velocity.x *= activeZone.velocity.x;
70
+ particle.velocity.y *= activeZone.velocity.y;
71
+ const zoneColor = this.zoneColor(activeZone);
72
+ p._temperatureLastZoneColor = zoneColor;
73
+ if (this.gradualColorTransition) {
74
+ const blend = this.stepBlendToward((_b = p._temperatureBlend) !== null && _b !== void 0 ? _b : 0, 1, deltaTime);
75
+ p._temperatureBlend = blend;
76
+ const outside = (_c = p._temperatureOutsideColor) !== null && _c !== void 0 ? _c : naturalColor;
77
+ this.writeColor(particle, this.mixColors(outside, zoneColor, blend));
78
+ }
79
+ else {
80
+ this.writeColor(particle, zoneColor);
81
+ p._temperatureBlend = 1;
82
+ }
83
+ p._temperatureInZone = true;
84
+ }
85
+ applyGradualOutsideColor(particle, p, naturalColor, deltaTime) {
86
+ var _a, _b, _c, _d;
87
+ const transitioningOut = p._temperatureTransitioningOut === true;
88
+ const startBlend = transitioningOut ? ((_a = p._temperatureBlend) !== null && _a !== void 0 ? _a : 1) : ((_b = p._temperatureBlend) !== null && _b !== void 0 ? _b : 0);
89
+ if (!transitioningOut && !this.matchesAnyZoneColorValue(naturalColor)) {
90
+ p._temperatureOutsideColor = naturalColor;
91
+ }
92
+ const blend = this.stepBlendToward(startBlend, 0, deltaTime);
93
+ p._temperatureBlend = blend;
94
+ if (!transitioningOut && blend <= 0.001) {
95
+ p._temperatureBlend = 0;
96
+ p._temperatureTransitioningOut = false;
97
+ p._temperatureLastZoneColor = null;
98
+ return;
99
+ }
100
+ const outside = transitioningOut
101
+ ? naturalColor
102
+ : ((_c = p._temperatureOutsideColor) !== null && _c !== void 0 ? _c : naturalColor);
103
+ const zone = (_d = p._temperatureLastZoneColor) !== null && _d !== void 0 ? _d : outside;
104
+ this.writeColor(particle, this.mixColors(outside, zone, blend));
105
+ if (blend <= 0.001) {
106
+ p._temperatureBlend = 0;
107
+ p._temperatureTransitioningOut = false;
108
+ p._temperatureLastZoneColor = null;
109
+ }
110
+ }
111
+ clearGradualColorState(particle, p) {
112
+ p._temperatureBlend = 0;
113
+ p._temperatureLastZoneColor = null;
114
+ }
115
+ findActiveZone(particle) {
28
116
  for (const zone of this.zones) {
29
- if (this.isInZone(particle, zone.center, zone.radius)) {
30
- particle.velocity.x *= zone.velocity.x;
31
- particle.velocity.y *= zone.velocity.y;
32
- particle.color.r = zone.color.r;
33
- particle.color.g = zone.color.g;
34
- particle.color.b = zone.color.b;
35
- break;
117
+ if (this.isInZone(particle, zone)) {
118
+ return zone;
36
119
  }
37
120
  }
121
+ return null;
38
122
  }
39
- /**
40
- * Checks if a particle is within a specified zone.
41
- */
42
- isInZone(particle, center, radius) {
43
- const dx = particle.movement.x - center.x;
44
- const dy = particle.movement.y - center.y;
123
+ zoneColor(zone) {
124
+ var _a;
125
+ return {
126
+ r: zone.color.r,
127
+ g: zone.color.g,
128
+ b: zone.color.b,
129
+ alpha: (_a = zone.color.alpha) !== null && _a !== void 0 ? _a : 1,
130
+ };
131
+ }
132
+ copyColor(particle) {
133
+ return {
134
+ r: particle.color.r,
135
+ g: particle.color.g,
136
+ b: particle.color.b,
137
+ alpha: particle.color.alpha,
138
+ };
139
+ }
140
+ writeColor(particle, color) {
141
+ particle.color.r = color.r;
142
+ particle.color.g = color.g;
143
+ particle.color.b = color.b;
144
+ particle.color.alpha = color.alpha;
145
+ }
146
+ mixColors(from, to, blend) {
147
+ const t = Math.max(0, Math.min(1, blend));
148
+ return {
149
+ r: this.lerp(from.r, to.r, t),
150
+ g: this.lerp(from.g, to.g, t),
151
+ b: this.lerp(from.b, to.b, t),
152
+ alpha: this.lerp(from.alpha, to.alpha, t),
153
+ };
154
+ }
155
+ stepBlendToward(current, target, deltaTime) {
156
+ const t = this.getBlendT(deltaTime);
157
+ const next = current + (target - current) * t;
158
+ if (target > current)
159
+ return Math.min(target, next);
160
+ return Math.max(target, next);
161
+ }
162
+ getBlendT(deltaTime) {
163
+ const speed = Math.max(0, this.colorTransitionSpeed);
164
+ if (speed <= 0)
165
+ return 0;
166
+ const dtSeconds = deltaTime >= 1 ? deltaTime / 60 : deltaTime;
167
+ return 1 - Math.exp(-speed * dtSeconds);
168
+ }
169
+ lerp(start, end, t) {
170
+ return start + (end - start) * t;
171
+ }
172
+ matchesAnyZoneColor(particle) {
173
+ return this.matchesAnyZoneColorValue(this.copyColor(particle));
174
+ }
175
+ matchesAnyZoneColorValue(color) {
176
+ for (const zone of this.zones) {
177
+ const zoneColor = this.zoneColor(zone);
178
+ if (color.r === zoneColor.r && color.g === zoneColor.g && color.b === zoneColor.b) {
179
+ return true;
180
+ }
181
+ }
182
+ return false;
183
+ }
184
+ isInZone(particle, zone) {
185
+ var _a, _b, _c, _d, _e;
186
+ const dx = particle.movement.x - zone.center.x;
187
+ const dy = particle.movement.y - zone.center.y;
188
+ const shapeType = (_a = zone.shapeType) !== null && _a !== void 0 ? _a : 'circle';
189
+ if (shapeType === 'square') {
190
+ const halfSize = (_b = zone.halfSize) !== null && _b !== void 0 ? _b : 0;
191
+ return Math.abs(dx) < halfSize && Math.abs(dy) < halfSize;
192
+ }
193
+ if (shapeType === 'rectangle') {
194
+ const halfWidth = (_c = zone.halfWidth) !== null && _c !== void 0 ? _c : 0;
195
+ const halfHeight = (_d = zone.halfHeight) !== null && _d !== void 0 ? _d : 0;
196
+ return Math.abs(dx) < halfWidth && Math.abs(dy) < halfHeight;
197
+ }
198
+ const radius = (_e = zone.radius) !== null && _e !== void 0 ? _e : 0;
45
199
  return Math.sqrt(dx * dx + dy * dy) < radius;
46
200
  }
47
- /**
48
- * Returns the name of the behavior.
49
- */
50
201
  getName() {
51
202
  return behaviourNames.TEMPERATURE_BEHAVIOUR;
52
203
  }
53
- /**
54
- * Returns properties for serialization or debugging.
55
- */
56
204
  getProps() {
57
205
  return {
58
206
  enabled: this.enabled,
59
207
  priority: this.priority,
60
208
  zones: this.zones,
209
+ gradualColorTransition: this.gradualColorTransition,
210
+ colorTransitionSpeed: this.colorTransitionSpeed,
61
211
  };
62
212
  }
63
213
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TemperatureBehaviour.js","sourceRoot":"","sources":["../../../src/lib/behaviour/TemperatureBehaviour.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,aAAa,CAAA;AAGnC,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAE7C;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,SAAS;IAA3D;;QACE,YAAO,GAAG,IAAI,CAAA;QACd,aAAQ,GAAG,GAAG,CAAA;QAEd,UAAK,GAAuE,EAAE,CAAA;IAuDhF,CAAC;IArDC;;;OAGG;IACH,IAAI,CAAC,QAAkB;QACrB,qDAAqD;IACvD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAkB;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAM;QAE9D,2CAA2C;QAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtD,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;gBACtC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;gBACtC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC/B,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC/B,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC/B,MAAK;YACP,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,QAAkB,EAAE,MAAa,EAAE,MAAc;QACxD,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;QACzC,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;QACzC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,MAAM,CAAA;IAC9C,CAAC;IAED;;OAEG;IACH,OAAO;QACL,OAAO,cAAc,CAAC,qBAAqB,CAAA;IAC7C,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAA;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"TemperatureBehaviour.js","sourceRoot":"","sources":["../../../src/lib/behaviour/TemperatureBehaviour.ts"],"names":[],"mappings":"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"}
@@ -3,10 +3,12 @@ import Particle from '../Particle';
3
3
  import type Model from '../Model';
4
4
  import type TurbulencePool from '../util/turbulencePool';
5
5
  /**
6
- * Toroidal screen/world wrap: particles that leave an axis-aligned rectangle
7
- * re-enter on the opposite side. Runs after {@link PositionBehaviour} (lower priority).
8
- * Syncs {@link Particle.movement} with wrapped {@link Particle.x}/{@link Particle.y}
9
- * (same pattern as {@link BounceBehaviour}). Do not combine with bounce on the same axis.
6
+ * Toroidal screen/world wrap: particles that fully leave an axis-aligned rectangle
7
+ * re-enter on the opposite side while still fully outside the view (no visible jump).
8
+ * Uses sprite bounds when available; falls back to particle size. Runs after
9
+ * {@link PositionBehaviour} (lower priority). Syncs {@link Particle.movement} with
10
+ * wrapped {@link Particle.x}/{@link Particle.y} (same pattern as {@link BounceBehaviour}).
11
+ * Do not combine with bounce on the same axis.
10
12
  */
11
13
  export default class ToroidalWrapBehaviour extends Behaviour {
12
14
  enabled: boolean;
@@ -1,10 +1,13 @@
1
1
  import Behaviour from './Behaviour';
2
2
  import BehaviourNames from './BehaviourNames';
3
+ import { getToroidalEdgeExtents, wrapToroidalAxis } from '../util/toroidalWrapExtents';
3
4
  /**
4
- * Toroidal screen/world wrap: particles that leave an axis-aligned rectangle
5
- * re-enter on the opposite side. Runs after {@link PositionBehaviour} (lower priority).
6
- * Syncs {@link Particle.movement} with wrapped {@link Particle.x}/{@link Particle.y}
7
- * (same pattern as {@link BounceBehaviour}). Do not combine with bounce on the same axis.
5
+ * Toroidal screen/world wrap: particles that fully leave an axis-aligned rectangle
6
+ * re-enter on the opposite side while still fully outside the view (no visible jump).
7
+ * Uses sprite bounds when available; falls back to particle size. Runs after
8
+ * {@link PositionBehaviour} (lower priority). Syncs {@link Particle.movement} with
9
+ * wrapped {@link Particle.x}/{@link Particle.y} (same pattern as {@link BounceBehaviour}).
10
+ * Do not combine with bounce on the same axis.
8
11
  */
9
12
  export default class ToroidalWrapBehaviour extends Behaviour {
10
13
  constructor() {
@@ -36,35 +39,20 @@ export default class ToroidalWrapBehaviour extends Behaviour {
36
39
  const maxX = base.maxX - this.inset;
37
40
  const minY = base.minY + this.inset;
38
41
  const maxY = base.maxY - this.inset;
42
+ const extents = getToroidalEdgeExtents(particle);
39
43
  let x = particle.x;
40
44
  let y = particle.y;
41
45
  let mx = particle.movement.x;
42
46
  let my = particle.movement.y;
43
- if (this.wrapX) {
44
- const w = maxX - minX;
45
- if (w > 0) {
46
- while (x < minX) {
47
- x += w;
48
- mx += w;
49
- }
50
- while (x > maxX) {
51
- x -= w;
52
- mx -= w;
53
- }
54
- }
47
+ if (this.wrapX && maxX > minX) {
48
+ const wrapped = wrapToroidalAxis(x, mx, minX, maxX, extents.left, extents.right, particle.velocity.x);
49
+ x = wrapped.position;
50
+ mx = wrapped.movement;
55
51
  }
56
- if (this.wrapY) {
57
- const h = maxY - minY;
58
- if (h > 0) {
59
- while (y < minY) {
60
- y += h;
61
- my += h;
62
- }
63
- while (y > maxY) {
64
- y -= h;
65
- my -= h;
66
- }
67
- }
52
+ if (this.wrapY && maxY > minY) {
53
+ const wrapped = wrapToroidalAxis(y, my, minY, maxY, extents.top, extents.bottom, particle.velocity.y);
54
+ y = wrapped.position;
55
+ my = wrapped.movement;
68
56
  }
69
57
  particle.x = x;
70
58
  particle.y = y;
@@ -1 +1 @@
1
- {"version":3,"file":"ToroidalWrapBehaviour.js","sourceRoot":"","sources":["../../../src/lib/behaviour/ToroidalWrapBehaviour.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToroidalWrapBehaviour.js","sourceRoot":"","sources":["../../../src/lib/behaviour/ToroidalWrapBehaviour.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type Particle from '../Particle';
2
+ export type ToroidalEdgeExtents = {
3
+ left: number;
4
+ right: number;
5
+ top: number;
6
+ bottom: number;
7
+ };
8
+ /**
9
+ * Axis-aligned edge offsets from particle center to sprite bounds.
10
+ * Falls back to scaled size when no sprite/texture is available yet.
11
+ */
12
+ export declare function getToroidalEdgeExtents(particle: Particle): ToroidalEdgeExtents;
13
+ export type ToroidalAxisWrapResult = {
14
+ position: number;
15
+ movement: number;
16
+ };
17
+ /**
18
+ * Wraps one axis only after the particle is fully outside the bounds,
19
+ * placing it fully outside on the opposite side to avoid visible jumps.
20
+ * Velocity sign prevents re-wrapping when the particle is entering from off-screen.
21
+ */
22
+ export declare function wrapToroidalAxis(position: number, movement: number, min: number, max: number, leadingExtent: number, trailingExtent: number, axisVelocity: number): ToroidalAxisWrapResult;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Axis-aligned edge offsets from particle center to sprite bounds.
3
+ * Falls back to scaled size when no sprite/texture is available yet.
4
+ */
5
+ export function getToroidalEdgeExtents(particle) {
6
+ var _a, _b, _c, _d, _e, _f;
7
+ const sprite = particle.sprite;
8
+ const texture = sprite === null || sprite === void 0 ? void 0 : sprite.texture;
9
+ if (sprite && texture) {
10
+ const scaleX = Math.abs(sprite.scale.x);
11
+ const scaleY = Math.abs(sprite.scale.y);
12
+ const width = texture.width * scaleX;
13
+ const height = texture.height * scaleY;
14
+ const anchorX = (_b = (_a = sprite.anchor) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0.5;
15
+ const anchorY = (_d = (_c = sprite.anchor) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0.5;
16
+ const rotation = (_f = (_e = sprite.rotation) !== null && _e !== void 0 ? _e : particle.rotation) !== null && _f !== void 0 ? _f : 0;
17
+ const cos = Math.abs(Math.cos(rotation));
18
+ const sin = Math.abs(Math.sin(rotation));
19
+ const halfW = (width * cos + height * sin) / 2;
20
+ const halfH = (width * sin + height * cos) / 2;
21
+ const centerOffsetX = width * (0.5 - anchorX) * cos - height * (0.5 - anchorY) * sin;
22
+ const centerOffsetY = width * (0.5 - anchorX) * sin + height * (0.5 - anchorY) * cos;
23
+ return {
24
+ left: halfW - centerOffsetX,
25
+ right: halfW + centerOffsetX,
26
+ top: halfH - centerOffsetY,
27
+ bottom: halfH + centerOffsetY,
28
+ };
29
+ }
30
+ const fallback = Math.max(Math.abs(particle.size.x), Math.abs(particle.size.y)) * 0.5;
31
+ return { left: fallback, right: fallback, top: fallback, bottom: fallback };
32
+ }
33
+ /**
34
+ * Wraps one axis only after the particle is fully outside the bounds,
35
+ * placing it fully outside on the opposite side to avoid visible jumps.
36
+ * Velocity sign prevents re-wrapping when the particle is entering from off-screen.
37
+ */
38
+ export function wrapToroidalAxis(position, movement, min, max, leadingExtent, trailingExtent, axisVelocity) {
39
+ let pos = position;
40
+ let mov = movement;
41
+ while (pos + trailingExtent < min && axisVelocity < 0) {
42
+ const overflow = min - pos - trailingExtent;
43
+ const next = max + leadingExtent + overflow;
44
+ mov += next - pos;
45
+ pos = next;
46
+ }
47
+ while (pos - leadingExtent > max && axisVelocity > 0) {
48
+ const overflow = pos - leadingExtent - max;
49
+ const next = min - trailingExtent - overflow;
50
+ mov += next - pos;
51
+ pos = next;
52
+ }
53
+ return { position: pos, movement: mov };
54
+ }
55
+ //# sourceMappingURL=toroidalWrapExtents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toroidalWrapExtents.js","sourceRoot":"","sources":["../../../src/lib/util/toroidalWrapExtents.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -51,5 +51,5 @@
51
51
  "lint:fix": "tslint --fix 'src/**/*.ts'",
52
52
  "test": "vitest run"
53
53
  },
54
- "version": "4.40.1"
54
+ "version": "4.41.0"
55
55
  }