Spaces:
Runtime error
Runtime error
File size: 4,510 Bytes
30c32c8 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
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;
|