soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
4.51 kB
const formatMessage = require('format-message');
const BlockType = require('../../extension-support/block-type');
const ArgumentType = require('../../extension-support/argument-type');
const Cast = require('../../util/cast');
const CANNON = require('./cannon.min.js');
const Icon = require('./icon.png');
/**
* Class for 3d Physics blocks
*/
class Fr3DBlocks {
constructor(runtime) {
/**
* The runtime instantiating this block package.
*/
this.runtime = runtime;
this.CANNON = CANNON
// Create the Cannon.js world before initializing other properties
this.world = new this.CANNON.World();
this._3d = {};
this.Three = {};
if (!vm.runtime.ext_jg3d) {
vm.extensionManager.loadExtensionURL('jg3d')
.then(() => {
this._3d = vm.runtime.ext_jg3d;
this.Three = this._3d.three;
})
} else {
this._3d = vm.runtime.ext_jg3d;
this.Three = this._3d.three;
}
}
/**
* metadata for this extension and its blocks.
* @returns {object}
*/
getInfo() {
return {
id: 'fr3d',
name: '3D Physics',
color1: '#D066FE',
color2: '#8000BC',
blockIconURI: Icon,
blocks: [
{
opcode: 'step',
text: 'step simulation',
blockType: BlockType.COMMAND,
},
{
opcode: 'addp',
text: 'enable physics for [NAME1]',
blockType: BlockType.COMMAND,
arguments: {
NAME1: { type: ArgumentType.STRING, defaultValue: "Object1" }
}
},
{
opcode: 'rmp',
text: 'disable physics for [NAME1]',
blockType: BlockType.COMMAND,
arguments: {
NAME1: { type: ArgumentType.STRING, defaultValue: "Object1" }
}
}
]
};
}
createShapeFromGeometry(geometry) {
if (geometry instanceof this.Three.BufferGeometry) {
const vertices = geometry.attributes.position.array;
const indices = [];
for (let i = 0; i < vertices.length / 3; i++) {
indices.push(i);
}
return new this.CANNON.Trimesh(vertices, indices);
} else if (geometry instanceof this.Three.Geometry) {
return new this.CANNON.ConvexPolyhedron(
geometry.vertices.map((v) => new this.CANNON.Vec3(v.x, v.y, v.z)),
geometry.faces.map((f) => [f.a, f.b, f.c]),
);
} else {
console.warn('Unsupported geometry type for collision shape creation:', geometry.type);
return null;
}
}
enablePhysicsForObject(objectName) {
if (!this._3d.scene) return;
const object = this._3d.scene.getObjectByName(objectName);
if (!object || !this._3d.scene) return;
const shape = this.createShapeFromGeometry(object.geometry);
if (!shape) {
console.warn('Failed to create a valid shape for the object:', object.name);
return;
}
const body = new this.CANNON.Body({
mass: 1, // You might want to adjust mass based on object size/type
});
body.addShape(shape);
this.world.addBody(body); // Add the body to the Cannon.js world
object.userData.physicsBody = body;
}
disablePhysicsForObject(objectName) {
const object = this._3d.scene.getObjectByName(objectName);
if (!object || !object.userData || !object.userData.physicsBody) return;
this.world.removeBody(object.userData.physicsBody); // Remove from world
delete object.userData.physicsBody;
}
step() {
// Step the Cannon.js world to simulate physics
this.world.step(1/60); // Update at 60 fps (adjust timestep as needed)
// Update Three.js object positions and rotations from physics bodies
this._3d.scene.traverse((object) => {
if (object.userData && object.userData.physicsBody) {
object.position.copy(object.userData.physicsBody.position);
object.quaternion.copy(object.userData.physicsBody.quaternion);
}
});
}
addp(args) {
this.enablePhysicsForObject(Cast.toString(args.NAME1))
}
rmp(args) {
this.disablePhysicsForObject(Cast.toString(args.NAME1))
}
}
module.exports = Fr3DBlocks;