@guinetik/gcanvas 1.0.0 → 1.0.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/demos/coordinates.html +698 -0
- package/demos/cube3d.html +23 -0
- package/demos/demos.css +17 -3
- package/demos/dino.html +42 -0
- package/demos/fluid-simple.html +22 -0
- package/demos/fluid.html +37 -0
- package/demos/gameobjects.html +626 -0
- package/demos/index.html +19 -7
- package/demos/js/blob.js +18 -5
- package/demos/js/coordinates.js +840 -0
- package/demos/js/cube3d.js +789 -0
- package/demos/js/dino.js +1420 -0
- package/demos/js/fluid-simple.js +253 -0
- package/demos/js/fluid.js +527 -0
- package/demos/js/gameobjects.js +176 -0
- package/demos/js/plane3d.js +256 -0
- package/demos/js/platformer.js +1579 -0
- package/demos/js/sphere3d.js +229 -0
- package/demos/js/sprite.js +473 -0
- package/demos/js/tde/accretiondisk.js +65 -12
- package/demos/js/tde/blackholescene.js +2 -2
- package/demos/js/tde/config.js +2 -2
- package/demos/js/tde/index.js +152 -27
- package/demos/js/tde/lensedstarfield.js +32 -25
- package/demos/js/tde/tdestar.js +78 -98
- package/demos/js/tde/tidalstream.js +24 -8
- package/demos/plane3d.html +24 -0
- package/demos/platformer.html +43 -0
- package/demos/sphere3d.html +24 -0
- package/demos/sprite.html +18 -0
- package/docs/README.md +230 -222
- package/docs/api/FluidSystem.md +173 -0
- package/docs/concepts/architecture-overview.md +204 -204
- package/docs/concepts/coordinate-system.md +384 -0
- package/docs/concepts/rendering-pipeline.md +279 -279
- package/docs/concepts/shapes-vs-gameobjects.md +187 -0
- package/docs/concepts/two-layer-architecture.md +229 -229
- package/docs/fluid-dynamics.md +99 -0
- package/docs/getting-started/first-game.md +354 -354
- package/docs/getting-started/installation.md +175 -157
- package/docs/modules/collision/README.md +2 -2
- package/docs/modules/fluent/README.md +6 -6
- package/docs/modules/game/README.md +303 -303
- package/docs/modules/isometric-camera.md +2 -2
- package/docs/modules/isometric.md +1 -1
- package/docs/modules/painter/README.md +328 -328
- package/docs/modules/particle/README.md +3 -3
- package/docs/modules/shapes/README.md +221 -221
- package/docs/modules/shapes/base/euclidian.md +123 -123
- package/docs/modules/shapes/base/shape.md +262 -262
- package/docs/modules/shapes/base/transformable.md +243 -243
- package/docs/modules/state/README.md +2 -2
- package/docs/modules/util/README.md +1 -1
- package/docs/modules/util/camera3d.md +3 -3
- package/docs/modules/util/scene3d.md +1 -1
- package/package.json +3 -1
- package/readme.md +19 -5
- package/src/collision/collision.js +75 -0
- package/src/game/game.js +11 -5
- package/src/game/index.js +2 -1
- package/src/game/objects/index.js +3 -0
- package/src/game/objects/platformer-scene.js +411 -0
- package/src/game/objects/scene.js +14 -0
- package/src/game/objects/sprite.js +529 -0
- package/src/game/pipeline.js +20 -16
- package/src/game/systems/FluidSystem.js +835 -0
- package/src/game/systems/index.js +11 -0
- package/src/game/ui/button.js +39 -18
- package/src/game/ui/cursor.js +14 -0
- package/src/game/ui/fps.js +12 -4
- package/src/game/ui/index.js +2 -0
- package/src/game/ui/stepper.js +549 -0
- package/src/game/ui/theme.js +123 -0
- package/src/game/ui/togglebutton.js +9 -3
- package/src/game/ui/tooltip.js +11 -4
- package/src/io/input.js +75 -45
- package/src/io/mouse.js +44 -19
- package/src/io/touch.js +35 -12
- package/src/math/fluid.js +507 -0
- package/src/math/index.js +2 -0
- package/src/mixins/anchor.js +17 -7
- package/src/motion/tweenetik.js +16 -0
- package/src/shapes/cube3d.js +599 -0
- package/src/shapes/index.js +3 -0
- package/src/shapes/plane3d.js +687 -0
- package/src/shapes/sphere3d.js +75 -6
- package/src/util/camera2d.js +315 -0
- package/src/util/camera3d.js +218 -12
- package/src/util/index.js +1 -0
- package/src/webgl/shaders/plane-shaders.js +332 -0
- package/src/webgl/shaders/sphere-shaders.js +4 -2
- package/types/fluent.d.ts +361 -0
- package/types/game.d.ts +303 -0
- package/types/index.d.ts +144 -5
- package/types/math.d.ts +361 -0
- package/types/motion.d.ts +271 -0
- package/types/particle.d.ts +373 -0
- package/types/shapes.d.ts +107 -9
- package/types/util.d.ts +353 -0
- package/types/webgl.d.ts +109 -0
- package/disk_example.png +0 -0
- package/tde.png +0 -0
package/types/motion.d.ts
CHANGED
|
@@ -676,3 +676,274 @@ export class Motion {
|
|
|
676
676
|
state?: MotionState | null
|
|
677
677
|
): MotionResult;
|
|
678
678
|
}
|
|
679
|
+
|
|
680
|
+
// ==========================================================================
|
|
681
|
+
// Standalone Motion Functions (V1 API)
|
|
682
|
+
// ==========================================================================
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Standalone bezier curve motion animation.
|
|
686
|
+
* @see Motion.bezier for class method equivalent
|
|
687
|
+
*/
|
|
688
|
+
export function bezierV1(
|
|
689
|
+
p0: [number, number],
|
|
690
|
+
p1: [number, number],
|
|
691
|
+
p2: [number, number],
|
|
692
|
+
p3: [number, number],
|
|
693
|
+
elapsedTime: number,
|
|
694
|
+
duration: number,
|
|
695
|
+
loop?: boolean,
|
|
696
|
+
yoyo?: boolean,
|
|
697
|
+
easingFn?: EasingFunction | null,
|
|
698
|
+
callbacks?: MotionCallbacks,
|
|
699
|
+
state?: MotionState | null
|
|
700
|
+
): MotionPositionResult;
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Standalone bounce animation.
|
|
704
|
+
* @see Motion.bounce for class method equivalent
|
|
705
|
+
*/
|
|
706
|
+
export function bounceV1(
|
|
707
|
+
maxHeight: number,
|
|
708
|
+
groundY: number,
|
|
709
|
+
bounceCount: number,
|
|
710
|
+
elapsedTime: number,
|
|
711
|
+
duration: number,
|
|
712
|
+
loop?: boolean,
|
|
713
|
+
easingFn?: EasingFunction | null,
|
|
714
|
+
callbacks?: MotionCallbacks,
|
|
715
|
+
state?: MotionState | null
|
|
716
|
+
): MotionValueResult;
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Standalone floating motion animation.
|
|
720
|
+
* @see Motion.float for class method equivalent
|
|
721
|
+
*/
|
|
722
|
+
export function floatV1(
|
|
723
|
+
target: PositionTarget,
|
|
724
|
+
elapsedTime: number,
|
|
725
|
+
duration: number,
|
|
726
|
+
speed: number,
|
|
727
|
+
randomness: number,
|
|
728
|
+
radius: number,
|
|
729
|
+
loop?: boolean,
|
|
730
|
+
easingFn?: EasingFunction | null,
|
|
731
|
+
callbacks?: MotionCallbacks,
|
|
732
|
+
state?: MotionState | null
|
|
733
|
+
): MotionPositionResult;
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Standalone path following animation.
|
|
737
|
+
* @see Motion.follow for class method equivalent
|
|
738
|
+
*/
|
|
739
|
+
export function followPath(
|
|
740
|
+
points: [number, number][],
|
|
741
|
+
closed: boolean,
|
|
742
|
+
elapsedTime: number,
|
|
743
|
+
duration: number,
|
|
744
|
+
loop?: boolean,
|
|
745
|
+
easingFn?: EasingFunction | null,
|
|
746
|
+
callbacks?: MotionCallbacks,
|
|
747
|
+
state?: MotionState | null
|
|
748
|
+
): MotionPositionResult;
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Standalone orbital motion animation.
|
|
752
|
+
* @see Motion.orbit for class method equivalent
|
|
753
|
+
*/
|
|
754
|
+
export function orbitV1(
|
|
755
|
+
centerX: number,
|
|
756
|
+
centerY: number,
|
|
757
|
+
radiusX: number,
|
|
758
|
+
radiusY: number,
|
|
759
|
+
startAngle: number,
|
|
760
|
+
elapsedTime: number,
|
|
761
|
+
duration: number,
|
|
762
|
+
loop?: boolean,
|
|
763
|
+
clockwise?: boolean,
|
|
764
|
+
easingFn?: EasingFunction | null,
|
|
765
|
+
callbacks?: MotionCallbacks,
|
|
766
|
+
state?: MotionState | null
|
|
767
|
+
): MotionPositionResult;
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Standalone oscillation animation.
|
|
771
|
+
* @see Motion.oscillate for class method equivalent
|
|
772
|
+
*/
|
|
773
|
+
export function oscillateV1(
|
|
774
|
+
min: number,
|
|
775
|
+
max: number,
|
|
776
|
+
elapsedTime: number,
|
|
777
|
+
duration: number,
|
|
778
|
+
loop?: boolean,
|
|
779
|
+
easingFn?: EasingFunction | null,
|
|
780
|
+
callbacks?: MotionCallbacks,
|
|
781
|
+
state?: MotionState | null
|
|
782
|
+
): MotionValueResult;
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Standalone parabolic arc animation.
|
|
786
|
+
* @see Motion.parabolic for class method equivalent
|
|
787
|
+
*/
|
|
788
|
+
export function parabolicV1(
|
|
789
|
+
start: number,
|
|
790
|
+
peak: number,
|
|
791
|
+
end: number,
|
|
792
|
+
elapsedTime: number,
|
|
793
|
+
duration: number,
|
|
794
|
+
loop?: boolean,
|
|
795
|
+
yoyo?: boolean,
|
|
796
|
+
easingFn?: EasingFunction | null,
|
|
797
|
+
callbacks?: MotionCallbacks,
|
|
798
|
+
state?: MotionState | null
|
|
799
|
+
): MotionValueResult;
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Standalone patrol animation.
|
|
803
|
+
* @see Motion.patrol for class method equivalent
|
|
804
|
+
*/
|
|
805
|
+
export function patrolV1(
|
|
806
|
+
initialX: number,
|
|
807
|
+
initialY: number,
|
|
808
|
+
elapsedTime: number,
|
|
809
|
+
moveTime: number,
|
|
810
|
+
waitTime: number,
|
|
811
|
+
radius: number,
|
|
812
|
+
loop?: boolean,
|
|
813
|
+
state?: MotionState | null
|
|
814
|
+
): MotionPositionResult;
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Standalone pendulum animation.
|
|
818
|
+
* @see Motion.pendulum for class method equivalent
|
|
819
|
+
*/
|
|
820
|
+
export function pendulumV1(
|
|
821
|
+
originAngle: number,
|
|
822
|
+
amplitude: number,
|
|
823
|
+
elapsedTime: number,
|
|
824
|
+
duration: number,
|
|
825
|
+
loop?: boolean,
|
|
826
|
+
damped?: boolean,
|
|
827
|
+
easingFn?: EasingFunction | null,
|
|
828
|
+
callbacks?: MotionCallbacks,
|
|
829
|
+
state?: MotionState | null
|
|
830
|
+
): MotionValueResult;
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Standalone pulse animation.
|
|
834
|
+
* @see Motion.pulse for class method equivalent
|
|
835
|
+
*/
|
|
836
|
+
export function pulseV1(
|
|
837
|
+
min: number,
|
|
838
|
+
max: number,
|
|
839
|
+
elapsedTime: number,
|
|
840
|
+
duration: number,
|
|
841
|
+
loop?: boolean,
|
|
842
|
+
yoyo?: boolean,
|
|
843
|
+
easingFn?: EasingFunction | null,
|
|
844
|
+
callbacks?: MotionCallbacks
|
|
845
|
+
): MotionValueResult;
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Standalone hop/jump animation.
|
|
849
|
+
* @see Motion.hop for class method equivalent
|
|
850
|
+
*/
|
|
851
|
+
export function hopV1(
|
|
852
|
+
startX: number,
|
|
853
|
+
startY: number,
|
|
854
|
+
endX: number,
|
|
855
|
+
endY: number,
|
|
856
|
+
height: number,
|
|
857
|
+
elapsedTime: number,
|
|
858
|
+
duration: number,
|
|
859
|
+
loop?: boolean,
|
|
860
|
+
easingFn?: EasingFunction | null,
|
|
861
|
+
callbacks?: MotionCallbacks,
|
|
862
|
+
state?: MotionState | null
|
|
863
|
+
): MotionPositionResult;
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Standalone shake animation.
|
|
867
|
+
* @see Motion.shake for class method equivalent
|
|
868
|
+
*/
|
|
869
|
+
export function shakeV1(
|
|
870
|
+
centerX: number,
|
|
871
|
+
centerY: number,
|
|
872
|
+
maxOffsetX: number,
|
|
873
|
+
maxOffsetY: number,
|
|
874
|
+
frequency: number,
|
|
875
|
+
decay: number,
|
|
876
|
+
elapsedTime: number,
|
|
877
|
+
duration: number,
|
|
878
|
+
loop?: boolean,
|
|
879
|
+
easingFn?: EasingFunction | null,
|
|
880
|
+
callbacks?: MotionCallbacks,
|
|
881
|
+
state?: MotionState | null
|
|
882
|
+
): MotionPositionResult;
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Standalone spiral animation.
|
|
886
|
+
* @see Motion.spiral for class method equivalent
|
|
887
|
+
*/
|
|
888
|
+
export function spiralV1(
|
|
889
|
+
centerX: number,
|
|
890
|
+
centerY: number,
|
|
891
|
+
startRadius: number,
|
|
892
|
+
endRadius: number,
|
|
893
|
+
startAngle: number,
|
|
894
|
+
revolutions: number,
|
|
895
|
+
elapsedTime: number,
|
|
896
|
+
duration: number,
|
|
897
|
+
loop?: boolean,
|
|
898
|
+
yoyo?: boolean,
|
|
899
|
+
easingFn?: EasingFunction | null,
|
|
900
|
+
callbacks?: MotionCallbacks,
|
|
901
|
+
state?: MotionState | null
|
|
902
|
+
): MotionPositionResult;
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Standalone spring animation.
|
|
906
|
+
* @see Motion.spring for class method equivalent
|
|
907
|
+
*/
|
|
908
|
+
export function springV1(
|
|
909
|
+
initial: number,
|
|
910
|
+
target: number,
|
|
911
|
+
elapsedTime: number,
|
|
912
|
+
duration: number,
|
|
913
|
+
loop?: boolean,
|
|
914
|
+
yoyo?: boolean,
|
|
915
|
+
springParams?: SpringParams,
|
|
916
|
+
callbacks?: MotionCallbacks
|
|
917
|
+
): SpringResult;
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Standalone swing animation.
|
|
921
|
+
* @see Motion.swing for class method equivalent
|
|
922
|
+
*/
|
|
923
|
+
export function swingV1(
|
|
924
|
+
centerX: number,
|
|
925
|
+
centerY: number,
|
|
926
|
+
maxAngle: number,
|
|
927
|
+
elapsedTime: number,
|
|
928
|
+
duration: number,
|
|
929
|
+
loop?: boolean,
|
|
930
|
+
yoyo?: boolean,
|
|
931
|
+
easingFn?: EasingFunction | null,
|
|
932
|
+
callbacks?: MotionCallbacks,
|
|
933
|
+
state?: MotionState | null
|
|
934
|
+
): MotionPositionResult;
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Standalone waypoint animation.
|
|
938
|
+
* @see Motion.waypoint for class method equivalent
|
|
939
|
+
*/
|
|
940
|
+
export function waypointV1(
|
|
941
|
+
target: PositionTarget,
|
|
942
|
+
elapsedTime: number,
|
|
943
|
+
waypoints: [number, number][],
|
|
944
|
+
speed: number,
|
|
945
|
+
waitTime: number,
|
|
946
|
+
loop?: boolean,
|
|
947
|
+
callbacks?: MotionCallbacks,
|
|
948
|
+
state?: MotionState | null
|
|
949
|
+
): WaypointResult;
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/// <reference lib="es2015" />
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GCanvas Particle System Module
|
|
5
|
+
* High-performance particle system with optional Camera3D support.
|
|
6
|
+
* @module particle
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { GameObject, GameObjectOptions, Game } from './game';
|
|
10
|
+
|
|
11
|
+
// ==========================================================================
|
|
12
|
+
// Particle Class
|
|
13
|
+
// ==========================================================================
|
|
14
|
+
|
|
15
|
+
/** RGBA color object */
|
|
16
|
+
export interface ParticleColor {
|
|
17
|
+
r: number;
|
|
18
|
+
g: number;
|
|
19
|
+
b: number;
|
|
20
|
+
a: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Particle shape type */
|
|
24
|
+
export type ParticleShape = 'circle' | 'square' | 'triangle';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Lightweight data class for particle systems.
|
|
28
|
+
* Uses object pooling via reset() to minimize garbage collection.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const p = new Particle();
|
|
32
|
+
* p.x = 100;
|
|
33
|
+
* p.y = 200;
|
|
34
|
+
* p.vx = 5;
|
|
35
|
+
* p.lifetime = 2;
|
|
36
|
+
*/
|
|
37
|
+
export class Particle {
|
|
38
|
+
/** X position */
|
|
39
|
+
x: number;
|
|
40
|
+
/** Y position */
|
|
41
|
+
y: number;
|
|
42
|
+
/** Z position (for 3D systems) */
|
|
43
|
+
z: number;
|
|
44
|
+
|
|
45
|
+
/** X velocity */
|
|
46
|
+
vx: number;
|
|
47
|
+
/** Y velocity */
|
|
48
|
+
vy: number;
|
|
49
|
+
/** Z velocity */
|
|
50
|
+
vz: number;
|
|
51
|
+
|
|
52
|
+
/** Particle size */
|
|
53
|
+
size: number;
|
|
54
|
+
/** Particle color */
|
|
55
|
+
color: ParticleColor;
|
|
56
|
+
/** Particle shape */
|
|
57
|
+
shape: ParticleShape;
|
|
58
|
+
|
|
59
|
+
/** Current age in seconds */
|
|
60
|
+
age: number;
|
|
61
|
+
/** Maximum lifetime in seconds */
|
|
62
|
+
lifetime: number;
|
|
63
|
+
/** Whether particle is alive */
|
|
64
|
+
alive: boolean;
|
|
65
|
+
|
|
66
|
+
/** Custom data for domain-specific behaviors */
|
|
67
|
+
custom: Record<string, any>;
|
|
68
|
+
|
|
69
|
+
/** Progress through lifetime (0 = born, 1 = about to die) */
|
|
70
|
+
readonly progress: number;
|
|
71
|
+
|
|
72
|
+
constructor();
|
|
73
|
+
|
|
74
|
+
/** Reset all properties for object pooling */
|
|
75
|
+
reset(): void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ==========================================================================
|
|
79
|
+
// ParticleEmitter Class
|
|
80
|
+
// ==========================================================================
|
|
81
|
+
|
|
82
|
+
/** Options for ParticleEmitter */
|
|
83
|
+
export interface ParticleEmitterOptions {
|
|
84
|
+
/** Emission rate (particles per second) */
|
|
85
|
+
rate?: number;
|
|
86
|
+
/** Position X */
|
|
87
|
+
x?: number;
|
|
88
|
+
/** Position Y */
|
|
89
|
+
y?: number;
|
|
90
|
+
/** Position Z */
|
|
91
|
+
z?: number;
|
|
92
|
+
/** Position spread (randomness) */
|
|
93
|
+
spread?: { x?: number; y?: number; z?: number };
|
|
94
|
+
/** Initial velocity */
|
|
95
|
+
velocity?: { x?: number; y?: number; z?: number };
|
|
96
|
+
/** Velocity spread (randomness) */
|
|
97
|
+
velocitySpread?: { x?: number; y?: number; z?: number };
|
|
98
|
+
/** Particle size range [min, max] */
|
|
99
|
+
size?: [number, number];
|
|
100
|
+
/** Particle lifetime range [min, max] */
|
|
101
|
+
lifetime?: [number, number];
|
|
102
|
+
/** Particle color */
|
|
103
|
+
color?: ParticleColor | ((particle: Particle) => ParticleColor);
|
|
104
|
+
/** Particle shape */
|
|
105
|
+
shape?: ParticleShape;
|
|
106
|
+
/** Custom initializer function */
|
|
107
|
+
init?: (particle: Particle, emitter: ParticleEmitter) => void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Emitter that spawns particles with configurable properties.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* const emitter = new ParticleEmitter({
|
|
115
|
+
* rate: 50,
|
|
116
|
+
* x: 400, y: 300,
|
|
117
|
+
* velocity: { x: 0, y: -100 },
|
|
118
|
+
* velocitySpread: { x: 50, y: 20 },
|
|
119
|
+
* lifetime: [1, 3],
|
|
120
|
+
* size: [2, 8],
|
|
121
|
+
* });
|
|
122
|
+
*/
|
|
123
|
+
export class ParticleEmitter {
|
|
124
|
+
/** Whether emitter is active */
|
|
125
|
+
active: boolean;
|
|
126
|
+
/** Emission rate (particles per second) */
|
|
127
|
+
rate: number;
|
|
128
|
+
/** Emitter position X */
|
|
129
|
+
x: number;
|
|
130
|
+
/** Emitter position Y */
|
|
131
|
+
y: number;
|
|
132
|
+
/** Emitter position Z */
|
|
133
|
+
z: number;
|
|
134
|
+
|
|
135
|
+
constructor(options?: ParticleEmitterOptions);
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Update emitter and return number of particles to spawn.
|
|
139
|
+
* @param dt - Delta time in seconds
|
|
140
|
+
* @returns Number of particles to spawn this frame
|
|
141
|
+
*/
|
|
142
|
+
update(dt: number): number;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Initialize a particle with this emitter's settings.
|
|
146
|
+
* @param particle - Particle to initialize
|
|
147
|
+
*/
|
|
148
|
+
emit(particle: Particle): void;
|
|
149
|
+
|
|
150
|
+
/** Start emitting */
|
|
151
|
+
start(): void;
|
|
152
|
+
|
|
153
|
+
/** Stop emitting */
|
|
154
|
+
stop(): void;
|
|
155
|
+
|
|
156
|
+
/** Burst spawn a specific number of particles */
|
|
157
|
+
burst(count: number): void;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ==========================================================================
|
|
161
|
+
// ParticleSystem Class
|
|
162
|
+
// ==========================================================================
|
|
163
|
+
|
|
164
|
+
/** Options for ParticleSystem */
|
|
165
|
+
export interface ParticleSystemOptions extends GameObjectOptions {
|
|
166
|
+
/** Maximum active particles (default: 5000) */
|
|
167
|
+
maxParticles?: number;
|
|
168
|
+
/** Optional Camera3D for 3D projection */
|
|
169
|
+
camera?: any; // Camera3D
|
|
170
|
+
/** Enable depth sorting (requires camera) */
|
|
171
|
+
depthSort?: boolean;
|
|
172
|
+
/** Canvas blend mode (default: 'source-over') */
|
|
173
|
+
blendMode?: GlobalCompositeOperation;
|
|
174
|
+
/** Array of updater functions */
|
|
175
|
+
updaters?: ParticleUpdater[];
|
|
176
|
+
/** Position particles in world space */
|
|
177
|
+
worldSpace?: boolean;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Particle updater function signature */
|
|
181
|
+
export type ParticleUpdater = (particle: Particle, dt: number, system: ParticleSystem) => void;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* High-performance particle management GameObject.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* const particles = new ParticleSystem(this, {
|
|
188
|
+
* camera: this.camera,
|
|
189
|
+
* depthSort: true,
|
|
190
|
+
* maxParticles: 3000,
|
|
191
|
+
* blendMode: 'screen',
|
|
192
|
+
* updaters: [Updaters.velocity, Updaters.lifetime, Updaters.gravity(150)],
|
|
193
|
+
* });
|
|
194
|
+
* particles.addEmitter('fountain', new ParticleEmitter({ rate: 50 }));
|
|
195
|
+
* this.pipeline.add(particles);
|
|
196
|
+
*/
|
|
197
|
+
export class ParticleSystem extends GameObject {
|
|
198
|
+
/** Active particles */
|
|
199
|
+
particles: Particle[];
|
|
200
|
+
/** Object pool for recycled particles */
|
|
201
|
+
pool: Particle[];
|
|
202
|
+
/** Maximum particles allowed */
|
|
203
|
+
maxParticles: number;
|
|
204
|
+
/** Named emitters */
|
|
205
|
+
emitters: Map<string, ParticleEmitter>;
|
|
206
|
+
/** Optional Camera3D for 3D projection */
|
|
207
|
+
camera: any | null;
|
|
208
|
+
/** Whether to depth sort particles */
|
|
209
|
+
depthSort: boolean;
|
|
210
|
+
/** Updater functions */
|
|
211
|
+
updaters: ParticleUpdater[];
|
|
212
|
+
/** Canvas blend mode (set via options, not an accessor) */
|
|
213
|
+
readonly _blendMode: GlobalCompositeOperation;
|
|
214
|
+
/** Position in world space */
|
|
215
|
+
worldSpace: boolean;
|
|
216
|
+
|
|
217
|
+
/** Current particle count */
|
|
218
|
+
readonly particleCount: number;
|
|
219
|
+
/** Pool size (recycled particles ready for reuse) */
|
|
220
|
+
readonly poolSize: number;
|
|
221
|
+
|
|
222
|
+
constructor(game: Game, options?: ParticleSystemOptions);
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Add an emitter to the system.
|
|
226
|
+
* @param name - Emitter identifier
|
|
227
|
+
* @param emitter - Emitter instance
|
|
228
|
+
*/
|
|
229
|
+
addEmitter(name: string, emitter: ParticleEmitter): ParticleSystem;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Remove an emitter from the system.
|
|
233
|
+
* @param name - Emitter identifier
|
|
234
|
+
*/
|
|
235
|
+
removeEmitter(name: string): ParticleSystem;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Get an emitter by name.
|
|
239
|
+
* @param name - Emitter identifier
|
|
240
|
+
*/
|
|
241
|
+
getEmitter(name: string): ParticleEmitter | undefined;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Acquire a particle from pool or create new.
|
|
245
|
+
*/
|
|
246
|
+
acquire(): Particle;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Release a particle back to pool.
|
|
250
|
+
* @param particle - Particle to release
|
|
251
|
+
*/
|
|
252
|
+
release(particle: Particle): void;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Emit particles using an emitter.
|
|
256
|
+
* @param count - Number of particles to emit
|
|
257
|
+
* @param emitter - Emitter to use
|
|
258
|
+
*/
|
|
259
|
+
emitParticles(count: number, emitter: ParticleEmitter): void;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Burst spawn particles.
|
|
263
|
+
* @param count - Number of particles
|
|
264
|
+
* @param emitterOrName - Emitter instance or name
|
|
265
|
+
*/
|
|
266
|
+
burst(count: number, emitterOrName: ParticleEmitter | string): void;
|
|
267
|
+
|
|
268
|
+
/** Clear all particles and return them to pool */
|
|
269
|
+
clear(): void;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Draw a single particle (override for custom rendering).
|
|
273
|
+
* @param ctx - Canvas context
|
|
274
|
+
* @param p - Particle to draw
|
|
275
|
+
* @param x - Screen X position
|
|
276
|
+
* @param y - Screen Y position
|
|
277
|
+
* @param scale - Size scale factor
|
|
278
|
+
*/
|
|
279
|
+
drawParticle(ctx: CanvasRenderingContext2D, p: Particle, x: number, y: number, scale: number): void;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ==========================================================================
|
|
283
|
+
// Updaters
|
|
284
|
+
// ==========================================================================
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Collection of composable particle updater functions.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* const system = new ParticleSystem(game, {
|
|
291
|
+
* updaters: [
|
|
292
|
+
* Updaters.velocity,
|
|
293
|
+
* Updaters.lifetime,
|
|
294
|
+
* Updaters.gravity(200),
|
|
295
|
+
* Updaters.fadeOut,
|
|
296
|
+
* Updaters.shrink,
|
|
297
|
+
* ]
|
|
298
|
+
* });
|
|
299
|
+
*/
|
|
300
|
+
export namespace Updaters {
|
|
301
|
+
/** Apply velocity to position */
|
|
302
|
+
const velocity: ParticleUpdater;
|
|
303
|
+
|
|
304
|
+
/** Update age and kill expired particles */
|
|
305
|
+
const lifetime: ParticleUpdater;
|
|
306
|
+
|
|
307
|
+
/** Fade out alpha over lifetime */
|
|
308
|
+
const fadeOut: ParticleUpdater;
|
|
309
|
+
|
|
310
|
+
/** Shrink size over lifetime */
|
|
311
|
+
const shrink: ParticleUpdater;
|
|
312
|
+
|
|
313
|
+
/** Grow size over lifetime */
|
|
314
|
+
const grow: ParticleUpdater;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Apply gravity acceleration.
|
|
318
|
+
* @param strength - Gravity strength (pixels per second squared)
|
|
319
|
+
* @param axis - Axis to apply gravity ('y' by default)
|
|
320
|
+
*/
|
|
321
|
+
function gravity(strength: number, axis?: 'x' | 'y' | 'z'): ParticleUpdater;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Apply friction/drag.
|
|
325
|
+
* @param factor - Friction factor (0-1, lower = more friction)
|
|
326
|
+
*/
|
|
327
|
+
function friction(factor: number): ParticleUpdater;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Apply wind force.
|
|
331
|
+
* @param forceX - X force
|
|
332
|
+
* @param forceY - Y force
|
|
333
|
+
*/
|
|
334
|
+
function wind(forceX: number, forceY: number): ParticleUpdater;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Constrain particles to bounds.
|
|
338
|
+
* @param bounds - Bounding box
|
|
339
|
+
* @param bounce - Bounce factor (0-1)
|
|
340
|
+
*/
|
|
341
|
+
function bounds(bounds: { x: number; y: number; width: number; height: number }, bounce?: number): ParticleUpdater;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Color transition over lifetime.
|
|
345
|
+
* @param startColor - Starting color
|
|
346
|
+
* @param endColor - Ending color
|
|
347
|
+
*/
|
|
348
|
+
function colorTransition(startColor: ParticleColor, endColor: ParticleColor): ParticleUpdater;
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Attract/repel from a point.
|
|
352
|
+
* @param x - Attractor X position
|
|
353
|
+
* @param y - Attractor Y position
|
|
354
|
+
* @param strength - Attraction strength (negative = repel)
|
|
355
|
+
*/
|
|
356
|
+
function attract(x: number, y: number, strength: number): ParticleUpdater;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Apply turbulence/noise to velocity.
|
|
360
|
+
* @param strength - Turbulence strength
|
|
361
|
+
* @param scale - Noise scale
|
|
362
|
+
*/
|
|
363
|
+
function turbulence(strength: number, scale?: number): ParticleUpdater;
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Orbital motion around a point.
|
|
367
|
+
* @param centerX - Center X
|
|
368
|
+
* @param centerY - Center Y
|
|
369
|
+
* @param speed - Angular speed
|
|
370
|
+
*/
|
|
371
|
+
function orbital(centerX: number, centerY: number, speed: number): ParticleUpdater;
|
|
372
|
+
}
|
|
373
|
+
|