2022-12-03 20:34:01 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2023-11-18 22:32:57 +01:00
|
|
|
using Godot;
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public class StreamContainer : Spatial {
|
2023-08-28 14:03:02 +02:00
|
|
|
// readonly variables
|
2023-11-18 22:32:57 +01:00
|
|
|
private readonly Transform _deactivatedTileTransform = new(Basis.Identity, Vector3.Up * 1000);
|
|
|
|
|
2022-12-02 21:09:40 +01:00
|
|
|
// scene nodes
|
|
|
|
private MeshInstance _bounds;
|
|
|
|
private Spatial _activeTiles;
|
2022-12-03 23:45:32 +01:00
|
|
|
private Queue<HexTile3D> _unusedTiles;
|
2023-08-28 14:48:54 +02:00
|
|
|
public TileWorld TileWorld;
|
2023-08-28 14:03:02 +02:00
|
|
|
private MultiMeshInstance _tileMultiMesh;
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2022-12-02 21:09:40 +01:00
|
|
|
// resources
|
2023-11-18 22:32:57 +01:00
|
|
|
private readonly PackedScene _hexTileScene = GD.Load<PackedScene>("res://scenes/HexTile3D.tscn");
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2022-12-03 00:43:19 +01:00
|
|
|
// exports
|
2023-11-18 22:32:57 +01:00
|
|
|
[Export] public Vector2 Dimensions = new(8, 4);
|
2022-12-28 16:22:53 +01:00
|
|
|
[Export] public NodePath World;
|
2023-11-18 22:32:57 +01:00
|
|
|
[Export] private bool ShowHexTiles;
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2022-12-04 20:51:02 +01:00
|
|
|
[Signal]
|
2023-11-18 22:32:57 +01:00
|
|
|
private delegate void TileClicked(HexTile3D tile3d);
|
|
|
|
|
2023-05-09 21:51:45 +02:00
|
|
|
[Signal]
|
2023-11-18 22:32:57 +01:00
|
|
|
private delegate void TileHovered(HexTile3D tile3d);
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2022-12-03 00:43:19 +01:00
|
|
|
// other members
|
2022-12-03 20:34:01 +01:00
|
|
|
private Rect2 _currentOffsetCoordRect;
|
|
|
|
private Rect2 _oldOffsetCoordRect;
|
2022-12-03 00:43:19 +01:00
|
|
|
private HexGrid _hexGrid;
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
private readonly Dictionary<Vector2, HexTile3D> _coordToTile = new();
|
|
|
|
private readonly Dictionary<HexTile3D, int> _tileToInstanceIndex = new();
|
|
|
|
public List<Vector2> RemovedCoords = new();
|
|
|
|
public List<Vector2> AddedCoords = new();
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public Rect2 CurrentOffsetCoordRect => _currentOffsetCoordRect;
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void SetWorld(TileWorld tileWorld) {
|
2023-08-28 14:48:54 +02:00
|
|
|
TileWorld = tileWorld;
|
2022-12-28 16:22:53 +01:00
|
|
|
}
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-02 21:09:40 +01:00
|
|
|
// Called when the node enters the scene tree for the first time.
|
2023-11-18 22:32:57 +01:00
|
|
|
public override void _Ready() {
|
2022-12-03 23:45:32 +01:00
|
|
|
_unusedTiles = new Queue<HexTile3D>();
|
2022-12-02 21:09:40 +01:00
|
|
|
_bounds = GetNode<MeshInstance>("Bounds");
|
|
|
|
_activeTiles = GetNode<Spatial>("ActiveTiles");
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
_tileMultiMesh = GetNode<MultiMeshInstance>("TileMultiMesh");
|
|
|
|
_tileMultiMesh.Multimesh.InstanceCount = (int)((Dimensions.x + 5) * (Dimensions.y + 5));
|
|
|
|
_tileMultiMesh.Multimesh.InstanceCount = 1810;
|
2023-11-18 22:32:57 +01:00
|
|
|
foreach (int i in Enumerable.Range(0, _tileMultiMesh.Multimesh.InstanceCount)) {
|
2023-08-28 14:03:02 +02:00
|
|
|
_tileMultiMesh.Multimesh.SetInstanceTransform(i, _deactivatedTileTransform);
|
|
|
|
}
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2022-12-03 00:43:19 +01:00
|
|
|
_hexGrid = new HexGrid();
|
2022-12-02 21:09:40 +01:00
|
|
|
|
|
|
|
Transform boundsTransform = Transform.Identity;
|
2022-12-03 20:34:01 +01:00
|
|
|
boundsTransform = boundsTransform.Scaled(new Vector3(Dimensions.x, 1, Dimensions.y));
|
2022-12-03 00:43:19 +01:00
|
|
|
_bounds.Transform = boundsTransform;
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-08-28 14:48:54 +02:00
|
|
|
TileWorld = GetNode<TileWorld>(World);
|
2022-12-03 00:43:19 +01:00
|
|
|
}
|
|
|
|
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void UpdateRects(Vector2 centerPlane) {
|
2022-12-03 20:34:01 +01:00
|
|
|
_oldOffsetCoordRect = _currentOffsetCoordRect;
|
|
|
|
|
|
|
|
Vector2 bottomLeftCoord = centerPlane - new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
|
|
|
Vector2 topRightCoord = centerPlane + new Vector2(Dimensions.x / 2, Dimensions.y / 2);
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-03 20:34:01 +01:00
|
|
|
// GD.Print("World rect now: " + _worldRect.ToString() + " center: " + _worldRect.GetCenter());
|
2022-12-03 00:43:19 +01:00
|
|
|
|
|
|
|
// y axis needs to be inverted as HexGrid's offset coordinates use the opposite axis direction
|
|
|
|
HexCell bottomLeftCell = _hexGrid.GetHexAt(new Vector2(bottomLeftCoord.x, topRightCoord.y));
|
|
|
|
HexCell topRightCell = _hexGrid.GetHexAt(new Vector2(topRightCoord.x, bottomLeftCoord.y));
|
2022-12-03 20:34:01 +01:00
|
|
|
_currentOffsetCoordRect = new Rect2(bottomLeftCell.OffsetCoords,
|
2022-12-03 00:43:19 +01:00
|
|
|
topRightCell.OffsetCoords - bottomLeftCell.OffsetCoords + Vector2.One);
|
2023-08-28 14:03:02 +02:00
|
|
|
|
|
|
|
// Vector2 centerOffset = _hexGrid.GetHexAt(centerPlane).OffsetCoords;
|
|
|
|
// _currentOffsetCoordRect = new Rect2(centerOffset + new Vector2(-Dimensions.x / 2, -Dimensions.y / 2),
|
|
|
|
// Dimensions);
|
2022-12-03 20:34:01 +01:00
|
|
|
// GD.Print("Offset rect now: " + _currentOffsetCoordRect.ToString() + " center: " +
|
|
|
|
// _currentOffsetCoordRect.GetCenter());
|
2022-12-03 00:43:19 +01:00
|
|
|
|
|
|
|
Transform boundsTransform = _bounds.Transform;
|
|
|
|
boundsTransform.origin.x = centerPlane.x;
|
|
|
|
boundsTransform.origin.z = centerPlane.y;
|
2022-12-02 21:09:40 +01:00
|
|
|
_bounds.Transform = boundsTransform;
|
2022-12-03 20:34:01 +01:00
|
|
|
|
|
|
|
// GD.Print("Bounds Transform: " + boundsTransform.ToString());
|
|
|
|
// GD.Print("Bounds Global : " + _bounds.GlobalTransform.ToString());
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (!_currentOffsetCoordRect.Equals(_oldOffsetCoordRect)) {
|
2022-12-03 20:34:01 +01:00
|
|
|
UpdateTileCache();
|
|
|
|
}
|
2022-12-03 00:43:19 +01:00
|
|
|
}
|
2022-12-03 20:34:01 +01:00
|
|
|
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void UpdateTileCache() {
|
2022-12-03 20:34:01 +01:00
|
|
|
RemovedCoords.Clear();
|
|
|
|
AddedCoords.Clear();
|
2022-12-03 23:45:32 +01:00
|
|
|
_unusedTiles.Clear();
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2022-12-03 23:45:32 +01:00
|
|
|
Rect2 expandedRect = _currentOffsetCoordRect.Merge(_oldOffsetCoordRect).Grow(2);
|
|
|
|
Rect2 clippedRect = _currentOffsetCoordRect.Clip(_oldOffsetCoordRect);
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2022-12-03 23:45:32 +01:00
|
|
|
MarkUnusedTiles(expandedRect, clippedRect);
|
|
|
|
AddNewTiles(expandedRect, clippedRect);
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
foreach (HexTile3D tile3D in _unusedTiles.ToArray()) {
|
2022-12-28 16:22:53 +01:00
|
|
|
RemovedCoords.Add(tile3D.OffsetCoords);
|
|
|
|
_activeTiles.RemoveChild(tile3D);
|
2023-01-04 22:49:00 +01:00
|
|
|
tile3D.Disconnect("TileClicked", this, nameof(OnTileClicked));
|
2023-05-09 21:51:45 +02:00
|
|
|
tile3D.Disconnect("TileHovered", this, nameof(OnTileHovered));
|
2022-12-28 16:22:53 +01:00
|
|
|
tile3D.QueueFree();
|
2022-12-03 23:45:32 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-28 16:22:53 +01:00
|
|
|
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void MarkUnusedTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
2022-12-03 23:45:32 +01:00
|
|
|
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.x) - 5,
|
2023-11-18 22:32:57 +01:00
|
|
|
Mathf.CeilToInt(expandedRect.Size.x) + 20)) {
|
2022-12-03 23:45:32 +01:00
|
|
|
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(expandedRect.Position.y) - 5,
|
2023-11-18 22:32:57 +01:00
|
|
|
Mathf.CeilToInt(expandedRect.Size.y) + 20)) {
|
|
|
|
Vector2 coord = new(coord_x, coord_y);
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (clippedRect.HasPoint(coord)) {
|
2022-12-03 23:45:32 +01:00
|
|
|
continue;
|
|
|
|
}
|
2022-12-28 16:22:53 +01:00
|
|
|
|
2022-12-03 20:34:01 +01:00
|
|
|
bool isInCurrent = _currentOffsetCoordRect.HasPoint(coord);
|
|
|
|
bool isInOld = _oldOffsetCoordRect.HasPoint(coord);
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (isInOld && !isInCurrent && _coordToTile.Keys.Contains(coord)) {
|
2022-12-03 23:45:32 +01:00
|
|
|
HexTile3D tile3D = _coordToTile[coord];
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
OnTileDeactivate(tile3D, coord);
|
2022-12-03 23:45:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void AddNewTiles(Rect2 expandedRect, Rect2 clippedRect) {
|
2022-12-03 23:45:32 +01:00
|
|
|
foreach (int coord_x in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.x),
|
2023-11-18 22:32:57 +01:00
|
|
|
Mathf.CeilToInt(_currentOffsetCoordRect.Size.x))) {
|
2022-12-03 23:45:32 +01:00
|
|
|
foreach (int coord_y in Enumerable.Range(Mathf.FloorToInt(_currentOffsetCoordRect.Position.y),
|
2023-11-18 22:32:57 +01:00
|
|
|
Mathf.CeilToInt(_currentOffsetCoordRect.Size.y))) {
|
|
|
|
Vector2 coord = new(coord_x, coord_y);
|
2022-12-03 23:45:32 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (clippedRect.HasPoint(coord)) {
|
2022-12-03 23:45:32 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (_unusedTiles.Count == 0) {
|
2022-12-03 20:34:01 +01:00
|
|
|
AddedCoords.Add(coord);
|
2022-12-03 23:45:32 +01:00
|
|
|
HexTile3D tile3D = GetTile3dAt(coord);
|
2023-11-18 22:32:57 +01:00
|
|
|
} else {
|
2022-12-03 23:45:32 +01:00
|
|
|
HexTile3D tile3D = _unusedTiles.Dequeue();
|
|
|
|
tile3D.OffsetCoords = coord;
|
2022-12-28 16:22:53 +01:00
|
|
|
Transform tileTransform = tile3D.Transform;
|
2023-08-28 14:48:54 +02:00
|
|
|
tileTransform.origin.y = TileWorld.GetHeightAtOffset(coord);
|
2022-12-28 16:22:53 +01:00
|
|
|
tile3D.Transform = tileTransform;
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
OnTileActivate(tile3D);
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-03 23:45:32 +01:00
|
|
|
_coordToTile[coord] = tile3D;
|
2022-12-03 20:34:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public HexTile3D GetTile3dAt(Vector2 offsetCoords) {
|
|
|
|
if (!_coordToTile.Keys.Contains(offsetCoords)) {
|
2022-12-03 23:45:32 +01:00
|
|
|
HexTile3D tile3D = (HexTile3D)_hexTileScene.Instance();
|
|
|
|
tile3D.OffsetCoords = offsetCoords;
|
|
|
|
_activeTiles.AddChild(tile3D);
|
2023-01-04 22:49:00 +01:00
|
|
|
tile3D.Connect("TileClicked", this, nameof(OnTileClicked));
|
2023-05-09 21:51:45 +02:00
|
|
|
tile3D.Connect("TileHovered", this, nameof(OnTileHovered));
|
2022-12-03 21:58:28 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
if (ShowHexTiles) {
|
2023-07-09 22:17:55 +02:00
|
|
|
MeshInstance HexTileMesh = tile3D.GetNode<MeshInstance>("Mesh");
|
|
|
|
HexTileMesh.Transform = HexTileMesh.Transform.Scaled(new Vector3(0.95f, 1, 0.95f));
|
|
|
|
}
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-03 23:45:32 +01:00
|
|
|
Transform tileTransform = tile3D.Transform;
|
2023-08-28 14:48:54 +02:00
|
|
|
tileTransform.origin.y = TileWorld.GetHeightAtOffset(offsetCoords);
|
2022-12-03 23:45:32 +01:00
|
|
|
tile3D.Transform = tileTransform;
|
2023-08-28 14:03:02 +02:00
|
|
|
|
|
|
|
_tileToInstanceIndex[tile3D] = _tileToInstanceIndex.Count;
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-03 23:45:32 +01:00
|
|
|
_coordToTile[offsetCoords] = tile3D;
|
2022-12-03 20:34:01 +01:00
|
|
|
}
|
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
OnTileActivate(_coordToTile[offsetCoords]);
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2022-12-03 20:34:01 +01:00
|
|
|
return _coordToTile[offsetCoords];
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void SetCenterTile(HexCell cell) {
|
2022-12-03 00:43:19 +01:00
|
|
|
UpdateRects(_hexGrid.GetHexCenter(cell));
|
2022-12-02 21:09:40 +01:00
|
|
|
}
|
2022-12-04 20:51:02 +01:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void SetTileMaterial(ShaderMaterial material) {
|
|
|
|
foreach (Spatial node in _activeTiles.GetChildren()) {
|
2023-05-09 21:51:45 +02:00
|
|
|
HexTile3D tile = (HexTile3D)node;
|
2023-11-18 22:32:57 +01:00
|
|
|
if (tile == null) {
|
2023-05-09 21:51:45 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
tile.Mesh.SetSurfaceMaterial(0, material);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void OnTileActivate(HexTile3D tile3D) {
|
2023-08-28 14:03:02 +02:00
|
|
|
int instanceIndex = _tileToInstanceIndex[tile3D];
|
|
|
|
|
2023-08-29 12:21:35 +02:00
|
|
|
Vector3 scale = Vector3.One;
|
2023-11-18 22:32:57 +01:00
|
|
|
if (ShowHexTiles) {
|
2023-08-29 12:21:35 +02:00
|
|
|
scale.x *= 0.96f;
|
|
|
|
scale.z *= 0.96f;
|
|
|
|
}
|
2023-11-18 22:32:57 +01:00
|
|
|
|
|
|
|
Transform instanceTransform =
|
|
|
|
new(tile3D.GlobalTransform.basis.Rotated(Vector3.Up, Mathf.Deg2Rad(30)).Scaled(scale),
|
|
|
|
tile3D.GlobalTransform.origin + Vector3.Up * -2.5f);
|
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, instanceTransform);
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void OnTileDeactivate(HexTile3D tile3D, Vector2 coord) {
|
2023-08-28 14:03:02 +02:00
|
|
|
int instanceIndex = _tileToInstanceIndex[tile3D];
|
|
|
|
_tileMultiMesh.Multimesh.SetInstanceTransform(instanceIndex, _deactivatedTileTransform);
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
_unusedTiles.Enqueue(tile3D);
|
|
|
|
_coordToTile.Remove(coord);
|
|
|
|
RemovedCoords.Add(coord);
|
|
|
|
}
|
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void OnTileClicked(HexTile3D tile) {
|
2023-01-04 22:49:00 +01:00
|
|
|
EmitSignal("TileClicked", tile);
|
2022-12-04 20:51:02 +01:00
|
|
|
}
|
2023-11-18 22:32:57 +01:00
|
|
|
|
|
|
|
public void OnTileHovered(HexTile3D tile) {
|
2023-05-09 21:51:45 +02:00
|
|
|
EmitSignal("TileHovered", tile);
|
|
|
|
}
|
2023-05-13 09:29:54 +02:00
|
|
|
|
2023-11-18 22:32:57 +01:00
|
|
|
public void OnWorldGenerated() {
|
|
|
|
foreach (Spatial node in _activeTiles.GetChildren()) {
|
2023-05-13 09:29:54 +02:00
|
|
|
HexTile3D tile = (HexTile3D)node;
|
2023-11-18 22:32:57 +01:00
|
|
|
if (tile == null) {
|
2023-05-13 09:29:54 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Transform tileTransform = tile.GlobalTransform;
|
2023-08-28 14:48:54 +02:00
|
|
|
tileTransform.origin.y = TileWorld.GetHeightAtOffset(tile.OffsetCoords);
|
2023-05-13 09:29:54 +02:00
|
|
|
tile.GlobalTransform = tileTransform;
|
2023-11-18 22:32:57 +01:00
|
|
|
|
2023-08-28 14:03:02 +02:00
|
|
|
OnTileActivate(tile);
|
2023-05-13 09:29:54 +02:00
|
|
|
}
|
|
|
|
}
|
2022-12-03 20:34:01 +01:00
|
|
|
}
|