(61d00a474) v0.9.7.1
This commit is contained in:
+235
@@ -0,0 +1,235 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
class BackgroundCreature : ISteerable
|
||||
{
|
||||
const float MaxDepth = 100.0f;
|
||||
|
||||
const float CheckWallsInterval = 5.0f;
|
||||
|
||||
public bool Enabled;
|
||||
|
||||
private BackgroundCreaturePrefab prefab;
|
||||
|
||||
private Vector2 position;
|
||||
|
||||
private Vector3 velocity;
|
||||
|
||||
private float depth;
|
||||
|
||||
private SteeringManager steeringManager;
|
||||
|
||||
private float checkWallsTimer;
|
||||
|
||||
private float wanderZPhase;
|
||||
private Vector2 obstacleDiff;
|
||||
private float obstacleDist;
|
||||
|
||||
public Swarm Swarm;
|
||||
|
||||
Vector2 drawPosition;
|
||||
public Vector2 TransformedPosition
|
||||
{
|
||||
get { return drawPosition; }
|
||||
}
|
||||
|
||||
public Vector2 SimPosition
|
||||
{
|
||||
get { return FarseerPhysics.ConvertUnits.ToSimUnits(position); }
|
||||
}
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
get { return position; }
|
||||
}
|
||||
|
||||
public Vector2 Velocity
|
||||
{
|
||||
get { return new Vector2(velocity.X, velocity.Y); }
|
||||
}
|
||||
|
||||
public Vector2 Steering
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BackgroundCreature(BackgroundCreaturePrefab prefab, Vector2 position)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
|
||||
this.position = position;
|
||||
|
||||
drawPosition = position;
|
||||
|
||||
steeringManager = new SteeringManager(this);
|
||||
|
||||
velocity = new Vector3(
|
||||
Rand.Range(-prefab.Speed, prefab.Speed),
|
||||
Rand.Range(-prefab.Speed, prefab.Speed),
|
||||
Rand.Range(0.0f, prefab.WanderZAmount));
|
||||
|
||||
checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval);
|
||||
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
position += new Vector2(velocity.X, velocity.Y) * deltaTime;
|
||||
depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth);
|
||||
|
||||
checkWallsTimer -= deltaTime;
|
||||
if (checkWallsTimer <= 0.0f && Level.Loaded != null)
|
||||
{
|
||||
checkWallsTimer = CheckWallsInterval;
|
||||
|
||||
obstacleDiff = Vector2.Zero;
|
||||
if (position.Y > Level.Loaded.Size.Y)
|
||||
{
|
||||
obstacleDiff = Vector2.UnitY;
|
||||
}
|
||||
else if (position.Y < 0.0f)
|
||||
{
|
||||
obstacleDiff = -Vector2.UnitY;
|
||||
}
|
||||
else if (position.X < 0.0f)
|
||||
{
|
||||
obstacleDiff = Vector2.UnitX;
|
||||
}
|
||||
else if (position.X > Level.Loaded.Size.X)
|
||||
{
|
||||
obstacleDiff = -Vector2.UnitX;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cells = Level.Loaded.GetCells(position, 1);
|
||||
if (cells.Count > 0)
|
||||
{
|
||||
int cellCount = 0;
|
||||
foreach (Voronoi2.VoronoiCell cell in cells)
|
||||
{
|
||||
Vector2 diff = cell.Center - position;
|
||||
if (diff.LengthSquared() > 5000.0f * 5000.0f) continue;
|
||||
obstacleDiff += diff;
|
||||
cellCount++;
|
||||
}
|
||||
if (cellCount > 0)
|
||||
{
|
||||
obstacleDiff /= cellCount;
|
||||
obstacleDist = obstacleDiff.Length();
|
||||
obstacleDiff = Vector2.Normalize(obstacleDiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Swarm != null)
|
||||
{
|
||||
Vector2 midPoint = Swarm.MidPoint();
|
||||
float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f;
|
||||
if (midPointDist > Swarm.MaxDistance)
|
||||
{
|
||||
steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * prefab.Speed);
|
||||
}
|
||||
steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion);
|
||||
}
|
||||
|
||||
if (prefab.WanderAmount > 0.0f)
|
||||
{
|
||||
steeringManager.SteeringWander(prefab.Speed);
|
||||
}
|
||||
|
||||
if (obstacleDiff != Vector2.Zero)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * prefab.Speed);
|
||||
}
|
||||
|
||||
steeringManager.Update(prefab.Speed);
|
||||
|
||||
if (prefab.WanderZAmount > 0.0f)
|
||||
{
|
||||
wanderZPhase += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount);
|
||||
velocity.Z = (float)Math.Sin(wanderZPhase) * prefab.Speed;
|
||||
}
|
||||
|
||||
velocity = Vector3.Lerp(velocity, new Vector3(Steering.X, Steering.Y, velocity.Z), deltaTime);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float rotation = 0.0f;
|
||||
if (!prefab.DisableRotation)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(velocity.X, -velocity.Y));
|
||||
if (velocity.X < 0.0f) rotation -= MathHelper.Pi;
|
||||
}
|
||||
|
||||
drawPosition = position;
|
||||
if (depth > 0.0f)
|
||||
{
|
||||
Vector2 camOffset = drawPosition - cam.WorldViewCenter;
|
||||
drawPosition -= camOffset * (depth / MaxDepth) * 0.05f;
|
||||
}
|
||||
|
||||
prefab.Sprite.Draw(spriteBatch,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundColor, (depth / MaxDepth) * 0.2f),
|
||||
rotation, (1.0f - (depth / MaxDepth) * 0.2f) * prefab.Scale,
|
||||
velocity.X > 0.0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally,
|
||||
(depth / MaxDepth));
|
||||
}
|
||||
}
|
||||
|
||||
class Swarm
|
||||
{
|
||||
public List<BackgroundCreature> Members;
|
||||
|
||||
public readonly float MaxDistance;
|
||||
public readonly float Cohesion;
|
||||
|
||||
public Vector2 MidPoint()
|
||||
{
|
||||
if (Members.Count == 0) return Vector2.Zero;
|
||||
|
||||
Vector2 midPoint = Vector2.Zero;
|
||||
|
||||
foreach (BackgroundCreature member in Members)
|
||||
{
|
||||
midPoint += member.SimPosition;
|
||||
}
|
||||
|
||||
midPoint /= Members.Count;
|
||||
|
||||
return midPoint;
|
||||
}
|
||||
|
||||
public Vector2 AvgVelocity()
|
||||
{
|
||||
if (Members.Count == 0) return Vector2.Zero;
|
||||
|
||||
Vector2 avgVel = Vector2.Zero;
|
||||
foreach (BackgroundCreature member in Members)
|
||||
{
|
||||
avgVel += member.Velocity;
|
||||
}
|
||||
avgVel /= Members.Count;
|
||||
return avgVel;
|
||||
}
|
||||
|
||||
public Swarm(List<BackgroundCreature> members, float maxDistance, float cohesion)
|
||||
{
|
||||
Members = members;
|
||||
MaxDistance = maxDistance;
|
||||
Cohesion = cohesion;
|
||||
foreach (BackgroundCreature bgSprite in members)
|
||||
{
|
||||
bgSprite.Swarm = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreatureManager
|
||||
{
|
||||
const int MaxSprites = 100;
|
||||
|
||||
const float CheckActiveInterval = 1.0f;
|
||||
|
||||
private float checkActiveTimer;
|
||||
|
||||
private List<BackgroundCreaturePrefab> prefabs = new List<BackgroundCreaturePrefab>();
|
||||
private List<BackgroundCreature> activeSprites = new List<BackgroundCreature>();
|
||||
|
||||
public BackgroundCreatureManager(string configPath)
|
||||
{
|
||||
LoadConfig(new ContentFile(configPath, ContentType.BackgroundCreaturePrefabs));
|
||||
}
|
||||
|
||||
public BackgroundCreatureManager(IEnumerable<ContentFile> files)
|
||||
{
|
||||
foreach(var file in files)
|
||||
{
|
||||
LoadConfig(file);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadConfig(ContentFile config)
|
||||
{
|
||||
try
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(config.Path);
|
||||
if (doc == null) { return; }
|
||||
var mainElement = doc.Root;
|
||||
if (mainElement.IsOverride())
|
||||
{
|
||||
mainElement = doc.Root.FirstElement();
|
||||
prefabs.Clear();
|
||||
DebugConsole.NewMessage($"Overriding all background creatures with '{config.Path}'", Color.Yellow);
|
||||
}
|
||||
else if (prefabs.Any())
|
||||
{
|
||||
DebugConsole.NewMessage($"Loading additional background creatures from file '{config.Path}'");
|
||||
}
|
||||
|
||||
foreach (XElement element in mainElement.Elements())
|
||||
{
|
||||
prefabs.Add(new BackgroundCreaturePrefab(element));
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError(String.Format("Failed to load BackgroundCreatures from {0}", config.Path), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnSprites(int count, Vector2? position = null)
|
||||
{
|
||||
activeSprites.Clear();
|
||||
|
||||
if (prefabs.Count == 0) return;
|
||||
|
||||
count = Math.Min(count, MaxSprites);
|
||||
|
||||
for (int i = 0; i < count; i++ )
|
||||
{
|
||||
Vector2 pos = Vector2.Zero;
|
||||
|
||||
if (position == null)
|
||||
{
|
||||
var wayPoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine==null);
|
||||
if (wayPoints.Any())
|
||||
{
|
||||
WayPoint wp = wayPoints[Rand.Int(wayPoints.Count, Rand.RandSync.ClientOnly)];
|
||||
|
||||
pos = new Vector2(wp.Rect.X, wp.Rect.Y);
|
||||
pos += Rand.Vector(200.0f, Rand.RandSync.ClientOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = Rand.Vector(2000.0f, Rand.RandSync.ClientOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (Vector2)position;
|
||||
}
|
||||
|
||||
|
||||
var prefab = prefabs[Rand.Int(prefabs.Count, Rand.RandSync.ClientOnly)];
|
||||
|
||||
int amount = Rand.Range(prefab.SwarmMin, prefab.SwarmMax, Rand.RandSync.ClientOnly);
|
||||
List<BackgroundCreature> swarmMembers = new List<BackgroundCreature>();
|
||||
|
||||
for (int n = 0; n < amount; n++)
|
||||
{
|
||||
var newSprite = new BackgroundCreature(prefab, pos);
|
||||
activeSprites.Add(newSprite);
|
||||
swarmMembers.Add(newSprite);
|
||||
}
|
||||
if (amount > 0)
|
||||
{
|
||||
new Swarm(swarmMembers, prefab.SwarmRadius, prefab.SwarmCohesion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSprites()
|
||||
{
|
||||
activeSprites.Clear();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (checkActiveTimer < 0.0f)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
sprite.Enabled = Math.Abs(sprite.TransformedPosition.X - cam.WorldViewCenter.X) < cam.WorldView.Width &&
|
||||
Math.Abs(sprite.TransformedPosition.Y - cam.WorldViewCenter.Y) < cam.WorldView.Height;
|
||||
}
|
||||
|
||||
checkActiveTimer = CheckActiveInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkActiveTimer -= deltaTime;
|
||||
}
|
||||
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Draw(spriteBatch, cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreaturePrefab
|
||||
{
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
public readonly float Speed;
|
||||
|
||||
public readonly float WanderAmount;
|
||||
|
||||
public readonly float WanderZAmount;
|
||||
|
||||
public readonly int SwarmMin, SwarmMax;
|
||||
public readonly float SwarmRadius, SwarmCohesion;
|
||||
|
||||
public readonly bool DisableRotation;
|
||||
|
||||
public readonly float Scale;
|
||||
|
||||
public BackgroundCreaturePrefab(XElement element)
|
||||
{
|
||||
Speed = element.GetAttributeFloat("speed", 1.0f);
|
||||
|
||||
WanderAmount = element.GetAttributeFloat("wanderamount", 0.0f);
|
||||
|
||||
WanderZAmount = element.GetAttributeFloat("wanderzamount", 0.0f);
|
||||
|
||||
SwarmMin = element.GetAttributeInt("swarmmin", 1);
|
||||
SwarmMax = element.GetAttributeInt("swarmmax", 1);
|
||||
|
||||
SwarmRadius = element.GetAttributeFloat("swarmradius", 200.0f);
|
||||
SwarmCohesion = element.GetAttributeFloat("swarmcohesion", 0.2f);
|
||||
|
||||
DisableRotation = element.GetAttributeBool("disablerotation", false);
|
||||
|
||||
Scale = element.GetAttributeFloat("scale", 1.0f);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("sprite", System.StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
Sprite = new Sprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
static partial class CaveGenerator
|
||||
{
|
||||
public static List<VertexPositionTexture> GenerateRenderVerticeList(List<Vector2[]> triangles)
|
||||
{
|
||||
var verticeList = new List<VertexPositionTexture>();
|
||||
for (int i = 0; i < triangles.Count; i++)
|
||||
{
|
||||
foreach (Vector2 vertex in triangles[i])
|
||||
{
|
||||
//shift the coordinates around a bit to make the texture repetition less obvious
|
||||
Vector2 uvCoords = new Vector2(
|
||||
vertex.X / 2000.0f + (float)Math.Sin(vertex.X / 500.0f) * 0.15f,
|
||||
vertex.Y / 2000.0f + (float)Math.Sin(vertex.Y / 700.0f) * 0.15f);
|
||||
|
||||
verticeList.Add(new VertexPositionTexture(new Vector3(vertex, 1.0f), uvCoords));
|
||||
}
|
||||
}
|
||||
|
||||
return verticeList;
|
||||
}
|
||||
|
||||
public static VertexPositionTexture[] GenerateWallShapes(List<VoronoiCell> cells, Level level)
|
||||
{
|
||||
float outWardThickness = 30.0f;
|
||||
|
||||
List<VertexPositionTexture> verticeList = new List<VertexPositionTexture>();
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
CompareCCW compare = new CompareCCW(cell.Center);
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
if (edge.Cell1 != null && edge.Cell1.Body == null && edge.Cell1.CellType != CellType.Empty) edge.Cell1 = null;
|
||||
if (edge.Cell2 != null && edge.Cell2.Body == null && edge.Cell2.CellType != CellType.Empty) edge.Cell2 = null;
|
||||
|
||||
if (compare.Compare(edge.Point1, edge.Point2) == -1)
|
||||
{
|
||||
var temp = edge.Point1;
|
||||
edge.Point1 = edge.Point2;
|
||||
edge.Point2 = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
if (!edge.IsSolid) continue;
|
||||
|
||||
GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1 == e.Point1 || edge.Point1 == e.Point2));
|
||||
GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2 == e.Point1 || edge.Point2 == e.Point2));
|
||||
|
||||
Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero;
|
||||
|
||||
float inwardThickness1 = 100;
|
||||
float inwardThickness2 = 100;
|
||||
if (leftEdge != null && !leftEdge.IsSolid)
|
||||
{
|
||||
leftNormal = edge.Point1 == leftEdge.Point1 ?
|
||||
Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) :
|
||||
Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2);
|
||||
inwardThickness1 = Vector2.Distance(leftEdge.Point1, leftEdge.Point2) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNormal = Vector2.Normalize(cell.Center - edge.Point1);
|
||||
inwardThickness1 = Vector2.Distance(edge.Point1, cell.Center) / 2;
|
||||
}
|
||||
|
||||
if (!MathUtils.IsValid(leftNormal))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Invalid left normal");
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
"Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.Remove(cell.Body);
|
||||
cell.Body = null;
|
||||
}
|
||||
leftNormal = Vector2.UnitX;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rightEdge != null && !rightEdge.IsSolid)
|
||||
{
|
||||
rightNormal = edge.Point2 == rightEdge.Point1 ?
|
||||
Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) :
|
||||
Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(rightEdge.Point1, rightEdge.Point2) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
rightNormal = Vector2.Normalize(cell.Center - edge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(edge.Point2, cell.Center) / 2;
|
||||
}
|
||||
|
||||
if (!MathUtils.IsValid(rightNormal))
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Invalid right normal");
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
"Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.Remove(cell.Body);
|
||||
cell.Body = null;
|
||||
}
|
||||
rightNormal = Vector2.UnitX;
|
||||
break;
|
||||
}
|
||||
|
||||
float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - cell.Center));
|
||||
float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - cell.Center));
|
||||
//handle wrapping around 0/360
|
||||
if (point1UV - point2UV > MathHelper.Pi)
|
||||
{
|
||||
point2UV += MathHelper.TwoPi;
|
||||
}
|
||||
//the texture wraps around the cell 4 times
|
||||
//TODO: define the uv scale in level generation parameters?
|
||||
point1UV = point1UV / MathHelper.TwoPi * 4;
|
||||
point2UV = point2UV / MathHelper.TwoPi * 4;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Vector2[] verts = new Vector2[3];
|
||||
VertexPositionTexture[] vertPos = new VertexPositionTexture[3];
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
verts[0] = edge.Point1 - leftNormal * outWardThickness;
|
||||
verts[1] = edge.Point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.Point1 + leftNormal * inwardThickness1;
|
||||
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.0f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point1UV, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
verts[0] = edge.Point1 + leftNormal * inwardThickness1;
|
||||
verts[1] = edge.Point2 - rightNormal * outWardThickness;
|
||||
verts[2] = edge.Point2 + rightNormal * inwardThickness2;
|
||||
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], 0.0f), new Vector2(point1UV, 0.5f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], 0.0f), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], 0.0f), new Vector2(point2UV, 0.5f));
|
||||
}
|
||||
verticeList.AddRange(vertPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verticeList.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FarseerPhysics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Level
|
||||
{
|
||||
private LevelRenderer renderer;
|
||||
|
||||
private BackgroundCreatureManager backgroundCreatureManager;
|
||||
|
||||
public LevelRenderer Renderer => renderer;
|
||||
|
||||
public void ReloadTextures()
|
||||
{
|
||||
renderer.ReloadTextures();
|
||||
|
||||
HashSet<Texture2D> uniqueTextures = new HashSet<Texture2D>();
|
||||
HashSet<Sprite> uniqueSprites = new HashSet<Sprite>();
|
||||
var allLevelObjects = levelObjectManager.GetAllObjects();
|
||||
foreach (var levelObj in allLevelObjects)
|
||||
{
|
||||
foreach (Sprite sprite in levelObj.Prefab.Sprites)
|
||||
{
|
||||
if (!uniqueTextures.Contains(sprite.Texture))
|
||||
{
|
||||
uniqueTextures.Add(sprite.Texture);
|
||||
uniqueSprites.Add(sprite);
|
||||
}
|
||||
}
|
||||
foreach (Sprite specularSprite in levelObj.Prefab.SpecularSprites)
|
||||
{
|
||||
if (!uniqueTextures.Contains(specularSprite.Texture))
|
||||
{
|
||||
uniqueTextures.Add(specularSprite.Texture);
|
||||
uniqueSprites.Add(specularSprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Sprite sprite in uniqueSprites)
|
||||
{
|
||||
sprite.ReloadTexture();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (renderer == null) return;
|
||||
renderer.Draw(spriteBatch, cam);
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
foreach (InterestingPosition pos in positionsOfInterest)
|
||||
{
|
||||
Color color = Color.Yellow;
|
||||
if (pos.PositionType == PositionType.Cave)
|
||||
{
|
||||
color = Color.DarkOrange;
|
||||
}
|
||||
else if (pos.PositionType == PositionType.Ruin)
|
||||
{
|
||||
color = Color.LightGray;
|
||||
}
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(pos.Position.X - 15.0f, -pos.Position.Y - 15.0f), new Vector2(30.0f, 30.0f), color, true);
|
||||
}
|
||||
|
||||
foreach (RuinGeneration.Ruin ruin in ruins)
|
||||
{
|
||||
Rectangle ruinArea = ruin.Area;
|
||||
ruinArea.Y = -ruinArea.Y - ruinArea.Height;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, ruinArea, Color.DarkSlateBlue, false, 0, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBack(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
float brightness = MathHelper.Clamp(1.1f + (cam.Position.Y - Size.Y) / 100000.0f, 0.1f, 1.0f);
|
||||
var lightColorHLS = generationParams.AmbientLightColor.RgbToHLS();
|
||||
lightColorHLS.Y *= brightness;
|
||||
|
||||
GameMain.LightManager.AmbientLight = ToolBox.HLSToRGB(lightColorHLS);
|
||||
|
||||
graphics.Clear(BackgroundColor);
|
||||
|
||||
if (renderer == null) return;
|
||||
renderer.DrawBackground(spriteBatch, cam, levelObjectManager, backgroundCreatureManager);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
foreach (LevelWall levelWall in extraWalls)
|
||||
{
|
||||
if (levelWall.Body.BodyType == BodyType.Static) continue;
|
||||
|
||||
Vector2 bodyPos = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
|
||||
levelWall.MoveState = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 16);
|
||||
|
||||
if (Vector2.DistanceSquared(bodyPos, levelWall.Body.Position) > 0.5f)
|
||||
{
|
||||
levelWall.Body.SetTransformIgnoreContacts(ref bodyPos, levelWall.Body.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using System.Linq;
|
||||
using FarseerPhysics.Dynamics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObject
|
||||
{
|
||||
public float SwingTimer;
|
||||
public float ScaleOscillateTimer;
|
||||
|
||||
public float CurrentSwingAmount;
|
||||
public Vector2 CurrentScaleOscillation;
|
||||
|
||||
public float CurrentRotation;
|
||||
|
||||
private List<SpriteDeformation> spriteDeformations = new List<SpriteDeformation>();
|
||||
|
||||
public Vector2 CurrentScale
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = Vector2.One;
|
||||
|
||||
public LightSource[] LightSources
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] LightSourceTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ParticleEmitter[] ParticleEmitters
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] ParticleEmitterTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public RoundSound[] Sounds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public SoundChannel[] SoundChannels
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public LevelTrigger[] SoundTriggers
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector2[,] CurrentSpriteDeformation
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
Sprite?.EnsureLazyLoaded();
|
||||
SpecularSprite?.EnsureLazyLoaded();
|
||||
Prefab.DeformableSprite?.EnsureLazyLoaded();
|
||||
|
||||
CurrentSwingAmount = Prefab.SwingAmountRad;
|
||||
CurrentScaleOscillation = Prefab.ScaleOscillation;
|
||||
|
||||
SwingTimer = Rand.Range(0.0f, MathHelper.TwoPi);
|
||||
ScaleOscillateTimer = Rand.Range(0.0f, MathHelper.TwoPi);
|
||||
|
||||
if (Prefab.ParticleEmitterPrefabs != null)
|
||||
{
|
||||
ParticleEmitters = new ParticleEmitter[Prefab.ParticleEmitterPrefabs.Count];
|
||||
ParticleEmitterTriggers = new LevelTrigger[Prefab.ParticleEmitterPrefabs.Count];
|
||||
for (int i = 0; i < Prefab.ParticleEmitterPrefabs.Count; i++)
|
||||
{
|
||||
ParticleEmitters[i] = new ParticleEmitter(Prefab.ParticleEmitterPrefabs[i]);
|
||||
ParticleEmitterTriggers[i] = Prefab.ParticleEmitterTriggerIndex[i] > -1 ?
|
||||
Triggers[Prefab.ParticleEmitterTriggerIndex[i]] : null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Prefab.LightSourceParams != null)
|
||||
{
|
||||
LightSources = new LightSource[Prefab.LightSourceParams.Count];
|
||||
LightSourceTriggers = new LevelTrigger[Prefab.LightSourceParams.Count];
|
||||
for (int i = 0; i < Prefab.LightSourceParams.Count; i++)
|
||||
{
|
||||
LightSources[i] = new LightSource(Prefab.LightSourceParams[i])
|
||||
{
|
||||
Position = new Vector2(Position.X, Position.Y),
|
||||
IsBackground = true
|
||||
};
|
||||
LightSourceTriggers[i] = Prefab.LightSourceTriggerIndex[i] > -1 ?
|
||||
Triggers[Prefab.LightSourceTriggerIndex[i]] : null;
|
||||
}
|
||||
}
|
||||
|
||||
Sounds = new RoundSound[Prefab.Sounds.Count];
|
||||
SoundChannels = new SoundChannel[Prefab.Sounds.Count];
|
||||
SoundTriggers = new LevelTrigger[Prefab.Sounds.Count];
|
||||
for (int i = 0; i < Prefab.Sounds.Count; i++)
|
||||
{
|
||||
Sounds[i] = Submarine.LoadRoundSound(Prefab.Sounds[i].SoundElement, false);
|
||||
SoundTriggers[i] = Prefab.Sounds[i].TriggerIndex > -1 ? Triggers[Prefab.Sounds[i].TriggerIndex] : null;
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
foreach (XElement subElement in Prefab.Config.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("deformablesprite", StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
foreach (XElement animationElement in subElement.Elements())
|
||||
{
|
||||
var newDeformation = SpriteDeformation.Load(animationElement, Prefab.Name);
|
||||
if (newDeformation != null)
|
||||
{
|
||||
newDeformation.Params = Prefab.SpriteDeformations[j].Params;
|
||||
spriteDeformations.Add(newDeformation);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (ParticleEmitters != null)
|
||||
{
|
||||
for (int i = 0; i < ParticleEmitters.Length; i++)
|
||||
{
|
||||
if (ParticleEmitterTriggers[i] != null && !ParticleEmitterTriggers[i].IsTriggered) continue;
|
||||
Vector2 emitterPos = LocalToWorld(Prefab.EmitterPositions[i]);
|
||||
ParticleEmitters[i].Emit(deltaTime, emitterPos, hullGuess: null,
|
||||
angle: ParticleEmitters[i].Prefab.CopyEntityAngle ? Rotation : 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
CurrentRotation = Rotation;
|
||||
if (ActivePrefab.SwingFrequency > 0.0f)
|
||||
{
|
||||
SwingTimer += deltaTime * ActivePrefab.SwingFrequency;
|
||||
SwingTimer = SwingTimer % MathHelper.TwoPi;
|
||||
//lerp the swing amount to the correct value to prevent it from abruptly changing to a different value
|
||||
//when a trigger changes the swing amoung
|
||||
CurrentSwingAmount = MathHelper.Lerp(CurrentSwingAmount, ActivePrefab.SwingAmountRad, deltaTime * 10.0f);
|
||||
|
||||
if (ActivePrefab.SwingAmountRad > 0.0f)
|
||||
{
|
||||
CurrentRotation += (float)Math.Sin(SwingTimer) * CurrentSwingAmount;
|
||||
}
|
||||
}
|
||||
|
||||
CurrentScale = Vector2.One * Scale;
|
||||
if (ActivePrefab.ScaleOscillationFrequency > 0.0f)
|
||||
{
|
||||
ScaleOscillateTimer += deltaTime * ActivePrefab.ScaleOscillationFrequency;
|
||||
ScaleOscillateTimer = ScaleOscillateTimer % MathHelper.TwoPi;
|
||||
CurrentScaleOscillation = Vector2.Lerp(CurrentScaleOscillation, ActivePrefab.ScaleOscillation, deltaTime * 10.0f);
|
||||
|
||||
float sin = (float)Math.Sin(ScaleOscillateTimer);
|
||||
CurrentScale *= new Vector2(
|
||||
1.0f + sin * CurrentScaleOscillation.X,
|
||||
1.0f + sin * CurrentScaleOscillation.Y);
|
||||
}
|
||||
|
||||
if (LightSources != null)
|
||||
{
|
||||
for (int i = 0; i < LightSources.Length; i++)
|
||||
{
|
||||
if (LightSourceTriggers[i] != null) LightSources[i].Enabled = LightSourceTriggers[i].IsTriggered;
|
||||
LightSources[i].Rotation = -CurrentRotation;
|
||||
LightSources[i].SpriteScale = CurrentScale;
|
||||
}
|
||||
}
|
||||
|
||||
if (spriteDeformations.Count > 0)
|
||||
{
|
||||
UpdateDeformations(deltaTime);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Sounds.Length; i++)
|
||||
{
|
||||
if (Sounds[i] == null) { continue; }
|
||||
if (SoundTriggers[i] == null || SoundTriggers[i].IsTriggered)
|
||||
{
|
||||
RoundSound roundSound = Sounds[i];
|
||||
Vector2 soundPos = LocalToWorld(new Vector2(Prefab.Sounds[i].Position.X, Prefab.Sounds[i].Position.Y));
|
||||
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), soundPos) <
|
||||
roundSound.Range * roundSound.Range)
|
||||
{
|
||||
if (SoundChannels[i] == null || !SoundChannels[i].IsPlaying)
|
||||
{
|
||||
SoundChannels[i] = roundSound.Sound.Play(roundSound.Volume, roundSound.Range, soundPos);
|
||||
}
|
||||
SoundChannels[i].Position = new Vector3(soundPos.X, soundPos.Y, 0.0f);
|
||||
}
|
||||
}
|
||||
else if (SoundChannels[i] != null && SoundChannels[i].IsPlaying)
|
||||
{
|
||||
SoundChannels[i].FadeOutAndDispose();
|
||||
SoundChannels[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDeformations(float deltaTime)
|
||||
{
|
||||
foreach (SpriteDeformation deformation in spriteDeformations)
|
||||
{
|
||||
if (deformation is PositionalDeformation positionalDeformation)
|
||||
{
|
||||
UpdatePositionalDeformation(positionalDeformation, deltaTime);
|
||||
}
|
||||
deformation.Update(deltaTime);
|
||||
}
|
||||
CurrentSpriteDeformation = SpriteDeformation.GetDeformation(spriteDeformations, ActivePrefab.DeformableSprite.Size);
|
||||
foreach (LightSource lightSource in LightSources)
|
||||
{
|
||||
if (lightSource?.DeformableLightSprite != null)
|
||||
{
|
||||
lightSource.DeformableLightSprite.Deform(CurrentSpriteDeformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePositionalDeformation(PositionalDeformation positionalDeformation, float deltaTime)
|
||||
{
|
||||
Matrix matrix = ActivePrefab.DeformableSprite.GetTransform(
|
||||
Position,
|
||||
ActivePrefab.DeformableSprite.Origin,
|
||||
CurrentRotation,
|
||||
Vector2.One * Scale);
|
||||
|
||||
Matrix rotationMatrix = Matrix.CreateRotationZ(CurrentRotation);
|
||||
|
||||
foreach (LevelTrigger trigger in Triggers)
|
||||
{
|
||||
foreach (Entity triggerer in trigger.Triggerers)
|
||||
{
|
||||
Vector2 moveAmount = triggerer.WorldPosition - trigger.TriggererPosition[triggerer];
|
||||
|
||||
moveAmount = Vector2.Transform(moveAmount, rotationMatrix);
|
||||
moveAmount /= (ActivePrefab.DeformableSprite.Size * Scale);
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
|
||||
positionalDeformation.Deform(trigger.WorldPosition, moveAmount, deltaTime, Matrix.Invert(matrix) *
|
||||
Matrix.CreateScale(1.0f / ActivePrefab.DeformableSprite.Size.X, 1.0f / ActivePrefab.DeformableSprite.Size.Y, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
for (int i = 0; i < Triggers.Count; i++)
|
||||
{
|
||||
if (!Triggers[i].UseNetworkSyncing) continue;
|
||||
Triggers[i].ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
partial void RemoveProjSpecific()
|
||||
{
|
||||
for (int i = 0; i < Sounds.Length; i++)
|
||||
{
|
||||
SoundChannels[i]?.Dispose();
|
||||
SoundChannels[i] = null;
|
||||
}
|
||||
if (LightSources != null)
|
||||
{
|
||||
for (int i = 0; i < LightSources.Length; i++)
|
||||
{
|
||||
LightSources[i].Remove();
|
||||
}
|
||||
LightSources = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectManager
|
||||
{
|
||||
private List<LevelObject> visibleObjectsBack = new List<LevelObject>();
|
||||
private List<LevelObject> visibleObjectsFront = new List<LevelObject>();
|
||||
|
||||
private Rectangle currentGridIndices;
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
foreach (LevelObject obj in visibleObjectsBack)
|
||||
{
|
||||
obj.Update(deltaTime);
|
||||
}
|
||||
foreach (LevelObject obj in visibleObjectsFront)
|
||||
{
|
||||
obj.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<LevelObject> GetVisibleObjects()
|
||||
{
|
||||
return visibleObjectsBack.Union(visibleObjectsFront);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks which level objects are in camera view and adds them to the visibleObjects lists
|
||||
/// </summary>
|
||||
private void RefreshVisibleObjects(Rectangle currentIndices)
|
||||
{
|
||||
visibleObjectsBack.Clear();
|
||||
visibleObjectsFront.Clear();
|
||||
|
||||
for (int x = currentIndices.X; x <= currentIndices.Width; x++)
|
||||
{
|
||||
for (int y = currentIndices.Y; y <= currentIndices.Height; y++)
|
||||
{
|
||||
if (objectGrid[x, y] == null) continue;
|
||||
foreach (LevelObject obj in objectGrid[x, y])
|
||||
{
|
||||
var objectList = obj.Position.Z >= 0 ? visibleObjectsBack : visibleObjectsFront;
|
||||
int drawOrderIndex = 0;
|
||||
for (int i = 0; i < objectList.Count; i++)
|
||||
{
|
||||
if (objectList[i] == obj)
|
||||
{
|
||||
drawOrderIndex = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (objectList[i].Position.Z < obj.Position.Z)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawOrderIndex = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (drawOrderIndex >= 0)
|
||||
{
|
||||
objectList.Insert(drawOrderIndex, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentGridIndices = currentIndices;
|
||||
}
|
||||
|
||||
|
||||
public void DrawObjects(SpriteBatch spriteBatch, Camera cam, bool drawFront, bool specular = false)
|
||||
{
|
||||
Rectangle indices = Rectangle.Empty;
|
||||
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
|
||||
if (indices.X >= objectGrid.GetLength(0)) return;
|
||||
indices.Y = (int)Math.Floor((cam.WorldView.Y - cam.WorldView.Height - Level.Loaded.BottomPos) / (float)GridSize);
|
||||
if (indices.Y >= objectGrid.GetLength(1)) return;
|
||||
|
||||
indices.Width = (int)Math.Floor(cam.WorldView.Right / (float)GridSize) + 1;
|
||||
if (indices.Width < 0) return;
|
||||
indices.Height = (int)Math.Floor((cam.WorldView.Y - Level.Loaded.BottomPos) / (float)GridSize) + 1;
|
||||
if (indices.Height < 0) return;
|
||||
|
||||
indices.X = Math.Max(indices.X, 0);
|
||||
indices.Y = Math.Max(indices.Y, 0);
|
||||
indices.Width = Math.Min(indices.Width, objectGrid.GetLength(0) - 1);
|
||||
indices.Height = Math.Min(indices.Height, objectGrid.GetLength(1) - 1);
|
||||
|
||||
float z = 0.0f;
|
||||
if (currentGridIndices != indices)
|
||||
{
|
||||
RefreshVisibleObjects(indices);
|
||||
}
|
||||
|
||||
var objectList = drawFront ? visibleObjectsFront : visibleObjectsBack;
|
||||
foreach (LevelObject obj in objectList)
|
||||
{
|
||||
Vector2 camDiff = new Vector2(obj.Position.X, obj.Position.Y) - cam.WorldViewCenter;
|
||||
camDiff.Y = -camDiff.Y;
|
||||
|
||||
Sprite activeSprite = specular ? obj.SpecularSprite : obj.Sprite;
|
||||
activeSprite?.Draw(
|
||||
spriteBatch,
|
||||
new Vector2(obj.Position.X, -obj.Position.Y) - camDiff * obj.Position.Z / 10000.0f,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundTextureColor, obj.Position.Z / 5000.0f),
|
||||
activeSprite.Origin,
|
||||
obj.CurrentRotation,
|
||||
obj.CurrentScale,
|
||||
SpriteEffects.None,
|
||||
z);
|
||||
|
||||
if (specular) continue;
|
||||
|
||||
if (obj.ActivePrefab.DeformableSprite != null)
|
||||
{
|
||||
if (obj.CurrentSpriteDeformation != null)
|
||||
{
|
||||
obj.ActivePrefab.DeformableSprite.Deform(obj.CurrentSpriteDeformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.ActivePrefab.DeformableSprite.Reset();
|
||||
}
|
||||
obj.ActivePrefab.DeformableSprite?.Draw(cam,
|
||||
new Vector3(new Vector2(obj.Position.X, obj.Position.Y) - camDiff * obj.Position.Z / 10000.0f, z * 10.0f),
|
||||
obj.ActivePrefab.DeformableSprite.Origin,
|
||||
obj.CurrentRotation,
|
||||
obj.CurrentScale,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundTextureColor, obj.Position.Z / 5000.0f));
|
||||
}
|
||||
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(obj.Position.X, -obj.Position.Y), new Vector2(10.0f, 10.0f), GUI.Style.Red, true);
|
||||
|
||||
foreach (LevelTrigger trigger in obj.Triggers)
|
||||
{
|
||||
if (trigger.PhysicsBody == null) continue;
|
||||
GUI.DrawLine(spriteBatch, new Vector2(obj.Position.X, -obj.Position.Y), new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y), Color.Cyan, 0, 3);
|
||||
|
||||
Vector2 flowForce = trigger.GetWaterFlowVelocity();
|
||||
if (flowForce.LengthSquared() > 1)
|
||||
{
|
||||
flowForce.Y = -flowForce.Y;
|
||||
GUI.DrawLine(spriteBatch, new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y), new Vector2(trigger.WorldPosition.X, -trigger.WorldPosition.Y) + flowForce * 10, GUI.Style.Orange, 0, 5);
|
||||
}
|
||||
trigger.PhysicsBody.UpdateDrawPosition();
|
||||
trigger.PhysicsBody.DebugDraw(spriteBatch, trigger.IsTriggered ? Color.Cyan : Color.DarkCyan);
|
||||
}
|
||||
}
|
||||
|
||||
z += 0.0001f;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
int objIndex = msg.ReadRangedInteger(0, objects.Count);
|
||||
objects[objIndex].ClientRead(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelObjectPrefab
|
||||
{
|
||||
public class SoundConfig
|
||||
{
|
||||
public readonly XElement SoundElement;
|
||||
public readonly Vector2 Position;
|
||||
public readonly int TriggerIndex;
|
||||
|
||||
public SoundConfig(XElement element, int triggerIndex)
|
||||
{
|
||||
SoundElement = element;
|
||||
Position = element.GetAttributeVector2("position", Vector2.Zero);
|
||||
TriggerIndex = triggerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> ParticleEmitterTriggerIndex
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public List<ParticleEmitterPrefab> ParticleEmitterPrefabs
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public List<Vector2> EmitterPositions
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public List<SoundConfig> Sounds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<SoundConfig>();
|
||||
|
||||
public List<int> LightSourceTriggerIndex
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<int>();
|
||||
public List<LightSourceParams> LightSourceParams
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<Lights.LightSourceParams>();
|
||||
|
||||
/// <summary>
|
||||
/// Only used for editing sprite deformation parameters. The actual LevelObjects use separate SpriteDeformation instances.
|
||||
/// </summary>
|
||||
public List<SpriteDeformation> SpriteDeformations
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<SpriteDeformation>();
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
LoadElementsProjSpecific(element, -1);
|
||||
}
|
||||
|
||||
private void LoadElementsProjSpecific(XElement element, int parentTriggerIndex)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "leveltrigger":
|
||||
case "trigger":
|
||||
LoadElementsProjSpecific(subElement, LevelTriggerElements.IndexOf(subElement));
|
||||
break;
|
||||
case "lightsource":
|
||||
LightSourceTriggerIndex.Add(parentTriggerIndex);
|
||||
LightSourceParams.Add(new LightSourceParams(subElement));
|
||||
break;
|
||||
case "particleemitter":
|
||||
if (ParticleEmitterPrefabs == null)
|
||||
{
|
||||
ParticleEmitterPrefabs = new List<ParticleEmitterPrefab>();
|
||||
EmitterPositions = new List<Vector2>();
|
||||
ParticleEmitterTriggerIndex = new List<int>();
|
||||
}
|
||||
|
||||
ParticleEmitterPrefabs.Add(new ParticleEmitterPrefab(subElement));
|
||||
ParticleEmitterTriggerIndex.Add(parentTriggerIndex);
|
||||
EmitterPositions.Add(subElement.GetAttributeVector2("position", Vector2.Zero));
|
||||
break;
|
||||
case "sound":
|
||||
Sounds.Add(new SoundConfig(subElement, parentTriggerIndex));
|
||||
break;
|
||||
case "deformablesprite":
|
||||
foreach (XElement deformElement in subElement.Elements())
|
||||
{
|
||||
var deformation = SpriteDeformation.Load(deformElement, Name);
|
||||
if (deformation != null)
|
||||
{
|
||||
SpriteDeformations.Add(deformation);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(XElement element)
|
||||
{
|
||||
this.Config = element;
|
||||
|
||||
SerializableProperty.SerializeProperties(this, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements().ToList())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "childobject":
|
||||
case "lightsource":
|
||||
subElement.Remove();
|
||||
break;
|
||||
case "deformablesprite":
|
||||
subElement.RemoveNodes();
|
||||
foreach (SpriteDeformation deformation in SpriteDeformations)
|
||||
{
|
||||
var deformationElement = new XElement("SpriteDeformation");
|
||||
deformation.Save(deformationElement);
|
||||
subElement.Add(deformationElement);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LightSourceParams lightSourceParams in LightSourceParams)
|
||||
{
|
||||
var lightElement = new XElement("LightSource");
|
||||
SerializableProperty.SerializeProperties(lightSourceParams, lightElement);
|
||||
element.Add(lightElement);
|
||||
}
|
||||
|
||||
foreach (ChildObject childObj in ChildObjects)
|
||||
{
|
||||
element.Add(new XElement("ChildObject",
|
||||
new XAttribute("names", string.Join(", ", childObj.AllowedNames)),
|
||||
new XAttribute("mincount", childObj.MinCount),
|
||||
new XAttribute("maxcount", childObj.MaxCount)));
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, float> overrideCommonness in OverrideCommonness)
|
||||
{
|
||||
bool elementFound = false;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("overridecommonness", System.StringComparison.OrdinalIgnoreCase)
|
||||
&& subElement.GetAttributeString("leveltype", "") == overrideCommonness.Key)
|
||||
{
|
||||
subElement.Attribute("commonness").Value = overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture);
|
||||
elementFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!elementFound)
|
||||
{
|
||||
element.Add(new XElement("overridecommonness",
|
||||
new XAttribute("leveltype", overrideCommonness.Key),
|
||||
new XAttribute("commonness", overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelTrigger
|
||||
{
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
if (ForceFluctuationStrength > 0.0f)
|
||||
{
|
||||
currentForceFluctuation = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
}
|
||||
if (stayTriggeredDelay > 0.0f)
|
||||
{
|
||||
triggeredTimer = msg.ReadRangedSingle(0.0f, stayTriggeredDelay, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class LevelRenderer : IDisposable
|
||||
{
|
||||
private static BasicEffect wallEdgeEffect, wallCenterEffect;
|
||||
|
||||
private Vector2 dustOffset;
|
||||
private Vector2 defaultDustVelocity;
|
||||
private Vector2 dustVelocity;
|
||||
|
||||
private RasterizerState cullNone;
|
||||
|
||||
private Level level;
|
||||
|
||||
private VertexBuffer wallVertices, bodyVertices;
|
||||
|
||||
public LevelRenderer(Level level)
|
||||
{
|
||||
defaultDustVelocity = Vector2.UnitY * 10.0f;
|
||||
|
||||
cullNone = new RasterizerState() { CullMode = CullMode.None };
|
||||
|
||||
if (wallEdgeEffect == null)
|
||||
{
|
||||
wallEdgeEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
DiffuseColor = new Vector3(0.8f, 0.8f, 0.8f),
|
||||
VertexColorEnabled = true,
|
||||
TextureEnabled = true,
|
||||
Texture = level.GenerationParams.WallEdgeSprite.Texture
|
||||
};
|
||||
wallEdgeEffect.CurrentTechnique = wallEdgeEffect.Techniques["BasicEffect_Texture"];
|
||||
}
|
||||
|
||||
if (wallCenterEffect == null)
|
||||
{
|
||||
wallCenterEffect = new BasicEffect(GameMain.Instance.GraphicsDevice)
|
||||
{
|
||||
VertexColorEnabled = true,
|
||||
TextureEnabled = true,
|
||||
Texture = level.GenerationParams.WallSprite.Texture
|
||||
};
|
||||
wallCenterEffect.CurrentTechnique = wallCenterEffect.Techniques["BasicEffect_Texture"];
|
||||
}
|
||||
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
public void ReloadTextures()
|
||||
{
|
||||
level.GenerationParams.WallEdgeSprite.ReloadTexture();
|
||||
wallEdgeEffect.Texture = level.GenerationParams.WallEdgeSprite.Texture;
|
||||
level.GenerationParams.WallSprite.ReloadTexture();
|
||||
wallCenterEffect.Texture = level.GenerationParams.WallSprite.Texture;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//calculate the sum of the forces of nearby level triggers
|
||||
//and use it to move the dust texture and water distortion effect
|
||||
Vector2 currentDustVel = defaultDustVelocity;
|
||||
foreach (LevelObject levelObject in level.LevelObjectManager.GetVisibleObjects())
|
||||
{
|
||||
//use the largest water flow velocity of all the triggers
|
||||
Vector2 objectMaxFlow = Vector2.Zero;
|
||||
foreach (LevelTrigger trigger in levelObject.Triggers)
|
||||
{
|
||||
Vector2 vel = trigger.GetWaterFlowVelocity(cam.WorldViewCenter);
|
||||
if (vel.LengthSquared() > objectMaxFlow.LengthSquared())
|
||||
{
|
||||
objectMaxFlow = vel;
|
||||
}
|
||||
}
|
||||
currentDustVel += objectMaxFlow;
|
||||
}
|
||||
|
||||
dustVelocity = Vector2.Lerp(dustVelocity, currentDustVel, deltaTime);
|
||||
|
||||
WaterRenderer.Instance?.ScrollWater(dustVelocity, deltaTime);
|
||||
|
||||
if (level.GenerationParams.WaterParticles != null)
|
||||
{
|
||||
Vector2 waterTextureSize = level.GenerationParams.WaterParticles.size * level.GenerationParams.WaterParticleScale;
|
||||
dustOffset += new Vector2(dustVelocity.X, -dustVelocity.Y) * level.GenerationParams.WaterParticleScale * deltaTime;
|
||||
while (dustOffset.X <= -waterTextureSize.X) dustOffset.X += waterTextureSize.X;
|
||||
while (dustOffset.X >= waterTextureSize.X) dustOffset.X -= waterTextureSize.X;
|
||||
while (dustOffset.Y <= -waterTextureSize.Y) dustOffset.Y += waterTextureSize.Y;
|
||||
while (dustOffset.Y >= waterTextureSize.Y) dustOffset.Y -= waterTextureSize.Y;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static VertexPositionColorTexture[] GetColoredVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
VertexPositionColorTexture[] verts = new VertexPositionColorTexture[vertices.Length];
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
verts[i] = new VertexPositionColorTexture(vertices[i].Position, color, vertices[i].TextureCoordinate);
|
||||
}
|
||||
return verts;
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(GetColoredVertices(vertices, color));
|
||||
}
|
||||
|
||||
public void SetBodyVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
bodyVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
bodyVertices.SetData(GetColoredVertices(vertices, color));
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionColorTexture[] vertices)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length,BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(vertices);
|
||||
}
|
||||
|
||||
public void SetBodyVertices(VertexPositionColorTexture[] vertices)
|
||||
{
|
||||
bodyVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
bodyVertices.SetData(vertices);
|
||||
}
|
||||
|
||||
public void DrawBackground(SpriteBatch spriteBatch, Camera cam,
|
||||
LevelObjectManager backgroundSpriteManager = null,
|
||||
BackgroundCreatureManager backgroundCreatureManager = null)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap);
|
||||
|
||||
Vector2 backgroundPos = cam.WorldViewCenter;
|
||||
|
||||
backgroundPos.Y = -backgroundPos.Y;
|
||||
backgroundPos *= 0.05f;
|
||||
|
||||
if (level.GenerationParams.BackgroundTopSprite != null)
|
||||
{
|
||||
int backgroundSize = (int)level.GenerationParams.BackgroundTopSprite.size.Y;
|
||||
if (backgroundPos.Y < backgroundSize)
|
||||
{
|
||||
if (backgroundPos.Y < 0)
|
||||
{
|
||||
var backgroundTop = level.GenerationParams.BackgroundTopSprite;
|
||||
backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, backgroundSize, (int)Math.Min(-backgroundPos.Y, backgroundSize));
|
||||
backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)),
|
||||
color: level.BackgroundTextureColor);
|
||||
}
|
||||
if (-backgroundPos.Y < GameMain.GraphicsHeight && level.GenerationParams.BackgroundSprite != null)
|
||||
{
|
||||
var background = level.GenerationParams.BackgroundSprite;
|
||||
background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), backgroundSize, backgroundSize);
|
||||
background.DrawTiled(spriteBatch,
|
||||
(backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero,
|
||||
new Vector2(GameMain.GraphicsWidth, (int)Math.Min(Math.Ceiling(backgroundSize - backgroundPos.Y), backgroundSize)),
|
||||
color: level.BackgroundTextureColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.NonPremultiplied,
|
||||
SamplerState.LinearWrap, DepthStencilState.DepthRead, null, null,
|
||||
cam.Transform);
|
||||
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: false);
|
||||
if (backgroundCreatureManager != null) backgroundCreatureManager.Draw(spriteBatch, cam);
|
||||
|
||||
if (level.GenerationParams.WaterParticles != null)
|
||||
{
|
||||
float textureScale = level.GenerationParams.WaterParticleScale;
|
||||
|
||||
Rectangle srcRect = new Rectangle(0, 0, 2048, 2048);
|
||||
Vector2 origin = new Vector2(cam.WorldView.X, -cam.WorldView.Y);
|
||||
Vector2 offset = -origin + dustOffset;
|
||||
while (offset.X <= -srcRect.Width * textureScale) offset.X += srcRect.Width * textureScale;
|
||||
while (offset.X > 0.0f) offset.X -= srcRect.Width * textureScale;
|
||||
while (offset.Y <= -srcRect.Height * textureScale) offset.Y += srcRect.Height * textureScale;
|
||||
while (offset.Y > 0.0f) offset.Y -= srcRect.Height * textureScale;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float scale = (1.0f - i * 0.2f);
|
||||
|
||||
//alpha goes from 1.0 to 0.0 when scale is in the range of 0.1 - 0.05
|
||||
float alpha = (cam.Zoom * scale) < 0.1f ? (cam.Zoom * scale - 0.05f) * 20.0f : 1.0f;
|
||||
if (alpha <= 0.0f) continue;
|
||||
|
||||
Vector2 offsetS = offset * scale
|
||||
+ new Vector2(cam.WorldView.Width, cam.WorldView.Height) * (1.0f - scale) * 0.5f
|
||||
- new Vector2(256.0f * i);
|
||||
|
||||
float texScale = scale * textureScale;
|
||||
|
||||
while (offsetS.X <= -srcRect.Width * texScale) offsetS.X += srcRect.Width * texScale;
|
||||
while (offsetS.X > 0.0f) offsetS.X -= srcRect.Width * texScale;
|
||||
while (offsetS.Y <= -srcRect.Height * texScale) offsetS.Y += srcRect.Height * texScale;
|
||||
while (offsetS.Y > 0.0f) offsetS.Y -= srcRect.Height * texScale;
|
||||
|
||||
level.GenerationParams.WaterParticles.DrawTiled(
|
||||
spriteBatch, origin + offsetS,
|
||||
new Vector2(cam.WorldView.Width - offsetS.X, cam.WorldView.Height - offsetS.Y),
|
||||
rect: srcRect, color: Color.White * alpha, textureScale: new Vector2(texScale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
RenderWalls(GameMain.Instance.GraphicsDevice, cam, specular: false);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.NonPremultiplied,
|
||||
SamplerState.LinearClamp, DepthStencilState.DepthRead, null, null,
|
||||
cam.Transform);
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: true);
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GameMain.DebugDraw && cam.Zoom > 0.05f)
|
||||
{
|
||||
var cells = level.GetCells(cam.WorldViewCenter, 2);
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(cell.Center.X - 10.0f, -cell.Center.Y - 10.0f), new Vector2(20.0f, 20.0f), Color.Cyan, true);
|
||||
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(cell.Edges[0].Point1.X + cell.Translation.X, -(cell.Edges[0].Point1.Y + cell.Translation.Y)),
|
||||
new Vector2(cell.Center.X, -(cell.Center.Y)),
|
||||
Color.Blue * 0.5f);
|
||||
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(edge.Point1.X + cell.Translation.X, -(edge.Point1.Y + cell.Translation.Y)),
|
||||
new Vector2(edge.Point2.X + cell.Translation.X, -(edge.Point2.Y + cell.Translation.Y)), cell.Body == null ? Color.Cyan * 0.5f : Color.White);
|
||||
}
|
||||
|
||||
foreach (Vector2 point in cell.BodyVertices)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(point.X + cell.Translation.X, -(point.Y + cell.Translation.Y)), new Vector2(10.0f, 10.0f), Color.White, true);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (List<Point> nodeList in level.SmallTunnels)
|
||||
{
|
||||
for (int i = 1; i < nodeList.Count; i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(nodeList[i - 1].X, -nodeList[i - 1].Y),
|
||||
new Vector2(nodeList[i].X, -nodeList[i].Y),
|
||||
Color.Lerp(Color.Yellow, GUI.Style.Red, i / (float)nodeList.Count), 0, 10);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var ruin in level.Ruins)
|
||||
{
|
||||
ruin.DebugDraw(spriteBatch);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 pos = new Vector2(0.0f, -level.Size.Y);
|
||||
|
||||
if (cam.WorldView.Y >= -pos.Y - 1024)
|
||||
{
|
||||
pos.X = cam.WorldView.X -1024;
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,new Rectangle(
|
||||
(int)(MathUtils.Round(pos.X, 1024)),
|
||||
-cam.WorldView.Y,
|
||||
width,
|
||||
(int)(cam.WorldView.Y + pos.Y) - 30),
|
||||
Color.Black, true);
|
||||
|
||||
spriteBatch.Draw(level.GenerationParams.WallEdgeSprite.Texture,
|
||||
new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)pos.Y-1000, width, 1024),
|
||||
new Rectangle(0, 0, width, -1024),
|
||||
level.BackgroundTextureColor, 0.0f,
|
||||
Vector2.Zero,
|
||||
SpriteEffects.None, 0.0f);
|
||||
}
|
||||
|
||||
if (cam.WorldView.Y - cam.WorldView.Height < level.SeaFloorTopPos + 1024)
|
||||
{
|
||||
pos = new Vector2(cam.WorldView.X - 1024, -level.BottomPos);
|
||||
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / 1024 + 4.0f) * 1024);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
||||
(int)(MathUtils.Round(pos.X, 1024)),
|
||||
(int)-(level.BottomPos - 30),
|
||||
width,
|
||||
(int)(level.BottomPos - (cam.WorldView.Y - cam.WorldView.Height))),
|
||||
Color.Black, true);
|
||||
|
||||
spriteBatch.Draw(level.GenerationParams.WallEdgeSprite.Texture,
|
||||
new Rectangle((int)(MathUtils.Round(pos.X, 1024)), (int)-level.BottomPos, width, 1024),
|
||||
new Rectangle(0, 0, width, -1024),
|
||||
level.BackgroundTextureColor, 0.0f,
|
||||
Vector2.Zero,
|
||||
SpriteEffects.FlipVertically, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam, bool specular)
|
||||
{
|
||||
if (wallVertices == null) return;
|
||||
|
||||
bool renderLevel = cam.WorldView.Y >= 0.0f;
|
||||
bool renderSeaFloor = cam.WorldView.Y - cam.WorldView.Height < level.SeaFloorTopPos + 1024;
|
||||
|
||||
if (!renderLevel && !renderSeaFloor) return;
|
||||
|
||||
Matrix transformMatrix = cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 100) * 0.5f;
|
||||
|
||||
wallEdgeEffect.Texture = specular && level.GenerationParams.WallEdgeSpriteSpecular != null ?
|
||||
level.GenerationParams.WallEdgeSpriteSpecular.Texture :
|
||||
level.GenerationParams.WallEdgeSprite.Texture;
|
||||
wallEdgeEffect.World = transformMatrix;
|
||||
wallCenterEffect.Texture = specular && level.GenerationParams.WallSpriteSpecular != null ?
|
||||
level.GenerationParams.WallSpriteSpecular.Texture :
|
||||
level.GenerationParams.WallSprite.Texture;
|
||||
wallCenterEffect.World = transformMatrix;
|
||||
|
||||
graphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
if (renderLevel)
|
||||
{
|
||||
graphicsDevice.SetVertexBuffer(bodyVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(bodyVertices.VertexCount / 3.0f));
|
||||
}
|
||||
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
if (!renderSeaFloor && wall == level.SeaFloor) continue;
|
||||
wallCenterEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.BodyVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.BodyVertices.VertexCount / 3.0f));
|
||||
}
|
||||
|
||||
var defaultRasterizerState = graphicsDevice.RasterizerState;
|
||||
graphicsDevice.RasterizerState = cullNone;
|
||||
wallEdgeEffect.World = transformMatrix;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
if (renderLevel)
|
||||
{
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wallVertices.VertexCount / 3.0f));
|
||||
}
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
{
|
||||
if (!renderSeaFloor && wall == level.SeaFloor) continue;
|
||||
wallEdgeEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallVertices.VertexCount / 3.0f));
|
||||
}
|
||||
graphicsDevice.RasterizerState = defaultRasterizerState;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (wallVertices != null) wallVertices.Dispose();
|
||||
if (bodyVertices != null) bodyVertices.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelWall : IDisposable
|
||||
{
|
||||
private VertexBuffer wallVertices, bodyVertices;
|
||||
|
||||
public VertexBuffer WallVertices
|
||||
{
|
||||
get { return wallVertices; }
|
||||
}
|
||||
|
||||
public VertexBuffer BodyVertices
|
||||
{
|
||||
get { return bodyVertices; }
|
||||
}
|
||||
|
||||
public Matrix GetTransform()
|
||||
{
|
||||
return body.BodyType == BodyType.Static ?
|
||||
Matrix.Identity :
|
||||
Matrix.CreateRotationZ(body.Rotation) *
|
||||
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(body.Position), 0.0f));
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(LevelRenderer.GetColoredVertices(vertices, color));
|
||||
}
|
||||
|
||||
public void SetBodyVertices(VertexPositionTexture[] vertices, Color color)
|
||||
{
|
||||
bodyVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
bodyVertices.SetData(LevelRenderer.GetColoredVertices(vertices, color));
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionColorTexture[] vertices)
|
||||
{
|
||||
if (wallVertices != null && !wallVertices.IsDisposed) wallVertices.Dispose();
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(vertices);
|
||||
}
|
||||
|
||||
public void SetBodyVertices(VertexPositionColorTexture[] vertices)
|
||||
{
|
||||
if (bodyVertices != null && !bodyVertices.IsDisposed) bodyVertices.Dispose();
|
||||
bodyVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
bodyVertices.SetData(vertices);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.RuinGeneration
|
||||
{
|
||||
partial class Ruin
|
||||
{
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (RuinShape shape in allShapes)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(shape.Center.X, -shape.Center.Y - 50), shape.DistanceFromEntrance.ToString(), Color.White, Color.Black * 0.5f, font: GUI.LargeFont);
|
||||
}
|
||||
foreach (Line line in walls)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), GUI.Style.Red, 0.0f, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
struct WaterVertexData
|
||||
{
|
||||
float DistortStrengthX;
|
||||
float DistortStrengthY;
|
||||
float WaterColorStrength;
|
||||
float WaterAlpha;
|
||||
|
||||
public WaterVertexData(float distortStrengthX, float distortStrengthY, float waterColorStrength, float waterAlpha)
|
||||
{
|
||||
DistortStrengthX = distortStrengthX;
|
||||
DistortStrengthY = distortStrengthY;
|
||||
WaterColorStrength = waterColorStrength;
|
||||
WaterAlpha = waterAlpha;
|
||||
}
|
||||
|
||||
public static implicit operator Color(WaterVertexData wd)
|
||||
{
|
||||
return new Color(wd.DistortStrengthX, wd.DistortStrengthY, wd.WaterColorStrength, wd.WaterAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
class WaterRenderer : IDisposable
|
||||
{
|
||||
public static WaterRenderer Instance;
|
||||
|
||||
public const int DefaultBufferSize = 2000;
|
||||
public const int DefaultIndoorsBufferSize = 3000;
|
||||
|
||||
public static Vector2 DistortionScale = new Vector2(2f, 2f);
|
||||
public static Vector2 DistortionStrength = new Vector2(0.25f, 0.25f);
|
||||
public static float BlurAmount = 0.0f;
|
||||
|
||||
public Vector2 WavePos
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public readonly Color waterColor = new Color(0.75f * 0.5f, 0.8f * 0.5f, 0.9f * 0.5f, 1.0f);
|
||||
|
||||
public readonly WaterVertexData IndoorsWaterColor = new WaterVertexData(0.1f, 0.1f, 0.5f, 1.0f);
|
||||
public readonly WaterVertexData IndoorsSurfaceTopColor = new WaterVertexData(0.5f, 0.5f, 0.0f, 1.0f);
|
||||
public readonly WaterVertexData IndoorsSurfaceBottomColor = new WaterVertexData(0.2f, 0.1f, 0.9f, 1.0f);
|
||||
|
||||
public VertexPositionTexture[] vertices = new VertexPositionTexture[DefaultBufferSize];
|
||||
public Dictionary<EntityGrid, VertexPositionColorTexture[]> IndoorsVertices = new Dictionary<EntityGrid, VertexPositionColorTexture[]>();// VertexPositionColorTexture[DefaultBufferSize * 2];
|
||||
|
||||
public Effect WaterEffect
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
private BasicEffect basicEffect;
|
||||
|
||||
public int PositionInBuffer = 0;
|
||||
public Dictionary<EntityGrid, int> PositionInIndoorsBuffer = new Dictionary<EntityGrid, int>();
|
||||
|
||||
public Texture2D WaterTexture { get; }
|
||||
|
||||
public WaterRenderer(GraphicsDevice graphicsDevice, ContentManager content)
|
||||
{
|
||||
#if WINDOWS
|
||||
WaterEffect = content.Load<Effect>("Effects/watershader");
|
||||
#endif
|
||||
#if LINUX || OSX
|
||||
|
||||
WaterEffect = content.Load<Effect>("Effects/watershader_opengl");
|
||||
#endif
|
||||
|
||||
WaterTexture = TextureLoader.FromFile("Content/Effects/waterbump.png");
|
||||
WaterEffect.Parameters["xWaterBumpMap"].SetValue(WaterTexture);
|
||||
WaterEffect.Parameters["waterColor"].SetValue(waterColor.ToVector4());
|
||||
|
||||
if (basicEffect == null)
|
||||
{
|
||||
basicEffect = new BasicEffect(GameMain.Instance.GraphicsDevice);
|
||||
basicEffect.VertexColorEnabled = false;
|
||||
|
||||
basicEffect.TextureEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderWater(SpriteBatch spriteBatch, RenderTarget2D texture, Camera cam)
|
||||
{
|
||||
spriteBatch.GraphicsDevice.BlendState = BlendState.NonPremultiplied;
|
||||
|
||||
WaterEffect.Parameters["xTexture"].SetValue(texture);
|
||||
Vector2 distortionStrength = cam == null ? DistortionStrength : DistortionStrength * cam.Zoom;
|
||||
WaterEffect.Parameters["xWaveWidth"].SetValue(DistortionStrength.X);
|
||||
WaterEffect.Parameters["xWaveHeight"].SetValue(DistortionStrength.Y);
|
||||
if (BlurAmount > 0.0f)
|
||||
{
|
||||
WaterEffect.CurrentTechnique = WaterEffect.Techniques["WaterShaderBlurred"];
|
||||
WaterEffect.Parameters["xBlurDistance"].SetValue(BlurAmount / 100.0f);
|
||||
}
|
||||
else
|
||||
{ WaterEffect.CurrentTechnique = WaterEffect.Techniques["WaterShader"];
|
||||
}
|
||||
|
||||
Vector2 offset = WavePos;
|
||||
if (cam != null)
|
||||
{
|
||||
offset += (cam.Position - new Vector2(cam.WorldView.Width / 2.0f, -cam.WorldView.Height / 2.0f));
|
||||
offset.Y += cam.WorldView.Height;
|
||||
offset.X += cam.WorldView.Width;
|
||||
offset *= DistortionScale;
|
||||
}
|
||||
offset.Y = -offset.Y;
|
||||
WaterEffect.Parameters["xUvOffset"].SetValue(new Vector2((offset.X / GameMain.GraphicsWidth) % 1.0f, (offset.Y / GameMain.GraphicsHeight) % 1.0f));
|
||||
WaterEffect.Parameters["xBumpPos"].SetValue(Vector2.Zero);
|
||||
|
||||
if (cam != null)
|
||||
{
|
||||
WaterEffect.Parameters["xBumpScale"].SetValue(new Vector2(
|
||||
(float)cam.WorldView.Width / GameMain.GraphicsWidth * DistortionScale.X,
|
||||
(float)cam.WorldView.Height / GameMain.GraphicsHeight * DistortionScale.Y));
|
||||
WaterEffect.Parameters["xTransform"].SetValue(cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f);
|
||||
WaterEffect.Parameters["xUvTransform"].SetValue(cam.ShaderTransform
|
||||
* Matrix.CreateOrthographicOffCenter(0, spriteBatch.GraphicsDevice.Viewport.Width * 2, spriteBatch.GraphicsDevice.Viewport.Height * 2, 0, 0, 1) * Matrix.CreateTranslation(0.5f, 0.5f, 0.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
WaterEffect.Parameters["xBumpScale"].SetValue(new Vector2(1.0f, 1.0f));
|
||||
WaterEffect.Parameters["xTransform"].SetValue(Matrix.Identity * Matrix.CreateTranslation(-1.0f, 1.0f, 0.0f));
|
||||
WaterEffect.Parameters["xUvTransform"].SetValue(Matrix.CreateScale(0.5f, -0.5f, 0.0f));
|
||||
}
|
||||
|
||||
WaterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
VertexPositionColorTexture[] verts = new VertexPositionColorTexture[6];
|
||||
|
||||
Rectangle view = cam != null ? cam.WorldView : spriteBatch.GraphicsDevice.Viewport.Bounds;
|
||||
|
||||
var corners = new Vector3[4];
|
||||
corners[0] = new Vector3(view.X, view.Y, 0.1f);
|
||||
corners[1] = new Vector3(view.Right, view.Y, 0.1f);
|
||||
corners[2] = new Vector3(view.Right, view.Y - view.Height, 0.1f);
|
||||
corners[3] = new Vector3(view.X, view.Y - view.Height, 0.1f);
|
||||
|
||||
WaterVertexData backGroundColor = new WaterVertexData(0.1f, 0.1f, 0.5f, 1.0f);
|
||||
verts[0] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[1] = new VertexPositionColorTexture(corners[1], backGroundColor, Vector2.Zero);
|
||||
verts[2] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[3] = new VertexPositionColorTexture(corners[0], backGroundColor, Vector2.Zero);
|
||||
verts[4] = new VertexPositionColorTexture(corners[2], backGroundColor, Vector2.Zero);
|
||||
verts[5] = new VertexPositionColorTexture(corners[3], backGroundColor, Vector2.Zero);
|
||||
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, 2);
|
||||
|
||||
foreach (KeyValuePair<EntityGrid, VertexPositionColorTexture[]> subVerts in IndoorsVertices)
|
||||
{
|
||||
if (!PositionInIndoorsBuffer.ContainsKey(subVerts.Key) || PositionInIndoorsBuffer[subVerts.Key] == 0) continue;
|
||||
|
||||
offset = WavePos;
|
||||
if (subVerts.Key.Submarine != null) { offset -= subVerts.Key.Submarine.WorldPosition; }
|
||||
if (cam != null)
|
||||
{
|
||||
offset += cam.Position - new Vector2(cam.WorldView.Width / 2.0f, -cam.WorldView.Height / 2.0f);
|
||||
offset.Y += cam.WorldView.Height;
|
||||
offset.X += cam.WorldView.Width;
|
||||
offset *= DistortionScale;
|
||||
}
|
||||
offset.Y = -offset.Y;
|
||||
WaterEffect.Parameters["xUvOffset"].SetValue(new Vector2((offset.X / GameMain.GraphicsWidth) % 1.0f, (offset.Y / GameMain.GraphicsHeight) % 1.0f));
|
||||
|
||||
WaterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
spriteBatch.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, subVerts.Value, 0, PositionInIndoorsBuffer[subVerts.Key] / 3);
|
||||
}
|
||||
}
|
||||
|
||||
public void ScrollWater(Vector2 vel, float deltaTime)
|
||||
{
|
||||
WavePos = WavePos - vel * deltaTime;
|
||||
}
|
||||
|
||||
public void RenderAir(GraphicsDevice graphicsDevice, Camera cam, RenderTarget2D texture, Matrix transform)
|
||||
{
|
||||
if (vertices == null || vertices.Length < 0 || PositionInBuffer <= 0) return;
|
||||
|
||||
basicEffect.Texture = texture;
|
||||
|
||||
basicEffect.View = Matrix.Identity;
|
||||
basicEffect.World = transform
|
||||
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f * Matrix.CreateTranslation(0.0f,0.0f,0f);
|
||||
basicEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
graphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
|
||||
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, vertices, 0, PositionInBuffer / 3);
|
||||
}
|
||||
|
||||
public void ResetBuffers()
|
||||
{
|
||||
PositionInBuffer = 0;
|
||||
PositionInIndoorsBuffer.Clear();
|
||||
IndoorsVertices.Clear();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing) return;
|
||||
|
||||
if (WaterEffect != null)
|
||||
{
|
||||
WaterEffect.Dispose();
|
||||
WaterEffect = null;
|
||||
}
|
||||
|
||||
if (basicEffect != null)
|
||||
{
|
||||
basicEffect.Dispose();
|
||||
basicEffect = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user