action-engine-js 1.0.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.
Files changed (93) hide show
  1. package/LICENSE +45 -0
  2. package/README.md +348 -0
  3. package/actionengine/3rdparty/goblin/goblin.js +9609 -0
  4. package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
  5. package/actionengine/camera/actioncamera.js +90 -0
  6. package/actionengine/camera/cameracollisionhandler.js +69 -0
  7. package/actionengine/character/actioncharacter.js +360 -0
  8. package/actionengine/character/actioncharacter3D.js +61 -0
  9. package/actionengine/core/app.js +430 -0
  10. package/actionengine/debug/basedebugpanel.js +858 -0
  11. package/actionengine/display/canvasmanager.js +75 -0
  12. package/actionengine/display/gl/programmanager.js +570 -0
  13. package/actionengine/display/gl/shaders/lineshader.js +118 -0
  14. package/actionengine/display/gl/shaders/objectshader.js +1756 -0
  15. package/actionengine/display/gl/shaders/particleshader.js +43 -0
  16. package/actionengine/display/gl/shaders/shadowshader.js +319 -0
  17. package/actionengine/display/gl/shaders/spriteshader.js +100 -0
  18. package/actionengine/display/gl/shaders/watershader.js +67 -0
  19. package/actionengine/display/graphics/actionmodel3D.js +191 -0
  20. package/actionengine/display/graphics/actionsprite3D.js +230 -0
  21. package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
  22. package/actionengine/display/graphics/lighting/actionlight.js +211 -0
  23. package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
  24. package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
  25. package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
  26. package/actionengine/display/graphics/renderableobject.js +44 -0
  27. package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
  28. package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
  29. package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
  30. package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
  31. package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
  32. package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
  33. package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
  34. package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
  35. package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
  36. package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
  37. package/actionengine/display/graphics/texture/texturemanager.js +242 -0
  38. package/actionengine/display/graphics/texture/textureregistry.js +177 -0
  39. package/actionengine/input/actionscrollablearea.js +1405 -0
  40. package/actionengine/input/inputhandler.js +1647 -0
  41. package/actionengine/math/geometry/geometrybuilder.js +161 -0
  42. package/actionengine/math/geometry/glbexporter.js +364 -0
  43. package/actionengine/math/geometry/glbloader.js +722 -0
  44. package/actionengine/math/geometry/modelcodegenerator.js +97 -0
  45. package/actionengine/math/geometry/triangle.js +33 -0
  46. package/actionengine/math/geometry/triangleutils.js +34 -0
  47. package/actionengine/math/mathutils.js +25 -0
  48. package/actionengine/math/matrix4.js +785 -0
  49. package/actionengine/math/physics/actionphysics.js +108 -0
  50. package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
  51. package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
  52. package/actionengine/math/physics/actionraycast.js +129 -0
  53. package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
  54. package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
  55. package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
  56. package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
  57. package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
  58. package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
  59. package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
  60. package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
  61. package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
  62. package/actionengine/math/quaternion.js +61 -0
  63. package/actionengine/math/vector2.js +277 -0
  64. package/actionengine/math/vector3.js +318 -0
  65. package/actionengine/math/viewfrustum.js +136 -0
  66. package/actionengine/network/ACTIONNETREADME.md +810 -0
  67. package/actionengine/network/client/ActionNetManager.js +802 -0
  68. package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
  69. package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
  70. package/actionengine/network/client/SyncSystem.js +422 -0
  71. package/actionengine/network/p2p/ActionNetPeer.js +142 -0
  72. package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
  73. package/actionengine/network/p2p/DataConnection.js +282 -0
  74. package/actionengine/network/p2p/README.md +510 -0
  75. package/actionengine/network/p2p/example.html +502 -0
  76. package/actionengine/network/server/ActionNetServer.js +577 -0
  77. package/actionengine/network/server/ActionNetServerSSL.js +579 -0
  78. package/actionengine/network/server/ActionNetServerUtils.js +458 -0
  79. package/actionengine/network/server/SERVERREADME.md +314 -0
  80. package/actionengine/network/server/package-lock.json +35 -0
  81. package/actionengine/network/server/package.json +13 -0
  82. package/actionengine/network/server/start.bat +27 -0
  83. package/actionengine/network/server/start.sh +25 -0
  84. package/actionengine/network/server/startwss.bat +27 -0
  85. package/actionengine/sound/audiomanager.js +1589 -0
  86. package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
  87. package/actionengine/sound/soundfont/actionparser.js +718 -0
  88. package/actionengine/sound/soundfont/actionreverb.js +252 -0
  89. package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
  90. package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
  91. package/actionengine/sound/soundfont/soundfont.js +2 -0
  92. package/dist/action-engine.min.js +328 -0
  93. package/package.json +35 -0
