Skip to content

Commit

Permalink
Messing with the damage system.
Browse files Browse the repository at this point in the history
Fixed massive memory usage when an entity was taking fire.
Tidied up some code and remembered how it all worked.
Seperated out the damage being dealt to a component from the damage frames. in the sim.
  • Loading branch information
se5a committed Jan 4, 2024
1 parent 318d158 commit 40d2165
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework.Constraints;
using Pulsar4X.Components;
using Pulsar4X.Orbital;
using Pulsar4X.Datablobs;
using Pulsar4X.DataStructures;
Expand All @@ -11,12 +12,71 @@ namespace Pulsar4X.Engine.Damage
public static class ComponentPlacement
{

/// <summary>
/// this creates a bitmap for a single component.
/// </summary>
/// <param name="componentDesign"></param>
/// <param name="typeID"></param>
/// <returns></returns>
public static RawBmp CreateComponentByteArray(ComponentDesign componentDesign)
{
//var vol = componentDesign.VolumePerUnit * 1000;
var volm3 = componentDesign.VolumePerUnit;
//we convert 3d volume to 2d area at 1px = 1cm resolution
var area = Math.Cbrt(volm3) * 2 * 1000;
var len = Math.Sqrt(area * componentDesign.AspectRatio);
var wid = area / len;


double floatdepth = Math.Pow(componentDesign.AspectRatio, (float)1 / 3);
double CSA = componentDesign.VolumePerUnit / floatdepth;
double floatwidth = Math.Sqrt(CSA) * (double)componentDesign.AspectRatio;
//int depth = (int)floatdepth;
int width = (int)len;
int height = (int)wid;
//int v2d = height * width;
//int volume = (int)volm3;

//if (componentDesign.AspectRatio > 1)
//{
// width = (int)(width / componentDesign.AspectRatio);
// height = (int)(height / componentDesign.AspectRatio);
//}


int imagedepth = 4;
int size = imagedepth * width * height;
int stride = width * imagedepth;

byte[] buffer = new byte[size];

for (int ix = 0; ix < width; ix++)
{
for (int iy = 0; iy < height; iy++)
{
RawBmp.SetPixel(ref buffer, stride, imagedepth, ix, iy, 255, 255,255, 255);
}
}

RawBmp bmp = new RawBmp()
{
ByteArray = buffer,
Stride = stride,
Depth = imagedepth,
Width = width,
Height = height,

};
return bmp;
}


public static RawBmp CreateShipBmp(EntityDamageProfileDB shipProfile)
{
// byte armorID = 255;//shipProfile.Armor.IDCode;
var po = shipProfile.PlacementOrder;

List<(string typeID, RawBmp bmp)> typeBitmaps = shipProfile.TypeBitmaps;
List<(string typeID, RawBmp bmp)> typeBitmaps = shipProfile.IndividualComponentBitmaps;
List<(int width, int height)> partsize = new List<(int width, int height)>();
partsize.Add((1, 1));
int componentWidthNum = 0;
Expand Down
10 changes: 8 additions & 2 deletions Pulsar4X/GameEngine/FeatureSets/DamageComplex/DamageProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static public void Process(Game game, StarSystem starSystem)
/// </summary>
/// <param name="damageableEntity"></param>
/// <param name="damageAmount"></param>
public static List<RawBmp> OnTakingDamage(Entity damageableEntity, DamageFragment damage)
public static void OnTakingDamage(Entity damageableEntity, DamageFragment damageFragment)
{

var db = damageableEntity.GetDataBlob<EntityDamageProfileDB>();
Expand All @@ -44,8 +44,14 @@ public static List<RawBmp> OnTakingDamage(Entity damageableEntity, DamageFragmen
}
//return;
}

var damages = DamageTools.DealDamageSim(db, damageFragment);

return DamageTools.DealDamage(db, damage);
foreach (var damage in damages.damageToComponents)
{
db.ComponentLookupTable[damage.id].HTKRemaining -= damage.damageAmount;
}


/*
if (damageableEntity.HasDataBlob<AsteroidDamageDB>())
Expand Down
86 changes: 15 additions & 71 deletions Pulsar4X/GameEngine/FeatureSets/DamageComplex/DamageTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,68 +152,14 @@ public static DamageResist FromColor(Color color)
byte id = color.R;
return DamageResistsLookupTable[id];
}

public static RawBmp CreateComponentByteArray(ComponentDesign componentDesign, byte typeID)
{

//var vol = componentDesign.VolumePerUnit * 1000;
var volm3 = componentDesign.VolumePerUnit;
//we convert 3d volume to 2d area at 1px = 1cm resolution
var area = Math.Cbrt(volm3) * 2 * 1000;
var len = Math.Sqrt(area * componentDesign.AspectRatio);
var wid = area / len;


double floatdepth = Math.Pow(componentDesign.AspectRatio, (float)1 / 3);
double CSA = componentDesign.VolumePerUnit / floatdepth;
double floatwidth = Math.Sqrt(CSA) * (double)componentDesign.AspectRatio;
//int depth = (int)floatdepth;
int width = (int)len;
int height = (int)wid;
//int v2d = height * width;
//int volume = (int)volm3;

//if (componentDesign.AspectRatio > 1)
//{
// width = (int)(width / componentDesign.AspectRatio);
// height = (int)(height / componentDesign.AspectRatio);
//}


int imagedepth = 4;
int size = imagedepth * width * height;
int stride = width * imagedepth;

byte[] buffer = new byte[size];

for (int ix = 0; ix < width; ix++)
{
for (int iy = 0; iy < height; iy++)
{
byte c = typeID;
RawBmp.SetPixel(ref buffer, stride, imagedepth, ix, iy, 255, 255,c, 255);
}
}

RawBmp bmp = new RawBmp()
{
ByteArray = buffer,
Stride = stride,
Depth = imagedepth,
Width = width,
Height = height,

};
return bmp;
}


public static List<RawBmp> DealDamage(EntityDamageProfileDB damageProfile, DamageFragment damage)

public static (List<(byte id, int damageAmount)> damageToComponents, List<RawBmp> damageFrames) DealDamageSim(EntityDamageProfileDB damageProfile, DamageFragment damage)
{
RawBmp shipDamageProfile = damageProfile.DamageProfile;

List<RawBmp> damageFrames = new List<RawBmp>();

List<(byte id, int damageAmount)> damageToComponents = new List<(byte, int)>();

var fragmentMass = damage.Mass;
(int x, int y) dpos = (0, 0);
var dvel = damage.Velocity;
Expand All @@ -223,9 +169,7 @@ public static List<RawBmp> DealDamage(EntityDamageProfileDB damageProfile, Damag
var pixelscale = 0.01;
double startMomentum = damage.Momentum;
double momentum = startMomentum;




//We need to figure out where the incoming damage intersects with the ship's damage profile "image"
var pwidth = damageProfile.DamageProfile.Width;
var pwIndex = pwidth - 1;//zero based arrays
Expand Down Expand Up @@ -312,26 +256,26 @@ public static List<RawBmp> DealDamage(EntityDamageProfileDB damageProfile, Damag
if (momentum > 0)
{
px = ( px.r, px.g, px.b, 0);
damageProfile.ComponentLookupTable[px.g].HTKRemaining -= 1;
damageToComponents.Add((px.g, 1));
}

}


//this is the damage fragment
thisFrame.SetPixel(dpos.x, dpos.y, byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)momentum);

//this is the entity being damaged.
thisFrame.SetPixel(savedpxloc.x, savedpxloc.y, savedpx.r, savedpx.g, savedpx.b, savedpx.a);
damageFrames.Add(thisFrame);
savedpxloc = dpos;
savedpx = px;



double dt = 1 / dvel.Length();
pos.X += dvel.X * dt;
pos.Y += dvel.Y * dt;
dpos.x = Convert.ToInt32(pos.X);
dpos.y = Convert.ToInt32(pos.Y);
}


Buffer.BlockCopy(damageFrames.Last().ByteArray, 0, byteArray, 0, shipDamageProfile.ByteArray.Length);
var finalFrame = new RawBmp()
{
Expand All @@ -342,11 +286,11 @@ public static List<RawBmp> DealDamage(EntityDamageProfileDB damageProfile, Damag
Stride = shipDamageProfile.Stride
};
finalFrame.SetPixel(savedpxloc.x, savedpxloc.y, savedpx.r, savedpx.g, savedpx.b, savedpx.a);
damageProfile.DamageSlides.Add(damageFrames);
//damageProfile.DamageSlides.Add(damageFrames);

damageProfile.DamageEvents.Add(damage);
damageProfile.DamageProfile = finalFrame;
return damageFrames;
return (damageToComponents, damageFrames);
}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,24 @@ public class EntityDamageProfileDB : BaseDataBlob
/// except we're only storing the guid here.
/// </summary>
public List<(string id, int count)> PlacementOrder;


/// <summary>
/// this allows us to encode the green value of the ShipDamageProfile to a component instance.
/// it's really a single dimentional version of the ship design's List<(ComponentDesign design, int count)> Components
/// it's really a single dimensional version of the ship design's List<(ComponentDesign design, int count)> Components
/// </summary>
public List<ComponentInstance> ComponentLookupTable = new List<ComponentInstance>();

public List<(string, RawBmp)> TypeBitmaps;
public List<ComponentInstance> ComponentLookupTable = new List<ComponentInstance>(255);
public List<(string id, RawBmp bmp)> IndividualComponentBitmaps = new List<(string, RawBmp)>(255);

//public List<(int index, int size)> Bulkheads; maybe connect armor/skin at these points.
//if we get around to doing technical stuff like being able to break a ship into two pieces,
//and having longditudinal structural parts...


public RawBmp DamageProfile;
public List<List<RawBmp>> DamageSlides = new List<List<RawBmp>>();


public List<DamageFragment> DamageEvents = new List<DamageFragment>();


[JsonConstructor]
private EntityDamageProfileDB()
{
Expand All @@ -64,7 +64,7 @@ public EntityDamageProfileDB(List<(ComponentDesign component, int count)> compon

private void Init(List<(ComponentDesign component, int count)> components, (ArmorBlueprint armorSD, float thickness) armor)
{
var typeBitmap = new List<(string, RawBmp)>();
var componentBitmaps = new List<(string, RawBmp)>(255);
var placementOrder = new List<(string, int)>();
var instances = new List<ComponentInstance>();

Expand All @@ -81,8 +81,8 @@ private void Init(List<(ComponentDesign component, int count)> components, (Armo
ArmorVertex.Add(((int)len,(int)(wid * (componenttype.count) * 0.5)));


RawBmp compBmp = DamageTools.CreateComponentByteArray(componenttype.component, (byte)typeBitmap.Count);
typeBitmap.Add((typeGuid, compBmp));
RawBmp compBmp = ComponentPlacement.CreateComponentByteArray(componenttype.component);
componentBitmaps.Add((typeGuid, compBmp));


placementOrder.Add((typeGuid, componenttype.count));
Expand All @@ -95,7 +95,7 @@ private void Init(List<(ComponentDesign component, int count)> components, (Armo


PlacementOrder = placementOrder;
TypeBitmaps = typeBitmap;
IndividualComponentBitmaps = componentBitmaps;
Armor = armor;
ComponentLookupTable = instances;
DamageProfile = ComponentPlacement.CreateShipBmp(this);
Expand Down Expand Up @@ -241,7 +241,7 @@ public EntityDamageProfileDB(EntityDamageProfileDB db )
Armor = db.Armor;
ArmorVertex = db.ArmorVertex;
PlacementOrder = db.PlacementOrder;
TypeBitmaps = db.TypeBitmaps;
IndividualComponentBitmaps = db.IndividualComponentBitmaps;
DamageProfile = db.DamageProfile;
}

Expand Down
43 changes: 43 additions & 0 deletions Pulsar4X/GameEngine/FeatureSets/DamageComplex/HowDamageWorks.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

Damage system is very much work in progress.
This file is a quick note on how it's intended to work.
this note may be incomplete and out of date at any point.

The vision for damage was to have some sort of falling sands physics model (without the "falling" and gravity)
the simulation would take a damage fragment with a given mass and velocity and sim it hitting the different materials of the ship.

it does this by using a data array for the ship which is layed out simular to a classic bitmap.
(see RawBmp class).
the different depths (or colours in a classic bitmap) provide data on the material type the damage fragment is hitting.
r : maps to a damage resistance table. currently only used by armor, (components default to 255 which is stainless steel)
and is set in the ui damage viewer (eek! obv was tempory wip for quick test setup.)
this has a byte ID (red) material hitpoints, and material density)
g : maps to the specific component instance. (ships currently will only be able to have 255 components max.)
b : currently unused
a : is the health of the material at this point.

An undamaged ship is suposed to have/share a "DamageProfile" of it's design class to save memory.
though I don't think this is currently the case.
once a ship becomes damaged it's damage profile will be the last frame of the sim.

Damage fragments are stored in the EntityDamageProfileDB as a list, so the ui can re-create the frames of the sim for the player.
(without storing the frames, as that very quickly increases in memory).

The 3d volume of the ship is converted into a 2d plane (see DamageTools.CreateComponentByteArray())
Currently 1px = 1cm

Intent at some point is to have the damage profile bitmap be a recursivly scaling data array.
eg a large undamaged ship might have a pixel = 1m, but as it takes damage, the pixels that are damaged
get subdivided into smaller scales.
my last attempt at trying to conceptualise the mechanics of how to store this data didn't get far.

although the ui uses this bitmap to display the ship layout in the ship design, and also to display the damage being dealt,
it's primarily a way to sim the damage, rather than eye candy.

components currently have a bitmap too which is probibly unneccisary.
I don't think it's really used other than to get soemthing for the ship damage profile to copy.
though maybe having something setup that can deterministicaly create component images would be nifty?

DamageViewer in the ui is currently mostly a debugging/visial developing tool rather than what the player is supposed to see,
hence a bunch of code to sim firing different weapons at it and some stuff which should be in the engine.

Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public static void BeamMovePhysics(BeamInfoDB beamInfo, int seconds)
Momentum = (float)(UniversalConstants.Science.PlankConstant * freq),
Length = (float)(beamInfo.Positions[0] - beamInfo.Positions[1]).Length(),
};
var slides = DamageProcessor.OnTakingDamage(beamInfo.TargetEntity, damage);
DamageProcessor.OnTakingDamage(beamInfo.TargetEntity, damage);
beamInfo.OwningEntity.Destroy();
}
else
Expand Down
1 change: 0 additions & 1 deletion Pulsar4X/GameEngine/GameEngine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Engine\Damage" />
<Folder Include="FeatureSets\DamageSimple" />
</ItemGroup>
</Project>
Loading

0 comments on commit 40d2165

Please sign in to comment.