v0.11.0.9
This commit is contained in:
+196
-36
@@ -1,30 +1,38 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
class BackgroundCreature : ISteerable
|
||||
{
|
||||
const float MaxDepth = 100.0f;
|
||||
const float MaxDepth = 10000.0f;
|
||||
|
||||
const float CheckWallsInterval = 5.0f;
|
||||
|
||||
public bool Enabled;
|
||||
public bool Visible;
|
||||
|
||||
private BackgroundCreaturePrefab prefab;
|
||||
public readonly BackgroundCreaturePrefab Prefab;
|
||||
|
||||
private readonly List<SpriteDeformation> uniqueSpriteDeformations = new List<SpriteDeformation>();
|
||||
private readonly List<SpriteDeformation> spriteDeformations = new List<SpriteDeformation>();
|
||||
private readonly List<SpriteDeformation> lightSpriteDeformations = new List<SpriteDeformation>();
|
||||
|
||||
private Vector2 position;
|
||||
|
||||
private Vector3 velocity;
|
||||
|
||||
private float depth;
|
||||
|
||||
private SteeringManager steeringManager;
|
||||
|
||||
private float checkWallsTimer;
|
||||
private float alpha = 1.0f;
|
||||
|
||||
private readonly SteeringManager steeringManager;
|
||||
|
||||
private float checkWallsTimer, flashTimer;
|
||||
|
||||
private float wanderZPhase;
|
||||
private Vector2 obstacleDiff;
|
||||
@@ -33,9 +41,16 @@ namespace Barotrauma
|
||||
public Swarm Swarm;
|
||||
|
||||
Vector2 drawPosition;
|
||||
public Vector2 TransformedPosition
|
||||
|
||||
public Vector2[,] CurrentSpriteDeformation
|
||||
{
|
||||
get { return drawPosition; }
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public Vector2[,] CurrentLightSpriteDeformation
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Vector2 SimPosition
|
||||
@@ -58,11 +73,10 @@ namespace Barotrauma
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
public BackgroundCreature(BackgroundCreaturePrefab prefab, Vector2 position)
|
||||
{
|
||||
this.prefab = prefab;
|
||||
|
||||
this.Prefab = prefab;
|
||||
this.position = position;
|
||||
|
||||
drawPosition = position;
|
||||
@@ -70,18 +84,73 @@ namespace Barotrauma
|
||||
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));
|
||||
Rand.Range(-prefab.Speed, prefab.Speed, Rand.RandSync.ClientOnly),
|
||||
Rand.Range(-prefab.Speed, prefab.Speed, Rand.RandSync.ClientOnly),
|
||||
Rand.Range(0.0f, prefab.WanderZAmount, Rand.RandSync.ClientOnly));
|
||||
|
||||
checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval);
|
||||
checkWallsTimer = Rand.Range(0.0f, CheckWallsInterval, Rand.RandSync.ClientOnly);
|
||||
|
||||
foreach (XElement subElement in prefab.Config.Elements())
|
||||
{
|
||||
List<SpriteDeformation> deformationList = null;
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "deformablesprite":
|
||||
deformationList = spriteDeformations;
|
||||
break;
|
||||
case "deformablelightsprite":
|
||||
deformationList = lightSpriteDeformations;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
foreach (XElement animationElement in subElement.Elements())
|
||||
{
|
||||
SpriteDeformation deformation = null;
|
||||
int sync = animationElement.GetAttributeInt("sync", -1);
|
||||
if (sync > -1)
|
||||
{
|
||||
string typeName = animationElement.GetAttributeString("type", "").ToLowerInvariant();
|
||||
deformation = uniqueSpriteDeformations.Find(d => d.TypeName == typeName && d.Sync == sync);
|
||||
}
|
||||
if (deformation == null)
|
||||
{
|
||||
deformation = SpriteDeformation.Load(animationElement, prefab.Name);
|
||||
if (deformation != null)
|
||||
{
|
||||
uniqueSpriteDeformations.Add(deformation);
|
||||
}
|
||||
}
|
||||
if (deformation != null)
|
||||
{
|
||||
deformationList.Add(deformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
position += new Vector2(velocity.X, velocity.Y) * deltaTime;
|
||||
depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, 0.0f, MaxDepth);
|
||||
depth = MathHelper.Clamp(depth + velocity.Z * deltaTime, Prefab.MinDepth, Prefab.MaxDepth * 10);
|
||||
|
||||
if (Prefab.FlashInterval > 0.0f)
|
||||
{
|
||||
flashTimer -= deltaTime;
|
||||
if (flashTimer > 0.0f)
|
||||
{
|
||||
alpha = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
//value goes from 0 to 1 and back to 0 during the flash
|
||||
alpha = (float)Math.Sin(-flashTimer / Prefab.FlashDuration * MathHelper.Pi) * PerlinNoise.GetPerlin((float)Timing.TotalTime * 0.1f, (float)Timing.TotalTime * 0.2f);
|
||||
if (flashTimer < -Prefab.FlashDuration)
|
||||
{
|
||||
flashTimer = Prefab.FlashInterval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkWallsTimer -= deltaTime;
|
||||
if (checkWallsTimer <= 0.0f && Level.Loaded != null)
|
||||
@@ -134,54 +203,145 @@ namespace Barotrauma
|
||||
float midPointDist = Vector2.Distance(SimPosition, midPoint) * 100.0f;
|
||||
if (midPointDist > Swarm.MaxDistance)
|
||||
{
|
||||
steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * prefab.Speed);
|
||||
steeringManager.SteeringSeek(midPoint, ((midPointDist / Swarm.MaxDistance) - 1.0f) * Prefab.Speed);
|
||||
}
|
||||
steeringManager.SteeringManual(deltaTime, Swarm.AvgVelocity() * Swarm.Cohesion);
|
||||
}
|
||||
|
||||
if (prefab.WanderAmount > 0.0f)
|
||||
if (Prefab.WanderAmount > 0.0f)
|
||||
{
|
||||
steeringManager.SteeringWander(prefab.Speed);
|
||||
steeringManager.SteeringWander(Prefab.Speed);
|
||||
}
|
||||
|
||||
if (obstacleDiff != Vector2.Zero)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * prefab.Speed);
|
||||
steeringManager.SteeringManual(deltaTime, -obstacleDiff * (1.0f - obstacleDist / 5000.0f) * Prefab.Speed);
|
||||
}
|
||||
|
||||
steeringManager.Update(prefab.Speed);
|
||||
steeringManager.Update(Prefab.Speed);
|
||||
|
||||
if (prefab.WanderZAmount > 0.0f)
|
||||
if (Prefab.WanderZAmount > 0.0f)
|
||||
{
|
||||
wanderZPhase += Rand.Range(-prefab.WanderZAmount, prefab.WanderZAmount);
|
||||
velocity.Z = (float)Math.Sin(wanderZPhase) * prefab.Speed;
|
||||
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);
|
||||
|
||||
UpdateDeformations(deltaTime);
|
||||
}
|
||||
|
||||
public void DrawLightSprite(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Draw(spriteBatch, cam, Prefab.LightSprite, Prefab.DeformableLightSprite, CurrentLightSpriteDeformation, Color.White * alpha);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Draw(spriteBatch,
|
||||
cam,
|
||||
Prefab.Sprite,
|
||||
Prefab.DeformableSprite,
|
||||
CurrentSpriteDeformation,
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundColor, depth / Math.Max(MaxDepth, Prefab.MaxDepth)) * alpha);
|
||||
}
|
||||
|
||||
private void Draw(SpriteBatch spriteBatch, Camera cam, Sprite sprite, DeformableSprite deformableSprite, Vector2[,] currentSpriteDeformation, Color color)
|
||||
{
|
||||
if (sprite == null && deformableSprite == null) { return; }
|
||||
if (color.A == 0) { return; }
|
||||
|
||||
float rotation = 0.0f;
|
||||
if (!prefab.DisableRotation)
|
||||
if (!Prefab.DisableRotation)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(velocity.X, -velocity.Y));
|
||||
if (velocity.X < 0.0f) rotation -= MathHelper.Pi;
|
||||
if (velocity.X < 0.0f) { rotation -= MathHelper.Pi; }
|
||||
}
|
||||
|
||||
drawPosition = position;
|
||||
if (depth > 0.0f)
|
||||
drawPosition = GetDrawPosition(cam);
|
||||
|
||||
float scale = GetScale();
|
||||
sprite?.Draw(spriteBatch,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
color,
|
||||
rotation,
|
||||
scale,
|
||||
Prefab.DisableFlipping || velocity.X > 0.0f ? SpriteEffects.None : SpriteEffects.FlipHorizontally,
|
||||
Math.Min(depth / MaxDepth, 1.0f));
|
||||
|
||||
if (deformableSprite != null)
|
||||
{
|
||||
if (currentSpriteDeformation != null)
|
||||
{
|
||||
deformableSprite.Deform(currentSpriteDeformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
deformableSprite.Reset();
|
||||
}
|
||||
deformableSprite?.Draw(cam,
|
||||
new Vector3(drawPosition.X, drawPosition.Y, Math.Min(depth / 10000.0f, 1.0f)),
|
||||
deformableSprite.Origin,
|
||||
rotation,
|
||||
Vector2.One * scale,
|
||||
color,
|
||||
mirror: Prefab.DisableFlipping || velocity.X <= 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 GetDrawPosition(Camera cam)
|
||||
{
|
||||
Vector2 drawPosition = WorldPosition;
|
||||
if (depth >= 0)
|
||||
{
|
||||
Vector2 camOffset = drawPosition - cam.WorldViewCenter;
|
||||
drawPosition -= camOffset * (depth / MaxDepth) * 0.05f;
|
||||
drawPosition -= camOffset * depth / MaxDepth;
|
||||
}
|
||||
return drawPosition;
|
||||
}
|
||||
|
||||
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));
|
||||
public float GetScale()
|
||||
{
|
||||
return Math.Max(1.0f - depth / MaxDepth, 0.05f) * Prefab.Scale;
|
||||
}
|
||||
|
||||
public Rectangle GetExtents(Camera cam)
|
||||
{
|
||||
Vector2 min = GetDrawPosition(cam);
|
||||
Vector2 max = min;
|
||||
|
||||
float scale = GetScale();
|
||||
GetSpriteExtents(Prefab.Sprite, ref min, ref max);
|
||||
GetSpriteExtents(Prefab.LightSprite, ref min, ref max);
|
||||
GetSpriteExtents(Prefab.DeformableSprite?.Sprite, ref min, ref max);
|
||||
GetSpriteExtents(Prefab.DeformableLightSprite?.Sprite, ref min, ref max);
|
||||
|
||||
return new Rectangle(min.ToPoint(), (max - min).ToPoint());
|
||||
|
||||
void GetSpriteExtents(Sprite sprite, ref Vector2 min, ref Vector2 max)
|
||||
{
|
||||
if (sprite == null) { return; }
|
||||
min.X = Math.Min(min.X, min.X - sprite.size.X * sprite.RelativeOrigin.X * scale);
|
||||
min.Y = Math.Min(min.Y, min.Y - sprite.size.Y * sprite.RelativeOrigin.Y * scale);
|
||||
max.X = Math.Max(max.X, max.X + sprite.size.X * (1.0f - sprite.RelativeOrigin.X) * scale);
|
||||
max.Y = Math.Max(max.Y, max.Y + sprite.size.Y * (1.0f - sprite.RelativeOrigin.Y) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDeformations(float deltaTime)
|
||||
{
|
||||
foreach (SpriteDeformation deformation in uniqueSpriteDeformations)
|
||||
{
|
||||
deformation.Update(deltaTime);
|
||||
}
|
||||
if (spriteDeformations.Count > 0)
|
||||
{
|
||||
CurrentSpriteDeformation = SpriteDeformation.GetDeformation(spriteDeformations, Prefab.DeformableSprite.Size);
|
||||
}
|
||||
if (lightSpriteDeformations.Count > 0)
|
||||
{
|
||||
CurrentLightSpriteDeformation = SpriteDeformation.GetDeformation(lightSpriteDeformations, Prefab.DeformableLightSprite.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+54
-35
@@ -9,14 +9,14 @@ namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreatureManager
|
||||
{
|
||||
const int MaxSprites = 100;
|
||||
const int MaxCreatures = 100;
|
||||
|
||||
const float CheckActiveInterval = 1.0f;
|
||||
const float VisibilityCheckInterval = 1.0f;
|
||||
|
||||
private float checkActiveTimer;
|
||||
private float checkVisibleTimer;
|
||||
|
||||
private List<BackgroundCreaturePrefab> prefabs = new List<BackgroundCreaturePrefab>();
|
||||
private List<BackgroundCreature> activeSprites = new List<BackgroundCreature>();
|
||||
private readonly List<BackgroundCreaturePrefab> prefabs = new List<BackgroundCreaturePrefab>();
|
||||
private readonly List<BackgroundCreature> creatures = new List<BackgroundCreature>();
|
||||
|
||||
public BackgroundCreatureManager(string configPath)
|
||||
{
|
||||
@@ -60,92 +60,111 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnSprites(int count, Vector2? position = null)
|
||||
public void SpawnCreatures(Level level, int count, Vector2? position = null)
|
||||
{
|
||||
activeSprites.Clear();
|
||||
creatures.Clear();
|
||||
|
||||
if (prefabs.Count == 0) return;
|
||||
if (prefabs.Count == 0) { return; }
|
||||
|
||||
count = Math.Min(count, MaxSprites);
|
||||
count = Math.Min(count, MaxCreatures);
|
||||
|
||||
for (int i = 0; i < count; i++ )
|
||||
List<BackgroundCreaturePrefab> availablePrefabs = new List<BackgroundCreaturePrefab>(prefabs);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Vector2 pos = Vector2.Zero;
|
||||
|
||||
if (position == null)
|
||||
{
|
||||
var wayPoints = WayPoint.WayPointList.FindAll(wp => wp.Submarine==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)];
|
||||
var prefab = ToolBox.SelectWeightedRandom(availablePrefabs, availablePrefabs.Select(p => p.GetCommonness(level.GenerationParams)).ToList(), Rand.RandSync.ClientOnly);
|
||||
if (prefab == null) { break; }
|
||||
|
||||
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);
|
||||
var creature = new BackgroundCreature(prefab, pos + Rand.Vector(Rand.Range(0.0f, prefab.SwarmRadius, Rand.RandSync.ClientOnly), Rand.RandSync.ClientOnly));
|
||||
creatures.Add(creature);
|
||||
swarmMembers.Add(creature);
|
||||
}
|
||||
if (amount > 0)
|
||||
if (amount > 1)
|
||||
{
|
||||
new Swarm(swarmMembers, prefab.SwarmRadius, prefab.SwarmCohesion);
|
||||
}
|
||||
if (creatures.Count(c => c.Prefab == prefab) > prefab.MaxCount)
|
||||
{
|
||||
availablePrefabs.Remove(prefab);
|
||||
if (availablePrefabs.Count <= 0) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearSprites()
|
||||
public void Clear()
|
||||
{
|
||||
activeSprites.Clear();
|
||||
creatures.Clear();
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (checkActiveTimer < 0.0f)
|
||||
if (checkVisibleTimer < 0.0f)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
int margin = 500;
|
||||
foreach (BackgroundCreature creature in creatures)
|
||||
{
|
||||
sprite.Enabled = Math.Abs(sprite.TransformedPosition.X - cam.WorldViewCenter.X) < cam.WorldView.Width &&
|
||||
Math.Abs(sprite.TransformedPosition.Y - cam.WorldViewCenter.Y) < cam.WorldView.Height;
|
||||
Rectangle extents = creature.GetExtents(cam);
|
||||
bool wasVisible = creature.Visible;
|
||||
creature.Visible =
|
||||
extents.Right >= cam.WorldView.X - margin &&
|
||||
extents.X <= cam.WorldView.Right + margin &&
|
||||
extents.Bottom >= cam.WorldView.Y - cam.WorldView.Height - margin &&
|
||||
extents.Y <= cam.WorldView.Y + margin;
|
||||
}
|
||||
|
||||
checkActiveTimer = CheckActiveInterval;
|
||||
checkVisibleTimer = VisibilityCheckInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkActiveTimer -= deltaTime;
|
||||
checkVisibleTimer -= deltaTime;
|
||||
}
|
||||
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
foreach (BackgroundCreature creature in creatures)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Update(deltaTime);
|
||||
if (!creature.Visible) { continue; }
|
||||
creature.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
foreach (BackgroundCreature sprite in activeSprites)
|
||||
foreach (BackgroundCreature creature in creatures)
|
||||
{
|
||||
if (!sprite.Enabled) continue;
|
||||
sprite.Draw(spriteBatch, cam);
|
||||
if (!creature.Visible) { continue; }
|
||||
creature.Draw(spriteBatch, cam);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLights(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
foreach (BackgroundCreature creature in creatures)
|
||||
{
|
||||
if (!creature.Visible) { continue; }
|
||||
creature.DrawLightSprite(spriteBatch, cam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+94
-27
@@ -1,50 +1,117 @@
|
||||
using System.Xml.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class BackgroundCreaturePrefab
|
||||
{
|
||||
public readonly Sprite Sprite;
|
||||
public readonly Sprite Sprite, LightSprite;
|
||||
public readonly DeformableSprite DeformableSprite, DeformableLightSprite;
|
||||
|
||||
public readonly float Speed;
|
||||
public readonly string Name;
|
||||
|
||||
public readonly float WanderAmount;
|
||||
public readonly XElement Config;
|
||||
|
||||
public readonly float WanderZAmount;
|
||||
[Serialize(1.0f, true)]
|
||||
public float Speed { get; private set; }
|
||||
|
||||
public readonly int SwarmMin, SwarmMax;
|
||||
public readonly float SwarmRadius, SwarmCohesion;
|
||||
[Serialize(0.0f, true)]
|
||||
public float WanderAmount { get; private set; }
|
||||
|
||||
public readonly bool DisableRotation;
|
||||
[Serialize(0.0f, true)]
|
||||
public float WanderZAmount { get; private set; }
|
||||
|
||||
[Serialize(1, true)]
|
||||
public int SwarmMin { get; private set; }
|
||||
|
||||
[Serialize(1, true)]
|
||||
public int SwarmMax { get; private set; }
|
||||
|
||||
[Serialize(200.0f, true)]
|
||||
public float SwarmRadius { get; private set; }
|
||||
|
||||
[Serialize(0.2f, true)]
|
||||
public float SwarmCohesion { get; private set; }
|
||||
|
||||
[Serialize(10.0f, true)]
|
||||
public float MinDepth { get; private set; }
|
||||
|
||||
[Serialize(1000.0f, true)]
|
||||
public float MaxDepth { get; private set; }
|
||||
|
||||
[Serialize(false, true)]
|
||||
public bool DisableRotation { get; private set; }
|
||||
|
||||
[Serialize(false, true)]
|
||||
public bool DisableFlipping { get; private set; }
|
||||
|
||||
[Serialize(1.0f, true)]
|
||||
public float Scale { get; private set; }
|
||||
|
||||
[Serialize(1.0f, true)]
|
||||
public float Commonness { get; private set; }
|
||||
|
||||
[Serialize(1000, true)]
|
||||
public int MaxCount { get; private set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float FlashInterval { get; private set; }
|
||||
|
||||
[Serialize(0.0f, true)]
|
||||
public float FlashDuration { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the commonness of the object in a specific level type.
|
||||
/// Key = name of the level type, value = commonness in that level type.
|
||||
/// </summary>
|
||||
public Dictionary<string, float> OverrideCommonness = new Dictionary<string, float>();
|
||||
|
||||
public readonly float Scale;
|
||||
|
||||
public BackgroundCreaturePrefab(XElement element)
|
||||
{
|
||||
Speed = element.GetAttributeFloat("speed", 1.0f);
|
||||
Name = element.Name.ToString();
|
||||
|
||||
WanderAmount = element.GetAttributeFloat("wanderamount", 0.0f);
|
||||
Config = element;
|
||||
|
||||
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);
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (!subElement.Name.ToString().Equals("sprite", System.StringComparison.OrdinalIgnoreCase)) { continue; }
|
||||
|
||||
Sprite = new Sprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "sprite":
|
||||
Sprite = new Sprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
case "deformablesprite":
|
||||
DeformableSprite = new DeformableSprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
case "lightsprite":
|
||||
LightSprite = new Sprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
case "deformablelightsprite":
|
||||
DeformableLightSprite = new DeformableSprite(subElement, lazyLoad: true);
|
||||
break;
|
||||
case "overridecommonness":
|
||||
string levelType = subElement.GetAttributeString("leveltype", "").ToLowerInvariant();
|
||||
if (!OverrideCommonness.ContainsKey(levelType))
|
||||
{
|
||||
OverrideCommonness.Add(levelType, subElement.GetAttributeFloat("commonness", 1.0f));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float GetCommonness(LevelGenerationParams generationParams)
|
||||
{
|
||||
if (generationParams?.Identifier != null &&
|
||||
(OverrideCommonness.TryGetValue(generationParams.Identifier, out float commonness) ||
|
||||
(generationParams.OldIdentifier != null && OverrideCommonness.TryGetValue(generationParams.OldIdentifier, out commonness))))
|
||||
{
|
||||
return commonness;
|
||||
}
|
||||
return Commonness;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,72 +9,82 @@ namespace Barotrauma
|
||||
{
|
||||
static partial class CaveGenerator
|
||||
{
|
||||
public static List<VertexPositionTexture> GenerateRenderVerticeList(List<Vector2[]> triangles)
|
||||
public static List<VertexPositionTexture> GenerateWallVertices(List<Vector2[]> triangles, LevelGenerationParams generationParams, float zCoord)
|
||||
{
|
||||
var verticeList = new List<VertexPositionTexture>();
|
||||
var vertices = 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));
|
||||
Vector2 uvCoords = vertex / generationParams.WallTextureSize;
|
||||
vertices.Add(new VertexPositionTexture(new Vector3(vertex, zCoord), uvCoords));
|
||||
}
|
||||
}
|
||||
|
||||
return verticeList;
|
||||
return vertices;
|
||||
}
|
||||
|
||||
public static VertexPositionTexture[] GenerateWallShapes(List<VoronoiCell> cells, Level level)
|
||||
public static List<VertexPositionTexture> GenerateWallEdgeVertices(List<VoronoiCell> cells, Level level, float zCoord)
|
||||
{
|
||||
float outWardThickness = 30.0f;
|
||||
float outWardThickness = level.GenerationParams.WallEdgeExpandOutwardsAmount;
|
||||
|
||||
List<VertexPositionTexture> verticeList = new List<VertexPositionTexture>();
|
||||
List<VertexPositionTexture> vertices = new List<VertexPositionTexture>();
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
CompareCCW compare = new CompareCCW(cell.Center);
|
||||
Vector2 minVert = cell.Edges[0].Point1;
|
||||
Vector2 maxVert = cell.Edges[0].Point1;
|
||||
float circumference = 0.0f;
|
||||
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;
|
||||
}
|
||||
circumference += Vector2.Distance(edge.Point1, edge.Point2);
|
||||
minVert = new Vector2(
|
||||
Math.Min(minVert.X, edge.Point1.X),
|
||||
Math.Min(minVert.Y, edge.Point1.Y));
|
||||
maxVert = new Vector2(
|
||||
Math.Max(maxVert.X, edge.Point1.X),
|
||||
Math.Max(maxVert.Y, edge.Point1.Y));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (VoronoiCell cell in cells)
|
||||
{
|
||||
Vector2 center = (minVert + maxVert) / 2;
|
||||
foreach (GraphEdge edge in cell.Edges)
|
||||
{
|
||||
if (!edge.IsSolid) continue;
|
||||
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));
|
||||
GraphEdge leftEdge = cell.Edges.Find(e => e != edge && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2)));
|
||||
var leftAdjacentCell = leftEdge?.AdjacentCell(cell);
|
||||
if (leftAdjacentCell != null)
|
||||
{
|
||||
var adjEdge = leftAdjacentCell.Edges.Find(e => e != leftEdge && e.IsSolid && (edge.Point1.NearlyEquals(e.Point1) || edge.Point1.NearlyEquals(e.Point2)));
|
||||
if (adjEdge != null) { leftEdge = adjEdge; }
|
||||
}
|
||||
|
||||
GraphEdge rightEdge = cell.Edges.Find(e => e != edge && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2)));
|
||||
var rightAdjacentCell = rightEdge?.AdjacentCell(cell);
|
||||
if (rightAdjacentCell != null)
|
||||
{
|
||||
var adjEdge = rightAdjacentCell.Edges.Find(e => e != rightEdge && e.IsSolid && (edge.Point2.NearlyEquals(e.Point1) || edge.Point2.NearlyEquals(e.Point2)));
|
||||
if (adjEdge != null) { rightEdge = adjEdge; }
|
||||
}
|
||||
|
||||
Vector2 leftNormal = Vector2.Zero, rightNormal = Vector2.Zero;
|
||||
|
||||
float inwardThickness1 = 100;
|
||||
float inwardThickness2 = 100;
|
||||
float inwardThickness1 = level.GenerationParams.WallEdgeExpandInwardsAmount;
|
||||
float inwardThickness2 = level.GenerationParams.WallEdgeExpandInwardsAmount;
|
||||
if (leftEdge != null && !leftEdge.IsSolid)
|
||||
{
|
||||
leftNormal = edge.Point1 == leftEdge.Point1 ?
|
||||
leftNormal = edge.Point1.NearlyEquals(leftEdge.Point1) ?
|
||||
Vector2.Normalize(leftEdge.Point2 - leftEdge.Point1) :
|
||||
Vector2.Normalize(leftEdge.Point1 - leftEdge.Point2);
|
||||
inwardThickness1 = Vector2.Distance(leftEdge.Point1, leftEdge.Point2) / 2;
|
||||
}
|
||||
else if (leftEdge != null)
|
||||
{
|
||||
leftNormal = -Vector2.Normalize(edge.GetNormal(cell) + leftEdge.GetNormal(leftAdjacentCell ?? cell));
|
||||
if (!MathUtils.IsValid(leftNormal)) { leftNormal = -edge.GetNormal(cell); }
|
||||
}
|
||||
else
|
||||
{
|
||||
leftNormal = Vector2.Normalize(cell.Center - edge.Point1);
|
||||
inwardThickness1 = Vector2.Distance(edge.Point1, cell.Center) / 2;
|
||||
}
|
||||
inwardThickness1 = Math.Min(Vector2.Distance(edge.Point1, cell.Center), inwardThickness1);
|
||||
|
||||
if (!MathUtils.IsValid(leftNormal))
|
||||
{
|
||||
@@ -86,7 +97,7 @@ namespace Barotrauma
|
||||
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.Remove(cell.Body);
|
||||
if (GameMain.World.BodyList.Contains(cell.Body)) { GameMain.World.Remove(cell.Body); }
|
||||
cell.Body = null;
|
||||
}
|
||||
leftNormal = Vector2.UnitX;
|
||||
@@ -95,16 +106,20 @@ namespace Barotrauma
|
||||
|
||||
if (rightEdge != null && !rightEdge.IsSolid)
|
||||
{
|
||||
rightNormal = edge.Point2 == rightEdge.Point1 ?
|
||||
rightNormal = edge.Point2.NearlyEquals(rightEdge.Point1) ?
|
||||
Vector2.Normalize(rightEdge.Point2 - rightEdge.Point1) :
|
||||
Vector2.Normalize(rightEdge.Point1 - rightEdge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(rightEdge.Point1, rightEdge.Point2) / 2;
|
||||
}
|
||||
else if (rightEdge != null)
|
||||
{
|
||||
rightNormal = -Vector2.Normalize(edge.GetNormal(cell) + rightEdge.GetNormal(rightAdjacentCell ?? cell));
|
||||
if (!MathUtils.IsValid(rightNormal)) { rightNormal = -edge.GetNormal(cell); }
|
||||
}
|
||||
else
|
||||
{
|
||||
rightNormal = Vector2.Normalize(cell.Center - edge.Point2);
|
||||
inwardThickness2 = Vector2.Distance(edge.Point2, cell.Center) / 2;
|
||||
}
|
||||
inwardThickness2 = Math.Min(Vector2.Distance(edge.Point2, cell.Center), inwardThickness2);
|
||||
|
||||
if (!MathUtils.IsValid(rightNormal))
|
||||
{
|
||||
@@ -117,24 +132,23 @@ namespace Barotrauma
|
||||
|
||||
if (cell.Body != null)
|
||||
{
|
||||
GameMain.World.Remove(cell.Body);
|
||||
if (GameMain.World.BodyList.Contains(cell.Body)) { 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));
|
||||
float point1UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point1 - center));
|
||||
float point2UV = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(edge.Point2 - center));
|
||||
//handle wrapping around 0/360
|
||||
if (point1UV - point2UV > MathHelper.Pi)
|
||||
{
|
||||
point2UV += MathHelper.TwoPi;
|
||||
if (point1UV - point2UV > MathHelper.Pi)
|
||||
{
|
||||
point1UV -= 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;
|
||||
int textureRepeatCount = (int)Math.Max(circumference / 2 / level.GenerationParams.WallEdgeTextureWidth, 1);
|
||||
point1UV = point1UV / MathHelper.TwoPi * textureRepeatCount;
|
||||
point2UV = point2UV / MathHelper.TwoPi * textureRepeatCount;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -147,9 +161,9 @@ namespace Barotrauma
|
||||
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));
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 0.0f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point1UV, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,16 +172,16 @@ namespace Barotrauma
|
||||
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));
|
||||
vertPos[0] = new VertexPositionTexture(new Vector3(verts[0], zCoord), new Vector2(point1UV, 1.0f));
|
||||
vertPos[1] = new VertexPositionTexture(new Vector3(verts[1], zCoord), new Vector2(point2UV, 0.0f));
|
||||
vertPos[2] = new VertexPositionTexture(new Vector3(verts[2], zCoord), new Vector2(point2UV, 1.0f));
|
||||
}
|
||||
verticeList.AddRange(vertPos);
|
||||
vertices.AddRange(vertPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verticeList.ToArray();
|
||||
return vertices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class DestructibleLevelWall : LevelWall, IDamageable
|
||||
{
|
||||
|
||||
public override float Alpha
|
||||
{
|
||||
get
|
||||
{
|
||||
if (FadeOutDuration <= 0.0f || FadeOutTimer < FadeOutDuration - 1.0f) { return 1.0f; }
|
||||
return MathHelper.Clamp(FadeOutDuration - FadeOutTimer, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
partial void AddDamageProjSpecific(float damage, Vector2 worldPosition)
|
||||
{
|
||||
if (damage <= 0.0f) { return; }
|
||||
Vector2 particlePos = worldPosition;
|
||||
if (!Cells.Any(c => c.IsPointInside(particlePos)))
|
||||
{
|
||||
bool intersectionFound = false;
|
||||
foreach (var cell in Cells)
|
||||
{
|
||||
foreach (var edge in cell.Edges)
|
||||
{
|
||||
if (MathUtils.GetLineIntersection(worldPosition, cell.Center, edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, out Vector2 intersection))
|
||||
{
|
||||
intersectionFound = true;
|
||||
particlePos = intersection;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (intersectionFound) { break; }
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 particleDir = particlePos - WorldPosition;
|
||||
if (particleDir.LengthSquared() > 0.0001f) { particleDir = Vector2.Normalize(particleDir); }
|
||||
int particleAmount = MathHelper.Clamp((int)damage, 1, 10);
|
||||
for (int i = 0; i < particleAmount; i++)
|
||||
{
|
||||
var particle = GameMain.ParticleManager.CreateParticle("iceshards",
|
||||
particlePos + Rand.Vector(5.0f),
|
||||
particleDir * Rand.Range(200.0f, 500.0f) + Rand.Vector(100.0f));
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDamage(float damage)
|
||||
{
|
||||
Damage = damage;
|
||||
if (Damage >= MaxHealth && !Destroyed)
|
||||
{
|
||||
CreateFragments();
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ namespace Barotrauma
|
||||
|
||||
private BackgroundCreatureManager backgroundCreatureManager;
|
||||
|
||||
public BackgroundCreatureManager BackgroundCreatureManager => backgroundCreatureManager;
|
||||
|
||||
public LevelRenderer Renderer => renderer;
|
||||
|
||||
public void ReloadTextures()
|
||||
@@ -33,14 +35,6 @@ namespace Barotrauma
|
||||
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)
|
||||
@@ -51,7 +45,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (renderer == null) return;
|
||||
if (renderer == null) { return; }
|
||||
renderer.Draw(spriteBatch, cam);
|
||||
|
||||
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
|
||||
@@ -123,22 +117,34 @@ namespace Barotrauma
|
||||
if (renderer == null) return;
|
||||
renderer.DrawBackground(spriteBatch, cam, LevelObjectManager, backgroundCreatureManager);
|
||||
}
|
||||
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
foreach (LevelWall levelWall in ExtraWalls)
|
||||
bool isGlobalUpdate = msg.ReadBoolean();
|
||||
if (isGlobalUpdate)
|
||||
{
|
||||
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)
|
||||
foreach (LevelWall levelWall in ExtraWalls)
|
||||
{
|
||||
levelWall.Body.SetTransformIgnoreContacts(ref bodyPos, levelWall.Body.Rotation);
|
||||
if (levelWall.Body.BodyType == BodyType.Static) { continue; }
|
||||
|
||||
Vector2 bodyPos = new Vector2(
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
levelWall.MoveState = msg.ReadRangedSingle(0.0f, MathHelper.TwoPi, 16);
|
||||
DestructibleLevelWall destructibleWall = levelWall as DestructibleLevelWall;
|
||||
if (Vector2.DistanceSquared(bodyPos, levelWall.Body.Position) > 0.5f && (destructibleWall == null || !destructibleWall.Destroyed))
|
||||
{
|
||||
levelWall.Body.SetTransformIgnoreContacts(ref bodyPos, levelWall.Body.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = msg.ReadUInt16();
|
||||
byte damageByte = msg.ReadByte();
|
||||
if (index < ExtraWalls.Count && ExtraWalls[index] is DestructibleLevelWall destructibleWall)
|
||||
{
|
||||
destructibleWall.SetDamage(destructibleWall.MaxHealth * damageByte / 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using System.Linq;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -74,10 +74,21 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool VisibleOnSonar
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float SonarRadius
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
Sprite?.EnsureLazyLoaded();
|
||||
SpecularSprite?.EnsureLazyLoaded();
|
||||
Prefab.DeformableSprite?.EnsureLazyLoaded();
|
||||
|
||||
CurrentSwingAmount = Prefab.SwingAmountRad;
|
||||
@@ -98,7 +109,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Prefab.LightSourceParams != null)
|
||||
if (Prefab.LightSourceParams != null && Prefab.LightSourceParams.Count > 0)
|
||||
{
|
||||
LightSources = new LightSource[Prefab.LightSourceParams.Count];
|
||||
LightSourceTriggers = new LevelTrigger[Prefab.LightSourceParams.Count];
|
||||
@@ -138,6 +149,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VisibleOnSonar = Prefab.SonarDisruption > 0.0f || Prefab.OverrideProperties.Any(p => p != null && p.SonarDisruption > 0.0f) ||
|
||||
(Triggers != null && Triggers.Any(t => !MathUtils.NearlyEqual(t.Force, Vector2.Zero) && t.ForceMode != LevelTrigger.TriggerForceMode.LimitVelocity || !string.IsNullOrWhiteSpace(t.InfectIdentifier)));
|
||||
if (VisibleOnSonar && Triggers.Any())
|
||||
{
|
||||
SonarRadius = Triggers.Select(t => t.ColliderRadius * 1.5f).Max();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
@@ -232,17 +250,21 @@ namespace Barotrauma
|
||||
deformation.Update(deltaTime);
|
||||
}
|
||||
CurrentSpriteDeformation = SpriteDeformation.GetDeformation(spriteDeformations, ActivePrefab.DeformableSprite.Size);
|
||||
foreach (LightSource lightSource in LightSources)
|
||||
if (LightSources != null)
|
||||
{
|
||||
if (lightSource?.DeformableLightSprite != null)
|
||||
foreach (LightSource lightSource in LightSources)
|
||||
{
|
||||
lightSource.DeformableLightSprite.Deform(CurrentSpriteDeformation);
|
||||
if (lightSource?.DeformableLightSprite != null)
|
||||
{
|
||||
lightSource.DeformableLightSprite.Deform(CurrentSpriteDeformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePositionalDeformation(PositionalDeformation positionalDeformation, float deltaTime)
|
||||
{
|
||||
if (Triggers == null) { return; }
|
||||
Matrix matrix = ActivePrefab.DeformableSprite.GetTransform(
|
||||
Position,
|
||||
ActivePrefab.DeformableSprite.Origin,
|
||||
@@ -258,7 +280,7 @@ namespace Barotrauma
|
||||
Vector2 moveAmount = triggerer.WorldPosition - trigger.TriggererPosition[triggerer];
|
||||
|
||||
moveAmount = Vector2.Transform(moveAmount, rotationMatrix);
|
||||
moveAmount /= (ActivePrefab.DeformableSprite.Size * Scale);
|
||||
moveAmount /= ActivePrefab.DeformableSprite.Size * Scale;
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
|
||||
positionalDeformation.Deform(trigger.WorldPosition, moveAmount, deltaTime, Matrix.Invert(matrix) *
|
||||
@@ -269,9 +291,10 @@ namespace Barotrauma
|
||||
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
if (Triggers == null) { return; }
|
||||
for (int i = 0; i < Triggers.Count; i++)
|
||||
{
|
||||
if (!Triggers[i].UseNetworkSyncing) continue;
|
||||
if (!Triggers[i].UseNetworkSyncing) { continue; }
|
||||
Triggers[i].ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
+32
-8
@@ -12,6 +12,8 @@ namespace Barotrauma
|
||||
private readonly List<LevelObject> visibleObjectsBack = new List<LevelObject>();
|
||||
private readonly List<LevelObject> visibleObjectsFront = new List<LevelObject>();
|
||||
|
||||
private double NextRefreshTime;
|
||||
|
||||
//Maximum number of visible objects drawn at once. Should be large enough to not have an effect during normal gameplay,
|
||||
//but small enough to prevent wrecking performance when zooming out very far
|
||||
const int MaxVisibleObjects = 500;
|
||||
@@ -38,11 +40,13 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Checks which level objects are in camera view and adds them to the visibleObjects lists
|
||||
/// </summary>
|
||||
private void RefreshVisibleObjects(Rectangle currentIndices)
|
||||
private void RefreshVisibleObjects(Rectangle currentIndices, float zoom)
|
||||
{
|
||||
visibleObjectsBack.Clear();
|
||||
visibleObjectsFront.Clear();
|
||||
|
||||
float minSizeToDraw = MathHelper.Lerp(10.0f, 5.0f, Math.Min(zoom * 20.0f, 1.0f));
|
||||
|
||||
for (int x = currentIndices.X; x <= currentIndices.Width; x++)
|
||||
{
|
||||
for (int y = currentIndices.Y; y <= currentIndices.Height; y++)
|
||||
@@ -50,6 +54,22 @@ namespace Barotrauma
|
||||
if (objectGrid[x, y] == null) { continue; }
|
||||
foreach (LevelObject obj in objectGrid[x, y])
|
||||
{
|
||||
if (zoom < 0.05f)
|
||||
{
|
||||
//hide if the sprite is very small when zoomed this far out
|
||||
if ((obj.Sprite != null && Math.Min(obj.Sprite.size.X * zoom, obj.Sprite.size.Y * zoom) < 5.0f) ||
|
||||
(obj.ActivePrefab?.DeformableSprite != null && Math.Min(obj.ActivePrefab.DeformableSprite.Sprite.size.X * zoom, obj.ActivePrefab.DeformableSprite.Sprite.size.Y * zoom) < minSizeToDraw))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float zCutoff = MathHelper.Lerp(5000.0f, 500.0f, (0.05f - zoom) * 20.0f);
|
||||
if (obj.Position.Z > zCutoff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var objectList = obj.Position.Z >= 0 ? visibleObjectsBack : visibleObjectsFront;
|
||||
int drawOrderIndex = 0;
|
||||
for (int i = 0; i < objectList.Count; i++)
|
||||
@@ -83,7 +103,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
public void DrawObjects(SpriteBatch spriteBatch, Camera cam, bool drawFront, bool specular = false)
|
||||
public void DrawObjects(SpriteBatch spriteBatch, Camera cam, bool drawFront)
|
||||
{
|
||||
Rectangle indices = Rectangle.Empty;
|
||||
indices.X = (int)Math.Floor(cam.WorldView.X / (float)GridSize);
|
||||
@@ -102,9 +122,14 @@ namespace Barotrauma
|
||||
indices.Height = Math.Min(indices.Height, objectGrid.GetLength(1) - 1);
|
||||
|
||||
float z = 0.0f;
|
||||
if (currentGridIndices != indices)
|
||||
if (currentGridIndices != indices && Timing.TotalTime > NextRefreshTime)
|
||||
{
|
||||
RefreshVisibleObjects(indices);
|
||||
RefreshVisibleObjects(indices, cam.Zoom);
|
||||
if (cam.Zoom < 0.1f)
|
||||
{
|
||||
//when zoomed very far out, refresh a little less often
|
||||
NextRefreshTime = Timing.TotalTime + MathHelper.Lerp(1.0f, 0.0f, cam.Zoom * 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
var objectList = drawFront ? visibleObjectsFront : visibleObjectsBack;
|
||||
@@ -113,19 +138,17 @@ namespace Barotrauma
|
||||
Vector2 camDiff = new Vector2(obj.Position.X, obj.Position.Y) - cam.WorldViewCenter;
|
||||
camDiff.Y = -camDiff.Y;
|
||||
|
||||
Sprite activeSprite = specular ? obj.SpecularSprite : obj.Sprite;
|
||||
Sprite activeSprite = 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),
|
||||
Color.Lerp(Color.White, Level.Loaded.BackgroundTextureColor, obj.Position.Z / 3000.0f),
|
||||
activeSprite.Origin,
|
||||
obj.CurrentRotation,
|
||||
obj.CurrentScale,
|
||||
SpriteEffects.None,
|
||||
z);
|
||||
|
||||
if (specular) continue;
|
||||
|
||||
if (obj.ActivePrefab.DeformableSprite != null)
|
||||
{
|
||||
if (obj.CurrentSpriteDeformation != null)
|
||||
@@ -149,6 +172,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(obj.Position.X, -obj.Position.Y), new Vector2(10.0f, 10.0f), GUI.Style.Red, true);
|
||||
|
||||
if (obj.Triggers == null) { continue; }
|
||||
foreach (LevelTrigger trigger in obj.Triggers)
|
||||
{
|
||||
if (trigger.PhysicsBody == null) continue;
|
||||
|
||||
+25
-6
@@ -126,7 +126,6 @@ namespace Barotrauma
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "childobject":
|
||||
case "lightsource":
|
||||
subElement.Remove();
|
||||
break;
|
||||
case "deformablesprite":
|
||||
@@ -141,11 +140,31 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (LightSourceParams lightSourceParams in LightSourceParams)
|
||||
for (int i = 0; i < LightSourceParams.Count; i++)
|
||||
{
|
||||
var lightElement = new XElement("LightSource");
|
||||
SerializableProperty.SerializeProperties(lightSourceParams, lightElement);
|
||||
element.Add(lightElement);
|
||||
int elementIndex = 0;
|
||||
bool wasSaved = false;
|
||||
foreach (XElement subElement in element.Elements().ToList())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "lightsource":
|
||||
if (elementIndex == i)
|
||||
{
|
||||
SerializableProperty.SerializeProperties(LightSourceParams[i], subElement);
|
||||
wasSaved = true;
|
||||
break;
|
||||
}
|
||||
elementIndex++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!wasSaved)
|
||||
{
|
||||
var lightElement = new XElement("LightSource");
|
||||
SerializableProperty.SerializeProperties(LightSourceParams[i], lightElement);
|
||||
element.Add(lightElement);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ChildObject childObj in ChildObjects)
|
||||
@@ -162,7 +181,7 @@ namespace Barotrauma
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("overridecommonness", System.StringComparison.OrdinalIgnoreCase)
|
||||
&& subElement.GetAttributeString("leveltype", "") == overrideCommonness.Key)
|
||||
&& subElement.GetAttributeString("leveltype", "").Equals(overrideCommonness.Key, System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
subElement.Attribute("commonness").Value = overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture);
|
||||
elementFound = true;
|
||||
|
||||
@@ -3,10 +3,68 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Voronoi2;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class LevelWallVertexBuffer : IDisposable
|
||||
{
|
||||
public VertexBuffer WallEdgeBuffer, WallBuffer;
|
||||
public readonly Texture2D WallTexture, EdgeTexture;
|
||||
private VertexPositionColorTexture[] wallVertices;
|
||||
private VertexPositionColorTexture[] wallEdgeVertices;
|
||||
|
||||
public bool IsDisposed
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public LevelWallVertexBuffer(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
|
||||
{
|
||||
this.wallVertices = LevelRenderer.GetColoredVertices(wallVertices, color);
|
||||
WallBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, wallVertices.Length, BufferUsage.WriteOnly);
|
||||
WallBuffer.SetData(this.wallVertices);
|
||||
WallTexture = wallTexture;
|
||||
|
||||
this.wallEdgeVertices = LevelRenderer.GetColoredVertices(wallEdgeVertices, color);
|
||||
WallEdgeBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, wallEdgeVertices.Length, BufferUsage.WriteOnly);
|
||||
WallEdgeBuffer.SetData(this.wallEdgeVertices);
|
||||
EdgeTexture = edgeTexture;
|
||||
}
|
||||
|
||||
public void Append(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Color color)
|
||||
{
|
||||
WallBuffer.Dispose();
|
||||
WallBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, this.wallVertices.Length + wallVertices.Length, BufferUsage.WriteOnly);
|
||||
int originalWallVertexCount = this.wallVertices.Length;
|
||||
Array.Resize(ref this.wallVertices, originalWallVertexCount + wallVertices.Length);
|
||||
Array.Copy(LevelRenderer.GetColoredVertices(wallVertices, color), 0, this.wallVertices, originalWallVertexCount, wallVertices.Length);
|
||||
WallBuffer.SetData(this.wallVertices);
|
||||
|
||||
WallEdgeBuffer.Dispose();
|
||||
WallEdgeBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, this.wallEdgeVertices.Length + wallEdgeVertices.Length, BufferUsage.WriteOnly);
|
||||
int originalWallEdgeVertexCount = this.wallEdgeVertices.Length;
|
||||
Array.Resize(ref this.wallEdgeVertices, originalWallEdgeVertexCount + wallEdgeVertices.Length);
|
||||
Array.Copy(LevelRenderer.GetColoredVertices(wallEdgeVertices, color), 0, this.wallEdgeVertices, originalWallEdgeVertexCount, wallEdgeVertices.Length);
|
||||
WallEdgeBuffer.SetData(this.wallEdgeVertices);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
IsDisposed = true;
|
||||
WallEdgeBuffer?.Dispose();
|
||||
WallBuffer?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class LevelRenderer : IDisposable
|
||||
{
|
||||
private static BasicEffect wallEdgeEffect, wallCenterEffect;
|
||||
@@ -15,11 +73,11 @@ namespace Barotrauma
|
||||
private Vector2 defaultDustVelocity;
|
||||
private Vector2 dustVelocity;
|
||||
|
||||
private RasterizerState cullNone;
|
||||
private readonly RasterizerState cullNone;
|
||||
|
||||
private Level level;
|
||||
private readonly Level level;
|
||||
|
||||
private VertexBuffer wallVertices, bodyVertices;
|
||||
private readonly List<LevelWallVertexBuffer> vertexBuffers = new List<LevelWallVertexBuffer>();
|
||||
|
||||
public LevelRenderer(Level level)
|
||||
{
|
||||
@@ -68,6 +126,7 @@ namespace Barotrauma
|
||||
Vector2 currentDustVel = defaultDustVelocity;
|
||||
foreach (LevelObject levelObject in level.LevelObjectManager.GetVisibleObjects())
|
||||
{
|
||||
if (levelObject.Triggers == null) { continue; }
|
||||
//use the largest water flow velocity of all the triggers
|
||||
Vector2 objectMaxFlow = Vector2.Zero;
|
||||
foreach (LevelTrigger trigger in levelObject.Triggers)
|
||||
@@ -94,7 +153,6 @@ namespace Barotrauma
|
||||
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)
|
||||
@@ -107,38 +165,27 @@ namespace Barotrauma
|
||||
return verts;
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionTexture[] vertices, Color color)
|
||||
public void SetVertices(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(GetColoredVertices(vertices, color));
|
||||
var existingBuffer = vertexBuffers.Find(vb => vb.WallTexture == wallTexture && vb.EdgeTexture == edgeTexture);
|
||||
if (existingBuffer != null)
|
||||
{
|
||||
existingBuffer.Append(wallVertices, wallEdgeVertices,color);
|
||||
}
|
||||
else
|
||||
{
|
||||
vertexBuffers.Add(new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallTexture, edgeTexture, 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,
|
||||
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;
|
||||
|
||||
@@ -173,10 +220,13 @@ namespace Barotrauma
|
||||
SamplerState.LinearWrap, DepthStencilState.DepthRead, null, null,
|
||||
cam.Transform);
|
||||
|
||||
if (backgroundSpriteManager != null) backgroundSpriteManager.DrawObjects(spriteBatch, cam, drawFront: false);
|
||||
if (backgroundCreatureManager != null) backgroundCreatureManager.Draw(spriteBatch, cam);
|
||||
backgroundSpriteManager?.DrawObjects(spriteBatch, cam, drawFront: false);
|
||||
if (cam.Zoom > 0.05f)
|
||||
{
|
||||
backgroundCreatureManager?.Draw(spriteBatch, cam);
|
||||
}
|
||||
|
||||
if (level.GenerationParams.WaterParticles != null)
|
||||
if (level.GenerationParams.WaterParticles != null && cam.Zoom > 0.05f)
|
||||
{
|
||||
float textureScale = level.GenerationParams.WaterParticleScale;
|
||||
|
||||
@@ -216,7 +266,7 @@ namespace Barotrauma
|
||||
|
||||
spriteBatch.End();
|
||||
|
||||
RenderWalls(GameMain.Instance.GraphicsDevice, cam, specular: false);
|
||||
RenderWalls(GameMain.Instance.GraphicsDevice, cam);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred,
|
||||
BlendState.NonPremultiplied,
|
||||
@@ -243,7 +293,8 @@ namespace Barotrauma
|
||||
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);
|
||||
new Vector2(edge.Point2.X + cell.Translation.X, -(edge.Point2.Y + cell.Translation.Y)), edge.NextToCave ? Color.Red : (cell.Body == null ? Color.Cyan * 0.5f : (edge.IsSolid ? Color.White : Color.Gray)),
|
||||
width: edge.NextToCave ? 8 :1);
|
||||
}
|
||||
|
||||
foreach (Vector2 point in cell.BodyVertices)
|
||||
@@ -252,7 +303,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (List<Point> nodeList in level.SmallTunnels)
|
||||
/*foreach (List<Point> nodeList in level.SmallTunnels)
|
||||
{
|
||||
for (int i = 1; i < nodeList.Count; i++)
|
||||
{
|
||||
@@ -261,7 +312,7 @@ namespace Barotrauma
|
||||
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)
|
||||
{
|
||||
@@ -270,108 +321,142 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
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);
|
||||
int topBarrierWidth = level.GenerationParams.WallEdgeSprite.Texture.Width;
|
||||
int topBarrierHeight = level.GenerationParams.WallEdgeSprite.Texture.Height;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,new Rectangle(
|
||||
(int)(MathUtils.Round(pos.X, 1024)),
|
||||
-cam.WorldView.Y,
|
||||
width,
|
||||
(int)(cam.WorldView.Y + pos.Y) - 30),
|
||||
pos.X = cam.WorldView.X - topBarrierWidth;
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / 1024 + 4.0f) * topBarrierWidth);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
||||
(int)MathUtils.Round(pos.X, topBarrierWidth),
|
||||
-cam.WorldView.Y,
|
||||
width,
|
||||
(int)(cam.WorldView.Y + pos.Y) - 60),
|
||||
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,
|
||||
new Rectangle((int)MathUtils.Round(pos.X, topBarrierWidth), (int)(pos.Y - topBarrierHeight + level.GenerationParams.WallEdgeExpandOutwardsAmount), width, topBarrierHeight),
|
||||
new Rectangle(0, 0, width, -topBarrierHeight),
|
||||
GameMain.LightManager?.LightingEnabled ?? false ? GameMain.LightManager.AmbientLight : level.WallColor, 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);
|
||||
int bottomBarrierWidth = level.GenerationParams.WallEdgeSprite.Texture.Width;
|
||||
int bottomBarrierHeight = level.GenerationParams.WallEdgeSprite.Texture.Height;
|
||||
pos = new Vector2(cam.WorldView.X - bottomBarrierWidth, -level.BottomPos);
|
||||
int width = (int)(Math.Ceiling(cam.WorldView.Width / bottomBarrierWidth + 4.0f) * bottomBarrierWidth);
|
||||
|
||||
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))),
|
||||
(int)(MathUtils.Round(pos.X, bottomBarrierWidth)),
|
||||
-(level.BottomPos - 60),
|
||||
width,
|
||||
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,
|
||||
new Rectangle((int)MathUtils.Round(pos.X, bottomBarrierWidth), -level.BottomPos - (int)level.GenerationParams.WallEdgeExpandOutwardsAmount, width, bottomBarrierHeight),
|
||||
new Rectangle(0, 0, width, -bottomBarrierHeight),
|
||||
GameMain.LightManager?.LightingEnabled ?? false ? GameMain.LightManager.AmbientLight : level.WallColor, 0.0f,
|
||||
Vector2.Zero,
|
||||
SpriteEffects.FlipVertically, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam, bool specular)
|
||||
public void RenderWalls(GraphicsDevice graphicsDevice, Camera cam)
|
||||
{
|
||||
if (wallVertices == null) return;
|
||||
if (!vertexBuffers.Any()) { return; }
|
||||
|
||||
bool renderLevel = cam.WorldView.Y >= 0.0f;
|
||||
bool renderSeaFloor = cam.WorldView.Y - cam.WorldView.Height < level.SeaFloorTopPos + 1024;
|
||||
|
||||
if (!renderLevel && !renderSeaFloor) return;
|
||||
var defaultRasterizerState = graphicsDevice.RasterizerState;
|
||||
|
||||
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)
|
||||
//render destructible walls
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wallVertices.VertexCount / 3.0f));
|
||||
var wallList = i == 0 ? level.ExtraWalls : level.UnsyncedExtraWalls;
|
||||
foreach (LevelWall wall in wallList)
|
||||
{
|
||||
if (!(wall is DestructibleLevelWall destructibleWall) || destructibleWall.Destroyed) { continue; }
|
||||
|
||||
wallCenterEffect.Texture = level.GenerationParams.DestructibleWallSprite?.Texture ?? level.GenerationParams.WallSprite.Texture;
|
||||
wallCenterEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallCenterEffect.Alpha = wall.Alpha;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallBuffer.VertexCount / 3.0f));
|
||||
|
||||
if (destructibleWall.Damage > 0.0f)
|
||||
{
|
||||
wallCenterEffect.Texture = level.GenerationParams.WallSpriteDestroyed.Texture;
|
||||
wallCenterEffect.Alpha = MathHelper.Lerp(0.2f, 1.0f, destructibleWall.Damage / destructibleWall.MaxHealth) * wall.Alpha;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallEdgeBuffer.VertexCount / 3.0f));
|
||||
}
|
||||
|
||||
wallEdgeEffect.Texture = level.GenerationParams.DestructibleWallEdgeSprite?.Texture ?? level.GenerationParams.WallEdgeSprite.Texture;
|
||||
wallEdgeEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallEdgeEffect.Alpha = wall.Alpha;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallEdgeBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallEdgeBuffer.VertexCount / 3.0f));
|
||||
}
|
||||
}
|
||||
foreach (LevelWall wall in level.ExtraWalls)
|
||||
|
||||
wallEdgeEffect.Alpha = 1.0f;
|
||||
wallCenterEffect.Alpha = 1.0f;
|
||||
|
||||
wallCenterEffect.World = transformMatrix;
|
||||
wallEdgeEffect.World = transformMatrix;
|
||||
|
||||
//render static walls
|
||||
foreach (var vertexBuffer in vertexBuffers)
|
||||
{
|
||||
if (!renderSeaFloor && wall == level.SeaFloor) continue;
|
||||
wallEdgeEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallCenterEffect.Texture = vertexBuffer.WallTexture;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(vertexBuffer.WallBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(vertexBuffer.WallBuffer.VertexCount / 3.0f));
|
||||
|
||||
wallEdgeEffect.Texture = vertexBuffer.EdgeTexture;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallVertices);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallVertices.VertexCount / 3.0f));
|
||||
graphicsDevice.SetVertexBuffer(vertexBuffer.WallEdgeBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(vertexBuffer.WallEdgeBuffer.VertexCount / 3.0f));
|
||||
}
|
||||
|
||||
wallCenterEffect.Texture = level.GenerationParams.WallSprite.Texture;
|
||||
wallEdgeEffect.Texture = level.GenerationParams.WallEdgeSprite.Texture;
|
||||
|
||||
//render non-destructible extra walls
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
var wallList = i == 0 ? level.ExtraWalls : level.UnsyncedExtraWalls;
|
||||
foreach (LevelWall wall in wallList)
|
||||
{
|
||||
if (wall is DestructibleLevelWall) { continue; }
|
||||
//TODO: use LevelWallVertexBuffers for extra walls as well
|
||||
wallCenterEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallCenterEffect.Alpha = wall.Alpha;
|
||||
wallCenterEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallBuffer.VertexCount / 3.0f));
|
||||
|
||||
wallEdgeEffect.World = wall.GetTransform() * transformMatrix;
|
||||
wallEdgeEffect.Alpha = wall.Alpha;
|
||||
wallEdgeEffect.CurrentTechnique.Passes[0].Apply();
|
||||
graphicsDevice.SetVertexBuffer(wall.WallEdgeBuffer);
|
||||
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, (int)Math.Floor(wall.WallEdgeBuffer.VertexCount / 3.0f));
|
||||
}
|
||||
}
|
||||
|
||||
graphicsDevice.RasterizerState = defaultRasterizerState;
|
||||
}
|
||||
|
||||
@@ -383,8 +468,11 @@ namespace Barotrauma
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (wallVertices != null) wallVertices.Dispose();
|
||||
if (bodyVertices != null) bodyVertices.Dispose();
|
||||
foreach (var vertexBuffer in vertexBuffers)
|
||||
{
|
||||
vertexBuffer.Dispose();
|
||||
}
|
||||
vertexBuffers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,55 +2,44 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelWall : IDisposable
|
||||
{
|
||||
private VertexBuffer wallVertices, bodyVertices;
|
||||
public LevelWallVertexBuffer VertexBuffer { get; private set; }
|
||||
|
||||
public VertexBuffer WallVertices
|
||||
{
|
||||
get { return wallVertices; }
|
||||
}
|
||||
public VertexBuffer WallBuffer { get { return VertexBuffer.WallBuffer; } }
|
||||
|
||||
public VertexBuffer BodyVertices
|
||||
{
|
||||
get { return bodyVertices; }
|
||||
}
|
||||
public VertexBuffer WallEdgeBuffer { get { return VertexBuffer.WallEdgeBuffer; } }
|
||||
|
||||
public virtual float Alpha => 1.0f;
|
||||
|
||||
public Matrix GetTransform()
|
||||
{
|
||||
return body.BodyType == BodyType.Static ?
|
||||
Matrix.Identity :
|
||||
Matrix.CreateRotationZ(body.Rotation) *
|
||||
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(body.Position), 0.0f));
|
||||
return Body.FixedRotation ?
|
||||
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(Body.Position), 0.0f)) :
|
||||
Matrix.CreateRotationZ(Body.Rotation) *
|
||||
Matrix.CreateTranslation(new Vector3(ConvertUnits.ToDisplayUnits(Body.Position), 0.0f));
|
||||
}
|
||||
|
||||
public void SetWallVertices(VertexPositionTexture[] vertices, Color color)
|
||||
public void SetWallVertices(VertexPositionTexture[] wallVertices, VertexPositionTexture[] wallEdgeVertices, Texture2D wallTexture, Texture2D edgeTexture, Color color)
|
||||
{
|
||||
wallVertices = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
wallVertices.SetData(LevelRenderer.GetColoredVertices(vertices, color));
|
||||
if (VertexBuffer != null && !VertexBuffer.IsDisposed) { VertexBuffer.Dispose(); }
|
||||
VertexBuffer = new LevelWallVertexBuffer(wallVertices, wallEdgeVertices, wallTexture, edgeTexture, color);
|
||||
}
|
||||
|
||||
public void SetBodyVertices(VertexPositionTexture[] vertices, Color color)
|
||||
public void GenerateVertices()
|
||||
{
|
||||
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);
|
||||
float zCoord = this is DestructibleLevelWall ? Rand.Range(0.9f, 1.0f) : 0.9f;
|
||||
List<VertexPositionTexture> wallVertices = CaveGenerator.GenerateWallVertices(triangles, level.GenerationParams, zCoord);
|
||||
SetWallVertices(
|
||||
wallVertices.ToArray(),
|
||||
CaveGenerator.GenerateWallEdgeVertices(Cells, level, zCoord).ToArray(),
|
||||
level.GenerationParams.WallSprite.Texture,
|
||||
level.GenerationParams.WallEdgeSprite.Texture,
|
||||
color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user