Particle system improvements:

- particles can collide with the outer walls of the sub
- drag + waterdrag parameters
- fixed particles "twitching" when the submarine is moving fast
- submarine velocity only affects the initial velocity of the particles (i.e. accelerating the sub doesn't automatically accelerate them)
This commit is contained in:
Regalis
2016-09-21 19:45:20 +03:00
parent b01b52172a
commit 721f4ff5a6
10 changed files with 230 additions and 68 deletions
+3
View File
@@ -817,6 +817,9 @@
<Content Include="Content\Particles\flames.png"> <Content Include="Content\Particles\flames.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Include="Content\Particles\shrapnel.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Content\UI\damageOverlay.png"> <Content Include="Content\UI\damageOverlay.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
@@ -234,4 +234,68 @@
velocitychange="0.0, 1.0"> velocitychange="0.0, 1.0">
<sprite texture="Content/Particles/spatter.png" sourcerect="128,128,128,128"/> <sprite texture="Content/Particles/spatter.png" sourcerect="128,128,128,128"/>
</flare> </flare>
<shrapnel
startsizemin="0.1,0.1" startsizemax="1.0,1.0"
startrotationmin ="0.0" startrotationmax="360"
startcolor="1.0, 1.0, 1.0" startalpha="1.0"
colorchange="0.0, 0.0, 0.0, -0.3"
lifetime="10.0"
drawtarget="both"
collideswithwalls="true"
collisionradius="10.0"
restitution="0.2"
waterdrag="0.1"
growtime ="0.0"
velocitychange="0.0, -5.0">
<sprite texture="Content/Particles/shrapnel.png" sourcerect="0,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="32,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="64,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="96,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="128,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="160,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="192,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="224,0,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="0,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="32,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="64,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="96,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="128,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="160,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="192,32,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="224,32,32,32"/>
</shrapnel>
<iceshards
startsizemin="0.1,0.1" startsizemax="1.0,1.0"
startrotationmin ="0.0" startrotationmax="360"
startcolor="1.0, 1.0, 1.0" startalpha="1.0"
colorchange="0.0, 0.0, 0.0, -0.3"
lifetime="10.0"
drawtarget="both"
collideswithwalls="true"
collisionradius="10.0"
restitution="0.2"
waterdrag="0.3"
growtime ="0.0"
velocitychange="0.0, -5.0">
<sprite texture="Content/Particles/shrapnel.png" sourcerect="0,64,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="32,64,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="64,64,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="96,64,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="128,64,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="160,64,48,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="208,64,48,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="0,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="32,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="64,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="96,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="128,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="160,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="192,96,32,32"/>
<sprite texture="Content/Particles/shrapnel.png" sourcerect="224,96,32,32"/>
</iceshards>
</prefabs> </prefabs>
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

+2
View File
@@ -163,6 +163,8 @@ namespace Barotrauma
hulls[1] = temp; hulls[1] = temp;
} }
flowTargetHull = hulls[0];
for (int i = 0 ; i <2; i++) for (int i = 0 ; i <2; i++)
{ {
if (hulls[i]==null) continue; if (hulls[i]==null) continue;
+15 -1
View File
@@ -537,8 +537,22 @@ namespace Barotrauma
if (sectionIndex < 0 || sectionIndex > sections.Length - 1) return; if (sectionIndex < 0 || sectionIndex > sections.Length - 1) return;
if (GameMain.Client == null) SetDamage(sectionIndex, sections[sectionIndex].damage + damage); var section = sections[sectionIndex];
int particleAmount = (int)(Math.Min(Health - section.damage, damage) * Rand.Range(0.1f, 1.0f));
for (int i = 0; i < particleAmount; i++)
{
Vector2 particlePos = new Vector2(
Rand.Range(section.rect.X, section.rect.Right),
Rand.Range(section.rect.Y - section.rect.Height, section.rect.Y));
if (Submarine != null) particlePos += Submarine.DrawPosition;
var particle = GameMain.ParticleManager.CreateParticle("shrapnel", particlePos, Rand.Vector(Rand.Range(1.0f, 50.0f)));
if (particle == null) break;
}
if (GameMain.Client == null) SetDamage(sectionIndex, section.damage + damage);
} }
public int FindSectionIndex(Vector2 displayPos) public int FindSectionIndex(Vector2 displayPos)
+12
View File
@@ -445,6 +445,18 @@ namespace Barotrauma
ApplyImpact(wallImpact, -collisionNormal, contact); ApplyImpact(wallImpact, -collisionNormal, contact);
Vector2 n;
FixedArray2<Vector2> particlePos;
contact.GetWorldManifold(out n, out particlePos);
int particleAmount = (int)(wallImpact*10.0f);
for (int i = 0; i < particleAmount; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("iceshards",
ConvertUnits.ToDisplayUnits(particlePos[0]) + Rand.Vector(Rand.Range(1.0f, 50.0f)),
Rand.Vector(Rand.Range(50.0f,500.0f)) + Velocity);
}
return true; return true;
} }
+95 -44
View File
@@ -37,6 +37,7 @@ namespace Barotrauma.Particles
private Vector2 velocityChange; private Vector2 velocityChange;
private Vector2 drawPosition; private Vector2 drawPosition;
private float drawRotation;
//private float checkCollisionTimer; //private float checkCollisionTimer;
@@ -66,6 +67,12 @@ namespace Barotrauma.Particles
set { velocityChange = value; } set { velocityChange = value; }
} }
public Vector2 Velocity
{
get { return velocity; }
set { velocity = value; }
}
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null) public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null)
{ {
@@ -74,26 +81,19 @@ namespace Barotrauma.Particles
spriteIndex = Rand.Int(prefab.Sprites.Count); spriteIndex = Rand.Int(prefab.Sprites.Count);
currentHull = Hull.FindHull(position, hullGuess); currentHull = Hull.FindHull(position, hullGuess);
//if (currentHull != null && currentHull.Submarine != null)
//{
// Vector2 subVel = ConvertUnits.ToDisplayUnits(currentHull.Submarine.Velocity);
// //subVel.Y = -subVel.Y;
// speed += subVel;
//}
//else
//{
// int a = 1;
//}
//if (currentHull == null) position = Submarine.Loaded == null ? position : position + Submarine.Loaded.Position;
this.position = position; this.position = position;
prevPosition = position; prevPosition = position;
drawPosition = position; drawPosition = position;
velocity = MathUtils.IsValid(speed) ? speed : Vector2.Zero; velocity = MathUtils.IsValid(speed) ? speed : Vector2.Zero;
if (currentHull != null && currentHull.Submarine != null)
{
velocity += ConvertUnits.ToDisplayUnits(currentHull.Submarine.Velocity);
}
this.rotation = rotation + Rand.Range(prefab.StartRotationMin, prefab.StartRotationMax); this.rotation = rotation + Rand.Range(prefab.StartRotationMin, prefab.StartRotationMax);
prevRotation = rotation; prevRotation = rotation;
@@ -142,12 +142,12 @@ namespace Barotrauma.Particles
public bool Update(float deltaTime) public bool Update(float deltaTime)
{ {
prevPosition = position;
Vector2 subVel = currentHull ==null || currentHull.Submarine==null ? Vector2.Zero : ConvertUnits.ToDisplayUnits(currentHull.Submarine.Velocity); prevRotation = rotation;
//over 3 times faster than position += velocity * deltatime //over 3 times faster than position += velocity * deltatime
position.X += (velocity.X+subVel.X) * deltaTime; position.X += velocity.X * deltaTime;
position.Y += (velocity.Y+subVel.Y) * deltaTime; position.Y += velocity.Y * deltaTime;
if (prefab.RotateToDirection) if (prefab.RotateToDirection)
{ {
@@ -161,6 +161,16 @@ namespace Barotrauma.Particles
rotation += angularVelocity * deltaTime; rotation += angularVelocity * deltaTime;
} }
if (prefab.WaterDrag > 0.0f &&
(currentHull == null || (currentHull.Submarine != null && position.Y - currentHull.Submarine.DrawPosition.Y < currentHull.Surface)))
{
ApplyDrag(prefab.WaterDrag, deltaTime);
}
else if (prefab.Drag > 0.0f)
{
ApplyDrag(prefab.Drag, deltaTime);
}
velocity.X += velocityChange.X * deltaTime; velocity.X += velocityChange.X * deltaTime;
velocity.Y += velocityChange.Y * deltaTime; velocity.Y += velocityChange.Y * deltaTime;
@@ -174,11 +184,20 @@ namespace Barotrauma.Particles
color.G / 255.0f + prefab.ColorChange.Y * deltaTime, color.G / 255.0f + prefab.ColorChange.Y * deltaTime,
color.B / 255.0f + prefab.ColorChange.Z * deltaTime); color.B / 255.0f + prefab.ColorChange.Z * deltaTime);
if ((prefab.DeleteOnCollision || prefab.CollidesWithWalls) && currentHull!=null) if (prefab.DeleteOnCollision || prefab.CollidesWithWalls)
{ {
Vector2 edgePos = position + prefab.CollisionRadius * Vector2.Normalize(velocity) * size.X; Vector2 edgePos = position + prefab.CollisionRadius * Vector2.Normalize(velocity) * size.X;
if (!Submarine.RectContains(currentHull.WorldRect, edgePos)) if (currentHull == null)
{
var collidedHull = Hull.FindHullOld(edgePos);
if (collidedHull != null)
{
if (prefab.DeleteOnCollision) return false;
OnWallCollisionOutside(collidedHull);
}
}
else if (!Submarine.RectContains(currentHull.WorldRect, edgePos))
{ {
if (prefab.DeleteOnCollision) return false; if (prefab.DeleteOnCollision) return false;
@@ -196,15 +215,13 @@ namespace Barotrauma.Particles
if (Math.Sign(velocity.X) != Math.Sign(gap.WorldRect.Center.X - currentHull.WorldRect.Center.X)) continue; if (Math.Sign(velocity.X) != Math.Sign(gap.WorldRect.Center.X - currentHull.WorldRect.Center.X)) continue;
} }
//Rectangle enlargedRect = new Rectangle(gap.Rect.X - 10, gap.Rect.Y + 10, gap.Rect.Width + 20, gap.Rect.Height + 20);
//if (!Submarine.RectContains(enlargedRect, position)) continue;
gapFound = true; gapFound = true;
} }
if (!gapFound) if (!gapFound)
{ {
OnWallCollision(currentHull, edgePos); OnWallCollisionInside(currentHull, edgePos);
} }
else else
{ {
@@ -212,21 +229,9 @@ namespace Barotrauma.Particles
hullGaps = currentHull == null ? new List<Gap>() : currentHull.ConnectedGaps; hullGaps = currentHull == null ? new List<Gap>() : currentHull.ConnectedGaps;
if (OnChangeHull != null) OnChangeHull(edgePos, currentHull); if (OnChangeHull != null) OnChangeHull(edgePos, currentHull);
} }
//Hull prevHull = Hull.FindHull(prevPosition, hullLimits, currentHull);
//if (prevHull == null) return false;
} }
//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; lifeTime -= deltaTime;
@@ -236,10 +241,22 @@ namespace Barotrauma.Particles
return true; return true;
} }
private void OnWallCollision(Hull prevHull, Vector2 position) private void ApplyDrag(float dragCoefficient, float deltaTime)
{
if (velocity == Vector2.Zero) return;
float speed = velocity.Length();
velocity -= (velocity / speed) * Math.Min(speed * speed * prefab.WaterDrag * deltaTime, 1.0f);
}
private void OnWallCollisionInside(Hull prevHull, Vector2 position)
{ {
Rectangle prevHullRect = prevHull.WorldRect; Rectangle prevHullRect = prevHull.WorldRect;
Vector2 subVel = ConvertUnits.ToDisplayUnits(prevHull.Submarine.Velocity);
velocity -= subVel;
if (position.Y < prevHullRect.Y - prevHullRect.Height) if (position.Y < prevHullRect.Y - prevHullRect.Height)
{ {
position.Y = prevHullRect.Y - prevHullRect.Height + 1.0f; position.Y = prevHullRect.Y - prevHullRect.Height + 1.0f;
@@ -264,30 +281,64 @@ namespace Barotrauma.Particles
} }
velocity *= prefab.Restitution; velocity *= prefab.Restitution;
velocity += subVel;
}
private void OnWallCollisionOutside(Hull collisionHull)
{
Rectangle hullRect = collisionHull.WorldRect;
if (position.Y < hullRect.Y - hullRect.Height)
{
position.Y = hullRect.Y - hullRect.Height - 1.0f;
velocity.Y = -velocity.Y;
}
else if (position.Y > hullRect.Y)
{
position.Y = hullRect.Y + 1.0f;
velocity.X = Math.Abs(velocity.Y) * Math.Sign(velocity.X);
velocity.Y = -velocity.Y;
}
if (position.X < hullRect.X)
{
position.X = hullRect.X - 1.0f;
velocity.X = -velocity.X;
}
else if (position.X > hullRect.X + hullRect.Width)
{
position.X = hullRect.X + hullRect.Width + 1.0f;
velocity.X = -velocity.X;
}
velocity *= prefab.Restitution;
}
public void UpdateDrawPos()
{
drawPosition = Physics.Interpolate(prevPosition, position);
drawRotation = Physics.Interpolate(prevRotation, rotation);
prevPosition = position;
prevRotation = rotation;
} }
public void Draw(SpriteBatch spriteBatch) public void Draw(SpriteBatch spriteBatch)
{ {
drawPosition = Physics.Interpolate(prevPosition, position);
float drawRotation = Physics.Interpolate(prevRotation, rotation);
//drawPosition = ConvertUnits.ToDisplayUnits(drawPosition);
Vector2 drawSize = size; Vector2 drawSize = size;
if (prefab.GrowTime>0.0f && totalLifeTime-lifeTime < prefab.GrowTime) if (prefab.GrowTime > 0.0f && totalLifeTime - lifeTime < prefab.GrowTime)
{ {
drawSize *= ((totalLifeTime - lifeTime) / prefab.GrowTime); drawSize *= ((totalLifeTime - lifeTime) / prefab.GrowTime);
} }
prefab.Sprites[spriteIndex].Draw(spriteBatch, prefab.Sprites[spriteIndex].Draw(spriteBatch,
new Vector2(drawPosition.X, -drawPosition.Y), new Vector2(drawPosition.X, -drawPosition.Y),
color * alpha, color * alpha,
prefab.Sprites[spriteIndex].Origin, drawRotation, prefab.Sprites[spriteIndex].Origin, drawRotation,
drawSize, SpriteEffects.None, prefab.Sprites[spriteIndex].Depth); drawSize, SpriteEffects.None, prefab.Sprites[spriteIndex].Depth);
prevPosition = position;
prevRotation = rotation;
} }
} }
} }
@@ -113,6 +113,14 @@ namespace Barotrauma.Particles
} }
} }
public void UpdateTransforms()
{
for (int i = 0; i < particleCount; i++)
{
particles[i].UpdateDrawPos();
}
}
public void Draw(SpriteBatch spriteBatch, bool inWater, ParticleBlendState blendState) public void Draw(SpriteBatch spriteBatch, bool inWater, ParticleBlendState blendState)
{ {
ParticlePrefab.DrawTargetType drawTarget = inWater ? ParticlePrefab.DrawTargetType.Water : ParticlePrefab.DrawTargetType.Air; ParticlePrefab.DrawTargetType drawTarget = inWater ? ParticlePrefab.DrawTargetType.Water : ParticlePrefab.DrawTargetType.Air;
@@ -20,6 +20,8 @@ namespace Barotrauma.Particles
public readonly Vector2 StartSizeMin, StartSizeMax; public readonly Vector2 StartSizeMin, StartSizeMax;
public readonly Vector2 SizeChangeMin, SizeChangeMax; public readonly Vector2 SizeChangeMin, SizeChangeMax;
public readonly float Drag, WaterDrag;
public readonly Color StartColor; public readonly Color StartColor;
public readonly float StartAlpha; public readonly float StartAlpha;
@@ -89,6 +91,9 @@ namespace Barotrauma.Particles
SizeChangeMax = SizeChangeMin; SizeChangeMax = SizeChangeMin;
} }
Drag = ToolBox.GetAttributeFloat(element, "drag", 0.0f);
WaterDrag = ToolBox.GetAttributeFloat(element, "waterdrag", 0.0f);
Restitution = ToolBox.GetAttributeFloat(element, "restitution", 0.5f); Restitution = ToolBox.GetAttributeFloat(element, "restitution", 0.5f);
switch (ToolBox.GetAttributeString(element, "blendstate", "alphablend")) switch (ToolBox.GetAttributeString(element, "blendstate", "alphablend"))
+16 -13
View File
@@ -109,23 +109,24 @@ namespace Barotrauma
} }
#endif #endif
if (GameMain.GameSession!=null) GameMain.GameSession.Update((float)deltaTime);
//EventManager.Update(gameTime);
if (Level.Loaded != null) Level.Loaded.Update((float)deltaTime);
Character.UpdateAll(cam, (float)deltaTime);
BackgroundCreatureManager.Update(cam, (float)deltaTime);
GameMain.ParticleManager.Update((float)deltaTime);
StatusEffect.UpdateAll((float)deltaTime);
Physics.accumulator = Math.Min(Physics.accumulator, Physics.step * 6); Physics.accumulator = Math.Min(Physics.accumulator, Physics.step * 6);
//Physics.accumulator = Physics.step; //Physics.accumulator = Physics.step;
while (Physics.accumulator >= Physics.step) while (Physics.accumulator >= Physics.step)
{ {
if (GameMain.GameSession != null) GameMain.GameSession.Update((float)Physics.step);
//EventManager.Update(gameTime);
if (Level.Loaded != null) Level.Loaded.Update((float)Physics.step);
Character.UpdateAll(cam, (float)Physics.step);
BackgroundCreatureManager.Update(cam, (float)Physics.step);
GameMain.ParticleManager.Update((float)Physics.step);
StatusEffect.UpdateAll((float)Physics.step);
if (Character.Controlled != null && Lights.LightManager.ViewTarget != null) if (Character.Controlled != null && Lights.LightManager.ViewTarget != null)
{ {
cam.TargetPos = Lights.LightManager.ViewTarget.WorldPosition; cam.TargetPos = Lights.LightManager.ViewTarget.WorldPosition;
@@ -210,6 +211,8 @@ namespace Barotrauma
sub.UpdateTransform(); sub.UpdateTransform();
} }
GameMain.ParticleManager.UpdateTransforms();
GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision; GameMain.LightManager.ObstructVision = Character.Controlled != null && Character.Controlled.ObstructVision;
GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam); GameMain.LightManager.UpdateLightMap(graphics, spriteBatch, cam);