A game where you get to play as a slime, made with Godot.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

129 lines
4.3 KiB

using Dictionary = Godot.Collections.Dictionary;
public readonly record struct TilePos(int X, int Y)
{
public TilePos GetNeighbor(Side side)
=> side switch {
Side.Left => new(X - 1, Y),
Side.Top => new(X, Y - 1),
Side.Right => new(X + 1, Y),
Side.Bottom => new(X, Y + 1),
_ => throw new ArgumentException($"Invalid Side value '{side}'", nameof(side)),
};
public TilePos GetNeighbor(Corner corner)
=> corner switch {
Corner.TopLeft => new(X - 1, Y - 1),
Corner.TopRight => new(X + 1, Y - 1),
Corner.BottomRight => new(X + 1, Y + 1),
Corner.BottomLeft => new(X - 1, Y + 1),
_ => throw new ArgumentException($"Invalid Corner value '{corner}'", nameof(corner)),
};
public static TilePos From(Vector2I value) => new(value.X, value.Y);
public Vector2I ToVector2I() => new(X, Y);
}
public struct Tile
{
public Corners<float> Height;
// TODO: Replace with enum or something more permanent?
public int TexturePrimary;
public int TextureSecondary;
public int TextureBlend;
public static Tile FromDictionary(Dictionary dict)
{
if (dict == null) return default;
float topLeft, topRight, bottomRight, bottomLeft;
switch (dict["heights"]) {
case { VariantType: Variant.Type.Float } variant:
var height = (float)variant;
(topLeft, topRight, bottomRight, bottomLeft) = (height, height, height, height);
break;
case { VariantType: Variant.Type.PackedFloat32Array } variant:
var heights = (float[])variant;
(topLeft, topRight, bottomRight, bottomLeft) = (heights[0], heights[1], heights[2], heights[3]);
break;
default: throw new Exception("Invalid variant type");
};
int texturePrimary, textureSecondary, textureBlend;
switch (dict["texture"]) {
case { VariantType: Variant.Type.Int } variant:
var texture = (int)variant;
(texturePrimary, textureSecondary, textureBlend) = (texture, 0, 0);
break;
case { VariantType: Variant.Type.PackedInt32Array } variant:
var textures = (int[])variant;
(texturePrimary, textureSecondary, textureBlend) = (textures[0], textures[1], textures[2]);
break;
default: throw new Exception("Invalid variant type");
};
return new(){
Height = new(topLeft, topRight, bottomRight, bottomLeft),
TexturePrimary = texturePrimary,
TextureSecondary = textureSecondary,
TextureBlend = textureBlend,
};
}
public readonly Dictionary ToDictionary()
{
if (Height.IsZeroApprox() && (TexturePrimary == 0) && (TextureBlend == 0))
return null;
return new(){
["heights"] = Height.IsEqualApprox() ? Height.TopLeft : new[]{ Height.TopLeft, Height.TopRight, Height.BottomRight, Height.BottomLeft },
["texture"] = (TextureBlend == 0) ? TexturePrimary : new[]{ TexturePrimary, TextureSecondary, TextureBlend },
};
}
}
public struct Corners<T>(T topLeft, T topRight, T bottomRight, T bottomLeft)
{
public T TopLeft = topLeft;
public T TopRight = topRight;
public T BottomRight = bottomRight;
public T BottomLeft = bottomLeft;
public T this[Corner corner] {
readonly get => corner switch {
Corner.TopLeft => TopLeft,
Corner.TopRight => TopRight,
Corner.BottomRight => BottomRight,
Corner.BottomLeft => BottomLeft,
_ => throw new ArgumentException($"Invalid Corner value '{corner}'", nameof(corner)),
};
set { switch (corner) {
case Corner.TopLeft : TopLeft = value; break;
case Corner.TopRight : TopRight = value; break;
case Corner.BottomRight : BottomRight = value; break;
case Corner.BottomLeft : BottomLeft = value; break;
default: throw new ArgumentException($"Invalid Corner value '{corner}'", nameof(corner));
} }
}
}
public static class CornersExtensions
{
public static void Adjust(this ref Corners<float> self, float amount)
{
self.TopLeft += amount;
self.TopRight += amount;
self.BottomRight += amount;
self.BottomLeft += amount;
}
public static bool IsZeroApprox(this Corners<float> self)
=> Mathf.IsZeroApprox(self.TopLeft ) && Mathf.IsZeroApprox(self.TopRight )
&& Mathf.IsZeroApprox(self.BottomRight) && Mathf.IsZeroApprox(self.BottomLeft);
public static bool IsEqualApprox(this Corners<float> self)
=> Mathf.IsEqualApprox(self.TopLeft, self.TopRight )
&& Mathf.IsEqualApprox(self.TopLeft, self.BottomRight)
&& Mathf.IsEqualApprox(self.TopLeft, self.BottomLeft );
}