Fuck yeah, particles! (Try the esword, press f to turn on. its great :) )

This commit is contained in:
spoogemonster
2013-09-13 02:34:20 +00:00
parent 89b64d5b0f
commit 911eb1f9b7
25 changed files with 1341 additions and 25 deletions
+5
View File
@@ -66,6 +66,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\References\Release\Gorgon.dll</HintPath>
</Reference>
<Reference Include="GorgonFramework">
<HintPath>..\References\Release\GorgonFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="NetSerializer, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -105,6 +108,8 @@
<Compile Include="Component\Mover\SlaveMoverComponent.cs" />
<Compile Include="Component\Physics\PhysicsComponent.cs" />
<Compile Include="Component\PlayerActionComp\PlayerActionCompC.cs" />
<Compile Include="Component\Renderable\ParticleSystem.cs" />
<Compile Include="Component\Renderable\ParticleSystemComponent.cs" />
<Compile Include="Component\Renderable\Speechbubble.cs" />
<Compile Include="Component\Renderable\WearableSpriteComponent.cs" />
<Compile Include="Component\Renderable\ItemSpriteComponent.cs" />
@@ -175,11 +175,14 @@ namespace CGO
public void LoadSprites(string name)
{
AddSprite(name);
AddSprite(name + "_inhand");
AddSprite(name + "_inhand_side");
if (IoCManager.Resolve<IResourceManager>().SpriteExists(name + "_inhand_back"))
AddSprite(name + "_inhand_back");
if (!HasSprite(name))
{
AddSprite(name);
AddSprite(name + "_inhand");
AddSprite(name + "_inhand_side");
if (IoCManager.Resolve<IResourceManager>().SpriteExists(name + "_inhand_back"))
AddSprite(name + "_inhand_back");
}
}
protected override bool WasClicked(PointF worldPos)
+777
View File
@@ -0,0 +1,777 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GorgonLibrary;
using GorgonLibrary.Graphics;
namespace CGO
{
public class ParticleSystem
{
#region Classes
private class Particle
{
/// <summary>
/// Particle position relative to the emit position
/// </summary>
public Vector2D Position;
/// <summary>
/// Where the emitter was when the particle was first emitted
/// </summary>
public Vector2D EmitterPosition;
/// <summary>
/// Particle's x/y velocity
/// </summary>
public Vector2D Velocity;
/// <summary>
/// Particle's x/y acceleration
/// </summary>
public Vector2D Acceleration;
/// <summary>
/// Particle's radial velocity - relative to EmitterPosition
/// </summary>
public float RadialVelocity;
/// <summary>
/// Particle's radial acceleration
/// </summary>
public float RadialAcceleration;
/// <summary>
/// Particle's tangential velocity - relative to EmitterPosition
/// </summary>
public float TangentialVelocity;
/// <summary>
/// Particle's tangential acceleration
/// </summary>
public float TangentialAcceleration;
/// <summary>
/// Particle's age -- from 0f
/// </summary>
public float Age;
/// <summary>
/// Time after which the particle will "die"
/// </summary>
public float Lifetime;
/// <summary>
/// Particle's spin about its center in radians
/// </summary>
public float Spin;
/// <summary>
/// Rate of change of particle's spin
/// </summary>
public float SpinVelocity;
/// <summary>
/// Particle's current size
/// </summary>
public float Size;
/// <summary>
/// Rate of change of particle's size change
/// </summary>
public float SizeDelta;
/// <summary>
/// Particle's current color
/// </summary>
public Vector4D Color;
/// <summary>
/// Rate of change of particle's color
/// </summary>
public Vector4D ColorDelta;
/// <summary>
/// Whether or not the particle is currently being drawn
/// </summary>
public bool Alive;
public Particle()
{
Position = ParticleDefaults.Position;
EmitterPosition = ParticleDefaults.EmitterPosition;
Velocity = ParticleDefaults.Velocity;
Acceleration = ParticleDefaults.Acceleration;
RadialVelocity = ParticleDefaults.RadialVelocity;
RadialAcceleration = ParticleDefaults.RadialAcceleration;
TangentialVelocity = ParticleDefaults.TangentialVelocity;
TangentialAcceleration = ParticleDefaults.TangentialAcceleration;
Age = ParticleDefaults.Age;
Lifetime = ParticleDefaults.Lifetime;
Spin = ParticleDefaults.Spin;
SpinVelocity = ParticleDefaults.SpinVelocity;
Size = ParticleDefaults.Size;
SizeDelta = ParticleDefaults.SizeDelta;
Color = ParticleDefaults.Color;
ColorDelta = ParticleDefaults.ColorDelta;
Alive = ParticleDefaults.Alive;
}
public void Update(float frameTime)
{
Age += frameTime;
if (Age >= Lifetime)
Alive = false;
Velocity += Acceleration*frameTime;
RadialVelocity += RadialAcceleration*frameTime;
TangentialVelocity += TangentialAcceleration*frameTime;
//Calculate delta p due to radial velocity
var positionRelativeToEmitter = Position - EmitterPosition;
var deltaRadial = RadialVelocity * frameTime;
var deltaPosition = positionRelativeToEmitter*(deltaRadial/positionRelativeToEmitter.Length);
//Calculate delta p due to tangential velocity
var radius = positionRelativeToEmitter.Length;
if (radius > 0)
{
var theta = MathUtility.ASin(positionRelativeToEmitter.X/radius);
theta += TangentialVelocity*frameTime;
deltaPosition += new Vector2D(radius*MathUtility.Sin(theta), radius*MathUtility.Cos(theta))
- positionRelativeToEmitter;
}
//Calculate delta p due to Velocity
deltaPosition += Velocity*frameTime;
Position += deltaPosition;
Spin += SpinVelocity*frameTime;
Size += SizeDelta*frameTime;
Color += ColorDelta*frameTime;
}
}
private struct ParticleDefaults
{
/// <summary>
/// Particle position relative to the emit position
/// </summary>
public static Vector2D Position = new Vector2D(0,0);
/// <summary>
/// Where the emitter was when the particle was first emitted
/// </summary>
public static Vector2D EmitterPosition = new Vector2D(0,0);
/// <summary>
/// Particle's x/y velocity
/// </summary>
public static Vector2D Velocity = new Vector2D(0,0);
/// <summary>
/// Particle's x/y acceleration
/// </summary>
public static Vector2D Acceleration = new Vector2D(0,0);
/// <summary>
/// Particle's radial velocity - relative to EmitterPosition
/// </summary>
public static float RadialVelocity = 1.0f;
/// <summary>
/// Particle's radial acceleration
/// </summary>
public static float RadialAcceleration = 0f;
/// <summary>
/// Particle's tangential velocity - relative to EmitterPosition
/// </summary>
public static float TangentialVelocity = 0f;
/// <summary>
/// Particle's tangential acceleration
/// </summary>
public static float TangentialAcceleration = 0f;
/// <summary>
/// Particle's age -- from 0f
/// </summary>
public static float Age = 0f;
/// <summary>
/// Time after which the particle will "die"
/// </summary>
public static float Lifetime = 1.0f;
/// <summary>
/// Particle's spin about its center in radians
/// </summary>
public static float Spin = 0f;
/// <summary>
/// Rate of change of particle's spin
/// </summary>
public static float SpinVelocity = 0f;
/// <summary>
/// Particle's current size
/// </summary>
public static float Size = 0f;
/// <summary>
/// Rate of change of particle's size change
/// </summary>
public static float SizeDelta = 0f;
/// <summary>
/// Particle's current color
/// </summary>
public static Vector4D Color = new Vector4D(1,0,0,0);
/// <summary>
/// Rate of change of particle's color
/// </summary>
public static Vector4D ColorDelta = new Vector4D(-1, 0, 0, 0);
/// <summary>
/// Whether or not the particle is currently being drawn
/// </summary>
public static bool Alive = false;
}
#endregion
#region Variables
private Particle[] _particles;
private Batch _batch;
private Random _rnd = new Random();
private float _particlesToEmit;
private List<Particle> _newParticles = new List<Particle>();
#endregion
#region Properties
/// <summary>
/// Emitter Position;
/// This is the logical position of the emitter object
/// </summary>
public Vector2D EmitterPosition { get; set; }
/// <summary>
/// Emission Offset;
/// This is where the particles should be emitted relative to the emitter position.
/// </summary>
public Vector2D EmissionOffset { get; set; }
/// <summary>
/// Emit Position
/// This is where the particles will be emitted.
/// </summary>
public Vector2D EmitPosition { get { return EmitterPosition + EmissionOffset; } }
/// <summary>
/// Emit
/// This controls whether particles are being emitted or not
/// </summary>
public bool Emit { get; set; }
/// <summary>
/// Emit Rate
/// This controls the rate in particles per second at which particles are emitted.
/// </summary>
public int EmitRate { get; set; }
/// <summary>
/// Maximum Particles To Display
/// This controls how many particles will be 'alive' at once. If the number of particles generated exceeds this,
/// the oldest particles will be culled first.
/// </summary>
public int MaximumParticleCount
{
get { return _particles.Length; }
set
{
if (value < 1)
throw new ArgumentOutOfRangeException("The number of particles cannot be less than 1.");
_particles = new Particle[value];
for (var i = 0; i < value; i++)
{
_particles[i] = new Particle();
}
}
}
/// <summary>
/// Particle Sprite
/// This is the sprite that will be drawn as the "particle".
/// </summary>
public Sprite ParticleSprite { get; set; }
/// <summary>
/// Emission Radius
/// This controls the range in radius from the emission position where the particles
/// will start. If the radius is 0, they will all be emitted at the EmitPosition.
/// </summary>
public Range<float> EmissionRadiusRange { get; set; }
/// <summary>
/// Velocity Range
/// This controls the particle's initial velocity
/// </summary>
public Vector2D Velocity { get; set; }
/// <summary>
/// Velocity Variance
/// This controls the random variation of the particle's initial velocity
/// </summary>
public float VelocityVariance { get; set; }
/// <summary>
/// Acceleration Range
/// This controls the particle's initial acceleration
/// </summary>
public Vector2D Acceleration { get; set; }
/// <summary>
/// Acceleration Variance
/// This controls the random variation of particle's initial acceleration
/// </summary>
public float AccelerationVariance { get; set; }
/// <summary>
/// Radial Velocity Range
/// This controls the particle's initial Radial velocity
/// </summary>
public float RadialVelocity { get; set; }
/// <summary>
/// Radial Velocity Variance
/// Radial This controls the random variation of the particle's initial Radial velocity
/// </summary>
public float RadialVelocityVariance { get; set; }
/// <summary>
/// Radial Acceleration Range
/// This controls the particle's initial Radial acceleration
/// </summary>
public float RadialAcceleration { get; set; }
/// <summary>
/// Radial Acceleration Variance
/// This controls the random variation of particle's initial Radial acceleration
/// </summary>
public float RadialAccelerationVariance { get; set; }
/// <summary>
/// Tangential Velocity Range
/// This controls the particle's initial tangential velocity
/// </summary>
public float TangentialVelocity { get; set; }
/// <summary>
/// Tangential Velocity Variance
/// This controls the random variation of the particle's initial tangential velocity
/// </summary>
public float TangentialVelocityVariance { get; set; }
/// <summary>
/// Tangential Acceleration Range
/// This controls the particle's initial tangential acceleration
/// </summary>
public float TangentialAcceleration { get; set; }
/// <summary>
/// Tangential Acceleration Variance
/// This controls the random variation of particle's initial tangential acceleration
/// </summary>
public float TangentialAccelerationVariance { get; set; }
/// <summary>
/// Lifetime
/// This controls the particle's lifetime
/// </summary>
public float Lifetime { get; set; }
/// <summary>
/// Lifetime Variance
/// This controls the variation in the particle's lifetime
/// </summary>
public float LifetimeVariance { get; set; }
/// <summary>
/// Spin Velocity
/// This controls the initial spin velocity over the life of the particle
/// </summary>
public Range<float> SpinVelocity { get; set; }
/// <summary>
/// Spin Velocity Variance
/// This controls the random variation of the initial spin velocity of the particle
/// </summary>
public float SpinVelocityVariance { get; set; }
/// <summary>
/// Size Range
/// This controls the range in size of the particle over the course of its lifetime
/// </summary>
public Range<float> SizeRange { get; set; }
/// <summary>
/// This controls how much particle size will vary between particles
/// </summary>
public float SizeVariance { get; set; }
/// <summary>
/// This controls the color range of the particle over the course of its lifetime
/// </summary>
public Range<Vector4D> ColorRange { get; set; }
/// <summary>
/// This controls how much particle color will vary between particles
/// </summary>
public float ColorVariance { get; set; }
/// <summary>
/// Retrieves the set of live particles, ordered by oldest (nearest to death) first
/// </summary>
private IEnumerable<Particle> LiveParticles
{
get { return _particles.Where(p => p.Alive).OrderByDescending(p => 1-(p.Lifetime-p.Age)/p.Lifetime); }
}
/// <summary>
/// Retrieves the set of dead particles
/// </summary>
private IEnumerable<Particle> DeadParticles
{
get { return _particles.Where(p => !p.Alive); }
}
private int DeadParticleCount
{
get { return DeadParticles.Count(); }
}
private int LiveParticleCount
{
get { return LiveParticles.Count(); }
}
#endregion
#region Methods
private float RandomFloat()
{
return (float) _rnd.NextDouble();
}
private float RandomSignedFloat()
{
return (float) (_rnd.NextDouble() - 0.5f)*2;
}
private float RandomRangeFloat(Range<float> randomRange)
{
return (RandomFloat() * (randomRange.End - randomRange.Start)) + randomRange.Start;
}
private float RandomRangeFloat(float start, float end)
{
return (RandomFloat()*(end - start)) + start;
}
private Vector2D RandomRangeVector2D(Range<Vector2D> randomRange)
{
return new Vector2D(
RandomRangeFloat(randomRange.Start.X, randomRange.End.X),
RandomRangeFloat(randomRange.Start.Y, randomRange.End.Y)
);
}
private Vector3D RandomRangeVector3D(Range<Vector3D> randomRange)
{
return new Vector3D(
RandomRangeFloat(randomRange.Start.X, randomRange.End.X),
RandomRangeFloat(randomRange.Start.Y, randomRange.End.Y),
RandomRangeFloat(randomRange.Start.Z, randomRange.End.Z)
);
}
private Vector4D RandomRangeVector4D(Range<Vector4D> randomRange)
{
return new Vector4D(
RandomRangeFloat(randomRange.Start.X, randomRange.End.X),
RandomRangeFloat(randomRange.Start.Y, randomRange.End.Y),
RandomRangeFloat(randomRange.Start.Z, randomRange.End.Z),
RandomRangeFloat(randomRange.Start.W, randomRange.End.W)
);
}
private float VariedFloat(float value, float variance)
{
return value + RandomSignedFloat() * variance;
}
private float VariedPositiveFloat(float value, float variance)
{
return value + RandomFloat() * variance;
}
private Vector2D VariedVector2D(Vector2D value, float variance)
{
return new Vector2D(
VariedFloat(value.X, variance),
VariedFloat(value.Y, variance)
);
}
private Vector2D VariedPositiveVector2D(Vector2D value, float variance)
{
return new Vector2D(
VariedPositiveFloat(value.X, variance),
VariedPositiveFloat(value.Y, variance)
);
}
private Vector3D VariedVector3D(Vector3D value, float variance)
{
return new Vector3D(
VariedFloat(value.X, variance),
VariedFloat(value.Y, variance),
VariedFloat(value.Z, variance)
);
}
private Vector3D VariedPositiveVector3D(Vector3D value, float variance)
{
return new Vector3D(
VariedPositiveFloat(value.X, variance),
VariedPositiveFloat(value.Y, variance),
VariedPositiveFloat(value.Z, variance)
);
}
private Vector4D VariedVector4D(Vector4D value, float variance)
{
return new Vector4D(
VariedFloat(value.X, variance),
VariedFloat(value.Y, variance),
VariedFloat(value.Z, variance),
VariedFloat(value.W, variance)
);
}
private Vector4D VariedPositiveVector4D(Vector4D value, float variance)
{
return new Vector4D(
VariedPositiveFloat(value.X, variance),
VariedPositiveFloat(value.Y, variance),
VariedPositiveFloat(value.Z, variance),
VariedPositiveFloat(value.W, variance)
);
}
private Vector4D Limit(Vector4D color)
{
if (Math.Max(color.X, Math.Max(color.Y, Math.Max(color.Z, color.W))) <= 255)
return color;
float x, y, z, w;
x = color.X;
y = color.Y;
z = color.Z;
w = color.W;
//RGB Max
var max = Math.Max(y, Math.Max(z, w));
if(max > 255)
{
var f = 255/max;
y = f*y;
z = f*z;
w = f*w;
}
if (x > 255)
x = 255;
return new Vector4D(x, y, z, w);
}
private Color ToColor(Vector4D color)
{
color = Limit(color);
return Color.FromArgb((int) color.X, (int)color.Y, (int)color.Z, (int)color.W);
}
public void Start()
{
Emit = true;
}
private void EmitParticle(Particle p)
{
p.Acceleration = VariedVector2D(Acceleration, AccelerationVariance);
p.Lifetime = VariedPositiveFloat(Lifetime, LifetimeVariance);
p.Age = 0;
if (p.Lifetime == 0)
return;
p.Alive = true;
p.Color = Limit(VariedPositiveVector4D(ColorRange.Start, ColorVariance));
var endColor = Limit(VariedPositiveVector4D(ColorRange.End, ColorVariance));
p.ColorDelta = (endColor - p.Color)/Lifetime;
p.EmitterPosition = EmitPosition;
var emitRadius = RandomRangeFloat(EmissionRadiusRange);
emitRadius = emitRadius > 0.01f ? emitRadius : 0.1f;
var emitAngle = RandomFloat()*2*MathUtility.PI;
p.Position = EmitPosition + new Vector2D(
emitRadius*MathUtility.Sin(emitAngle),
emitRadius*MathUtility.Cos(emitAngle)
);
p.RadialAcceleration = VariedFloat(RadialAcceleration, RadialAccelerationVariance);
p.RadialVelocity = VariedFloat(RadialVelocity, RadialVelocityVariance);
p.Size = VariedPositiveFloat(SizeRange.Start, SizeVariance);
var endSize = VariedPositiveFloat(SizeRange.End, SizeVariance);
p.SizeDelta = (endSize - p.Size)/Lifetime;
//TODO Add initial spin?
p.SpinVelocity = VariedFloat(SpinVelocity.Start, SpinVelocityVariance);
//TODO add spin velocity delta?
p.TangentialAcceleration = VariedFloat(TangentialAcceleration, TangentialAccelerationVariance);
p.TangentialVelocity = VariedFloat(TangentialVelocity, TangentialVelocityVariance);
p.Velocity = VariedVector2D(Velocity, VelocityVariance);
}
/// <summary>
/// Move JUST the emitter
/// </summary>
/// <remarks>
/// This moves the emitter's position
/// </remarks>
/// <param name="toPosition"></param>
public void MoveEmitter(Vector2D toPosition)
{
EmitterPosition = toPosition;
}
/// <summary>
/// Move JUST the particles, moving the emitter to offset
/// </summary>
/// <remarks>
/// This moves the particles, but not the emitter. This changes the particles positions relative to the emitter.
/// </remarks>
/// <param name="toPosition"></param>
public void MoveParticles(Vector2D toPosition)
{
var offset = toPosition - EmitterPosition;
MoveParticlesOffset(offset);
}
/// <summary>
/// Move JUST the particles, moving the emitter to offset
/// </summary>
/// <remarks>
/// This moves the particles, but not the emitter. This changes the particles positions relative to the emitter.
/// </remarks>
/// <param name="offset"></param>
public void MoveParticlesOffset(Vector2D offset)
{
Parallel.ForEach(LiveParticles, particle =>
{
particle.Position += offset;
particle.EmitterPosition += offset;
});
}
/// <summary>
/// Move the whole system, both emitter and particles
/// </summary>
/// <remarks>
/// Practically, this simply changes the emitter logical position. Since the particles are positioned relative to the
/// emitter, they "move" as well.
/// </remarks>
/// <param name="toPosition"></param>
public void Move(Vector2D toPosition)
{
MoveParticles(toPosition);
EmitterPosition = toPosition;
}
public void Update(float frameTime)
{
Parallel.ForEach(LiveParticles, particle => particle.Update(frameTime));
if (!Emit)
return;
_particlesToEmit += frameTime*EmitRate;
var newParticleCount = (int)Math.Floor(_particlesToEmit);
//This should go down to zero.
_particlesToEmit -= newParticleCount;
//Clear out last update
_newParticles.Clear();
//Take some dead particles
_newParticles.AddRange(DeadParticles.Take(newParticleCount));
newParticleCount -= _newParticles.Count();
//If there aren't enough dead ones, take the remainder from the live ones, oldest first.
if(newParticleCount > 0)
_newParticles.AddRange(LiveParticles.Take(newParticleCount));
for (var i = 0; i < _newParticles.Count(); i++)
{
EmitParticle(_newParticles[i]);
}
}
public void Render()
{
//_batch.Clear();
foreach (var particle in LiveParticles)
{
ParticleSprite.Color = ToColor(particle.Color);
ParticleSprite.Position = particle.Position;
ParticleSprite.Rotation = MathUtility.Degrees(particle.Spin);
ParticleSprite.UniformScale = particle.Size;
//_batch.AddClone(ParticleSprite);
ParticleSprite.Draw();
}
//_batch.Draw();
}
#endregion
#region Constructor/Destructors
public ParticleSystem(Sprite particleSprite, Vector2D position)
{
MaximumParticleCount = 200;
//TODO start with sane defaults
Acceleration = Vector2D.Zero;
AccelerationVariance = 0f;
ColorRange = new Range<Vector4D>(Vector4D.UnitX * 255, Vector4D.Zero);
ColorVariance = 0f;
EmissionOffset = Vector2D.Zero;
EmissionRadiusRange = new Range<float>(0f,0f);
Emit = false;
EmitRate = 1;
EmitterPosition = position;
Lifetime = 1.0f;
LifetimeVariance = 0f;
ParticleSprite = particleSprite;
RadialAcceleration = 0f;
RadialAccelerationVariance = 0f;
RadialVelocity = 0f;
RadialVelocityVariance = 0f;
SizeRange = new Range<float>(10,0);
SizeVariance = 1.0f;
SpinVelocity = new Range<float>(0f, 0f);
SpinVelocityVariance = 0f;
TangentialAcceleration = 0;
TangentialAccelerationVariance = 0;
TangentialVelocity = 0;
TangentialVelocityVariance = 0;
Velocity = Vector2D.Zero;
VelocityVariance = 0;
}
#endregion
}
}
@@ -0,0 +1,238 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using ClientInterfaces.GOC;
using ClientInterfaces.Resource;
using ClientWindow;
using GameObject;
using GorgonLibrary;
using GorgonLibrary.Graphics;
using GorgonLibrary.Graphics.Utilities;
using SS13.IoC;
using SS13_Shared;
using SS13_Shared.GO;
using SS13_Shared.GO.Component.Particles;
namespace CGO
{
public class ParticleSystemComponent : Component, IRenderableComponent
{
#region Variables.
private Random _rnd = new Random(); // Random number generator.
private ParticleSystem _emitter; // List of particle emitters.
private RenderImage _particleImage; // Particle image.
private Sprite _particleSprite; // Particle sprite.
private PreciseTimer _timer = new PreciseTimer(); // Timer object.
private Vector4D _particlesColorStart = Vector4D.UnitX;
private Vector4D _particlesColorEnd = Vector4D.Zero;
private bool _active = false;
private int _particleRate = 1;
public DrawDepth DrawDepth { get; set; }
#endregion
public ParticleSystemComponent()
{
Family = ComponentFamily.Particles;
DrawDepth = DrawDepth.ItemsOnTables;
_particleSprite = IoCManager.Resolve<IResourceManager>().GetSprite("");
CreateEmitter(new Vector2D(0,0));
}
public override Type StateType
{
get { return typeof(ParticleSystemComponentState); }
}
public void OnMove(object sender, VectorEventArgs args)
{
var offset = new Vector2D(args.VectorTo.X, args.VectorTo.Y) -
new Vector2D(args.VectorFrom.X, args.VectorFrom.Y);
_emitter.MoveEmitter(_emitter.EmitterPosition + offset);
}
public override void OnAdd(Entity owner)
{
base.OnAdd(owner);
var transform = Owner.GetComponent<TransformComponent>(ComponentFamily.Transform);
transform.OnMove += OnMove;
/*
_particleImage = new RenderImage("ParticleImage" + Owner.Uid, 64, 64, ImageBufferFormats.BufferRGB888A8);
CreateParticle();
_particleSprite = new Sprite("ParticleSprite" + Owner.Uid, _particleImage);
_particleSprite.Axis = new Vector2D(32, 32);
*/
_particleSprite = IoCManager.Resolve<IResourceManager>().GetSprite("star1");
_emitter.ParticleSprite = _particleSprite;
}
public override void OnRemove()
{
var transform = Owner.GetComponent<TransformComponent>(ComponentFamily.Transform);
transform.OnMove -= OnMove;
_particleSprite.Image = null;
_particleSprite = null;
_particleImage.Dispose();
_particleImage = null;
_emitter = null;
base.OnRemove();
}
public override void SetParameter(ComponentParameter parameter)
{
base.SetParameter(parameter);
dynamic parameterValue;
switch (parameter.MemberName)
{
case "drawdepth":
DrawDepth = ((DrawDepth)Enum.Parse(typeof(DrawDepth), parameter.GetValue<string>(), true));
break;
case "colorStart":
parameterValue = parameter.GetValue<Vector4>();
_particlesColorStart = new Vector4D(parameterValue.X, parameterValue.Y, parameterValue.Z, parameterValue.W);
UpdateParticleColor();
break;
case "colorEnd":
parameterValue = parameter.GetValue<Vector4>();
_particlesColorEnd = new Vector4D(parameterValue.X, parameterValue.Y, parameterValue.Z, parameterValue.W);
UpdateParticleColor();
break;
case "particlesPerSecond":
_particleRate = parameter.GetValue<int>();
UpdateParticleRate();
break;
}
}
public override ComponentReplyMessage RecieveMessage(object sender, ComponentMessageType type,
params object[] list)
{
ComponentReplyMessage reply = base.RecieveMessage(sender, type, list);
if (sender == this) //Don't listen to our own messages!
return ComponentReplyMessage.Empty;
switch (type)
{
case ComponentMessageType.SetDrawDepth:
DrawDepth = (DrawDepth)list[0];
break;
}
return reply;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
_emitter.Update(frameTime);
}
public virtual void Render(Vector2D topLeft, Vector2D bottomRight)
{
var blend = Gorgon.CurrentRenderTarget.BlendingMode;
Gorgon.CurrentRenderTarget.BlendingMode = BlendingModes.Additive;
Vector2D renderPos =
ClientWindowData.WorldToScreen(
Owner.GetComponent<TransformComponent>(ComponentFamily.Transform).Position);
_emitter.Move(renderPos);
_emitter.Render();
Gorgon.CurrentRenderTarget.BlendingMode = blend;
}
private void UpdateParticleColor()
{
_emitter.ColorRange = new Range<Vector4D>(_particlesColorStart, _particlesColorEnd);
}
private void UpdateParticleRate()
{
_emitter.EmitRate = _particleRate;
}
private void UpdateActive()
{
_emitter.Emit = _active;
}
/// <summary>
/// Function to create a particle.
/// </summary>
private void CreateParticle()
{
Color particleColor;
_particleImage.Clear(Color.Transparent);
_particleImage.BeginDrawing();
for (int x = 64; x > 0; x--)
{
particleColor = Color.FromArgb(255 - ((x * 4) - 1), 255, 255, 255);
_particleImage.FilledCircle(32.0f, 32.0f, x / 2, particleColor);
}
_particleImage.EndDrawing();
}
/// <summary>
/// Function to create a particle emitter.
/// </summary>
/// <param name="position">The position of the emitter.</param>
/// <returns>A new emitter.</returns>
private void CreateEmitter(Vector2D position)
{
_emitter = null;
_emitter = new ParticleSystem(_particleSprite, position);
_emitter.ColorRange = new Range<Vector4D>(_particlesColorStart, _particlesColorEnd);
_emitter.Emit = _active;
_emitter.Lifetime = 10f;
_emitter.LifetimeVariance = 2f;
_emitter.SizeRange = new Range<float>(0.1f, 0.05f);
_emitter.SizeVariance = 0.05f;
_emitter.Acceleration = new Vector2D(0, 1.5f);
_emitter.RadialVelocity = 10f;
_emitter.RadialAcceleration = -1 * _emitter.RadialVelocity/(_emitter.Lifetime-2);
_emitter.EmissionRadiusRange = new Range<float>(5, 20);
}
public float Bottom
{
get
{
return Owner.GetComponent<TransformComponent>(ComponentFamily.Transform).Position.Y +
(_particleSprite.Height / 2);
}
}
public override void HandleComponentState(dynamic __state)
{
var state = (ParticleSystemComponentState) __state;
if(state.Active != _active)
{
_active = state.Active;
UpdateActive();
}
if (state.StartColor.X != _particlesColorStart.X
|| state.StartColor.Y != _particlesColorStart.Y
|| state.StartColor.Z != _particlesColorStart.Z
|| state.StartColor.W != _particlesColorStart.W)
{
_particlesColorStart = new Vector4D(state.StartColor.X, state.StartColor.Y,
state.StartColor.Z, state.StartColor.W);
UpdateParticleColor();
}
if (state.EndColor.X != _particlesColorEnd.X
|| state.EndColor.Y != _particlesColorEnd.Y
|| state.EndColor.Z != _particlesColorEnd.Z
|| state.EndColor.W != _particlesColorEnd.W)
{
_particlesColorEnd = new Vector4D(state.EndColor.X, state.EndColor.Y,
state.EndColor.Z, state.EndColor.W);
UpdateParticleColor();
}
}
}
}
@@ -112,6 +112,11 @@ namespace CGO
BuildDirectionalSprites();
}
public bool HasSprite(string key)
{
return sprites.ContainsKey(key);
}
#endregion
private void BuildDirectionalSprites()
+3 -1
View File
@@ -247,7 +247,9 @@
</None>
<None Include="MessageLogging\messageLoggerService.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Graphics\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
+2 -2
View File
@@ -216,9 +216,9 @@ namespace ClientServices.Placement
ComponentParameter spriteParam = template.GetBaseSpriteParamaters().FirstOrDefault();
//Will break if states not ordered correctly.
if (spriteParam == null) return;
//if (spriteParam == null) return;
var spriteName = spriteParam.GetValue<string>();
var spriteName = spriteParam == null?"":spriteParam.GetValue<string>();
Sprite sprite = ResourceManager.GetSprite(spriteName);
CurrentBaseSprite = sprite;
+6 -5
View File
@@ -1021,7 +1021,8 @@ namespace ClientServices.State.States
/// <param name="frametime">time since the last frame was rendered.</param>
private void RenderComponents(float frameTime, RectangleF viewPort)
{
List<Component> components = _entityManager.ComponentManager.GetComponents(ComponentFamily.Renderable);
IEnumerable<Component> components = _entityManager.ComponentManager.GetComponents(ComponentFamily.Renderable)
.Union(_entityManager.ComponentManager.GetComponents(ComponentFamily.Particles));
IEnumerable<IRenderableComponent> floorRenderables = from IRenderableComponent c in components
orderby c.Bottom ascending , c.DrawDepth ascending
@@ -1029,7 +1030,7 @@ namespace ClientServices.State.States
select c;
RenderList(new Vector2D(viewPort.Left, viewPort.Top), new Vector2D(viewPort.Right, viewPort.Bottom),
floorRenderables.ToList());
floorRenderables);
IEnumerable<IRenderableComponent> largeRenderables = from IRenderableComponent c in components
orderby c.Bottom ascending
@@ -1038,7 +1039,7 @@ namespace ClientServices.State.States
select c;
RenderList(new Vector2D(viewPort.Left, viewPort.Top), new Vector2D(viewPort.Right, viewPort.Bottom),
largeRenderables.ToList());
largeRenderables);
IEnumerable<IRenderableComponent> ceilingRenderables = from IRenderableComponent c in components
orderby c.Bottom ascending , c.DrawDepth ascending
@@ -1046,10 +1047,10 @@ namespace ClientServices.State.States
select c;
RenderList(new Vector2D(viewPort.Left, viewPort.Top), new Vector2D(viewPort.Right, viewPort.Bottom),
ceilingRenderables.ToList());
ceilingRenderables);
}
private void RenderList(Vector2D topleft, Vector2D bottomright, List<IRenderableComponent> renderables)
private void RenderList(Vector2D topleft, Vector2D bottomright, IEnumerable<IRenderableComponent> renderables)
{
foreach (IRenderableComponent component in renderables)
{
@@ -35,7 +35,12 @@ namespace ClientServices.UserInterface.Components
{
_resourceManager = resourceManager;
var SpriteName = entityTemplate.GetBaseSpriteParamaters().FirstOrDefault().GetValue<string>();
var spriteNameParam = entityTemplate.GetBaseSpriteParamaters().FirstOrDefault();
string SpriteName = "";
if (spriteNameParam != null)
{
SpriteName = spriteNameParam.GetValue<string>();
}
string ObjectName = entityTemplate.Name;
associatedTemplate = entityTemplate;
+3 -3
View File
@@ -26,7 +26,7 @@ namespace GameObject
public List<Component> GetComponents(ComponentFamily family)
{
return components[ComponentFamily.Renderable].Cast<Component>().ToList();
return components[family].Cast<Component>().ToList();
}
/// <summary>
@@ -56,8 +56,8 @@ namespace GameObject
foreach (ComponentFamily family in Enum.GetValues(typeof (ComponentFamily)))
{
// Hack the update loop to allow us to render somewhere in the GameScreen render loop
if (family == ComponentFamily.Renderable)
continue;
/*if (family == ComponentFamily.Renderable)
continue;*/
foreach (Component component in components[family])
{
component.Update(frameTime);
+31
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using SS13_Shared;
using SS13_Shared.GO;
namespace GameObject
@@ -93,6 +94,12 @@ namespace GameObject
case "boolean":
case "bool":
return typeof (bool);
case "vector2":
return typeof(Vector2);
case "vector3":
return typeof(Vector3);
case "vector4":
return typeof(Vector4);
default:
return null;
}
@@ -161,6 +168,30 @@ namespace GameObject
{
paramValue = paramRawValue;
}
else if (paramType == typeof (Vector2))
{
var args = paramRawValue.Split(',');
if (args.Length != 2)
throw new ArgumentException("Could not parse parameter " + paramName +
" as Vector2. Value: " + paramRawValue);
paramValue = new Vector2(float.Parse(args[0]), float.Parse(args[1]));
}
else if (paramType == typeof(Vector3))
{
var args = paramRawValue.Split(',');
if (args.Length != 3)
throw new ArgumentException("Could not parse parameter " + paramName +
" as Vector3. Value: " + paramRawValue);
paramValue = new Vector3(float.Parse(args[0]), float.Parse(args[1]), float.Parse(args[2]));
}
else if (paramType == typeof(Vector4))
{
var args = paramRawValue.Split(',');
if (args.Length != 4)
throw new ArgumentException("Could not parse parameter " + paramName +
" as Vector4. Value: " + paramRawValue);
paramValue = new Vector4(float.Parse(args[0]), float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]));
}
else
{
throw new ArgumentException("Could not parse parameter " + paramName +
+1 -6
View File
@@ -84,13 +84,8 @@ namespace SGO
private void SetState(LightState state)
{
_state = state;
SendState();
}
private void SendState()
{
}
public override ComponentState GetComponentState()
{
return new LightComponentState(_state, _colorR, _colorG, _colorB, _mode);
@@ -0,0 +1,69 @@
using System;
using System.Drawing;
using GameObject;
using SS13.IoC;
using SS13_Shared;
using SS13_Shared.GO;
using SS13_Shared.GO.Component.Light;
using SS13_Shared.GO.Component.Particles;
using ServerInterfaces.Chat;
namespace SGO
{
public class ParticleSystemComponent : Component
{
private Vector4 _startColor = new Vector4(255, 0, 0, 0);
private Vector4 _endColor = new Vector4(0, 0, 0, 0);
private bool _active = false;
public ParticleSystemComponent()
{
Family = ComponentFamily.Particles;
}
public override void SetParameter(ComponentParameter parameter)
{
base.SetParameter(parameter);
switch (parameter.MemberName)
{
case "colorStart":
_startColor = parameter.GetValue<Vector4>();
break;
case "colorEnd":
_endColor = parameter.GetValue<Vector4>();
break;
case "startActive":
_active = parameter.GetValue<bool>();
break;
}
}
public override ComponentReplyMessage RecieveMessage(object sender, ComponentMessageType type,
params object[] list)
{
ComponentReplyMessage reply = base.RecieveMessage(sender, type, list);
if (sender == this)
return reply;
switch (type)
{
case ComponentMessageType.Activate:
HandleClickedInHand();
break;
}
return reply;
}
private void HandleClickedInHand()
{
_active = !_active;
}
public override ComponentState GetComponentState()
{
return new ParticleSystemComponentState(_active, _startColor, _endColor);
}
}
}
+1
View File
@@ -83,6 +83,7 @@
<Compile Include="Component\Item\ItemCapability\BreatherCapability.cs" />
<Compile Include="Component\Item\ItemCapability\HealthScanCapability.cs" />
<Compile Include="Component\Light\LightComponent.cs" />
<Compile Include="Component\Particles\ParticleSystemComponent.cs" />
<Compile Include="Component\Physics\PhysicsComponent.cs" />
<Compile Include="Component\Objectives\ObjectivesComponent.cs" />
<Compile Include="Component\PlayerActionComp\PlayerActionCompS.cs" />
+8
View File
@@ -34,4 +34,12 @@
<Component name="ClickableComponent"></Component>
</Components>
</EntityTemplate>
<EntityTemplate name="Particles">
<Components>
<Component name="TransformComponent"></Component>
<Component name="VelocityComponent"></Component>
<Component name="NetworkMoverComponent"></Component>
<Component name="ParticleSystemComponent"></Component>
</Components>
</EntityTemplate>
</EntityTemplates>
+5
View File
@@ -13,6 +13,11 @@
<Parameter name="addsprite" type="string" value="sword_on" />
</Parameters>
</Component>
<Component name="ParticleSystemComponent">
<Parameters>
<Parameter name="particlesPerSecond" type="int" value="30" />
</Parameters>
</Component>
<Component name="PhysicsComponent"></Component>
<Component name="ClickableComponent"></Component>
<Component name="BasicItemComponent"></Component>
@@ -0,0 +1,20 @@
using System;
namespace SS13_Shared.GO.Component.Particles
{
[Serializable]
public class ParticleSystemComponentState : ComponentState
{
public bool Active;
public Vector4 StartColor;
public Vector4 EndColor;
public ParticleSystemComponentState(bool active, Vector4 startColor, Vector4 endColor)
: base(ComponentFamily.Particles)
{
Active = active;
StartColor = startColor;
EndColor = endColor;
}
}
}
+2 -1
View File
@@ -38,7 +38,8 @@
Transform,
Velocity,
Direction,
SVars
SVars,
Particles
}
public enum ItemComponentNetMessage
+3
View File
@@ -130,6 +130,7 @@
<Compile Include="GO\Component\EntityStats\EntityStatsComponentState.cs" />
<Compile Include="GO\Component\Light\LightComponentState.cs" />
<Compile Include="GO\Component\Mover\MoverComponentState.cs" />
<Compile Include="GO\Component\Particles\ParticleSystemComponentState.cs" />
<Compile Include="GO\Component\Physics\PhysicsComponentState.cs" />
<Compile Include="GO\Component\Renderable\RenderableComponentState.cs" />
<Compile Include="GO\Component\Renderable\SpriteComponentState.cs" />
@@ -180,6 +181,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ChatConfig.cs" />
<Compile Include="UIComponents.cs" />
<Compile Include="Vector3.cs" />
<Compile Include="Vector4.cs" />
<Compile Include="VectorEventArgs.cs" />
</ItemGroup>
<ItemGroup>
Binary file not shown.
+130
View File
@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SS13_Shared.Serialization;
namespace SS13_Shared
{
[Serializable]
public class Vector4
: INetSerializableType
{
#region Class Variables
/// <summary>
/// The X component of the vector
/// </summary>
private float x;
/// <summary>
/// The Y component of the vector
/// </summary>
private float y;
/// <summary>
/// The Z component of the vector
/// </summary>
private float z;
/// <summary>
/// The W component of the vector
/// </summary>
private float w;
#endregion
#region Constructors
/// <summary>
/// Constructor for the Vector3 class accepting three floats
/// </summary>
/// <param name="x">The new x value for the Vector3</param>
/// <param name="y">The new y value for the Vector3</param>
/// <param name="z">The new z value for the Vector3</param>
/// <param name="w">The new w value for the Vector3</param>
/// <implementation>
/// Uses the mutator properties for the Vector3 components to allow verification of input (if implemented)
/// This results in the need for pre-initialisation initialisation of the Vector3 components to 0
/// Due to the necessity for struct's variables to be set in the constructor before moving control
/// </implementation>
public Vector4(float x, float y, float z, float w)
{
// Pre-initialisation initialisation
// Implemented because a struct's variables always have to be set in the constructor before moving control
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 0;
// Initialisation
X = x;
Y = y;
Z = z;
W = w;
}
/// <summary>
/// Constructor for the Vector3 class from another Vector3 object
/// </summary>
/// <param name="v1">Vector3 representing the new values for the Vector3</param>
/// <implementation>
/// Copies values from Vector3 v1 to this vector, does not hold a reference to object v1
/// </implementation>
public Vector4(Vector4 v1)
{
// Pre-initialisation initialisation
// Implemented because a struct's variables always have to be set in the constructor before moving control
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 0;
// Initialisation
X = v1.X;
Y = v1.Y;
Z = v1.Z;
W = v1.W;
}
#endregion
#region Accessors & Mutators
/// <summary>
/// Property for the x component of the Vector3
/// </summary>
public float X
{
get { return x; }
set { x = value; }
}
/// <summary>
/// Property for the y component of the Vector3
/// </summary>
public float Y
{
get { return y; }
set { y = value; }
}
/// <summary>
/// Property for the z component of the Vector3
/// </summary>
public float Z
{
get { return z; }
set { z = value; }
}
/// <summary>
/// Property for the w component of the Vector3
/// </summary>
public float W
{
get { return w; }
set { w = value; }
}
#endregion
}
}
+7
View File
@@ -27,4 +27,11 @@
<Component name="BasicInteractableComponent"></Component>
</Components>
</EntityTemplate>
<EntityTemplate name="Particles">
<Components>
<Component name="TransformComponent"></Component>
<Component name="VelocityComponent"></Component>
<Component name="BasicMoverComponent"></Component>
</Components>
</EntityTemplate>
</EntityTemplates>
+7
View File
@@ -34,6 +34,13 @@
<Parameter name="startState" type="string" value="Off" />
</Parameters>
</Component>
<Component name="ParticleSystemComponent">
<Parameters>
<Parameter name="colorStart" type="Vector4" value="255,128,200,255" />
<Parameter name="colorEnd" type="Vector4" value="80,104,180,255" />
<Parameter name="startActive" type="bool" value="false" />
</Parameters>
</Component>
</Components>
</EntityTemplate>
</EntityTemplates>
+2 -1
View File
@@ -113,7 +113,8 @@ namespace ServerServices.Placement
{
created.GetComponent<ITransformComponent>(ComponentFamily.Transform).TranslateTo(
new Vector2(xRcv, yRcv));
created.GetComponent<IDirectionComponent>(ComponentFamily.Direction).Direction = dirRcv;
if(created.HasComponent(ComponentFamily.Direction))
created.GetComponent<IDirectionComponent>(ComponentFamily.Direction).Direction = dirRcv;
created.SendMessage(this, ComponentMessageType.WallMountTile, new Vector2(tileX, tileY));
}
}
+2
View File
@@ -0,0 +1,2 @@
call runclient.bat
call runclient.bat