//---------------------------------------------------------------------------------------------------------------------------------------------------
//
// 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.Engine.Init;
using DarkWynter.Stream;
///
/// Particle game object
///
public class Particle : GameObject
{
#region Properties
double angle = 0.0;
///
/// Particle-type Enumeration
///
public Enums_Engine.ParticleType particleType;
///
/// Number of collisions
///
public int hasCollided = -1;
///
/// Time after last collision occured
///
public Stopwatch hasCollidedTimer = new Stopwatch();
///
/// ID of player who fired this particle
///
public int ownerID = -1;
///
/// Is the particle allowed to hurt the player who fired it
///
public bool hurtOwner = false;
private Stopwatch hurtOwnerTimer = new Stopwatch();
private float waveRadius = 0.0f;
List billboards = new List();
int smokeCounter = 0;
#endregion
#region Construction Methods
///
/// Constructor
///
public Particle(Load gameObjectLoader):base(gameObjectLoader)
{
mass.objectType = Enums_Engine.ObjectType.PARTICLE;
mass.gameObjectPointer = this;
mass.boundingVolume = new BoundingVolume(new BoundingSphere(mass.currentPosition, 2.0f));
mass.objectHeight = mass.boundingVolume.radius;
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;
mass.energy = 1.0f;
mass.isMoving = true;
waveRadius = 1.0f;
hasCollided = -1;
hurtOwner = false;
hurtOwnerTimer = Stopwatch.StartNew();
collisionWithPlayerResponse = Enums_Engine.CollisionResponses.HEALTHLOSS;
}
///
/// Load particle info from XML
///
/// Particle node
/// ObjectLibrary
/// True if load was successful
public override bool Load(ObjectLibrary objectLibrary)
{
// Set up Model
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;
// Add Sprite Textures
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/Fire"));
draw.textureList.Add(Statics_Engine.SystemSettings.content.Load("Content/_textures/Wind"));
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 our particle object
///
/// ObjectLibrary
public override void Update(ref ObjectLibrary objectLibrary)
{
mass.Update();
mass.boundingVolume.UpdateSphere(mass.currentPosition);
//Update COR based on energy level
mass.COR = Statics_Engine.ParticleSettings.Wind.WIND_COLD_COR - ((mass.energy / 2.0f) + 0.5f) * (Statics_Engine.ParticleSettings.Wind.WIND_COLD_COR - Statics_Engine.ParticleSettings.Wind.WIND_HOT_COR);
mass.dynamicFrictionCoefficient = Statics_Engine.ParticleSettings.Wind.WIND_COLD_FRICTION - ((mass.energy / 2.0f) + 0.5f) * (Statics_Engine.ParticleSettings.Wind.WIND_COLD_FRICTION - Statics_Engine.ParticleSettings.Wind.WIND_HOT_FRICTION);
mass.Rotate(0.0f, 0.2f);
// Send properties and control signal to gpu
Vector4 gpu_particleType = new Vector4(0);
if (this.particleType == Enums_Engine.ParticleType.Earth) { gpu_particleType.Y = 0.0f; } // Earth = x0xx
if (this.particleType == Enums_Engine.ParticleType.Water) { gpu_particleType.Y = 1.0f; } // Water = x1xx
if (this.particleType == Enums_Engine.ParticleType.Air) { gpu_particleType.Y = 2.0f; } // Gas = x2xx
gpu_particleType.Z = (mass.energy / 2.0f) + 0.5f; // Fire = xxNx
gpu_particleType.W = waveRadius;
}
#endregion
#region Collision Responses
///
/// Add Particle specific responses to an object to object collision involving this and collidedObject
///
/// Object colliding with this object
/// 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,
Vector3.Distance((mass.mass * gravityNormalComponent), totalForceNormalComponent),
combinedTangentialForce);
}
else
{
mass.AddForce(mass.mass * -velocityTangentialComponent / Statics_Engine.SystemSettings.dt);
mass.AddForce(-totalForceTangentialComponent);
}
}
}
#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;
}
///
/// Draw the particle's bounding sphere around it
///
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();
}
///
/// Draw any billboard associated with this particle
///
/// ObjectLibrary
/// List of Billboards
public override void Draw_Billboards(ObjectLibrary objectLibrary, BillboardList gameObjectBillboards)
{
float radius = 10.0f;
// Trig Position Cycle
angle += 0.1;
if (angle > Math.PI * 2.0f)
{ angle = 0.0f; }
Random random = new Random();
Vector3 offset = new Vector3(
(float) (radius * Math.Cos(angle)),
0.0f,
(float) (radius * Math.Cos(angle))
);
if( billboards.Count < 10)
{
Billboard billboard = new Billboard(null);
billboard.Load(mass.currentPosition + offset, Vector3.Zero, 15.0f, 15.0f, draw.textureList[0]);
//billboard.Load(mass.currentPosition + offset, Vector3.Zero, 15.0f, 15.0f, Engine.DarkWynterEngine.video.CurrentTexture);
billboards.Add(billboard);
}
else
{
// Remove next billboard
Billboard billboard = billboards[smokeCounter];
billboards.RemoveAt(smokeCounter);
smokeCounter++;
// Recycle counter
if (smokeCounter == 5)
smokeCounter = 0;
billboard.Position = mass.currentPosition + offset;
billboard.Load(mass.currentPosition + offset, Vector3.Zero, 15.0f, 15.0f, draw.textureList[0]);
//billboard.SetTexture(Engine.DarkWynterEngine.video.CurrentTexture);
billboards.Add(billboard);
}
// Add a billboard texture above the particle
// draw all billboard in list
for (int i = 0; i < billboards.Count; i++)
{
gameObjectBillboards.Add(billboards[i] as IBillboard);
}
}
#endregion
}
}