//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// 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);
}
}
}
}
}