@@ -0,0 +1,72 @@
1
+ class ActionPhysicsConvexShape3D extends ActionPhysicsObject3D {
2
+ constructor(physicsWorld, vertices, mass = 1, initialPosition = new Vector3(0, 500, 0), colors = []) {
3
+ // Convert input vertices to Goblin.Vector3 for physics
4
+ const goblinVertices = vertices.map(v => new Goblin.Vector3(v.x, v.y, v.z));
5
+
6
+ // Create the Goblin physics shape first, so we can access its faces
7
+ const goblinShape = new Goblin.ConvexShape(goblinVertices);
8
+
9
+ // Default colors if none provided
10
+ const defaultColors = [
11
+ "#FF5733", // Coral
12
+ "#F9A826", // Orange
13
+ "#6A0572", // Purple
14
+ "#4D89E5", // Blue
15
+ "#2E8B57" // SeaGreen
16
+ ];
17
+
18
+ // Create triangles based on the actual faces of the convex hull
19
+ const triangles = [];
20
+
21
+ // Each face in the Goblin shape is a triangular face of the convex hull
22
+ goblinShape.faces.forEach((face, index) => {
23
+ // Get the vertices of this face
24
+ const v1 = new Vector3(face.a.point.x, face.a.point.y, face.a.point.z);
25
+ const v2 = new Vector3(face.b.point.x, face.b.point.y, face.b.point.z);
26
+ const v3 = new Vector3(face.c.point.x, face.c.point.y, face.c.point.z);
27
+
28
+ // Choose a color for this face
29
+ const color = colors[index % colors.length] || defaultColors[index % defaultColors.length];
30
+
31
+ // Create a triangle with the vertices of this face
32
+ triangles.push(new Triangle(v1, v2, v3, color));
33
+ });
34
+
35
+ // Pass triangles to parent constructor
36
+ super(physicsWorld, triangles);
37
+
38
+ // Create the rigid body
39
+ this.body = new Goblin.RigidBody(goblinShape, mass);
40
+ this.body.position.set(
41
+ initialPosition.x,
42
+ initialPosition.y,
43
+ initialPosition.z
44
+ );
45
+
46
+ this.body.linear_damping = 0.01;
47
+ this.body.angular_damping = 0.01;
48
+
49
+ this.storeOriginalData();
50
+ }
51
+
52
+ storeOriginalData() {
53
+ this.originalNormals = [];
54
+ this.originalVerts = [];
55
+
56
+ this.triangles.forEach((triangle) => {
57
+ this.originalNormals.push(new Vector3(
58
+ triangle.normal.x,
59
+ triangle.normal.y,
60
+ triangle.normal.z
61
+ ));
62
+
63
+ triangle.vertices.forEach((vertex) => {
64
+ this.originalVerts.push(new Vector3(
65
+ vertex.x,
66
+ vertex.y,
67
+ vertex.z
68
+ ));
69
+ });
70
+ });
71
+ }
72
+ }
@@ -0,0 +1,117 @@
1
+ // actionengine/math/physics/actionphysicscylinder3D.js
2
+ class ActionPhysicsCylinder3D extends ActionPhysicsObject3D {
3
+ constructor(
4
+ physicsWorld,
5
+ radius = 2,
6
+ height = 10,
7
+ mass = 1,
8
+ initialPosition = new Vector3(0, 10, 0),
9
+ color1 = "#FF0000",
10
+ color2 = "#0000FF"
11
+ ) {
12
+ // Create visual mesh with triangles
13
+ const triangles = [];
14
+
15
+ // Segments for mesh detail
16
+ const radialSegments = 12;
17
+ const heightSegments = 4;
18
+
19
+ // Helper function to create cylinder vertices
20
+ const createVertex = (theta, y, radius) => {
21
+ return new Vector3(
22
+ radius * Math.cos(theta),
23
+ y,
24
+ radius * Math.sin(theta)
25
+ );
26
+ };
27
+
28
+ // Helper to alternate colors for triangle checkerboard pattern
29
+ const getColor = (x, y) => ((x + y) % 2 === 0) ? color1 : color2;
30
+
31
+ const halfHeight = height / 2;
32
+
33
+ // 1. Create Cylinder Body
34
+ for (let y = 0; y < heightSegments; y++) {
35
+ const yBottom = -halfHeight + (y / heightSegments) * height;
36
+ const yTop = -halfHeight + ((y + 1) / heightSegments) * height;
37
+
38
+ for (let x = 0; x < radialSegments; x++) {
39
+ const theta = (x / radialSegments) * Math.PI * 2;
40
+ const thetaNext = ((x + 1) % radialSegments) / radialSegments * Math.PI * 2;
41
+
42
+ // Create four vertices for this quad segment
43
+ const v1 = createVertex(theta, yBottom, radius);
44
+ const v2 = createVertex(thetaNext, yBottom, radius);
45
+ const v3 = createVertex(thetaNext, yTop, radius);
46
+ const v4 = createVertex(theta, yTop, radius);
47
+
48
+ // Create two triangles with outward-facing normals
49
+ triangles.push(new Triangle(v1, v3, v2, getColor(x, y)));
50
+ triangles.push(new Triangle(v1, v4, v3, getColor(x, y)));
51
+ }
52
+ }
53
+
54
+ // 2. Create Top Cap
55
+ const topCenter = new Vector3(0, halfHeight, 0);
56
+ for (let x = 0; x < radialSegments; x++) {
57
+ const theta = (x / radialSegments) * Math.PI * 2;
58
+ const thetaNext = ((x + 1) % radialSegments) / radialSegments * Math.PI * 2;
59
+
60
+ const v1 = createVertex(theta, halfHeight, radius);
61
+ const v2 = createVertex(thetaNext, halfHeight, radius);
62
+
63
+ // Create triangle with upward-facing normal
64
+ triangles.push(new Triangle(v1, topCenter, v2, getColor(x, heightSegments)));
65
+ }
66
+
67
+ // 3. Create Bottom Cap
68
+ const bottomCenter = new Vector3(0, -halfHeight, 0);
69
+ for (let x = 0; x < radialSegments; x++) {
70
+ const theta = (x / radialSegments) * Math.PI * 2;
71
+ const thetaNext = ((x + 1) % radialSegments) / radialSegments * Math.PI * 2;
72
+
73
+ const v1 = createVertex(theta, -halfHeight, radius);
74
+ const v2 = createVertex(thetaNext, -halfHeight, radius);
75
+
76
+ // Create triangle with downward-facing normal
77
+ triangles.push(new Triangle(v1, v2, bottomCenter, getColor(x, heightSegments + 1)));
78
+ }
79
+
80
+ super(physicsWorld, triangles);
81
+
82
+ // Create physics shape and body
83
+ const shape = new Goblin.CylinderShape(radius, halfHeight);
84
+ this.body = new Goblin.RigidBody(shape, mass);
85
+ this.body.position.set(
86
+ initialPosition.x,
87
+ initialPosition.y,
88
+ initialPosition.z
89
+ );
90
+
91
+ this.body.linear_damping = 0.01;
92
+ this.body.angular_damping = 0.01;
93
+
94
+ this.storeOriginalData();
95
+ }
96
+
97
+ storeOriginalData() {
98
+ this.originalNormals = [];
99
+ this.originalVerts = [];
100
+
101
+ this.triangles.forEach((triangle) => {
102
+ this.originalNormals.push(new Vector3(
103
+ triangle.normal.x,
104
+ triangle.normal.y,
105
+ triangle.normal.z
106
+ ));
107
+
108
+ triangle.vertices.forEach((vertex) => {
109
+ this.originalVerts.push(new Vector3(
110
+ vertex.x,
111
+ vertex.y,
112
+ vertex.z
113
+ ));
114
+ });
115
+ });
116
+ }
117
+ }
@@ -0,0 +1,74 @@
1
+ // actionengine/math/physics/actionphysicsmesh3D.js
2
+ class ActionPhysicsMesh3D extends ActionPhysicsObject3D {
3
+ constructor(
4
+ physicsWorld,
5
+ vertices, // Array of Vector3 positions
6
+ indices, // Array of indices forming triangles (groups of 3)
7
+ mass = 0, // Default to static (0 = immovable)
8
+ initialPosition = new Vector3(0, 0, 0),
9
+ colors = null // Optional array of colors for each triangle
10
+ ) {
11
+ // Create triangles from vertices and indices
12
+ const triangles = [];
13
+
14
+ // Process indices in groups of 3 to form triangles
15
+ for (let i = 0; i < indices.length; i += 3) {
16
+ const v1 = vertices[indices[i]].clone();
17
+ const v2 = vertices[indices[i+1]].clone();
18
+ const v3 = vertices[indices[i+2]].clone();
19
+
20
+ // Determine color for this triangle
21
+ let color = "#AAAAAA"; // Default gray
22
+ if (colors && colors[Math.floor(i/3)]) {
23
+ color = colors[Math.floor(i/3)];
24
+ } else if (colors && colors.length === 1) {
25
+ color = colors[0];
26
+ }
27
+
28
+ triangles.push(new Triangle(v1, v2, v3, color));
29
+ }
30
+
31
+ super(physicsWorld, triangles);
32
+
33
+ // Convert vertices to Goblin.Vector3 for the physics engine
34
+ const goblinVertices = vertices.map(v => new Goblin.Vector3(v.x, v.y, v.z));
35
+
36
+ // Create physics shape and body
37
+ const shape = new Goblin.MeshShape(goblinVertices, indices);
38
+ this.body = new Goblin.RigidBody(shape, mass);
39
+ this.body.position.set(
40
+ initialPosition.x,
41
+ initialPosition.y,
42
+ initialPosition.z
43
+ );
44
+
45
+ // Set damping properties if it's not static
46
+ if (mass > 0) {
47
+ this.body.linear_damping = 0.01;
48
+ this.body.angular_damping = 0.01;
49
+ }
50
+
51
+ this.storeOriginalData();
52
+ }
53
+
54
+ storeOriginalData() {
55
+ this.originalNormals = [];
56
+ this.originalVerts = [];
57
+
58
+ this.triangles.forEach((triangle) => {
59
+ this.originalNormals.push(new Vector3(
60
+ triangle.normal.x,
61
+ triangle.normal.y,
62
+ triangle.normal.z
63
+ ));
64
+
65
+ triangle.vertices.forEach((vertex) => {
66
+ this.originalVerts.push(new Vector3(
67
+ vertex.x,
68
+ vertex.y,
69
+ vertex.z
70
+ ));
71
+ });
72
+ });
73
+ }
74
+ }
@@ -0,0 +1,100 @@
1
+ class ActionPhysicsPlane3D extends ActionPhysicsObject3D {
2
+ constructor(
3
+ physicsWorld,
4
+ orientation = 1,
5
+ width = 100,
6
+ length = 100,
7
+ mass = 0,
8
+ initialPosition = new Vector3(0, 0, 0),
9
+ normalDirection = 1, // 1 = up/positive, -1 = down/negative
10
+ doubleSided = true // Whether to create back-facing triangles
11
+ ) {
12
+ // Create visual mesh with triangles
13
+ const segments = 10; // Can be adjusted based on needed detail
14
+ const triangles = [];
15
+ const getColor = (x, z) => ((Math.floor(x) + Math.floor(z)) % 2 === 0) ? "#FFFFFF" : "#CCCCCC";
16
+ const getBackColor = (x, z) => ((Math.floor(x) + Math.floor(z)) % 2 === 0) ? "#DDDDDD" : "#999999";
17
+
18
+ // Generate grid of vertices
19
+ for (let x = 0; x < segments; x++) {
20
+ for (let z = 0; z < segments; z++) {
21
+ const x1 = (x / segments - 0.5) * width;
22
+ const x2 = ((x + 1) / segments - 0.5) * width;
23
+ const z1 = (z / segments - 0.5) * length;
24
+ const z2 = ((z + 1) / segments - 0.5) * length;
25
+
26
+ // Create vertices based on orientation
27
+ let v1, v2, v3, v4;
28
+ if (orientation === 0) { // YZ plane
29
+ v1 = new Vector3(0, x1, z1);
30
+ v2 = new Vector3(0, x2, z1);
31
+ v3 = new Vector3(0, x2, z2);
32
+ v4 = new Vector3(0, x1, z2);
33
+ } else if (orientation === 1) { // XZ plane (ground plane)
34
+ v1 = new Vector3(x1, 0, z1);
35
+ v2 = new Vector3(x2, 0, z1);
36
+ v3 = new Vector3(x2, 0, z2);
37
+ v4 = new Vector3(x1, 0, z2);
38
+ } else { // XY plane
39
+ v1 = new Vector3(x1, z1, 0);
40
+ v2 = new Vector3(x2, z1, 0);
41
+ v3 = new Vector3(x2, z2, 0);
42
+ v4 = new Vector3(x1, z2, 0);
43
+ }
44
+
45
+ // Front-facing triangles (based on normalDirection)
46
+ if (normalDirection > 0) {
47
+ triangles.push(new Triangle(v1, v3, v2, getColor(x, z)));
48
+ triangles.push(new Triangle(v1, v4, v3, getColor(x, z)));
49
+ } else {
50
+ triangles.push(new Triangle(v1, v2, v3, getColor(x, z)));
51
+ triangles.push(new Triangle(v1, v3, v4, getColor(x, z)));
52
+ }
53
+
54
+ // Back-facing triangles (if doubleSided is true)
55
+ if (doubleSided) {
56
+ if (normalDirection > 0) {
57
+ triangles.push(new Triangle(v1, v2, v3, getBackColor(x, z)));
58
+ triangles.push(new Triangle(v1, v3, v4, getBackColor(x, z)));
59
+ } else {
60
+ triangles.push(new Triangle(v1, v3, v2, getBackColor(x, z)));
61
+ triangles.push(new Triangle(v1, v4, v3, getBackColor(x, z)));
62
+ }
63
+ }
64
+ }
65
+ }
66
+
67
+ super(physicsWorld, triangles);
68
+
69
+ const shape = new Goblin.PlaneShape(orientation, width/2, length/2);
70
+ this.body = new Goblin.RigidBody(shape, mass);
71
+ this.body.position.set(
72
+ initialPosition.x,
73
+ initialPosition.y,
74
+ initialPosition.z
75
+ );
76
+
77
+ this.storeOriginalData();
78
+ }
79
+
80
+ storeOriginalData() {
81
+ this.originalNormals = [];
82
+ this.originalVerts = [];
83
+
84
+ this.triangles.forEach((triangle) => {
85
+ this.originalNormals.push(new Vector3(
86
+ triangle.normal.x,
87
+ triangle.normal.y,
88
+ triangle.normal.z
89
+ ));
90
+
91
+ triangle.vertices.forEach((vertex) => {
92
+ this.originalVerts.push(new Vector3(
93
+ vertex.x,
94
+ vertex.y,
95
+ vertex.z
96
+ ));
97
+ });
98
+ });
99
+ }
100
+ }
@@ -0,0 +1,95 @@
1
+ // actionengine/math/physics/actionphysicssphere3D.js
2
+ /**
3
+ * ActionPhysicsSphere3D - 3D Sphere Physics Object with Single Color System
4
+ *
5
+ * BREAKING CHANGE: Previously used black/white checkerboard pattern.
6
+ * Now uses single color system for consistent developer experience.
7
+ *
8
+ * @param {ActionPhysicsWorld3D} physicsWorld - The physics world
9
+ * @param {number} radius - Sphere radius (default: 5)
10
+ * @param {number} mass - Physics mass (default: 1)
11
+ * @param {Vector3} initialPosition - Starting position (default: 0,500,0)
12
+ * @param {string} color - Hex color string like "#FF0000" (default: "#FFFFFF" white)
13
+ */
14
+ class ActionPhysicsSphere3D extends ActionPhysicsObject3D {
15
+ constructor(physicsWorld, radius = 5, mass = 1, initialPosition = new Vector3(0, 500, 0), color = "#FFFFFF") {
16
+ // Visual mesh creation with single color system
17
+ const segments = 8;
18
+ const triangles = [];
19
+
20
+ // All triangles use the same color (changed from checkerboard pattern)
21
+ const sphereColor = color;
22
+
23
+ const createVertex = (phi, theta) => new Vector3(
24
+ radius * Math.sin(phi) * Math.cos(theta),
25
+ radius * Math.cos(phi),
26
+ radius * Math.sin(phi) * Math.sin(theta)
27
+ );
28
+
29
+ // Sphere segments generation
30
+ for (let lat = 0; lat <= segments; lat++) {
31
+ const phi = (lat / segments) * Math.PI;
32
+ const nextPhi = ((lat + 1) / segments) * Math.PI;
33
+ for (let lon = 0; lon < segments; lon++) {
34
+ const theta = (lon / segments) * 2 * Math.PI;
35
+ const nextTheta = ((lon + 1) / segments) * 2 * Math.PI;
36
+
37
+ if (lat === 0) {
38
+ triangles.push(new Triangle(
39
+ new Vector3(0, radius, 0),
40
+ createVertex(Math.PI / segments, nextTheta),
41
+ createVertex(Math.PI / segments, theta),
42
+ sphereColor
43
+ ));
44
+ } else if (lat === segments - 1) {
45
+ triangles.push(new Triangle(
46
+ new Vector3(0, -radius, 0),
47
+ createVertex(Math.PI - Math.PI / segments, theta),
48
+ createVertex(Math.PI - Math.PI / segments, nextTheta),
49
+ sphereColor
50
+ ));
51
+ } else {
52
+ const v1 = createVertex(phi, theta);
53
+ const v2 = createVertex(nextPhi, theta);
54
+ const v3 = createVertex(nextPhi, nextTheta);
55
+ const v4 = createVertex(phi, nextTheta);
56
+ triangles.push(new Triangle(v1, v3, v2, sphereColor));
57
+ triangles.push(new Triangle(v1, v4, v3, sphereColor));
58
+ }
59
+ }
60
+ }
61
+
62
+ super(physicsWorld, triangles);
63
+
64
+ const shape = new Goblin.SphereShape(radius);
65
+ this.body = new Goblin.RigidBody(shape, mass);
66
+ this.body.position.set(
67
+ initialPosition.x,
68
+ initialPosition.y,
69
+ initialPosition.z
70
+ );
71
+
72
+ this.body.linear_damping = 0.01;
73
+ this.body.angular_damping = 0.01;
74
+
75
+ // Store original data for visual updates
76
+ this.originalNormals = [];
77
+ this.originalVerts = [];
78
+
79
+ this.triangles.forEach((triangle) => {
80
+ this.originalNormals.push(new Vector3(
81
+ triangle.normal.x,
82
+ triangle.normal.y,
83
+ triangle.normal.z
84
+ ));
85
+
86
+ triangle.vertices.forEach((vertex) => {
87
+ this.originalVerts.push(new Vector3(
88
+ vertex.x,
89
+ vertex.y,
90
+ vertex.z
91
+ ));
92
+ });
93
+ });
94
+ }
95
+ }
@@ -0,0 +1,61 @@
1
+ // actionengine/math/quaternion.js
2
+ class Quaternion {
3
+ constructor(x = 0, y = 0, z = 0, w = 1) {
4
+ this.x = x;
5
+ this.y = y;
6
+ this.z = z;
7
+ this.w = w;
8
+ }
9
+
10
+ static fromAxisAngle(axis, angle) {
11
+ const halfAngle = angle * 0.5;
12
+ const s = Math.sin(halfAngle);
13
+ return new Quaternion(
14
+ axis.x * s,
15
+ axis.y * s,
16
+ axis.z * s,
17
+ Math.cos(halfAngle)
18
+ );
19
+ }
20
+
21
+ static fromEulerY(yAngle) {
22
+ const halfAngle = yAngle * 0.5;
23
+ return new Quaternion(
24
+ 0,
25
+ Math.sin(halfAngle),
26
+ 0,
27
+ Math.cos(halfAngle)
28
+ );
29
+ }
30
+
31
+ slerp(other, t) {
32
+ let cosHalfTheta = this.x * other.x + this.y * other.y +
33
+ this.z * other.z + this.w * other.w;
34
+
35
+ if (Math.abs(cosHalfTheta) >= 1.0) {
36
+ return this;
37
+ }
38
+
39
+ const halfTheta = Math.acos(cosHalfTheta);
40
+ const sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
41
+
42
+ if (Math.abs(sinHalfTheta) < 0.001) {
43
+ return new Quaternion(
44
+ this.x * 0.5 + other.x * 0.5,
45
+ this.y * 0.5 + other.y * 0.5,
46
+ this.z * 0.5 + other.z * 0.5,
47
+ this.w * 0.5 + other.w * 0.5
48
+ );
49
+ }
50
+
51
+ const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta;
52
+ const ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
53
+
54
+ return new Quaternion(
55
+ this.x * ratioA + other.x * ratioB,
56
+ this.y * ratioA + other.y * ratioB,
57
+ this.z * ratioA + other.z * ratioB,
58
+ this.w * ratioA + other.w * ratioB
59
+ );
60
+ }
61
+ }