//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {License Information: Creative Commons} //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace ElementalGame { #region Using Statements using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using System.Diagnostics; using System.Xml; #endregion public struct EarthProperties { public static float EARTH_MASS = 5.0f; // Mass value public static float EARTH_COLD_COR = 0.7f; // Coefficient of Restitution public static float EARTH_HOT_COR = 0.1f; public static float EARTH_COLD_FRICTION = 0.5f; public static float EARTH_HOT_FRICTION = 0.7f; } public struct WaterProperties { public static float WATER_MASS = 3.0f; // Mass value public static float WATER_COLD_COR = 0.7f; // Coefficient of Restitution public static float WATER_HOT_COR = 0.1f; public static float WATER_COLD_FRICTION = 0.15f; public static float WATER_HOT_FRICTION = 0.05f; } public struct AirProperties { public static float WIND_MASS = 2.0f; // Mass value public static float WIND_COLD_COR = 0.4f; // Coefficient of Restitution public static float WIND_HOT_COR = 0.6f; public static float WIND_COLD_FRICTION = 0.1f; public static float WIND_HOT_FRICTION = 0.1f; } public class Particle : GameObject { public const int HURT_OWNER_TIME_MILLISEC = 5000; public const int TIME_TO_COLLIDE_AGAIN_MILLISEC = 500; public const int TIME_TO_DISSIPATE = 10000; // Wait 10 seconds before removing particles off the board public enum State { Solid, Liquid, Gas }; public float materialShininess = 7000.0f; new private float[] materialDiffuse = { 0.3f, 0.3f, 0.3f, 1.0f }; // Diffuse cofactor new private float[] materialSpecular = { 0.3f, 0.3f, 0.3f, 1.0f }; // Specular cofactor // Particle-type Enumeration public enum ParticleType { Earth, Water, Air }; public ParticleType particleType = new ParticleType(); public ParticleSounds pSounds = new ParticleSounds(); public int hasCollided = -1; public bool hurtOwner = false; public bool hasBeenShot = false; public int ownerID = -1; public Stopwatch hurtOwnerTimer = new Stopwatch(); public Stopwatch hasCollidedTimer = new Stopwatch(); public Stopwatch dissipationTimer = new Stopwatch(); public float distanceTravelled = 0.0f; public float waveRadius = 0.0f; public bool waveIncreasing = false; //Collision sensor public Sensor collisionSensor; // Construtor // public Particle(Mass darkMass) { mass = darkMass; mass.energy = 1.0f; mass.objectType = Mass.ObjectType.PARTICLE; hasBeenShot = true; mass.gameObjectPointer = this; _boundingSphere.Center = Vector3.Zero + mass.currentPosition; _boundingSphere.Radius = 2.0f; mass.objectHeight = _boundingSphere.Radius; switch (particleType) { case ParticleType.Earth: mass.mass = EarthProperties.EARTH_MASS; mass.COR = EarthProperties.EARTH_COLD_COR; mass.dynamicFrictionCoefficient = EarthProperties.EARTH_COLD_FRICTION; break; case ParticleType.Water: mass.mass = WaterProperties.WATER_MASS; mass.COR = WaterProperties.WATER_COLD_COR; mass.dynamicFrictionCoefficient = WaterProperties.WATER_COLD_FRICTION; break; case ParticleType.Air: mass.mass = AirProperties.WIND_MASS; mass.COR = AirProperties.WIND_COLD_COR; mass.dynamicFrictionCoefficient = AirProperties.WIND_COLD_FRICTION; break; } collisionSensor = new Sensor(ObjectLibrary.darkMatter[ObjectLibrary.darkMatterIterator++]); collisionSensor.ownerPointer = this; } public override void Load( XmlNode node) { base.Load(node); if (particleType == ParticleType.Water) { materialShininess = 70.0f; } } public override void Update(ObjectLibrary objectLibrary) { if (hurtOwner == false && hurtOwnerTimer.ElapsedMilliseconds >= HURT_OWNER_TIME_MILLISEC) { hurtOwner = true; hurtOwnerTimer.Stop(); } if (hasCollided > -1) { // check timer to see if we can collide with players again if (hasCollidedTimer.ElapsedMilliseconds >= TIME_TO_COLLIDE_AGAIN_MILLISEC) { hasCollided = -1; hasCollidedTimer.Stop(); } } mass.UpdatePosition(); _boundingSphere.Center = Vector3.Zero + mass.currentPosition; // If moving, play sound if (mass.velocity.Length() > 100.0f || pSounds.particleSoundTimer.ElapsedMilliseconds < XML.GameSettings.PARTICLE_SOUND_TIME_LIMIT) { // Play audio for each human foreach (Human human in objectLibrary.humans) { if (human.IsAlive()) { Audio.Attack(pSounds, this, human.mass, (float) pSounds.particleSoundTimer.ElapsedMilliseconds); } } } else { Audio.StopAttack(pSounds); } // Advance the signal variable for the shader animation switch (particleType) { case ParticleType.Water: { if (dissipationTimer.ElapsedMilliseconds > TIME_TO_DISSIPATE && mass.mass <= (WaterProperties.WATER_MASS / 2.0f) + 1) { // Particle has exceeded the number of allowed collisions and it's mass is below the threshold so we can remove it ObjectLibrary.lookupMap.RemoveLast(mass); ObjectLibrary.lookupMap.RemoveCurrent(mass); mass.ClearValues(); mass.deadObject = true; dissipationTimer.Stop(); return; } if (waveIncreasing) { if (waveRadius > Math.PI * 2) waveIncreasing = false; else waveRadius += 0.005f; } else { if (waveRadius < Math.PI) waveIncreasing = true; else waveRadius -= 0.005f; } //Update COR based on energy level mass.COR = WaterProperties.WATER_COLD_COR - ((mass.energy / 2.0f) + 0.5f) * (WaterProperties.WATER_COLD_COR - WaterProperties.WATER_HOT_COR); mass.dynamicFrictionCoefficient = WaterProperties.WATER_COLD_FRICTION - ((mass.energy / 2.0f) + 0.5f) * (WaterProperties.WATER_COLD_FRICTION - WaterProperties.WATER_HOT_FRICTION); break; } case ParticleType.Earth: { if (dissipationTimer.ElapsedMilliseconds > TIME_TO_DISSIPATE && mass.mass <= (EarthProperties.EARTH_MASS / 2.0f) + 1.0f) { // Particle has exceeded the number of allowed collisions and it's mass is below the threshold so we can remove it ObjectLibrary.lookupMap.RemoveLast(mass); ObjectLibrary.lookupMap.RemoveCurrent(mass); mass.ClearValues(); mass.deadObject = true; dissipationTimer.Stop(); return; } if (waveIncreasing) { if (waveRadius > 2.0f) waveIncreasing = false; else waveRadius += 0.001f; } else { if (waveRadius < 0.5f) waveIncreasing = true; else waveRadius -= 0.001f; } //Update COR based on energy level mass.COR = EarthProperties.EARTH_COLD_COR - ((mass.energy / 2.0f) + 0.5f) * (EarthProperties.EARTH_COLD_COR - EarthProperties.EARTH_HOT_COR); mass.dynamicFrictionCoefficient = EarthProperties.EARTH_COLD_FRICTION - ((mass.energy / 2.0f) + 0.5f) * (EarthProperties.EARTH_COLD_FRICTION - EarthProperties.EARTH_HOT_FRICTION); break; } case ParticleType.Air: { if (dissipationTimer.ElapsedMilliseconds > TIME_TO_DISSIPATE && mass.mass <= (AirProperties.WIND_MASS / 2.0f) + 1.0f) { // Particle has exceeded the number of allowed collisions and it's mass is below the threshold so we can remove it ObjectLibrary.lookupMap.RemoveLast(mass); ObjectLibrary.lookupMap.RemoveCurrent(mass); mass.ClearValues(); mass.deadObject = true; dissipationTimer.Stop(); return; } mass.Rotate(0.0f, 0.2f); //Update COR based on energy level mass.COR = AirProperties.WIND_COLD_COR - ((mass.energy / 2.0f) + 0.5f) * (AirProperties.WIND_COLD_COR - AirProperties.WIND_HOT_COR); mass.dynamicFrictionCoefficient = AirProperties.WIND_COLD_FRICTION - ((mass.energy / 2.0f) + 0.5f) * (AirProperties.WIND_COLD_FRICTION - AirProperties.WIND_HOT_FRICTION); break; } } Vector4 gpu_particleType = new Vector4(0); if (this.particleType == ParticleType.Earth) { gpu_particleType.Y = 0.0f; } // Earth = x0xx if (this.particleType == ParticleType.Water) { gpu_particleType.Y = 1.0f; } // Water = x1xx if (this.particleType == ParticleType.Air) { gpu_particleType.Y = 2.0f; } // Gas = x2xx gpu_particleType.Z = (mass.energy / 2.0f) + 0.5f; // Fire = xxNx gpu_particleType.W = waveRadius; objectValues = new VertexFogBinormalTangentWeightTess(); matrix = Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); objectValues.Color = new Vector4(matrix.M11, matrix.M12, matrix.M13, matrix.M14); // Store the first row objectValues.Binormal = new Vector4(matrix.M21, matrix.M22, matrix.M23, matrix.M24); // Store the second row objectValues.Tangent = new Vector4(matrix.M31, matrix.M32, matrix.M33, matrix.M34); // Store the third row objectValues.BlendWeight = new Vector4(matrix.M41, matrix.M42, matrix.M43, matrix.M44); // Store the fourth row objectValues.Fog = new Vector4(0.0f, gpu_particleType.Y, gpu_particleType.Z, gpu_particleType.W); // Store the scale } public override void DrawShadow(ModelManager modelManager) { ModelInfo modelInfo = new ModelInfo(); // Calculate ObjectSpace(Rotation) and WorldSpace(Translation) Transformation Matrix matrix = Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); // Matrices ShaderParameters.World.SetValue(matrix); modelInfo = modelManager.GetModelInfo(objectModelName); // Draw the model foreach (ModelMesh mesh in modelInfo.model.Meshes) { foreach (Effect currentEffect in mesh.Effects) { currentEffect.CurrentTechnique = currentEffect.Techniques["ShadowMap"]; } mesh.Draw(); } } public void DrawBoundingSphere(ModelManager modelManager) { ModelInfo modelInfo = new ModelInfo(); matrix = Matrix.CreateScale(_boundingSphere.Radius) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); float[] color = { 1, 1, 1, 1 }; ShaderParameters.World.SetValue(matrix); ShaderParameters.coreMaterialDiffuse.SetValue(color); ShaderParameters.modelTexture1.SetValue(GameObjectList.particleColdAirTex); modelInfo = modelManager.GetModelInfo(objectModelName); // Draw the model but with the shield shader foreach (ModelMesh mesh in modelInfo.model.Meshes) { foreach (Effect currentEffect in mesh.Effects) { currentEffect.CurrentTechnique = currentEffect.Techniques["ShieldShaderMain"]; } mesh.Draw(); } } public override void Draw(ModelManager modelManager) { ModelInfo modelInfo = new ModelInfo(); // Lighting ShaderParameters.coreShininess.SetValue(materialShininess); ShaderParameters.coreMaterialDiffuse.SetValue(materialDiffuse); ShaderParameters.coreMaterialSpecular.SetValue(materialSpecular); //if (viewFrustum.Contains(boundingSphere) == ContainmentType.Contains || // viewFrustum.Contains(boundingSphere) == ContainmentType.Intersects) { // Calculate ObjectSpace(Rotation) and WorldSpace(Translation) Transformation Matrix matrix = Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); Vector4 gpu_particleType = new Vector4(0); if (this.particleType == ParticleType.Earth) { gpu_particleType.Y = 0.0f; } // Earth = x0xx if (this.particleType == ParticleType.Water) { gpu_particleType.Y = 1.0f; } // Water = x1xx if (this.particleType == ParticleType.Air) { gpu_particleType.Y = 2.0f; } // Gas = x2xx gpu_particleType.Z = _mass.energy; // Fire = xxNx ShaderParameters.particleType.SetValue(gpu_particleType); // Matricies ShaderParameters.World.SetValue(matrix); ShaderParameters.particleEnergyValue.SetValue((mass.energy / 2.0f) + 0.5f); ShaderParameters.WaveRadius.SetValue(waveRadius); //ShaderParameters.boulderLookVector.SetValue(new Vector4(motionVector, 0.0f)); switch (particleType) { case ParticleType.Air: { ShaderParameters.modelTexture2.SetValue(GameObjectList.particleHotAirTex); ShaderParameters.bumpTexture2.SetValue(GameObjectList.particleHotAirTexBump); ShaderParameters.modelTexture1.SetValue(GameObjectList.particleColdAirTex); ShaderParameters.bumpTexture1.SetValue(GameObjectList.particleColdAirTexBump); break; } case ParticleType.Earth: { ShaderParameters.modelTexture2.SetValue(GameObjectList.particleHotEarthTex); ShaderParameters.bumpTexture2.SetValue(GameObjectList.particleHotEarthTexBump); ShaderParameters.modelTexture1.SetValue(GameObjectList.particleColdEarthTex); ShaderParameters.bumpTexture1.SetValue(GameObjectList.particleColdEarthTexBump); break; } case ParticleType.Water: { ShaderParameters.modelTexture2.SetValue(GameObjectList.particleHotWaterTex); ShaderParameters.bumpTexture2.SetValue(GameObjectList.particleHotWaterTexBump); ShaderParameters.modelTexture1.SetValue(GameObjectList.particleColdWaterTex); ShaderParameters.bumpTexture1.SetValue(GameObjectList.particleColdWaterTexBump); break; } } modelInfo = modelManager.GetModelInfo(objectModelName); // Draw the model foreach (ModelMesh mesh in modelInfo.model.Meshes) { foreach (Effect currentEffect in mesh.Effects) { currentEffect.CurrentTechnique = currentEffect.Techniques["ParticleShaderMain"]; } mesh.Draw(); } } } // Heat Disipation private void DissipateHeat(Particle particle) { if (mass.energy > 0.0f) { // Release heat mass.ChangeEnergy(-0.001f); } else if (particle.mass.energy < 0.0f) { // Absorb heat mass.ChangeEnergy(0.001f); } else { // Particle has reached it's stable state so isChanging is set to false mass.isChanging = false; } } } }