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.
- package/LICENSE +45 -0
- package/README.md +348 -0
- package/actionengine/3rdparty/goblin/goblin.js +9609 -0
- package/actionengine/3rdparty/goblin/goblin.min.js +5 -0
- package/actionengine/camera/actioncamera.js +90 -0
- package/actionengine/camera/cameracollisionhandler.js +69 -0
- package/actionengine/character/actioncharacter.js +360 -0
- package/actionengine/character/actioncharacter3D.js +61 -0
- package/actionengine/core/app.js +430 -0
- package/actionengine/debug/basedebugpanel.js +858 -0
- package/actionengine/display/canvasmanager.js +75 -0
- package/actionengine/display/gl/programmanager.js +570 -0
- package/actionengine/display/gl/shaders/lineshader.js +118 -0
- package/actionengine/display/gl/shaders/objectshader.js +1756 -0
- package/actionengine/display/gl/shaders/particleshader.js +43 -0
- package/actionengine/display/gl/shaders/shadowshader.js +319 -0
- package/actionengine/display/gl/shaders/spriteshader.js +100 -0
- package/actionengine/display/gl/shaders/watershader.js +67 -0
- package/actionengine/display/graphics/actionmodel3D.js +191 -0
- package/actionengine/display/graphics/actionsprite3D.js +230 -0
- package/actionengine/display/graphics/lighting/actiondirectionalshadowlight.js +864 -0
- package/actionengine/display/graphics/lighting/actionlight.js +211 -0
- package/actionengine/display/graphics/lighting/actionomnidirectionalshadowlight.js +862 -0
- package/actionengine/display/graphics/lighting/lightingconstants.js +263 -0
- package/actionengine/display/graphics/lighting/lightmanager.js +789 -0
- package/actionengine/display/graphics/renderableobject.js +44 -0
- package/actionengine/display/graphics/renderers/actionrenderer2D.js +341 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/actionrenderer3D.js +655 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/canvasmanager3D.js +82 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/debugrenderer3D.js +493 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/objectrenderer3D.js +790 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/spriteRenderer3D.js +266 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/sunrenderer3D.js +140 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/waterrenderer3D.js +173 -0
- package/actionengine/display/graphics/renderers/actionrenderer3D/weatherrenderer3D.js +87 -0
- package/actionengine/display/graphics/texture/proceduraltexture.js +192 -0
- package/actionengine/display/graphics/texture/texturemanager.js +242 -0
- package/actionengine/display/graphics/texture/textureregistry.js +177 -0
- package/actionengine/input/actionscrollablearea.js +1405 -0
- package/actionengine/input/inputhandler.js +1647 -0
- package/actionengine/math/geometry/geometrybuilder.js +161 -0
- package/actionengine/math/geometry/glbexporter.js +364 -0
- package/actionengine/math/geometry/glbloader.js +722 -0
- package/actionengine/math/geometry/modelcodegenerator.js +97 -0
- package/actionengine/math/geometry/triangle.js +33 -0
- package/actionengine/math/geometry/triangleutils.js +34 -0
- package/actionengine/math/mathutils.js +25 -0
- package/actionengine/math/matrix4.js +785 -0
- package/actionengine/math/physics/actionphysics.js +108 -0
- package/actionengine/math/physics/actionphysicsobject3D.js +164 -0
- package/actionengine/math/physics/actionphysicsworld3D.js +238 -0
- package/actionengine/math/physics/actionraycast.js +129 -0
- package/actionengine/math/physics/shapes/actionphysicsbox3D.js +158 -0
- package/actionengine/math/physics/shapes/actionphysicscapsule3D.js +200 -0
- package/actionengine/math/physics/shapes/actionphysicscompoundshape3D.js +147 -0
- package/actionengine/math/physics/shapes/actionphysicscone3D.js +126 -0
- package/actionengine/math/physics/shapes/actionphysicsconvexshape3D.js +72 -0
- package/actionengine/math/physics/shapes/actionphysicscylinder3D.js +117 -0
- package/actionengine/math/physics/shapes/actionphysicsmesh3D.js +74 -0
- package/actionengine/math/physics/shapes/actionphysicsplane3D.js +100 -0
- package/actionengine/math/physics/shapes/actionphysicssphere3D.js +95 -0
- package/actionengine/math/quaternion.js +61 -0
- package/actionengine/math/vector2.js +277 -0
- package/actionengine/math/vector3.js +318 -0
- package/actionengine/math/viewfrustum.js +136 -0
- package/actionengine/network/ACTIONNETREADME.md +810 -0
- package/actionengine/network/client/ActionNetManager.js +802 -0
- package/actionengine/network/client/ActionNetManagerGUI.js +1709 -0
- package/actionengine/network/client/ActionNetManagerP2P.js +1537 -0
- package/actionengine/network/client/SyncSystem.js +422 -0
- package/actionengine/network/p2p/ActionNetPeer.js +142 -0
- package/actionengine/network/p2p/ActionNetTrackerClient.js +623 -0
- package/actionengine/network/p2p/DataConnection.js +282 -0
- package/actionengine/network/p2p/README.md +510 -0
- package/actionengine/network/p2p/example.html +502 -0
- package/actionengine/network/server/ActionNetServer.js +577 -0
- package/actionengine/network/server/ActionNetServerSSL.js +579 -0
- package/actionengine/network/server/ActionNetServerUtils.js +458 -0
- package/actionengine/network/server/SERVERREADME.md +314 -0
- package/actionengine/network/server/package-lock.json +35 -0
- package/actionengine/network/server/package.json +13 -0
- package/actionengine/network/server/start.bat +27 -0
- package/actionengine/network/server/start.sh +25 -0
- package/actionengine/network/server/startwss.bat +27 -0
- package/actionengine/sound/audiomanager.js +1589 -0
- package/actionengine/sound/soundfont/ACTIONSOUNDFONT_README.md +205 -0
- package/actionengine/sound/soundfont/actionparser.js +718 -0
- package/actionengine/sound/soundfont/actionreverb.js +252 -0
- package/actionengine/sound/soundfont/actionsoundfont.js +543 -0
- package/actionengine/sound/soundfont/sf2playerlicence.txt +29 -0
- package/actionengine/sound/soundfont/soundfont.js +2 -0
- package/dist/action-engine.min.js +328 -0
- 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
|
+
}
|