GodotComponentTest/scenes/Game.cs

365 lines
14 KiB
C#

using Godot;
using System.Diagnostics;
using System.Linq;
using Array = Godot.Collections.Array;
public class Game : Spatial
{
// ui elements
private Label _framesPerSecondLabel;
private Label _centerLabel;
private Label _tileOffsetLabel;
private Label _numTilesLabel;
private Label _mouseWorldLabel;
private Label _mouseTileOffsetLabel;
private Label _mouseTileCubeLabel;
private Label _numCoordsAddedLabel;
private Label _numCoordsRemovedLabel;
private TextureRect _worldTextureRect;
private TextureRect _heightTextureRect;
private Button _generateWorldButton;
private Control _gameUi;
private Label _goldCountLabel;
// scene nodes
private Spatial _tileHighlight;
private Spatial _mouseTileHighlight;
private StreamContainer _streamContainer;
private Area _streamContainerArea;
private Spatial _streamContainerActiveTiles;
private Player _player;
private TileWorld _tileWorld;
private Camera _camera;
private World _world;
private WorldView _worldView;
// Resources
private PackedScene _tileHighlightScene;
private ShaderMaterial _tileMaterial;
// other members
private HexGrid _hexGrid;
private HexCell _lastTile;
private HexCell _currentTile;
private Vector3 _cameraOffset;
private ImageTexture _blackWhitePatternTexture;
private InteractionSystem _interactionSystem;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
// debugStatsContainer
Container debugStatsContainer = (Container)FindNode("DebugStatsContainer");
_framesPerSecondLabel = debugStatsContainer.GetNode<Label>("fps_label");
_centerLabel = debugStatsContainer.GetNode<Label>("center_label");
_tileOffsetLabel = debugStatsContainer.GetNode<Label>("tile_offset_label");
_numTilesLabel = debugStatsContainer.GetNode<Label>("num_tiles_label");
_mouseWorldLabel = debugStatsContainer.GetNode<Label>("mouse_world_label");
_mouseTileOffsetLabel = debugStatsContainer.GetNode<Label>("mouse_tile_offset_label");
_mouseTileCubeLabel = debugStatsContainer.GetNode<Label>("mouse_tile_cube_label");
_numCoordsAddedLabel = debugStatsContainer.GetNode<Label>("num_coords_added_label");
_numCoordsRemovedLabel = debugStatsContainer.GetNode<Label>("num_coords_removed_label");
// UI elements
Container worldGeneratorContainer = (Container)FindNode("WorldGeneratorContainer");
_worldTextureRect = worldGeneratorContainer.GetNode<TextureRect>("WorldTextureRect");
_heightTextureRect = worldGeneratorContainer.GetNode<TextureRect>("HeightTextureRect");
_generateWorldButton = worldGeneratorContainer.GetNode<Button>("WorldGenerateButton");
_gameUi = (Control)FindNode("GameUI");
_goldCountLabel = _gameUi.GetNode<Label>("GoldCount");
Debug.Assert(_goldCountLabel != null);
// scene nodes
_tileHighlight = GetNode<Spatial>("TileHighlight");
_mouseTileHighlight = GetNode<Spatial>("MouseTileHighlight");
_streamContainer = (StreamContainer)FindNode("StreamContainer");
_streamContainerArea = _streamContainer.GetNode<Area>("Area");
_streamContainerActiveTiles = _streamContainer.GetNode<Spatial>("ActiveTiles");
_player = GetNode<Player>("Player");
_tileWorld = GetNode<TileWorld>("TileWorld");
_camera = (Camera)FindNode("Camera");
_cameraOffset = _camera.GlobalTranslation - _player.GlobalTranslation;
_world = (World)FindNode("World");
_worldView = (WorldView)FindNode("WorldView");
// populate UI values
Slider generatorWorldSizeSlider = worldGeneratorContainer.GetNode<Slider>("HBoxContainer/WorldSizeSlider");
generatorWorldSizeSlider.Value = _tileWorld.Size;
Debug.Assert(_tileWorld != null);
// resources
_tileHighlightScene = GD.Load<PackedScene>("utils/TileHighlight.tscn");
_tileMaterial = GD.Load<ShaderMaterial>("materials/HexTileTextureLookup.tres");
Debug.Assert(_tileMaterial != null);
_blackWhitePatternTexture = new ImageTexture();
Image image = new Image();
image.Load("assets/4x4checker.png");
_blackWhitePatternTexture.CreateFromImage(image, (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
// other members
_lastTile = new HexCell();
_currentTile = new HexCell();
_hexGrid = new HexGrid();
_interactionSystem = GetNode<InteractionSystem>("InteractionSystem");
Debug.Assert(_interactionSystem != null);
// update data
_worldTextureRect.RectSize = Vector2.One * _tileWorld.Size;
_heightTextureRect.RectSize = Vector2.One * _tileWorld.Size;
// connect signals
_streamContainerArea.Connect("input_event", this, nameof(OnAreaInputEvent));
_streamContainer.Connect("TileClicked", this, nameof(OnTileClicked));
_streamContainer.Connect("TileHovered", this, nameof(OnTileHovered));
_tileWorld.Connect("WorldGenerated", this, nameof(OnWorldGenerated));
_generateWorldButton.Connect("pressed", this, nameof(OnGenerateButton));
_player.TaskQueueComponent.Connect("StartInteraction", _interactionSystem,
nameof(_interactionSystem.OnStartInteraction));
_player.Connect("GoldCountChanged", this, nameof(OnGoldCountChanged));
// register entity events
foreach (Node node in GetNode("Entities").GetChildren())
{
if (node.HasSignal("EntityClicked"))
{
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
}
}
// perform dependency injection
//_streamContainer.SetWorld(_tileWorld);Clicked
WorldInfoComponent worldInfoComponent = _player.GetNode<WorldInfoComponent>("WorldInfo");
if (worldInfoComponent != null)
{
worldInfoComponent.SetWorld(_tileWorld);
}
_tileWorld.Generate(_tileWorld.Size);
UpdateCurrentTile();
_streamContainer.SetCenterTile(_currentTile);
}
public override void _Input(InputEvent inputEvent)
{
if (inputEvent.IsAction("Forward"))
{
GD.Print("Forward");
}
if (inputEvent.IsAction("Back"))
{
GD.Print("Back");
}
}
public void UpdateCurrentTile()
{
// cast a ray from the camera to center
Vector3 cameraNormal = _camera.ProjectRayNormal(_camera.GetViewport().Size * 0.5f);
Vector3 cameraPosition = _camera.ProjectRayOrigin(_camera.GetViewport().Size * 0.5f);
Vector3 cameraDir = cameraNormal - cameraPosition;
Vector3 centerCoord;
if (Mathf.Abs(cameraDir.y) > Globals.EpsPosition)
{
centerCoord = cameraPosition + cameraNormal * (-cameraPosition.y / cameraNormal.y);
}
else
{
centerCoord = _camera.GlobalTranslation;
centerCoord.y = 0;
}
_world.SetCenterPlaneCoord(new Vector2(_player.GlobalTranslation.x, _player.GlobalTranslation.z));
_currentTile = _hexGrid.GetHexAt(new Vector2(centerCoord.x, centerCoord.z));
_centerLabel.Text = centerCoord.ToString("F3");
_tileOffsetLabel.Text = _currentTile.OffsetCoords.ToString();
}
public override void _Process(float delta)
{
_framesPerSecondLabel.Text = Engine.GetFramesPerSecond().ToString();
_lastTile = _currentTile;
UpdateCurrentTile();
Transform tileHighlightTransform = Transform.Identity;
Vector2 currentTileCenter = _hexGrid.GetHexCenter(_currentTile);
tileHighlightTransform.origin.x = currentTileCenter.x;
tileHighlightTransform.origin.z = currentTileCenter.y;
_tileHighlight.Transform = tileHighlightTransform;
if (_currentTile.CubeCoords != _lastTile.CubeCoords)
{
_streamContainer.SetCenterTile(_currentTile);
_numTilesLabel.Text = _streamContainerActiveTiles.GetChildCount().ToString();
_numCoordsAddedLabel.Text = _streamContainer.AddedCoords.Count.ToString();
_numCoordsRemovedLabel.Text = _streamContainer.RemovedCoords.Count.ToString();
}
Transform cameraTransform = _camera.Transform;
cameraTransform.origin = _player.GlobalTranslation + _cameraOffset;
_camera.Transform = cameraTransform;
}
public void OnGenerateButton()
{
GD.Print("Generating");
Slider worldSizeSlider = (Slider)FindNode("WorldSizeSlider");
if (worldSizeSlider == null)
{
GD.PrintErr("Could not find WorldSizeSlider!");
return;
}
_tileWorld.Seed = _tileWorld.Seed + 1;
_tileWorld.Generate((int)worldSizeSlider.Value);
}
public void OnAreaInputEvent(Node camera, InputEvent inputEvent, Vector3 position, Vector3 normal,
int shapeIndex)
{
HexCell cellAtCursor = _hexGrid.GetHexAt(new Vector2(position.x, position.z));
Transform highlightTransform = Transform.Identity;
_mouseWorldLabel.Text = position.ToString("F3");
_mouseTileOffsetLabel.Text = cellAtCursor.OffsetCoords.ToString("N");
_mouseTileCubeLabel.Text = cellAtCursor.CubeCoords.ToString("N");
_mouseTileHighlight.Transform = highlightTransform;
if (inputEvent is InputEventMouseButton && ((InputEventMouseButton)inputEvent).Pressed)
{
_streamContainer.EmitSignal("TileClicked", _streamContainer.GetTile3dAt(cellAtCursor.OffsetCoords));
}
}
public void OnTileClicked(HexTile3D tile)
{
if (_player == null)
{
return;
}
if (_player.InteractionComponent != null)
{
_player.InteractionComponent.EmitSignal("InteractionEnd");
}
_player.TaskQueueComponent.Reset();
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
new NavigationComponent.NavigationPoint(tile.GlobalTranslation)));
}
public void OnTileHovered(HexTile3D tile)
{
Transform highlightTransform = tile.GlobalTransform;
_mouseTileHighlight.Transform = highlightTransform;
_mouseWorldLabel.Text = highlightTransform.origin.ToString("F3");
_mouseTileOffsetLabel.Text = tile.OffsetCoords.ToString("N");
_mouseTileCubeLabel.Text = tile.Cell.CubeCoords.ToString("N");
_player.Navigation.FindPath(_player, _player.GlobalTranslation, tile.GlobalTranslation);
}
public void OnEntityClicked(Entity entity)
{
GD.Print("Clicked on entity at " + entity.GlobalTranslation);
Spatial mountPoint = (Spatial)entity.FindNode("MountPoint");
if (mountPoint != null)
{
_player.TaskQueueComponent.Reset();
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.NavigationTask(
new NavigationComponent.NavigationPoint(mountPoint.GlobalTransform)));
_player.TaskQueueComponent.Queue.Enqueue(new TaskQueueComponent.InteractionTask(entity));
}
}
public void ResetGameState()
{
Transform playerStartTransform = Transform.Identity;
float height = _tileWorld.GetHeightAtOffset(new Vector2(0, 0));
playerStartTransform.origin.y = height;
_player.Transform = playerStartTransform;
_player.TaskQueueComponent.Reset();
_player.Navigation.PlanDirectPath(_player, playerStartTransform.origin, playerStartTransform.origin,
playerStartTransform.basis.Quat());
_goldCountLabel.Text = "0";
foreach (Spatial entity in GetNode("Entities").GetChildren())
{
Transform entityTransform = entity.Transform;
Vector2 entityPlanePos = new Vector2(entityTransform.origin.x, entityTransform.origin.z);
Vector2 entityOffsetCoordinates = _hexGrid.GetHexAt(entityPlanePos).OffsetCoords;
float entityHeight = _tileWorld.GetHeightAtOffset(entityOffsetCoordinates);
entityTransform.origin.y = entityHeight;
entity.Transform = entityTransform;
}
}
public void OnWorldGenerated()
{
GD.Print("Using new map. Size: " + (int)_tileWorld.ColormapImage.GetSize().x);
_goldCountLabel.Text = "0";
UpdateWorldTextures();
_streamContainer.OnWorldGenerated();
// Reset player transform to offset 0,0 and at current height
ResetGameState();
// Connect all signals of the generated world
foreach (Node node in _tileWorld.Entities.GetChildren())
{
if (node.HasSignal("EntityClicked"))
{
node.Connect("EntityClicked", this, nameof(OnEntityClicked));
}
}
}
private void UpdateWorldTextures()
{
GD.Print("Updating World textures");
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
ImageTexture newHeightTexture = new ImageTexture();
newHeightTexture.CreateFromImage(_tileWorld.HeightmapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_heightTextureRect.Texture = newHeightTexture;
}
public void OnGoldCountChanged(int goldCount)
{
AnimationPlayer animationPlayer = _gameUi.GetNode<AnimationPlayer>("AnimationPlayer");
_goldCountLabel.Text = goldCount.ToString();
animationPlayer.CurrentAnimation = "FlashLabel";
animationPlayer.Seek(0);
animationPlayer.Play();
}
}