//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// Copyright (C)2007 DarkWynter Studios. All rights reserved.
//
//---------------------------------------------------------------------------------------------------------------------------------------------------
// {Contact : darkwynter.com for licensing information
//---------------------------------------------------------------------------------------------------------------------------------------------------
namespace DarkWynter.Engine.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;
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;
}
///
/// 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_Engine.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_Engine.PlayerSettings.PARTICLE_START_DISTANCE * direction),
initialPosition + ((Statics_Engine.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_Engine.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_Engine.BulletType.Air:
mass.mass = Statics_Engine.ParticleSettings.Wind.WIND_MASS;
// Load Air Textures
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/AirParticleCold"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/AirParticleCold_bump"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/AirParticleFire"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/AirParticleFire_bump"));
break;
case Enums_Engine.BulletType.Earth:
mass.mass = Statics_Engine.ParticleSettings.Earth.EARTH_MASS;
// Load Earth Textures
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/EarthParticleFrozen"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/EarthParticleFrozen_bump"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/EarthParticleLava"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/EarthParticleLava_bump"));
break;
case Enums_Engine.BulletType.Water:
mass.mass = Statics_Engine.ParticleSettings.Water.WATER_MASS;
// Load Water Textures
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/WaterParticleIce"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/WaterParticleIce_bump"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/WaterParticleBoiling"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/WaterParticleBoiling_bump"));
break;
}
// Start Timer
dissipationTimer = new Stopwatch();
dissipationTimer.Start();
}
#endregion
#region Update Methods
///
/// Update
///
/// ObjectLibrary
public override void Update(ref ObjectLibrary objectLibrary)
{
for (int i = 0; i < objectLibrary.bots.Count; i++)
{
if (objectLibrary.bots[i].IsAlive())
{
// Shoot at bot
}
}
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
}
}