768 lines
22 KiB
C#
768 lines
22 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Diagnostics.CodeAnalysis;
|
||
using Godot;
|
||
using Godot.Collections;
|
||
using RobotAndDonkey.Game;
|
||
using RobotAndDonkey.Game.Board;
|
||
using RobotAndDonkey.Game.Modifiers;
|
||
using RobotAndDonkey.Game.Pois;
|
||
using RobotAndDonkey.Game.Utils;
|
||
|
||
public partial class HexBoard3D : Node3D
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
if (m_Board == null)
|
||
{
|
||
var random = new SRandom(241);
|
||
var board = Board.Generate(ref random, EDifficulty.Easy);
|
||
Configure(board);
|
||
}
|
||
}
|
||
|
||
public void Configure(Cell cell)
|
||
{
|
||
m_CellByHex[cell.Hex] = cell;
|
||
RebuildCellVisual(cell);
|
||
}
|
||
|
||
public void ModifyCell(Cell cell, EModifierId modifier, Tween tween)
|
||
{
|
||
m_CellByHex[cell.Hex] = cell;
|
||
|
||
tween.TweenCallback(Callable.From(() => RebuildCellVisual(cell)));
|
||
tween.Parallel();
|
||
SpawnCellUpdateVfx(cell, tween);
|
||
tween.Parallel().TweenCallback(Callable.From(() => Main.Instance.Music.Play(modifier)));
|
||
tween.TweenInterval(TotalAnimationDuration);
|
||
}
|
||
|
||
public void ModifyPoi(Cell cell, Poi poi, Tween tween)
|
||
{
|
||
m_CellByHex[cell.Hex] = cell;
|
||
|
||
tween.TweenCallback(Callable.From(() => RebuildCellVisual(cell)));
|
||
tween.Parallel();
|
||
if (poi != null)
|
||
{
|
||
tween.Parallel().TweenCallback(Callable.From(() => { Main.Instance.Music.Play(poi); }));
|
||
tween.TweenInterval(poi is Donkey ? 2.0 : TotalAnimationDuration);
|
||
}
|
||
SpawnCellUpdateVfx(cell, tween);
|
||
}
|
||
|
||
public void Configure(Board board)
|
||
{
|
||
var boardChanged = !ReferenceEquals(m_Board, board);
|
||
m_Board = board;
|
||
|
||
if (m_Board == null)
|
||
{
|
||
ClearBoard();
|
||
return;
|
||
}
|
||
|
||
if (boardChanged)
|
||
BuildBoard();
|
||
}
|
||
|
||
private void BuildBoard()
|
||
{
|
||
ClearBoard();
|
||
|
||
if (m_Board == null || m_Board.Cells.IsDefaultOrEmpty)
|
||
{
|
||
BoardBounds = new();
|
||
return;
|
||
}
|
||
|
||
m_CellByHex.Clear();
|
||
m_CellNodes.Clear();
|
||
|
||
var minX = float.MaxValue;
|
||
var maxX = float.MinValue;
|
||
var minZ = float.MaxValue;
|
||
var maxZ = float.MinValue;
|
||
var hasAnyCell = false;
|
||
|
||
foreach (var cell in m_Board.Cells)
|
||
{
|
||
m_CellByHex[cell.Hex] = cell;
|
||
|
||
var world = cell.Hex.ToWorld();
|
||
BuildCellNode(cell);
|
||
|
||
var x = world.X;
|
||
var z = world.Y;
|
||
|
||
if (x < minX)
|
||
minX = x;
|
||
if (x > maxX)
|
||
maxX = x;
|
||
if (z < minZ)
|
||
minZ = z;
|
||
if (z > maxZ)
|
||
maxZ = z;
|
||
hasAnyCell = true;
|
||
}
|
||
|
||
if (hasAnyCell)
|
||
BoardBounds = new(new(minX, minZ), new(maxX - minX, maxZ - minZ));
|
||
else
|
||
BoardBounds = new();
|
||
|
||
CreateHighlightMesh();
|
||
CreateSelectedMesh();
|
||
}
|
||
|
||
private void ClearBoard()
|
||
{
|
||
foreach (var child in GetChildren())
|
||
child.QueueFree();
|
||
|
||
m_PoiSprites.Clear();
|
||
m_AvatarSprites.Clear();
|
||
m_DonkeySprites.Clear();
|
||
m_CellByHex.Clear();
|
||
m_CellNodes.Clear();
|
||
|
||
m_HighlightInstance = null;
|
||
m_SelectedInstance = null;
|
||
|
||
HighlightedCell = null;
|
||
SelectedCell = null;
|
||
}
|
||
|
||
public override void _Process(double delta)
|
||
{
|
||
var camera = GetViewport()?.GetCamera3D();
|
||
if (camera == null)
|
||
return;
|
||
|
||
var camPos = camera.GlobalPosition;
|
||
|
||
foreach (var sprite in m_PoiSprites)
|
||
{
|
||
if (!IsInstanceValid(sprite))
|
||
continue;
|
||
|
||
var pos = sprite.GlobalPosition;
|
||
var target = new Vector3(camPos.X, pos.Y, camPos.Z);
|
||
sprite.LookAtFromPosition(sprite.GlobalPosition, target, Vector3.Up, true);
|
||
}
|
||
|
||
if (!m_UseMouseHighlight)
|
||
UpdateHighlight(camera);
|
||
}
|
||
|
||
public override void _UnhandledInput(InputEvent @event)
|
||
{
|
||
if (Input.IsActionJustPressed("cell_select") && HighlightedCell != null)
|
||
SelectCell(HighlightedCell);
|
||
|
||
switch (@event)
|
||
{
|
||
case InputEventMouseMotion:
|
||
case InputEventMouseButton:
|
||
{
|
||
m_UseMouseHighlight = true;
|
||
var camera = GetViewport()?.GetCamera3D();
|
||
if (camera != null)
|
||
UpdateHighlight(camera);
|
||
break;
|
||
}
|
||
|
||
case InputEventJoypadMotion:
|
||
case InputEventJoypadButton:
|
||
{
|
||
m_UseMouseHighlight = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
private void CreateHighlightMesh()
|
||
{
|
||
if (m_HighlightInstance != null)
|
||
return;
|
||
|
||
m_HighlightInstance = new()
|
||
{
|
||
Mesh = m_HexMesh,
|
||
Name = "HighlightHex",
|
||
Visible = false
|
||
};
|
||
|
||
if (HighlightMaterial != null)
|
||
m_HighlightInstance.MaterialOverride = HighlightMaterial;
|
||
else
|
||
{
|
||
var mat = new StandardMaterial3D
|
||
{
|
||
ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded,
|
||
Transparency = BaseMaterial3D.TransparencyEnum.Alpha,
|
||
AlbedoColor = new(1f, 1f, 1f, 0.4f),
|
||
NoDepthTest = true
|
||
};
|
||
m_HighlightInstance.MaterialOverride = mat;
|
||
}
|
||
|
||
AddChild(m_HighlightInstance);
|
||
}
|
||
|
||
[MemberNotNull(nameof(m_SelectedInstance))]
|
||
private void CreateSelectedMesh()
|
||
{
|
||
if (m_SelectedInstance != null)
|
||
return;
|
||
|
||
m_SelectedInstance = new()
|
||
{
|
||
Mesh = m_HexMesh,
|
||
Name = "SelectedHex",
|
||
Visible = false
|
||
};
|
||
|
||
if (SelectedMaterial != null)
|
||
m_SelectedInstance.MaterialOverride = SelectedMaterial;
|
||
else
|
||
{
|
||
var mat = new StandardMaterial3D
|
||
{
|
||
ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded,
|
||
Transparency = BaseMaterial3D.TransparencyEnum.Alpha,
|
||
AlbedoColor = new(1f, 1f, 1f, 0.6f),
|
||
NoDepthTest = true
|
||
};
|
||
m_SelectedInstance.MaterialOverride = mat;
|
||
}
|
||
|
||
AddChild(m_SelectedInstance);
|
||
}
|
||
|
||
private void UpdateHighlight(Camera3D camera)
|
||
{
|
||
if (m_Board == null || m_Board.Cells.IsDefaultOrEmpty)
|
||
return;
|
||
|
||
var viewport = GetViewport();
|
||
if (viewport == null)
|
||
return;
|
||
|
||
Vector2 screenPos;
|
||
if (m_UseMouseHighlight)
|
||
screenPos = viewport.GetMousePosition();
|
||
else
|
||
{
|
||
var rect = viewport.GetVisibleRect();
|
||
screenPos = rect.Size * 0.5f;
|
||
}
|
||
|
||
var origin = camera.ProjectRayOrigin(screenPos);
|
||
var dir = camera.ProjectRayNormal(screenPos);
|
||
|
||
if (Mathf.Abs(dir.Y) < 0.0001f)
|
||
{
|
||
HideHighlight();
|
||
return;
|
||
}
|
||
|
||
var t = -origin.Y / dir.Y;
|
||
if (t < 0)
|
||
{
|
||
HideHighlight();
|
||
return;
|
||
}
|
||
|
||
var hit = origin + dir * t;
|
||
var hex = Hex.FromWorld(new(hit.X, hit.Z));
|
||
|
||
if (!m_CellByHex.TryGetValue(hex, out var cell))
|
||
{
|
||
HideHighlight();
|
||
return;
|
||
}
|
||
|
||
if (HighlightedCell != null && HighlightedCell.Hex.Equals(hex))
|
||
return;
|
||
|
||
HighlightedCell = cell;
|
||
|
||
if (m_HighlightInstance != null)
|
||
{
|
||
var world = cell.Hex.ToWorld();
|
||
var pos = new Vector3(world.X, HighlightHeight, world.Y);
|
||
m_HighlightInstance.Transform = new(Basis.Identity, pos);
|
||
m_HighlightInstance.Visible = true;
|
||
}
|
||
}
|
||
|
||
private void SelectCell(Cell cell)
|
||
{
|
||
if (cell == null)
|
||
return;
|
||
|
||
SelectedCell = cell;
|
||
|
||
if (m_SelectedInstance == null)
|
||
CreateSelectedMesh();
|
||
|
||
var world = cell.Hex.ToWorld();
|
||
var pos = new Vector3(world.X, SelectedHeight, world.Y);
|
||
m_SelectedInstance.Transform = new(Basis.Identity, pos);
|
||
m_SelectedInstance.Visible = true;
|
||
|
||
Tooltip.Instance?.Describe(cell);
|
||
}
|
||
|
||
private void HideHighlight()
|
||
{
|
||
HighlightedCell = null;
|
||
if (m_HighlightInstance != null)
|
||
m_HighlightInstance.Visible = false;
|
||
}
|
||
|
||
private void BuildCellNode(Cell cell)
|
||
{
|
||
var hex = cell.Hex;
|
||
|
||
var cellNode = new Node3D { Name = $"Cell_{hex}" };
|
||
|
||
cellNode.Transform = BuildCellTransform(cell);
|
||
|
||
var meshInstance = new MeshInstance3D
|
||
{
|
||
Mesh = m_HexMesh,
|
||
Name = "HexMesh"
|
||
};
|
||
|
||
var mat = GetMaterialForType(cell.Type);
|
||
if (mat != null)
|
||
meshInstance.MaterialOverride = mat;
|
||
|
||
cellNode.AddChild(meshInstance);
|
||
|
||
if (DebuffScene != null)
|
||
{
|
||
foreach (var modifier in cell.Modifiers)
|
||
{
|
||
if (modifier is not UnreliableModifierBase && modifier is not CorruptModifierBase)
|
||
continue;
|
||
|
||
if (modifier.DebuffSources.Count > 0)
|
||
continue;
|
||
|
||
var area = DebuffScene.Instantiate<CorruptionArea>();
|
||
area.Color = modifier is UnreliableModifierBase ? InterferenceColor : CorruptColor;
|
||
area.Position = new(0f, 0.1f, 0f);
|
||
cellNode.AddChild(area);
|
||
}
|
||
}
|
||
|
||
if (cell.Poi is not null)
|
||
{
|
||
var (tex, pivot) = GetTextureAndPivotForPoi(cell.Poi);
|
||
if (tex != null)
|
||
{
|
||
var sprite = new Sprite3D
|
||
{
|
||
Texture = tex,
|
||
Billboard = BaseMaterial3D.BillboardModeEnum.Enabled,
|
||
Centered = true,
|
||
NoDepthTest = true,
|
||
PixelSize = 0.01f,
|
||
Name = $"{cell.Poi.GetType().Name}_Sprite"
|
||
};
|
||
|
||
ApplyPivot(sprite, pivot);
|
||
sprite.Position = new(0f, PoiHeight, 0f);
|
||
|
||
cellNode.AddChild(sprite);
|
||
m_PoiSprites.Add(sprite);
|
||
|
||
if (cell.Poi is Avatar avatar)
|
||
m_AvatarSprites[avatar] = sprite;
|
||
|
||
if (cell.Poi is Donkey donkey)
|
||
m_DonkeySprites[donkey] = sprite;
|
||
}
|
||
|
||
var infoNode = BuildPoiInfoNode(cell);
|
||
if (infoNode != null)
|
||
{
|
||
infoNode.Position = new(0f, PoiInfoHeight, 0f);
|
||
cellNode.AddChild(infoNode);
|
||
}
|
||
}
|
||
|
||
AddChild(cellNode);
|
||
m_CellNodes[hex] = cellNode;
|
||
}
|
||
|
||
private void RebuildCellVisual(Cell cell)
|
||
{
|
||
if (m_CellNodes.TryGetValue(cell.Hex, out var oldNode) && IsInstanceValid(oldNode))
|
||
oldNode.QueueFree();
|
||
|
||
BuildCellNode(cell);
|
||
}
|
||
|
||
private Transform3D BuildCellTransform(Cell cell)
|
||
{
|
||
var world = cell.Hex.ToWorld();
|
||
var position = new Vector3(world.X, 0f, world.Y);
|
||
var rotation = Basis.Rotated(new(0, 1, 0), MathF.PI * (60 * m_CameraRotationIndex) / 180f);
|
||
return new(rotation, position);
|
||
}
|
||
|
||
private void UpdateCellTransforms()
|
||
{
|
||
if (m_Board == null || m_Board.Cells.IsDefaultOrEmpty)
|
||
return;
|
||
|
||
foreach (var cell in m_Board.Cells)
|
||
{
|
||
if (!m_CellNodes.TryGetValue(cell.Hex, out var node) || !IsInstanceValid(node))
|
||
continue;
|
||
|
||
node.Transform = BuildCellTransform(cell);
|
||
}
|
||
}
|
||
|
||
private Material GetMaterialForType(ECellType type)
|
||
{
|
||
if (CellTypeMaterials != null && CellTypeMaterials.Count > (int)type && CellTypeMaterials[(int)type] != null)
|
||
return CellTypeMaterials[(int)type];
|
||
|
||
var mat = new StandardMaterial3D
|
||
{
|
||
ShadingMode = BaseMaterial3D.ShadingModeEnum.PerPixel,
|
||
};
|
||
return mat;
|
||
}
|
||
|
||
private (Texture2D texture, Vector2 pivot) GetTextureAndPivotForPoi(Poi poi)
|
||
{
|
||
return poi switch
|
||
{
|
||
Crate => (CrateTexture, CratePivot),
|
||
Shed => (ShedTexture, ShedPivot),
|
||
Tower => (TowerTexture, TowerPivot),
|
||
Donkey d => (GetDonkeyTexture(d.Direction), DonkeyPivot),
|
||
Avatar a => (GetAvatarTexture(a.Direction), AvatarPivot),
|
||
_ => (null, default)
|
||
};
|
||
}
|
||
|
||
private Node3D BuildPoiInfoNode(Cell cell)
|
||
{
|
||
if (cell.Poi is null)
|
||
return null;
|
||
|
||
switch (cell.Poi)
|
||
{
|
||
case Crate crate:
|
||
{
|
||
if (crate.Amount > 0)
|
||
{
|
||
var label = new Label3D
|
||
{
|
||
Text = crate.Amount.ToString(),
|
||
FontSize = 72,
|
||
Name = "Crate_Amount",
|
||
Billboard = BaseMaterial3D.BillboardModeEnum.Enabled
|
||
};
|
||
return label;
|
||
}
|
||
|
||
var check = CreateCheckmarkSprite();
|
||
if (check != null)
|
||
check.Name = "Crate_Checkmark";
|
||
return check;
|
||
}
|
||
|
||
case Shed shed:
|
||
{
|
||
var remaining = shed.Remaining;
|
||
if (remaining > 0)
|
||
{
|
||
var label = new Label3D
|
||
{
|
||
Text = $"-{remaining}",
|
||
FontSize = 72,
|
||
Name = "Shed_Remaining",
|
||
Billboard = BaseMaterial3D.BillboardModeEnum.Enabled
|
||
};
|
||
return label;
|
||
}
|
||
|
||
var check = CreateCheckmarkSprite();
|
||
if (check != null)
|
||
check.Name = "Shed_Checkmark";
|
||
return check;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
private Sprite3D CreateCheckmarkSprite()
|
||
{
|
||
if (CheckmarkTexture == null)
|
||
return null;
|
||
|
||
var sprite = new Sprite3D
|
||
{
|
||
Texture = CheckmarkTexture,
|
||
Billboard = BaseMaterial3D.BillboardModeEnum.Enabled,
|
||
Centered = true,
|
||
NoDepthTest = true,
|
||
PixelSize = 0.01f,
|
||
Name = "CheckmarkSprite"
|
||
};
|
||
|
||
return sprite;
|
||
}
|
||
|
||
private void ApplyPivot(Sprite3D sprite, Vector2 pivotNormalized)
|
||
{
|
||
if (sprite.Texture is not { } tex)
|
||
return;
|
||
|
||
var sizeI = tex.GetSize();
|
||
var size = new Vector2(sizeI.X, sizeI.Y);
|
||
|
||
var pivotFromCenter = pivotNormalized - new Vector2(0.5f, 0.5f);
|
||
var offset = pivotFromCenter * size;
|
||
|
||
sprite.Offset = offset;
|
||
}
|
||
|
||
public void SetCameraRotationIndex(int rotationIndex)
|
||
{
|
||
rotationIndex = Mathf.PosMod(rotationIndex, 6);
|
||
if (m_CameraRotationIndex == rotationIndex)
|
||
return;
|
||
|
||
m_CameraRotationIndex = rotationIndex;
|
||
|
||
UpdateCellTransforms();
|
||
|
||
foreach (var kvp in m_AvatarSprites)
|
||
{
|
||
var avatar = kvp.Key;
|
||
var sprite = kvp.Value;
|
||
if (!IsInstanceValid(sprite))
|
||
continue;
|
||
|
||
sprite.Texture = GetAvatarTexture(avatar.Direction);
|
||
ApplyPivot(sprite, AvatarPivot);
|
||
}
|
||
|
||
foreach (var kvp in m_DonkeySprites)
|
||
{
|
||
var donkey = kvp.Key;
|
||
var sprite = kvp.Value;
|
||
if (!IsInstanceValid(sprite))
|
||
continue;
|
||
|
||
sprite.Texture = GetDonkeyTexture(donkey.Direction);
|
||
ApplyPivot(sprite, DonkeyPivot);
|
||
}
|
||
}
|
||
|
||
private Texture2D GetAvatarTexture(EDirection worldDirection)
|
||
{
|
||
var dirIndex = (int)worldDirection;
|
||
var relative = Mathf.PosMod(dirIndex - m_CameraRotationIndex, 6);
|
||
|
||
return (EDirection)relative switch
|
||
{
|
||
EDirection.Right => AvatarRightTexture,
|
||
EDirection.TopRight => AvatarTopRightTexture,
|
||
EDirection.TopLeft => AvatarTopLeftTexture,
|
||
EDirection.Left => AvatarLeftTexture,
|
||
EDirection.BottomLeft => AvatarBottomLeftTexture,
|
||
EDirection.BottomRight => AvatarBottomRightTexture,
|
||
_ => throw new UnreachableException()
|
||
};
|
||
}
|
||
|
||
private Texture2D GetDonkeyTexture(EDirection worldDirection)
|
||
{
|
||
var dirIndex = (int)worldDirection;
|
||
var relative = Mathf.PosMod(dirIndex - m_CameraRotationIndex, 6);
|
||
|
||
return (EDirection)relative switch
|
||
{
|
||
EDirection.Right => DonkeyRightTexture,
|
||
EDirection.TopRight => DonkeyTopRightTexture,
|
||
EDirection.TopLeft => DonkeyTopLeftTexture,
|
||
EDirection.Left => DonkeyLeftTexture,
|
||
EDirection.BottomLeft => DonkeyBottomLeftTexture,
|
||
EDirection.BottomRight => DonkeyBottomRightTexture,
|
||
_ => throw new UnreachableException()
|
||
};
|
||
}
|
||
|
||
private void SpawnCellUpdateVfx(Cell cell, Tween tween)
|
||
{
|
||
var mesh1 = new MeshInstance3D() { Mesh = m_HexMesh, Visible = false };
|
||
var mesh2 = new MeshInstance3D() { Mesh = m_HexMesh, Visible = false };
|
||
|
||
var mat1 = new StandardMaterial3D
|
||
{
|
||
ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded,
|
||
Transparency = BaseMaterial3D.TransparencyEnum.Alpha,
|
||
AlbedoColor = new(1f, 1f, 1f, 0.4f),
|
||
NoDepthTest = true
|
||
};
|
||
|
||
var mat2 = new StandardMaterial3D
|
||
{
|
||
ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded,
|
||
Transparency = BaseMaterial3D.TransparencyEnum.Alpha,
|
||
AlbedoColor = new(1f, 1f, 1f, 0.4f),
|
||
NoDepthTest = true
|
||
};
|
||
|
||
mesh1.MaterialOverride = mat1;
|
||
mesh2.MaterialOverride = mat2;
|
||
|
||
var world = cell.Hex.ToWorld();
|
||
var position = new Vector3(world.X, 0.1f, world.Y);
|
||
mesh1.Position = position;
|
||
mesh2.Position = position;
|
||
|
||
tween.TweenCallback(Callable.From(() =>
|
||
{
|
||
AddChild(mesh1);
|
||
AddChild(mesh2);
|
||
}));
|
||
tween.TweenProperty(mesh1, "scale", new Vector3(2, 1, 2), TotalAnimationDuration);
|
||
tween.Parallel().TweenProperty(mesh2, "position", position + new Vector3(0, 1, 0), TotalAnimationDuration);
|
||
tween.Parallel().TweenProperty(mat1, "albedo_color", new Color(1, 1, 1, 0.0f), TotalAnimationDuration);
|
||
tween.Parallel().TweenProperty(mat2, "albedo_color", new Color(1, 1, 1, 0.0f), TotalAnimationDuration);
|
||
tween.TweenCallback(Callable.From(() =>
|
||
{
|
||
mesh1.QueueFree();
|
||
mesh2.QueueFree();
|
||
}));
|
||
}
|
||
|
||
|
||
[ExportGroup("POI Pivots (normalized, 0–1)")]
|
||
[Export]
|
||
public Vector2 CratePivot { get; set; } = new(0.5f, 1.0f);
|
||
|
||
[Export]
|
||
public Vector2 ShedPivot { get; set; } = new(0.5f, 1.0f);
|
||
|
||
[Export]
|
||
public Vector2 TowerPivot { get; set; } = new(0.5f, 1.0f);
|
||
|
||
[Export]
|
||
public Vector2 DonkeyPivot { get; set; } = new(0.5f, 1.0f);
|
||
|
||
[Export]
|
||
public Vector2 AvatarPivot { get; set; } = new(0.5f, 1.0f);
|
||
|
||
[Export]
|
||
public Array<Material> CellTypeMaterials { get; set; } = new();
|
||
|
||
[ExportGroup("POI Textures")]
|
||
[Export]
|
||
public Texture2D CrateTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D ShedTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D TowerTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarTopRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarTopLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarBottomLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D AvatarBottomRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyTopRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyTopLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyBottomLeftTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D DonkeyBottomRightTexture { get; set; }
|
||
|
||
[Export]
|
||
public Texture2D CheckmarkTexture { get; set; }
|
||
|
||
[ExportGroup("Cell effects")]
|
||
[Export]
|
||
public PackedScene DebuffScene { get; set; }
|
||
|
||
[Export]
|
||
public Color CorruptColor { get; set; } = new(0.6f, 0.1f, 0.8f, 0.45f);
|
||
|
||
[Export]
|
||
public Color InterferenceColor { get; set; } = new(0.1f, 0.8f, 0.6f, 0.45f);
|
||
|
||
[ExportGroup("Highlight")]
|
||
[Export]
|
||
public Material HighlightMaterial { get; set; }
|
||
|
||
[Export]
|
||
public float HighlightHeight { get; set; } = 0.02f;
|
||
|
||
[Export]
|
||
public Material SelectedMaterial { get; set; }
|
||
|
||
[Export]
|
||
public float SelectedHeight { get; set; } = 0.03f;
|
||
|
||
public float TotalAnimationDuration => 0.375f / SettingsManager.Instance.GameSpeed;
|
||
|
||
public Cell HighlightedCell { get; private set; }
|
||
public Cell SelectedCell { get; private set; }
|
||
public Rect2 BoardBounds { get; private set; }
|
||
|
||
private const float PoiHeight = 0.15f;
|
||
private const float PoiInfoHeight = 0.25f;
|
||
|
||
private readonly System.Collections.Generic.Dictionary<Avatar, Sprite3D> m_AvatarSprites = new();
|
||
private readonly System.Collections.Generic.Dictionary<Hex, Cell> m_CellByHex = new();
|
||
private readonly System.Collections.Generic.Dictionary<Hex, Node3D> m_CellNodes = new();
|
||
private readonly System.Collections.Generic.Dictionary<Donkey, Sprite3D> m_DonkeySprites = new();
|
||
private readonly ArrayMesh m_HexMesh = HexMeshBuilder.CreateFlatHexMesh();
|
||
private readonly List<Sprite3D> m_PoiSprites = new();
|
||
|
||
private Board m_Board;
|
||
private int m_CameraRotationIndex;
|
||
private MeshInstance3D m_HighlightInstance;
|
||
private MeshInstance3D m_SelectedInstance;
|
||
private bool m_UseMouseHighlight = true;
|
||
} |