//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynterEngine.GameObjects { #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 using Globals; using Physics; using ObjectLib; using GameObjects; /// /// A Bullet /// public class Bullet : GameObject { /// /// Timer used to identify when to recycle the object /// public Stopwatch dissipationTimer = new Stopwatch(); /// /// Particle-type Enumeration /// public Enums.BulletType bulletType; //private ParticleSounds pSounds = new ParticleSounds(); /// /// A counter for the number of collisions that have occured /// public int hasCollided = -1; /// /// Stopwatch for recycling the object after it has collided /// public Stopwatch hasCollidedTimer = new Stopwatch(); /// /// ID of the player who fired this bullet /// public int ownerID = -1; /// /// Boolean check to see if the player was hit by their own bullet /// public bool hurtOwner = false; private Stopwatch hurtOwnerTimer = new Stopwatch(); private float waveRadius = 0.0f; /// /// Constructor /// public Bullet() { mass.objectType = Enums.ObjectType.PARTICLE; mass.gameObjectPointer = this; mass.objectHeight = mass.boundingVolume.radius; mass.isMoving = true; mass.energy = 1.0f; waveRadius = 1.0f; hasCollided = -1; hurtOwner = false; hurtOwnerTimer = Stopwatch.StartNew(); collisionWithPlayerResponse = Enums.CollisionResponses.HEALTHLOSS; switch (bulletType) { case Enums.BulletType.Earth: mass.mass = Statics.ParticleSettings.Earth.EARTH_MASS; mass.COR = Statics.ParticleSettings.Earth.EARTH_COLD_COR; mass.dynamicFrictionCoefficient = Statics.ParticleSettings.Earth.EARTH_COLD_FRICTION; break; case Enums.BulletType.Water: mass.mass = Statics.ParticleSettings.Water.WATER_MASS; mass.COR = Statics.ParticleSettings.Water.WATER_COLD_COR; mass.dynamicFrictionCoefficient = Statics.ParticleSettings.Water.WATER_COLD_FRICTION; break; case Enums.BulletType.Air: mass.mass = Statics.ParticleSettings.Wind.WIND_MASS; mass.COR = Statics.ParticleSettings.Wind.WIND_COLD_COR; mass.dynamicFrictionCoefficient = Statics.ParticleSettings.Wind.WIND_COLD_FRICTION; break; } } /// /// Load bullet information from XML /// /// The bullet's XML node /// ObjectLibrary /// True if load was successful, else false public override bool Load(XmlNode node, ObjectLibrary objectLibrary) { // return false; //base.Load(node, objectLibrary); // Set up Model Manager bool success = objectLibrary.modelManager.AddNewModel(node.Attributes["type"].Value, node.Attributes["model"].Value, node.Attributes["texture"].Value, node.Attributes["bumpTexture"].Value); // Return unsuccessfully if can't load user supplied XML data if (!success) { return true; } // Start Type properties //gameObject.mass.objectType = objectType; // mass.gameObjectPointer = this; objectModelName = node.Attributes["type"].Value; mass.scale = new Vector3((float.Parse(node.Attributes["maxScale"].Value))); mass.mass = float.Parse(node.Attributes["mass"].Value); mass.isMoving = false; isCollectable = bool.Parse(node.Attributes["isCollectable"].Value); isKey = bool.Parse(node.Attributes["isKey"].Value); if (isKey) { collisionWithPlayerResponse = Enums.CollisionResponses.HEALTHBONUS; } objectValues = new VertexFogBinormalTangent(); objectValues.Fog = new Vector4(mass.scale, 0.0f); // Store the scale objectValues.Binormal = new Vector4(mass.currentRotation.X, mass.currentRotation.Y, mass.currentRotation.Z, mass.currentRotation.W); // Store the quaternion rotation objectValues.Tangent = new Vector4(mass.currentPosition, 0.0f); return true; } /// /// Function to Initialize a new bullet /// /// ID of player who fired the bullet /// Type of bullet /// Starting position /// Direction of motion of the bullet /// Mass of the bullet /// Thermal energy value of the bullet public void PrepAttack(int playerID, Enums.BulletType type, Vector3 initialPosition, Vector3 direction, int particleMassValue, int particleThermalValue) { // Set Type and Id bulletType = type; ownerID = playerID; // Set Direction direction.Normalize(); mass.normalVector = Vector3.Zero + direction; // Set Position mass.SetPosition(initialPosition + (Statics.PlayerSettings.PARTICLE_START_DISTANCE * direction), initialPosition + ((Statics.PlayerSettings.PARTICLE_START_DISTANCE + 10) * direction)); mass.lastPosition = Vector3.Zero + initialPosition; mass.boundingVolume = new BoundingVolume(new BoundingSphere(mass.currentPosition, 2.0f)); // Add Force mass.AddForce(direction * Statics.PlayerSettings.DIRECT_ATTACK_FORCE); // Shift and Apply DPad Values between 1 and 75 //mass.scale = particleMassValue / 2250.0f + 3; //mass.boundingVolume.Radius = mass.scale.Y/2; //mass.boundingVolume.Update(mass.currentPosition, mass.lastPosition); // Set Energy Level Shift from 0 to 100 to -1 to 1 mass.energy = ((float)particleThermalValue * 2 - 75) / 75; if (mass.energy != 0.0f){mass.isChanging = true;} // Set Textures switch (type) { case Enums.BulletType.Air: mass.mass = Statics.ParticleSettings.Wind.WIND_MASS; // Load Air Textures textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/AirParticleCold")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/AirParticleCold_bump")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/AirParticleFire")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/AirParticleFire_bump")); break; case Enums.BulletType.Earth: mass.mass = Statics.ParticleSettings.Earth.EARTH_MASS; // Load Earth Textures textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/EarthParticleFrozen")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/EarthParticleFrozen_bump")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/EarthParticleLava")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/EarthParticleLava_bump")); break; case Enums.BulletType.Water: mass.mass = Statics.ParticleSettings.Water.WATER_MASS; // Load Water Textures textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/WaterParticleIce")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/WaterParticleIce_bump")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/WaterParticleBoiling")); textureList.Add(Statics.SystemSettings.content.Load("Content/_textures/WaterParticleBoiling_bump")); break; } // Start Timer dissipationTimer = new Stopwatch(); dissipationTimer.Start(); // Instancing objectValues = new VertexFogBinormalTangent(); objectValues.Fog = new Vector4(mass.scale, 0.0f); // Store the scale objectValues.Binormal = new Vector4(mass.currentRotation.X, mass.currentRotation.Y, mass.currentRotation.Z, mass.currentRotation.W); // Store the quaternion rotation objectValues.Tangent = new Vector4(mass.currentPosition, 0.0f); // Store the translation } /// /// Update /// /// ObjectLibrary public override void Update(ref ObjectLibrary objectLibrary) { //mass.UpdatePosition(); //mass.boundingVolume.UpdateSphere(mass.currentPosition); //Update COR based on energy level //mass.COR = Statics.ParticleSettings.Wind.WIND_COLD_COR - ((mass.energy / 2.0f) + 0.5f) * (Statics.ParticleSettings.Wind.WIND_COLD_COR - Statics.ParticleSettings.Wind.WIND_HOT_COR); //mass.dynamicFrictionCoefficient = Statics.ParticleSettings.Wind.WIND_COLD_FRICTION - ((mass.energy / 2.0f) + 0.5f) * (Statics.ParticleSettings.Wind.WIND_COLD_FRICTION - Statics.ParticleSettings.Wind.WIND_HOT_FRICTION); mass.Rotate(0.0f, 0.2f); // Send properties and control signal to Shaders Vector4 gpu_particleType = new Vector4(0); if (this.bulletType == Enums.BulletType.Earth) { gpu_particleType.Y = 0.0f; } // Earth = x0xx if (this.bulletType == Enums.BulletType.Water) { gpu_particleType.Y = 1.0f; } // Water = x1xx if (this.bulletType == Enums.BulletType.Air) { gpu_particleType.Y = 2.0f; } // Gas = x2xx gpu_particleType.Z = (mass.energy / 2.0f) + 0.5f; // Fire = xxNx gpu_particleType.W = waveRadius; // Instancing buffers objectValues = new VertexFogBinormalTangent(); objectValues.Fog = new Vector4(mass.scale.Y, gpu_particleType.Y, gpu_particleType.Z, gpu_particleType.W); // Store the scale objectValues.Binormal = new Vector4(mass.currentRotation.X, mass.currentRotation.Y, mass.currentRotation.Z, mass.currentRotation.W); // Store the quaternion rotation objectValues.Tangent = new Vector4(mass.currentPosition, 0.0f); // Store the translation } /// /// Function for debugging to compare the size of the bullet with it's bounding volume /// /// Model manager public void DrawBoundingSphere(ModelManager modelManager) { matrix = Matrix.CreateScale(mass.boundingVolume.radius) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); ShaderParameters.World.SetValue(matrix); ModelInfo modelInfo = modelManager.GetModelInfo(objectModelName); float[] color = { 1, 1, 1, 1 }; ShaderParameters.materialDiffuse.SetValue(color); ShaderParameters.modelTexture1.SetValue(textureList[0]); // 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(); } } /// /// Add Particle specific responses to an object to object collision involving this and collidedObject /// /// Object colliding with this object /// The resultant force of collision /// ObjectLibrary /// True = this object needs to be recycled public override bool ObjectCollisionResponse(GameObject collidedObject, Vector3 resultantForce, ObjectLibrary objectLibrary) { mass.AddForce(resultantForce); if (collidedObject.mass.objectType == Enums.ObjectType.PLAYER) { // Add Player specific responses to the collided player // Remove this object return true; } return false; } /// /// Add Particle specific responses to an object to terrain collision involving this /// /// Terrain public override void TerrainCollisionResponse(Terrain terrain) { base.GetObjectHeight(terrain); // Add Gravity if terrain and player are touching if (heightDifference < 0.0f) { mass.AddForce(mass.mass * Statics.GameSettings.accelDueToGravity); } else if (heightDifference > 0.0f) { // Call base first base.TerrainCollisionResponse(terrain); if (combinedNormalForce.Y < 0.0f) { mass.AddForce(-combinedNormalForce); } else { mass.AddForce(-velocityNormalComponent); } mass.AddForce(heightDifference * surfaceNormal * terrain.particleSurfaceTension * mass.COR); if (combinedTangentialForce.Length() >= 0.5f) { mass.AddForce(mass.mass * -gravityTangentialComponent); mass.AddFriction(mass.dynamicFrictionCoefficient + terrain.mass.dynamicFrictionCoefficient, (mass.mass * gravityNormalComponent.Length()) + totalForceNormalComponent.Length(), combinedTangentialForce); } else { mass.AddForce(mass.mass * -velocityTangentialComponent / Statics.SystemSettings.dt); mass.AddForce(-totalForceTangentialComponent); } } } } }