//--------------------------------------------------------------------------------------------------------------------------------------------------- // // Copyright (C)2007 DarkWynter Studios. All rights reserved. // //--------------------------------------------------------------------------------------------------------------------------------------------------- // {Contact : darkwynter.com for licensing information //--------------------------------------------------------------------------------------------------------------------------------------------------- namespace DarkWynter.Game.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 DarkWynter.Engine.GameObjects; using DarkWynter.Engine.Globals; using DarkWynter.Engine.Physics; using DarkWynter.Engine.ObjectLib; using GameObjects; using DarkWynter.Stream; using DarkWynter.Engine.Init; /// /// A Bullet /// public class Bullet : GameObject { #region Properties /// /// Timer used to identify when to recycle the object /// public Stopwatch dissipationTimer = new Stopwatch(); /// /// Particle-type Enumeration /// public Enums_Engine.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; #endregion #region Construction Methods /// /// Constructor /// public Bullet(Load gameObjectLoader) : base(gameObjectLoader) { mass.objectType = Enums_Engine.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_Engine.CollisionResponses.HEALTHLOSS; switch (bulletType) { case Enums_Engine.BulletType.Earth: mass.mass = Statics_Engine.ParticleSettings.Earth.EARTH_MASS; mass.COR = Statics_Engine.ParticleSettings.Earth.EARTH_COLD_COR; mass.dynamicFrictionCoefficient = Statics_Engine.ParticleSettings.Earth.EARTH_COLD_FRICTION; break; case Enums_Engine.BulletType.Water: mass.mass = Statics_Engine.ParticleSettings.Water.WATER_MASS; mass.COR = Statics_Engine.ParticleSettings.Water.WATER_COLD_COR; mass.dynamicFrictionCoefficient = Statics_Engine.ParticleSettings.Water.WATER_COLD_FRICTION; break; case Enums_Engine.BulletType.Air: mass.mass = Statics_Engine.ParticleSettings.Wind.WIND_MASS; mass.COR = Statics_Engine.ParticleSettings.Wind.WIND_COLD_COR; mass.dynamicFrictionCoefficient = Statics_Engine.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(ObjectLibrary objectLibrary) { // Set up Model Manager bool success = LoadModel(load.node); // Return unsuccessfully if can't load user supplied XML data if (!success) { return false; } draw.drawMethod = Enums_Stream.DrawMethod.BasicGameObject_Draw; drawBoundingVolume = draw; draw.technique = "BasicLightingShaderMain"; drawBoundingVolume.technique = "ShieldShaderMain"; // Start Type properties objectModelName = load.node.Attributes["name"].Value; drawBoundingVolume.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/whitesquare")); drawBoundingVolume.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/Wind")); mass.scale = new Vector3((float.Parse(load.node.Attributes["maxScale"].Value))); mass.mass = float.Parse(load.node.Attributes["mass"].Value); mass.isMoving = false; isCollectable = bool.Parse(load.node.Attributes["isCollectable"].Value); isKey = bool.Parse(load.node.Attributes["isKey"].Value); if (isKey) { collisionWithPlayerResponse = Enums_Engine.CollisionResponses.HEALTHBONUS; } return true; } #endregion #region Update Methods /// /// Update /// /// ObjectLibrary public override void Update(ref ObjectLibrary objectLibrary) { return; mass.Update(); 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_Engine.BulletType.Earth) { gpu_particleType.Y = 0.0f; } // Earth = x0xx if (this.bulletType == Enums_Engine.BulletType.Water) { gpu_particleType.Y = 1.0f; } // Water = x1xx if (this.bulletType == Enums_Engine.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 //dynamicObjectValues = new VertexFogBinormalTangent(); //dynamicObjectValues.Fog = new Vector4(mass.scale.Y, gpu_particleType.Y, gpu_particleType.Z, gpu_particleType.W); // Store the scale //dynamicObjectValues.Binormal = new Vector4(mass.currentRotation.X, // mass.currentRotation.Y, // mass.currentRotation.Z, // mass.currentRotation.W); // Store the quaternion rotation //dynamicObjectValues.Tangent = new Vector4(mass.currentPosition, 0.0f); // Store the translation } #endregion #region Draw Methods /// /// Draw the particle object /// public override Draw Draw() { // Calculate ObjectSpace(Rotation) and WorldSpace(Translation) Transformation Matrix draw.matrix = draw.initialTransform * Matrix.CreateScale(mass.scale) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); return draw; } /// /// Function for debugging to compare the size of the bullet with it's bounding volume /// public void DrawBoundingSphere() { drawBoundingVolume.matrix = drawBoundingVolume.initialTransform * Matrix.CreateScale(mass.boundingVolume.radius) * Matrix.CreateFromQuaternion(mass.currentRotation) * Matrix.CreateTranslation(mass.currentPosition); float[] color = { 1, 1, 1, 1 }; ShaderParameters.DrawFX.materialDiffuse.SetValue(color); drawBoundingVolume.DoDraw(); } #endregion #region CollisionResponse Methods /// /// 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_Engine.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_Engine.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_Engine.SystemSettings.dt); mass.AddForce(-totalForceTangentialComponent); } } } #endregion } }