using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; namespace Subsurface.Particles { class Particle { private ParticlePrefab prefab; private Vector2 position; private Vector2 prevPosition; private Vector2 velocity; private float rotation; private float prevRotation; private float angularVelocity; private Vector2 size; private Vector2 sizeChange; private Color color; private float alpha; private float totalLifeTime; private float lifeTime; private Vector2 velocityChange; private Vector2 drawPosition; //private float checkCollisionTimer; private Hull currentHull; private List hullLimits; public ParticlePrefab.DrawTargetType DrawTarget { get { return prefab.DrawTarget; } } public Vector2 Size { get { return size; } set { size = value; } } public Vector2 VelocityChange { get { return velocityChange; } set { velocityChange = value; } } public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation) { this.prefab = prefab; this.position = position; prevPosition = position; drawPosition = position; velocity = speed; this.rotation = rotation + Rand.Range(prefab.StartRotationMin, prefab.StartRotationMax); prevRotation = rotation; angularVelocity = prefab.AngularVelocityMin + (prefab.AngularVelocityMax - prefab.AngularVelocityMin) * Rand.Range(0.0f, 1.0f); totalLifeTime = prefab.LifeTime; lifeTime = prefab.LifeTime; size = prefab.StartSizeMin + (prefab.StartSizeMax - prefab.StartSizeMin) * Rand.Range(0.0f, 1.0f); sizeChange = prefab.SizeChangeMin + (prefab.SizeChangeMax - prefab.SizeChangeMin) * Rand.Range(0.0f, 1.0f); color = prefab.StartColor; alpha = prefab.StartAlpha; velocityChange = prefab.VelocityChange; if (prefab.DeleteOnCollision || prefab.CollidesWithWalls) { //currentHull = Hull.FindHull(position); hullLimits = new List(); hullLimits = FindLimits(position); } if (prefab.RotateToDirection) { this.rotation = MathUtils.VectorToAngle(new Vector2(velocity.X, -velocity.Y)); prevRotation = rotation; } } private List FindLimits(Vector2 position) { List hullList = new List(); currentHull = Hull.FindHull(position); if (currentHull == null) return hullList; hullList.Add(currentHull); return FindAdjacentHulls(hullList, currentHull, Math.Abs(velocity.X)>Math.Abs(velocity.Y)); } private List FindAdjacentHulls(List adjacentHulls, Hull currentHull, bool isHorizontal) { foreach (Gap gap in Gap.GapList) { if (gap.isHorizontal != isHorizontal) continue; if (gap.Open < 0.01f) continue; if (gap.linkedTo.Count==1) { if (!adjacentHulls.Contains(gap.linkedTo[0] as Hull)) { adjacentHulls.Add(gap.linkedTo[0] as Hull); } } else if (gap.linkedTo[0] == currentHull && gap.linkedTo[1] != null) { if (!adjacentHulls.Contains(gap.linkedTo[1] as Hull)) { adjacentHulls.Add(gap.linkedTo[1] as Hull); FindAdjacentHulls(adjacentHulls, gap.linkedTo[1] as Hull, isHorizontal); } } else if (gap.linkedTo[1] == currentHull && gap.linkedTo[0] != null) { if (!adjacentHulls.Contains(gap.linkedTo[0] as Hull)) { adjacentHulls.Add(gap.linkedTo[0] as Hull); FindAdjacentHulls(adjacentHulls, gap.linkedTo[0] as Hull, isHorizontal); } } } return adjacentHulls; } public bool Update(float deltaTime) { //over 3 times faster than position += velocity * deltatime position.X += velocity.X * deltaTime; position.Y += velocity.Y * deltaTime; if (prefab.RotateToDirection) { if (velocityChange != Vector2.Zero || angularVelocity != 0.0f) { rotation = MathUtils.VectorToAngle(new Vector2(velocity.X, -velocity.Y)); } } else { rotation += angularVelocity * deltaTime; } velocity.X += velocityChange.X * deltaTime; velocity.Y += velocityChange.Y * deltaTime; size.X += sizeChange.X * deltaTime; size.Y += sizeChange.Y * deltaTime; alpha += prefab.ColorChange.W * deltaTime; color = new Color( color.R / 255.0f + prefab.ColorChange.X * deltaTime, color.G / 255.0f + prefab.ColorChange.Y * deltaTime, color.B / 255.0f + prefab.ColorChange.Z * deltaTime); if ((prefab.DeleteOnCollision || prefab.CollidesWithWalls) && currentHull!=null) { bool insideHull = false; foreach (Hull hull in hullLimits) { if (!Submarine.RectContains(hull.Rect, position)) continue; insideHull = true; break; } if (!insideHull) { if (prefab.DeleteOnCollision) return false; Hull prevHull = Hull.FindHull(prevPosition, hullLimits, currentHull); if (prevHull == null) return false; OnWallCollision(prevHull); } //if (position.Y < currentHull.Rect.Y-currentHull.Rect.Height) //{ // position.Y = currentHull.Rect.Y - currentHull.Rect.Height; // velocity.Y *= -0.2f; //} //if (!Submarine.RectContains(currentHull.Rect, position)) return false; } lifeTime -= deltaTime; if (lifeTime <= 0.0f || alpha <= 0.0f || size.X <= 0.0f || size.Y <= 0.0f) return false; return true; } private void OnWallCollision(Hull prevHull) { float restitution = 0.05f; if (position.Y < prevHull.Rect.Y - prevHull.Rect.Height) { position.Y = prevHull.Rect.Y - prevHull.Rect.Height + 1.0f; velocity.Y = -velocity.Y; } else if (position.Y > prevHull.Rect.Y) { position.Y = prevHull.Rect.Y - 1.0f; velocity.Y = -velocity.Y; } if (position.X < prevHull.Rect.X) { position.X = prevHull.Rect.X + 1.0f; velocity.X = -velocity.X; } else if (position.X > prevHull.Rect.X + prevHull.Rect.Width) { position.X = prevHull.Rect.X + prevHull.Rect.Width - 1.0f; velocity.X = -velocity.X; } velocity *= restitution; } public void Draw(SpriteBatch spriteBatch) { drawPosition = Physics.Interpolate(prevPosition, position); drawPosition.Y = -drawPosition.Y; float drawRotation = Physics.Interpolate(prevRotation, rotation); //drawPosition = ConvertUnits.ToDisplayUnits(drawPosition); Vector2 drawSize = size; if (prefab.GrowTime>0.0f && totalLifeTime-lifeTime < prefab.GrowTime) { drawSize *= ((totalLifeTime - lifeTime) / prefab.GrowTime); } prefab.Sprite.Draw(spriteBatch, drawPosition, color*alpha, prefab.Sprite.origin, drawRotation, drawSize, SpriteEffects.None, prefab.Sprite.Depth); //spriteBatch.Draw( // prefab.sprite.Texture, // drawPosition, // null, // color*alpha, // drawRotation, // prefab.sprite.origin, // size, // SpriteEffects.None, prefab.sprite.Depth); prevPosition = position; prevRotation = rotation; } } }