init commit
This commit is contained in:
152
js/instances/BasePart.js
Normal file
152
js/instances/BasePart.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import * as THREE from "three";
|
||||
import * as CANNON from "cannon-es";
|
||||
import { Instance } from "./Instance.js";
|
||||
|
||||
export class BasePart extends Instance {
|
||||
constructor() {
|
||||
super("BasePart");
|
||||
|
||||
// === Visual properties ===
|
||||
this.Color = 0x00ff00;
|
||||
this.Size = new THREE.Vector3(1, 1, 1);
|
||||
this.Position = new THREE.Vector3(0, 0, 0);
|
||||
this.Orientation = new THREE.Euler(0, 0, 0);
|
||||
this.Anchored = false; // Roblox-style toggle
|
||||
|
||||
// === Three.js setup ===
|
||||
const geometry = new THREE.BoxGeometry(this.Size.x, this.Size.y, this.Size.z);
|
||||
const material = new THREE.MeshStandardMaterial({ color: this.Color });
|
||||
this.mesh = new THREE.Mesh(geometry, material);
|
||||
this.mesh.castShadow = true;
|
||||
this.mesh.receiveShadow = true;
|
||||
this.mesh.userData.basePart = this;
|
||||
|
||||
// === Cannon.js setup ===
|
||||
const shape = new CANNON.Box(
|
||||
new CANNON.Vec3(this.Size.x / 2, this.Size.y / 2, this.Size.z / 2)
|
||||
);
|
||||
this.body = new CANNON.Body({
|
||||
mass: 1,
|
||||
position: new CANNON.Vec3(this.Position.x, this.Position.y, this.Position.z),
|
||||
shape: shape,
|
||||
});
|
||||
this.body.userData = { basePart: this };
|
||||
|
||||
this._originalMass = this.body.mass; // store default mass
|
||||
this._renderService = null; // assigned when added to scene
|
||||
}
|
||||
|
||||
// === Scene lifecycle ===
|
||||
OnAddedToScene(parent) {
|
||||
const dm = this.GetDataModel();
|
||||
const renderService = dm.GetService("RenderService");
|
||||
this._renderService = renderService;
|
||||
|
||||
if (renderService.scene) renderService.scene.add(this.mesh);
|
||||
if (!renderService.physicsWorld) renderService._initPhysicsWorld();
|
||||
|
||||
renderService.physicsWorld.addBody(this.body);
|
||||
this._applyAnchoredState();
|
||||
}
|
||||
|
||||
// === Anchoring logic ===
|
||||
setAnchored(value) {
|
||||
if (this.Anchored === value) return;
|
||||
this.Anchored = value;
|
||||
this._applyAnchoredState();
|
||||
}
|
||||
|
||||
_applyAnchoredState() {
|
||||
if (!this.body) return;
|
||||
if (this.Anchored) {
|
||||
this.body.type = CANNON.Body.STATIC;
|
||||
this.body.mass = 0;
|
||||
this.body.velocity.set(0, 0, 0);
|
||||
this.body.angularVelocity.set(0, 0, 0);
|
||||
} else {
|
||||
this.body.type = CANNON.Body.DYNAMIC;
|
||||
this.body.mass = this._originalMass || 1;
|
||||
}
|
||||
this.body.updateMassProperties();
|
||||
}
|
||||
|
||||
// === Updates ===
|
||||
updateVisual() {
|
||||
// Only update mesh from physics if not anchored
|
||||
if (!this.Anchored) {
|
||||
this.mesh.position.copy(this.body.position);
|
||||
this.mesh.quaternion.copy(this.body.quaternion);
|
||||
}
|
||||
}
|
||||
|
||||
updateBodyPosition() {
|
||||
this.body.position.set(this.Position.x, this.Position.y, this.Position.z);
|
||||
this.body.quaternion.setFromEuler(
|
||||
this.Orientation.x,
|
||||
this.Orientation.y,
|
||||
this.Orientation.z
|
||||
);
|
||||
this.body.velocity.set(0, 0, 0);
|
||||
this.body.angularVelocity.set(0, 0, 0);
|
||||
}
|
||||
|
||||
updateSizes() {
|
||||
// Update Three geometry
|
||||
this.mesh.geometry.dispose();
|
||||
this.mesh.geometry = new THREE.BoxGeometry(this.Size.x, this.Size.y, this.Size.z);
|
||||
|
||||
// Update Cannon shape
|
||||
this.body.shapes = [];
|
||||
const newShape = new CANNON.Box(
|
||||
new CANNON.Vec3(this.Size.x / 2, this.Size.y / 2, this.Size.z / 2)
|
||||
);
|
||||
this.body.addShape(newShape);
|
||||
this.body.updateMassProperties();
|
||||
}
|
||||
|
||||
OnReplicated() {
|
||||
if (this.IsReplicated) {
|
||||
this.body.type = CANNON.Body.KINEMATIC;
|
||||
this.body.velocity.set(0, 0, 0);
|
||||
this.body.angularVelocity.set(0, 0, 0);
|
||||
}
|
||||
|
||||
this.body.position.copy(this.Position);
|
||||
this.body.quaternion.setFromEuler(
|
||||
this.Orientation.x,
|
||||
this.Orientation.y,
|
||||
this.Orientation.z
|
||||
);
|
||||
|
||||
this.updateVisual();
|
||||
}
|
||||
|
||||
OnPhysicsTick() {
|
||||
|
||||
if (this.body.position.y < -1000) {
|
||||
// Fell out of world, destroy like in Roblox
|
||||
this.Destroy();
|
||||
console.debug("BasePart fell out of world and was destroyed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.IsReplicated || this.Anchored) return;
|
||||
|
||||
this.Position.set(
|
||||
this.body.position.x,
|
||||
this.body.position.y,
|
||||
this.body.position.z
|
||||
);
|
||||
this.Orientation.setFromQuaternion(this.body.quaternion);
|
||||
}
|
||||
|
||||
// === Cleanup ===
|
||||
Destroy() {
|
||||
if (this._renderService) {
|
||||
if (this.mesh.parent) this.mesh.parent.remove(this.mesh);
|
||||
if (this._renderService.physicsWorld)
|
||||
this._renderService.physicsWorld.removeBody(this.body);
|
||||
}
|
||||
super.Destroy();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user