From 4569ad90b8f1c53ba66c98e0c9bb8876f5660003 Mon Sep 17 00:00:00 2001 From: -=yb4f310 Date: Thu, 16 Nov 2017 13:54:51 +0100 Subject: [PATCH] particle explosions --- src/game-lib-a-1-event.js | 8 +-- src/game-lib-a-component-a.js | 74 +++++++++++++++++++++++++ src/game-lib-d3-api-audio.js | 8 +++ src/game-lib-d3-api-particle-engine.js | 19 ++++++- src/game-lib-d3-api-particle.js | 8 +++ src/game-lib-d3-audio.js | 2 + src/game-lib-d3-particle-engine.js | 2 + src/game-lib-d3-particle.js | 64 +++++++++++++++++++++- src/game-lib-system-audio.js | 8 +++ src/game-lib-system-gui.js | 20 ++++++- src/game-lib-system-particle.js | 76 +++++++++++++++++++++++--- src/game-lib-system-storage.js | 10 +++- 12 files changed, 280 insertions(+), 19 deletions(-) diff --git a/src/game-lib-a-1-event.js b/src/game-lib-a-1-event.js index 48857cf..27d58a8 100644 --- a/src/game-lib-a-1-event.js +++ b/src/game-lib-a-1-event.js @@ -69,7 +69,7 @@ GameLib.Event.COMPONENT_DELETED = 0x33; GameLib.Event.COMPONENT_TYPES_UPDATED = 0x34; GameLib.Event.AUDIO_ENDED = 0x35; GameLib.Event.COMPONENT_LINKED = 0x36; -//GameLib.Event.SOLVER_INSTANCE_CREATED = 0x37; +GameLib.Event.DONE_SAVING = 0x37; GameLib.Event.BEFORE_RENDER = 0x38; GameLib.Event.AFTER_RENDER = 0x39; GameLib.Event.ARRAY_ITEM_ADDED = 0x3a; @@ -84,7 +84,7 @@ GameLib.Event.PARENT_WORLD_CHANGE = 0x42; GameLib.Event.ANIMATE = 0x43; GameLib.Event.ANIMATION_COMPILE_SUCCESS = 0x44; GameLib.Event.ANIMATION_COMPILE_FAILED = 0x45; -//GameLib.Event.CUSTOM_CODE_SYSTEM_STARTED = 0x46; +GameLib.Event.SAVING = 0x46; GameLib.Event.GAME_OVER = 0x47; GameLib.Event.GAME_START = 0x48; GameLib.Event.TOUCH_START = 0x49; @@ -176,7 +176,7 @@ GameLib.Event.GetEventName = function(number) { case 0x34 : return 'component_types_updated'; case 0x35 : return 'audio_ended'; case 0x36 : return 'component_linked'; - case 0x37 : return 'unused';//'solver_instance_created'; + case 0x37 : return 'done_saving'; case 0x38 : return 'before_render'; case 0x39 : return 'after_render'; case 0x3a : return 'array_item_added'; @@ -191,7 +191,7 @@ GameLib.Event.GetEventName = function(number) { case 0x43 : return 'animate'; case 0x44 : return 'animation_compile_success'; case 0x45 : return 'animation_compile_failed'; - case 0x46 : return 'unused'; + case 0x46 : return 'saving'; case 0x47 : return 'game_over'; case 0x48 : return 'game_start'; case 0x49 : return 'touch_start'; diff --git a/src/game-lib-a-component-a.js b/src/game-lib-a-component-a.js index 02743b3..d6d1df4 100644 --- a/src/game-lib-a-component-a.js +++ b/src/game-lib-a-component-a.js @@ -632,8 +632,80 @@ GameLib.Component.prototype.saveToRemoteAPI = function() { GameLib.Component.prototype.save = function(remote) { + var toSave = []; + var saved = []; + var failed = []; + this.buildIdToObject(); + if (this.saveSubscription || this.saveErrorSubscription) { + console.warn('another save is in progress'); + return; + } + + GameLib.Event.Emit( + GameLib.Event.SAVING, + { + component: this + } + ); + + this.saveSubscription = GameLib.Event.Subscribe( + GameLib.Event.COMPONENT_SAVED, + function(data) { + + saved.push(data.component); + + if (failed.length + saved.length === toSave.length) { + + this.saveSubscription.remove(); + + this.saveSubscription = null; + + this.saveErrorSubscription.remove(); + + this.saveErrorSubscription = null; + + GameLib.Event.Emit( + GameLib.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + + this.saveErrorSubscription = GameLib.Event.Subscribe( + GameLib.Event.SAVE_COMPONENT_ERROR, + function(data) { + + failed.push(data.component); + + if (failed.length + saved.length === toSave.length) { + + this.saveSubscription.remove(); + + this.saveSubscription = null; + + this.saveErrorSubscription.remove(); + + this.saveErrorSubscription = null; + + GameLib.Event.Emit( + GameLib.Event.DONE_SAVING, + { + failed: failed, + saved: saved + } + ) + } + + }.bind(this) + ); + for (var property in this.idToObject) { if ( this.idToObject.hasOwnProperty(property) && @@ -644,6 +716,8 @@ GameLib.Component.prototype.save = function(remote) { apiObject.componentType = this.idToObject[property].componentType; + toSave.push(apiObject); + this.publish( GameLib.Event.SAVE_COMPONENT, { diff --git a/src/game-lib-d3-api-audio.js b/src/game-lib-d3-api-audio.js index d3d31e4..5050898 100644 --- a/src/game-lib-d3-api-audio.js +++ b/src/game-lib-d3-api-audio.js @@ -6,6 +6,7 @@ * @param loop * @param volume * @param camera + * @param overplay * @param parentEntity * @constructor */ @@ -16,6 +17,7 @@ GameLib.D3.API.Audio = function( loop, volume, camera, + overplay, parentEntity ) { @@ -49,6 +51,11 @@ GameLib.D3.API.Audio = function( } this.camera = camera; + if (GameLib.Utils.UndefinedOrNull(overplay)) { + overplay = false; + } + this.overplay = overplay; + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { parentEntity = null; } @@ -81,6 +88,7 @@ GameLib.D3.API.Audio.FromObject = function(objectAudio) { objectAudio.loop, objectAudio.volume, apiCamera, + objectAudio.overplay, objectAudio.parentEntity ); diff --git a/src/game-lib-d3-api-particle-engine.js b/src/game-lib-d3-api-particle-engine.js index f486f13..f86680e 100644 --- a/src/game-lib-d3-api-particle-engine.js +++ b/src/game-lib-d3-api-particle-engine.js @@ -10,6 +10,7 @@ * @param frequency * @param elapsed * @param camera + * @param pulse * @param parentEntity * @constructor */ @@ -24,6 +25,7 @@ GameLib.D3.API.ParticleEngine = function( frequency, elapsed, camera, + pulse, parentEntity ) { @@ -77,6 +79,11 @@ GameLib.D3.API.ParticleEngine = function( } this.camera = camera; + if (GameLib.Utils.UndefinedOrNull(pulse)) { + pulse = false; + } + this.pulse = pulse; + if (GameLib.Utils.UndefinedOrNull(parentEntity)) { parentEntity = null; } @@ -103,6 +110,15 @@ GameLib.D3.API.ParticleEngine.FromObject = function(objectParticleEngine) { } } + var apiCamera = null; + if (objectParticleEngine.camera) { + if (objectParticleEngine.camera instanceof Object) { + apiCamera = GameLib.D3.API.Camera.FromObject(objectParticleEngine.camera); + } else { + apiCamera = objectParticleEngine.camera; + } + } + var apiPosition = null; if (objectParticleEngine.position) { apiPosition = GameLib.API.Vector3.FromObject(objectParticleEngine.position); @@ -124,7 +140,8 @@ GameLib.D3.API.ParticleEngine.FromObject = function(objectParticleEngine) { objectParticleEngine.particlesPerSecond, objectParticleEngine.frequency, objectParticleEngine.elapsed, - objectParticleEngine.camera, + apiCamera, + objectParticleEngine.pulse, objectParticleEngine.parentEntity ); diff --git a/src/game-lib-d3-api-particle.js b/src/game-lib-d3-api-particle.js index ae04292..449deec 100644 --- a/src/game-lib-d3-api-particle.js +++ b/src/game-lib-d3-api-particle.js @@ -15,6 +15,7 @@ * @param scale * @param direction * @param directionFn + * @param speedType * @param speed * @param scaleFn * @param scaleType @@ -38,6 +39,7 @@ GameLib.D3.API.Particle = function( directionType, direction, directionFn, + speedType, speed, scaleType, scale, @@ -114,6 +116,11 @@ GameLib.D3.API.Particle = function( } this.directionFn = directionFn; + if (GameLib.Utils.UndefinedOrNull(speedType)) { + speedType = GameLib.D3.Particle.SPEED_TYPE_CONSTANT; + } + this.speedType = speedType; + if (GameLib.Utils.UndefinedOrNull(speed)) { speed = 1; } @@ -193,6 +200,7 @@ GameLib.D3.API.Particle.FromObject = function(objectParticle) { objectParticle.directionType, GameLib.API.Vector3.FromObject(objectParticle.direction), objectParticle.directionFn, + objectParticle.speedType, objectParticle.speed, objectParticle.scaleType, GameLib.API.Vector3.FromObject(objectParticle.scale), diff --git a/src/game-lib-d3-audio.js b/src/game-lib-d3-audio.js index 0bbb9d9..500a725 100644 --- a/src/game-lib-d3-audio.js +++ b/src/game-lib-d3-audio.js @@ -28,6 +28,7 @@ GameLib.D3.Audio = function( apiAudio.loop, apiAudio.volume, apiAudio.camera, + apiAudio.overplay, apiAudio.parentEntity ); @@ -121,6 +122,7 @@ GameLib.D3.Audio.prototype.toApiObject = function() { this.loop, this.volume, GameLib.Utils.IdOrNull(this.camera), + this.overplay, GameLib.Utils.IdOrNull(this.parentEntity) ); diff --git a/src/game-lib-d3-particle-engine.js b/src/game-lib-d3-particle-engine.js index 37b4384..f2f97cc 100644 --- a/src/game-lib-d3-particle-engine.js +++ b/src/game-lib-d3-particle-engine.js @@ -32,6 +32,7 @@ GameLib.D3.ParticleEngine = function( apiParticleEngine.frequency, apiParticleEngine.elapsed, apiParticleEngine.camera, + apiParticleEngine.pulse, apiParticleEngine.parentEntity ); @@ -271,6 +272,7 @@ GameLib.D3.ParticleEngine.prototype.toApiObject = function() { this.frequency, this.elapsed, GameLib.Utils.IdOrNull(this.camera), + this.pulse, GameLib.Utils.IdOrNull(this.parentEntity) ); diff --git a/src/game-lib-d3-particle.js b/src/game-lib-d3-particle.js index 2494395..a86d3c9 100644 --- a/src/game-lib-d3-particle.js +++ b/src/game-lib-d3-particle.js @@ -35,6 +35,7 @@ GameLib.D3.Particle = function( apiParticle.directionType, apiParticle.direction, apiParticle.directionFn, + apiParticle.speedType, apiParticle.speed, apiParticle.scaleType, apiParticle.scale, @@ -121,7 +122,8 @@ GameLib.D3.Particle.POSITION_OFFSET_TYPE_FUNCTION = 0x3; GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT = 0x1; GameLib.D3.Particle.DIRECTION_TYPE_RANDOM = 0x2; -GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION = 0x3; +GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED = 0x3; +GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION = 0x4; GameLib.D3.Particle.SCALE_TYPE_CONSTANT = 0x1; GameLib.D3.Particle.SCALE_TYPE_LINEAR = 0x2; @@ -130,6 +132,14 @@ GameLib.D3.Particle.SCALE_TYPE_RANDOM = 0x4; GameLib.D3.Particle.SCALE_TYPE_RANDOM_X_EQUALS_Y = 0x6; GameLib.D3.Particle.SCALE_TYPE_FUNCTION = 0x7; +GameLib.D3.Particle.SPEED_TYPE_CONSTANT = 0x1; +GameLib.D3.Particle.SPEED_TYPE_LINEAR = 0x2; +GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL = 0x3; +GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC = 0x4; +GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG = 0x5; +GameLib.D3.Particle.SPEED_TYPE_EXP = 0x6; +GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP = 0x7; + GameLib.D3.Particle.ROTATION_TYPE_CONSTANT = 0x1; GameLib.D3.Particle.ROTATION_TYPE_RANDOM = 0x2; GameLib.D3.Particle.ROTATION_TYPE_FUNCTION = 0x3; @@ -232,6 +242,54 @@ GameLib.D3.Particle.prototype.cloneInstance = function() { } } + clone.userData.direction = this.direction.clone(); + + if (this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT) { + + /** + * Nothing to do + */ + + } else if ( + this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM || + this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED + ) { + + addX = GameLib.Utils.GetRandomIntInclusive(1,2); + addY = GameLib.Utils.GetRandomIntInclusive(1,2); + addZ = GameLib.Utils.GetRandomIntInclusive(1,2); + + clone.userData.direction.x = 0; + clone.userData.direction.y = 0; + clone.userData.direction.z = 0; + + if (addX === 1) { + clone.userData.direction.x += Math.random() * this.direction.x; + } else { + clone.userData.direction.x -= Math.random() * this.direction.x; + } + + if (addY === 1) { + clone.userData.direction.y -= Math.random() * this.direction.y; + } else { + clone.userData.direction.y += Math.random() * this.direction.y; + } + + if (addZ === 1) { + clone.userData.direction.z -= Math.random() * this.direction.z; + } else { + clone.userData.direction.z += Math.random() * this.direction.z; + } + + if (this.directionType === GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED) { + clone.userData.direction.normalize(); + } + + } else { + throw new Error('not yet implemented') + } + + if (this.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) { clone.scale.x += this.scale.x; clone.scale.y += this.scale.y; @@ -270,9 +328,10 @@ GameLib.D3.Particle.prototype.cloneInstance = function() { } } - clone.userData.direction = this.direction.clone(); + clone.userData.scale = this.scale.clone(); clone.userData.lifeTime = this.lifeTime; + clone.userData.speedType = this.speedType; clone.userData.speed = this.speed; clone.userData.scene = this.mesh.parentScene.instance; @@ -303,6 +362,7 @@ GameLib.D3.Particle.prototype.toApiObject = function() { this.directionType, this.direction.toApiObject(), this.directionFn, + this.speedType, this.speed, this.scaleType, this.scale.toApiObject(), diff --git a/src/game-lib-system-audio.js b/src/game-lib-system-audio.js index 2885ae4..5bda769 100644 --- a/src/game-lib-system-audio.js +++ b/src/game-lib-system-audio.js @@ -80,10 +80,18 @@ GameLib.System.Audio.prototype.playAudio = function(data) { this.audioComponents.map( function(audio) { if (audio.name === data.name) { + + if (audio.instance.isPlaying && audio.overplay) { + audio.instance.stop(); + } + if (!audio.instance.isPlaying) { audio.instance.play(); audio.instance.onEnded = function() { + + this.isPlaying = false; + GameLib.Event.Emit( GameLib.Event.AUDIO_ENDED, { diff --git a/src/game-lib-system-gui.js b/src/game-lib-system-gui.js index 42ebcc4..021fa87 100644 --- a/src/game-lib-system-gui.js +++ b/src/game-lib-system-gui.js @@ -756,10 +756,27 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, { 'constant': GameLib.D3.Particle.DIRECTION_TYPE_CONSTANT, 'random': GameLib.D3.Particle.DIRECTION_TYPE_RANDOM, + 'random normalized': GameLib.D3.Particle.DIRECTION_TYPE_RANDOM_NORMALIZED, 'function': GameLib.D3.Particle.DIRECTION_TYPE_FUNCTION } ) ); + } else if (property === 'speedType') { + controllers.push( + folder.add( + object, + property, + { + 'constant': GameLib.D3.Particle.SPEED_TYPE_CONSTANT, + 'linear': GameLib.D3.Particle.SPEED_TYPE_LINEAR, + 'exponential': GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL, + 'logarithmic': GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC, + '1 / log': GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG, + 'exp' : GameLib.D3.Particle.SPEED_TYPE_EXP, + '1 / exp' : GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP + } + ) + ); } else if (property === 'scaleType') { controllers.push( folder.add( @@ -1159,7 +1176,8 @@ GameLib.System.GUI.prototype.buildControl = function(folder, componentTemplate, property === 'opacity' || property === 'opacityFactor' || property === 'metalness' || - property === 'roughness' + property === 'roughness' || + property === 'volume' ) { controllers.push(folder.add(object, property, 0, 1.0, 0.001)); } else if ( diff --git a/src/game-lib-system-particle.js b/src/game-lib-system-particle.js index 7c64897..157a613 100644 --- a/src/game-lib-system-particle.js +++ b/src/game-lib-system-particle.js @@ -130,10 +130,46 @@ GameLib.System.Particle.prototype.beforeRender = function(data) { particleEngine.particles = particleEngine.particles.reduce( function(result, particle){ - - particle.position.x += particle.userData.direction.x * data.delta * particle.userData.speed; - particle.position.y += particle.userData.direction.y * data.delta * particle.userData.speed; - particle.position.z += particle.userData.direction.z * data.delta * particle.userData.speed; + + var speed = particle.userData.speed; + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_CONSTANT) { + speed = data.delta * particle.userData.speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_LINEAR) { + speed = data.delta * particle.userData.speed; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_EXPONENTIAL) { + speed = Math.pow(particle.userData.speed, 2) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_LOGARITHMIC) { + speed = Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_LOG) { + speed = 1 / Math.log(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_EXP) { + speed = Math.exp(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + if (particle.userData.speedType === GameLib.D3.Particle.SPEED_TYPE_ONE_OVER_EXP) { + speed = 1 / Math.exp(particle.userData.speed) * data.delta; + particle.userData.speed += speed; + } + + particle.position.x += particle.userData.direction.x * speed; + particle.position.y += particle.userData.direction.y * speed; + particle.position.z += particle.userData.direction.z * speed; if (particleEngine.templateParticle.scaleType === GameLib.D3.Particle.SCALE_TYPE_CONSTANT) { /** @@ -187,13 +223,37 @@ GameLib.System.Particle.prototype.beforeRender = function(data) { if (particleEngine.enabled && !particleEngine.disabledForRemoval) { - if (particleEngine.elapsed > particleEngine.frequency) { + var instanceClone = null; - particleEngine.elapsed = 0; + if (particleEngine.pulse) { - var instanceClone = particleEngine.templateParticle.cloneInstance(); + if (particleEngine.particles.length === 0) { - particleEngine.particles.push(instanceClone); + particleEngine.elapsed = 0; + + /** + * This is a 'pulse' engine - so spawn all the particles at once and spawn again when all particles + * are gone + */ + for (var i = 0; i < particleEngine.particlesPerSecond; i++) { + instanceClone = particleEngine.templateParticle.cloneInstance(); + particleEngine.particles.push(instanceClone); + } + + } + + } else { + + /** + * This is a 'stream' engine - spawn particles one at a time when its time to do so + */ + if (particleEngine.elapsed > particleEngine.frequency) { + + particleEngine.elapsed = 0; + + instanceClone = particleEngine.templateParticle.cloneInstance(); + particleEngine.particles.push(instanceClone); + } } } diff --git a/src/game-lib-system-storage.js b/src/game-lib-system-storage.js index f52ccfd..6252bf2 100644 --- a/src/game-lib-system-storage.js +++ b/src/game-lib-system-storage.js @@ -291,7 +291,8 @@ GameLib.System.Storage.prototype.save = function(data) { GameLib.Event.Emit( GameLib.Event.SAVE_COMPONENT_ERROR, { - message: this.responseText + message: this.responseText, + component : data.apiObject } ) } @@ -300,14 +301,16 @@ GameLib.System.Storage.prototype.save = function(data) { GameLib.Event.Emit( GameLib.Event.COMPONENT_SAVED, { - message: response.message || 'Successfully saved the component' + message: response.message || 'Successfully saved the component', + component : data.apiObject } ) } else { GameLib.Event.Emit( GameLib.Event.SAVE_COMPONENT_ERROR, { - message: response.message || 'The server responded but failed to save the component' + message: response.message || 'The server responded but failed to save the component', + component : data.apiObject } ) } @@ -651,6 +654,7 @@ GameLib.System.Storage.prototype.loadComponent = function(apiUrl, toProcess, inc apiUrl + '/component/load/' + id ); + xhr.send(); }.bind(this)