|
9 | 9 | "name": "ParticleEmitter3D", |
10 | 10 | "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/f2e5a34bf465f781866677762d385d6c8e9e8d203383f2df9a3b7e0fad6a2cb5_fire.svg", |
11 | 11 | "shortDescription": "Display a large number of particles in 3D to create visual effects in a 3D game.", |
12 | | - "version": "2.1.1", |
| 12 | + "version": "2.2.0", |
13 | 13 | "description": [ |
14 | 14 | "3D particle emitters let you create and display many small particles to simulate visual effects in your game — like fire, explosions, smoke, or dust.", |
15 | 15 | "", |
|
62 | 62 | " return;", |
63 | 63 | "}", |
64 | 64 | "", |
| 65 | + "const game = runtimeScene.getGame();", |
| 66 | + "", |
65 | 67 | "class ParticleEmitter3DRenderer extends gdjs.CustomRuntimeObject3DRenderer {", |
66 | 68 | " constructor(", |
67 | 69 | " object,", |
|
88 | 90 | " this._object.getZ()", |
89 | 91 | " );", |
90 | 92 | "", |
| 93 | + " // Force the scale to 1 because the particle emitter doesn't really has a size.", |
91 | 94 | " threeObject3D.scale.set(", |
92 | 95 | " this._object.isFlippedX() ? -1 : 1,", |
93 | 96 | " this._object.isFlippedY() ? -1 : 1,", |
|
100 | 103 | " }", |
101 | 104 | "}", |
102 | 105 | "", |
| 106 | + "const coneLength = 64;", |
| 107 | + "", |
| 108 | + "class ParticleEmitterHelper extends THREE.Object3D {", |
| 109 | + " /** @type {gdjs.CustomRuntimeObject3D} */", |
| 110 | + " object;", |
| 111 | + " /** @type {THREE.LineSegments} */", |
| 112 | + " cone;", |
| 113 | + " /** @type {THREE.LineSegments} */", |
| 114 | + " centerLine;", |
| 115 | + " /** @type {THREE.Mesh} */", |
| 116 | + " originBox;", |
| 117 | + "", |
| 118 | + "\t/**", |
| 119 | + " * @param gdjs.CustomRuntimeObject3D object", |
| 120 | + "\t */", |
| 121 | + " constructor(object) {", |
| 122 | + " super();", |
| 123 | + " this.object = object;", |
| 124 | + " this.type = 'ParticleEmitterHelper';", |
| 125 | + "", |
| 126 | + " const coneGeometry = new THREE.BufferGeometry();", |
| 127 | + " const conePositions = [", |
| 128 | + " 0, 0, 0, 0, 0, 1,", |
| 129 | + " 0, 0, 0, 1, 0, 1,", |
| 130 | + " 0, 0, 0, - 1, 0, 1,", |
| 131 | + " 0, 0, 0, 0, 1, 1,", |
| 132 | + " 0, 0, 0, 0, - 1, 1", |
| 133 | + " ];", |
| 134 | + " for (let i = 0, j = 1, l = 32; i < l; i++ , j++) {", |
| 135 | + " const p1 = (i / l) * Math.PI * 2;", |
| 136 | + " const p2 = (j / l) * Math.PI * 2;", |
| 137 | + " conePositions.push(", |
| 138 | + " Math.cos(p1), Math.sin(p1), 1,", |
| 139 | + " Math.cos(p2), Math.sin(p2), 1", |
| 140 | + " );", |
| 141 | + " }", |
| 142 | + " coneGeometry.setAttribute('position', new THREE.Float32BufferAttribute(conePositions, 3));", |
| 143 | + " this.cone = new THREE.LineSegments(", |
| 144 | + " coneGeometry,", |
| 145 | + " new THREE.LineBasicMaterial({ fog: false, toneMapped: false })", |
| 146 | + " );", |
| 147 | + " this.add(this.cone);", |
| 148 | + " const centerLineGeometry = new THREE.BufferGeometry();", |
| 149 | + " centerLineGeometry.setAttribute('position', new THREE.Float32BufferAttribute([", |
| 150 | + " 0, 0, 0, 0, 0, coneLength", |
| 151 | + " ], 3));", |
| 152 | + " this.centerLine = new THREE.LineSegments(", |
| 153 | + " centerLineGeometry,", |
| 154 | + " new THREE.LineBasicMaterial({ fog: false, toneMapped: false })", |
| 155 | + " );", |
| 156 | + " this.add(this.centerLine);", |
| 157 | + "", |
| 158 | + " this.originBox = new THREE.Mesh(", |
| 159 | + " new THREE.BoxGeometry(16, 16, 16),", |
| 160 | + " new THREE.MeshBasicMaterial({ fog: false, toneMapped: false })", |
| 161 | + " );", |
| 162 | + " this.add(this.originBox);", |
| 163 | + " this.update();", |
| 164 | + "", |
| 165 | + " this.originBox.gdjsRuntimeObject = object;", |
| 166 | + " }", |
| 167 | + "", |
| 168 | + " dispose() {", |
| 169 | + " this.cone.geometry.dispose();", |
| 170 | + " this.cone.material.dispose();", |
| 171 | + " this.centerLine.geometry.dispose();", |
| 172 | + " this.centerLine.material.dispose();", |
| 173 | + " this.originBox.geometry.dispose();", |
| 174 | + " this.originBox.material.dispose();", |
| 175 | + " }", |
| 176 | + "", |
| 177 | + " update() {", |
| 178 | + " const coneWidth = coneLength * Math.sin(gdjs.toRad(this.object._getSpayConeAngle()));", |
| 179 | + " const coneHeight = coneLength * Math.cos(gdjs.toRad(this.object._getSpayConeAngle()));", |
| 180 | + " this.cone.scale.set(coneWidth, coneWidth, coneHeight);", |
| 181 | + " const startColor = gdjs.rgbOrHexStringToNumber(this.object._getStartColor())", |
| 182 | + " const endColor = gdjs.rgbOrHexStringToNumber(this.object._getEndColor());", |
| 183 | + " this.cone.material.color.set(endColor);", |
| 184 | + " this.centerLine.material.color.set(startColor);", |
| 185 | + " this.originBox.material.color.set(startColor);", |
| 186 | + " }", |
| 187 | + "}", |
| 188 | + "", |
103 | 189 | "/**", |
104 | 190 | " * @param {string} colorString", |
105 | 191 | " * @param {THREE.Vector4} threeColor", |
|
290 | 376 | " break;", |
291 | 377 | " }", |
292 | 378 | " }", |
| 379 | + "", |
| 380 | + " setImage(resourceName) {", |
| 381 | + " const texture = game.getImageManager().getThreeTexture(resourceName);", |
| 382 | + " this.particleSystem.texture = texture;", |
| 383 | + " }", |
293 | 384 | "}", |
294 | 385 | "", |
295 | 386 | "", |
|
6666 | 6757 | "gdjs.__particleEmmiter3DExtension = {", |
6667 | 6758 | " ParticleEmitter3DRenderer,", |
6668 | 6759 | " ParticleEmitterAdapter,", |
| 6760 | + " ParticleEmitterHelper,", |
6669 | 6761 | "", |
6670 | 6762 | " ApplyCollision,", |
6671 | 6763 | " ApplyForce,", |
|
6879 | 6971 | { |
6880 | 6972 | "type": "BuiltinCommonInstructions::JsCode", |
6881 | 6973 | "inlineCode": [ |
6882 | | - "const BatchedRenderer = gdjs.__particleEmmiter3DExtension.BatchedRenderer;", |
6883 | | - "const ParticleSystem = gdjs.__particleEmmiter3DExtension.ParticleSystem;", |
6884 | | - "const TextureLoader = gdjs.__particleEmmiter3DExtension.TextureLoader;", |
6885 | | - "const IntervalValue = gdjs.__particleEmmiter3DExtension.IntervalValue;", |
6886 | | - "const ConstantValue = gdjs.__particleEmmiter3DExtension.ConstantValue;", |
6887 | | - "const ConstantColor = gdjs.__particleEmmiter3DExtension.ConstantColor;", |
6888 | | - "const ColorOverLife = gdjs.__particleEmmiter3DExtension.ColorOverLife;", |
6889 | | - "const SizeOverLife = gdjs.__particleEmmiter3DExtension.SizeOverLife;", |
6890 | | - "const ApplyForce = gdjs.__particleEmmiter3DExtension.ApplyForce;", |
6891 | | - "const Gradient = gdjs.__particleEmmiter3DExtension.Gradient;", |
6892 | | - "const PiecewiseBezier = gdjs.__particleEmmiter3DExtension.PiecewiseBezier;", |
6893 | | - "const Bezier = gdjs.__particleEmmiter3DExtension.Bezier;", |
6894 | | - "const PointEmitter = gdjs.__particleEmmiter3DExtension.PointEmitter;", |
6895 | | - "const ConeEmitter = gdjs.__particleEmmiter3DExtension.ConeEmitter;", |
6896 | | - "const RenderMode = gdjs.__particleEmmiter3DExtension.RenderMode;", |
| 6974 | + "const {", |
| 6975 | + " ParticleEmitterAdapter,", |
| 6976 | + " ParticleEmitter3DRenderer,", |
| 6977 | + " ParticleEmitterHelper,", |
6897 | 6978 | "", |
6898 | | - "const { ParticleEmitterAdapter, ParticleEmitter3DRenderer } = gdjs.__particleEmmiter3DExtension;", |
| 6979 | + " ParticleSystem,", |
| 6980 | + " IntervalValue,", |
| 6981 | + " ConstantValue,", |
| 6982 | + " ConstantColor,", |
| 6983 | + " ColorOverLife,", |
| 6984 | + " SizeOverLife,", |
| 6985 | + " ApplyForce,", |
| 6986 | + " Gradient,", |
| 6987 | + " PiecewiseBezier,", |
| 6988 | + " Bezier,", |
| 6989 | + " PointEmitter,", |
| 6990 | + " ConeEmitter,", |
| 6991 | + " RenderMode", |
| 6992 | + "} = gdjs.__particleEmmiter3DExtension;", |
6899 | 6993 | "", |
6900 | 6994 | "/** @type {gdjs.CustomRuntimeObject} */", |
6901 | 6995 | "const object = objects[0];", |
6902 | 6996 | "", |
6903 | 6997 | "// Here runtimeScene is the gdjs.CustomRuntimeObjectInstanceContainer inside the custom object.", |
6904 | 6998 | "const gameScene = object.getRuntimeScene();", |
| 6999 | + "const game = runtimeScene.getGame();", |
6905 | 7000 | "", |
6906 | | - "/** @type {SpriteObjectDataType} */", |
6907 | | - "const particleSpriteData = object._instanceContainer._objects.get(\"Particle\");", |
6908 | | - "const resourceName = particleSpriteData.animations[0].directions[0].sprites[0].image;", |
6909 | | - "const texture = object", |
6910 | | - " .getInstanceContainer()", |
6911 | | - " .getGame()", |
6912 | | - " .getImageManager().getThreeTexture(resourceName);", |
| 7001 | + "const texture = game.getImageManager().getThreeTexture('');", |
6913 | 7002 | "", |
6914 | 7003 | "// Set the blending here because changes are not applied after the emitter creation.", |
6915 | 7004 | "const blendingString = object._getBlending();", |
|
6991 | 7080 | "", |
6992 | 7081 | "const particleEmitter3DRenderer = new ParticleEmitter3DRenderer(object, object._instanceContainer, object.getInstanceContainer());", |
6993 | 7082 | "object._renderer = particleEmitter3DRenderer;", |
6994 | | - "particleEmitter3DRenderer._threeGroup = particleSystem.emitter;", |
6995 | | - "layer.getRenderer().add3DRendererObject(particleSystem.emitter);", |
| 7083 | + "if (game.isInGameEdition && game.isInGameEdition()) {", |
| 7084 | + " const particleEmitterHelper = new ParticleEmitterHelper(object);", |
| 7085 | + " particleEmitter3DRenderer._threeGroup = particleEmitterHelper;", |
| 7086 | + " layer.getRenderer().add3DRendererObject(particleEmitterHelper);", |
| 7087 | + "}", |
| 7088 | + "else {", |
| 7089 | + " particleEmitter3DRenderer._threeGroup = particleSystem.emitter;", |
| 7090 | + " layer.getRenderer().add3DRendererObject(particleSystem.emitter);", |
| 7091 | + "}", |
6996 | 7092 | "", |
6997 | 7093 | "particleSystem.emitter.updateMatrixWorld(true);", |
6998 | 7094 | "", |
|
7344 | 7440 | "Object.GravityTop()", |
7345 | 7441 | "" |
7346 | 7442 | ] |
| 7443 | + }, |
| 7444 | + { |
| 7445 | + "type": { |
| 7446 | + "value": "ParticleEmitter3D::ParticleEmitter3D::UpdateImage" |
| 7447 | + }, |
| 7448 | + "parameters": [ |
| 7449 | + "Object", |
| 7450 | + "" |
| 7451 | + ] |
7347 | 7452 | } |
7348 | 7453 | ], |
7349 | 7454 | "events": [ |
|
7433 | 7538 | ] |
7434 | 7539 | } |
7435 | 7540 | ] |
| 7541 | + }, |
| 7542 | + { |
| 7543 | + "type": "BuiltinCommonInstructions::Standard", |
| 7544 | + "conditions": [], |
| 7545 | + "actions": [ |
| 7546 | + { |
| 7547 | + "type": { |
| 7548 | + "value": "ParticleEmitter3D::ParticleEmitter3D::UpdateHelper" |
| 7549 | + }, |
| 7550 | + "parameters": [ |
| 7551 | + "Object", |
| 7552 | + "" |
| 7553 | + ] |
| 7554 | + } |
| 7555 | + ] |
| 7556 | + } |
| 7557 | + ], |
| 7558 | + "parameters": [ |
| 7559 | + { |
| 7560 | + "description": "Object", |
| 7561 | + "name": "Object", |
| 7562 | + "supplementaryInformation": "ParticleEmitter3D::ParticleEmitter3D", |
| 7563 | + "type": "object" |
| 7564 | + } |
| 7565 | + ], |
| 7566 | + "objectGroups": [] |
| 7567 | + }, |
| 7568 | + { |
| 7569 | + "fullName": "Update helper", |
| 7570 | + "functionType": "Action", |
| 7571 | + "name": "UpdateHelper", |
| 7572 | + "private": true, |
| 7573 | + "sentence": "Update graphical helper of _PARAM0_", |
| 7574 | + "events": [ |
| 7575 | + { |
| 7576 | + "type": "BuiltinCommonInstructions::JsCode", |
| 7577 | + "inlineCode": [ |
| 7578 | + "const game = runtimeScene.getGame();", |
| 7579 | + "if (game.isInGameEdition && game.isInGameEdition()) {", |
| 7580 | + " const particleEmitterHelper = objects[0].get3DRendererObject();", |
| 7581 | + " particleEmitterHelper.update();", |
| 7582 | + "}" |
| 7583 | + ], |
| 7584 | + "parameterObjects": "Object", |
| 7585 | + "useStrict": true, |
| 7586 | + "eventsSheetExpanded": false |
| 7587 | + } |
| 7588 | + ], |
| 7589 | + "parameters": [ |
| 7590 | + { |
| 7591 | + "description": "Object", |
| 7592 | + "name": "Object", |
| 7593 | + "supplementaryInformation": "ParticleEmitter3D::ParticleEmitter3D", |
| 7594 | + "type": "object" |
| 7595 | + } |
| 7596 | + ], |
| 7597 | + "objectGroups": [] |
| 7598 | + }, |
| 7599 | + { |
| 7600 | + "fullName": "Update particle image", |
| 7601 | + "functionType": "Action", |
| 7602 | + "name": "UpdateImage", |
| 7603 | + "private": true, |
| 7604 | + "sentence": "Update particle image of _PARAM0_", |
| 7605 | + "events": [ |
| 7606 | + { |
| 7607 | + "type": "BuiltinCommonInstructions::JsCode", |
| 7608 | + "inlineCode": [ |
| 7609 | + "/** @type {gdjs.CustomRuntimeObject3D} */\r", |
| 7610 | + "const object = objects[0];\r", |
| 7611 | + "/** @type {SpriteObjectDataType} */\r", |
| 7612 | + "const particleSpriteData = object._instanceContainer._objects.get(\"Particle\");\r", |
| 7613 | + "/** @type {gdjs.SpriteAnimationData} */\r", |
| 7614 | + "const animation = particleSpriteData.animations[0];\r", |
| 7615 | + "const animationFrame = animation ? animation.directions[0].sprites[0] : null;\r", |
| 7616 | + "const resourceName = animationFrame ? animationFrame.image : '';\r", |
| 7617 | + "object.__particleEmitterAdapter.setImage(resourceName);" |
| 7618 | + ], |
| 7619 | + "parameterObjects": "Object", |
| 7620 | + "useStrict": true, |
| 7621 | + "eventsSheetExpanded": true |
7436 | 7622 | } |
7437 | 7623 | ], |
7438 | 7624 | "parameters": [ |
|
0 commit comments