✨ New sfx and vfx and features in building
This commit is contained in:
		| @@ -19,6 +19,11 @@ public partial class PlacementManager : Node2D | |||||||
|     private static readonly List<string> BuildableTiles = ["wall", "miner"]; |     private static readonly List<string> BuildableTiles = ["wall", "miner"]; | ||||||
|     private readonly Dictionary<Node2D, BuildTask> _buildTasks = new(); |     private readonly Dictionary<Node2D, BuildTask> _buildTasks = new(); | ||||||
|     private AudioStreamPlayer _completionSound; |     private AudioStreamPlayer _completionSound; | ||||||
|  |     private AudioStreamPlayer _buildingSound; | ||||||
|  |     private AudioStreamPlayer _canceledSound; | ||||||
|  |     private AudioStreamPlayer _cannotDeploySound; | ||||||
|  |     private AudioStreamPlayer _notReadySound; | ||||||
|  |     private AudioStreamPlayer _insufficientFundsSound; | ||||||
|     private Node2D _currentGhost; // Keep track of the current ghost building |     private Node2D _currentGhost; // Keep track of the current ghost building | ||||||
|  |  | ||||||
|     public override void _Ready() |     public override void _Ready() | ||||||
| @@ -26,13 +31,25 @@ public partial class PlacementManager : Node2D | |||||||
|         base._Ready(); |         base._Ready(); | ||||||
|  |  | ||||||
|         // Setup completion sound |         // Setup completion sound | ||||||
|         _completionSound = new AudioStreamPlayer(); |         _completionSound = CreateAudioPlayer("res://Sounds/Events/ConstructionComplete.wav"); | ||||||
|         AddChild(_completionSound); |         _buildingSound = CreateAudioPlayer("res://Sounds/Events/Building.wav"); | ||||||
|         var sound = GD.Load<AudioStream>("res://Sounds/Events/ConstructionComplete.wav"); |         _canceledSound = CreateAudioPlayer("res://Sounds/Events/Canceled.wav"); | ||||||
|  |         _cannotDeploySound = CreateAudioPlayer("res://Sounds/Events/CannotDeployHere.wav"); | ||||||
|  |         _notReadySound = CreateAudioPlayer("res://Sounds/Events/NotReady.wav"); | ||||||
|  |         _insufficientFundsSound = CreateAudioPlayer("res://Sounds/Events/InsufficientFunds.wav"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private AudioStreamPlayer CreateAudioPlayer(string path) | ||||||
|  |     { | ||||||
|  |         var player = new AudioStreamPlayer(); | ||||||
|  |         AddChild(player); | ||||||
|  |         var sound = GD.Load<AudioStream>(path); | ||||||
|         if (sound != null) |         if (sound != null) | ||||||
|         { |         { | ||||||
|             _completionSound.Stream = sound; |             player.Stream = sound; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return player; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void OnBuildCompleted() |     private void OnBuildCompleted() | ||||||
| @@ -194,24 +211,25 @@ public partial class PlacementManager : Node2D | |||||||
|         _ghostBuilding.SetGhostMode(canPlace); |         _ghostBuilding.SetGhostMode(canPlace); | ||||||
|  |  | ||||||
|         // Left click to place |         // Left click to place | ||||||
|         if (Input.IsActionPressed("build_tile") && canPlace) |         if (Input.IsActionPressed("build_tile")) | ||||||
|         { |         { | ||||||
|             var building = Registry.GetBuilding(_currentBuildingId); |             var building = Registry.GetBuilding(_currentBuildingId); | ||||||
|             if (building == null) return; |             if (building == null) return; | ||||||
|  |  | ||||||
|             if (!CanStartNewBuild()) |             if (!CanStartNewBuild()) | ||||||
|             { |             { | ||||||
|                 // Optionally show feedback to player that build queue is full |                 _notReadySound.Play(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Consume resources first |             // Consume resources first | ||||||
|             if (!ConsumeBuildingResources(_currentBuildingId)) |             if (!ConsumeBuildingResources(_currentBuildingId)) | ||||||
|             { |             { | ||||||
|                 // Optionally show feedback to player that they can't afford this building |                 _insufficientFundsSound.Play(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // Create the building instance first | ||||||
|             var scene = building.Scene; |             var scene = building.Scene; | ||||||
|             var buildingInstance = (BaseTile)scene.Instantiate(); |             var buildingInstance = (BaseTile)scene.Instantiate(); | ||||||
|             buildingInstance.RotationDegrees = _currentRotation; |             buildingInstance.RotationDegrees = _currentRotation; | ||||||
| @@ -219,23 +237,30 @@ public partial class PlacementManager : Node2D | |||||||
|             buildingInstance.Position = _ghostBuilding.Position; |             buildingInstance.Position = _ghostBuilding.Position; | ||||||
|             AddChild(buildingInstance); |             AddChild(buildingInstance); | ||||||
|  |  | ||||||
|             // Check if area is free before placing |             // First check if area is free | ||||||
|             if (!IsAreaFree(_hoveredCell, building.Size, _currentRotation, building.Layer)) |             if (!IsAreaFree(_hoveredCell, building.Size, _currentRotation, building.Layer)) | ||||||
|             { |             { | ||||||
|  |                 _cannotDeploySound.Play(); | ||||||
|                 RefundBuildingResources(_currentBuildingId); |                 RefundBuildingResources(_currentBuildingId); | ||||||
|                 buildingInstance.QueueFree(); |                 buildingInstance.QueueFree(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Occupy the area |             // If we get here, area is free, so we can safely occupy it | ||||||
|             Grid.OccupyArea(_hoveredCell, buildingInstance, building.Size, _currentRotation, building.Layer); |             Grid.OccupyArea(_hoveredCell, buildingInstance, building.Size, _currentRotation, building.Layer); | ||||||
|  |  | ||||||
|             if (building.BuildTime > 0f) |             if (building.BuildTime > 0f) | ||||||
|             { |             { | ||||||
|  |                 var wasQueueEmpty = _buildTasks.Count == 0; | ||||||
|                 var buildTask = new BuildTask(OnBuildCompleted); |                 var buildTask = new BuildTask(OnBuildCompleted); | ||||||
|                 _buildTasks[buildingInstance] = buildTask; |                 _buildTasks[buildingInstance] = buildTask; | ||||||
|  |  | ||||||
|                 buildingInstance.StartConstruction(building.BuildTime, () => { |                 // Play building sound only when adding to an empty queue | ||||||
|  |                 if (wasQueueEmpty) | ||||||
|  |                     _buildingSound.Play(); | ||||||
|  |  | ||||||
|  |                 buildingInstance.StartConstruction(building.BuildTime, () => | ||||||
|  |                 { | ||||||
|                     // On construction complete |                     // On construction complete | ||||||
|                     if (_buildTasks.TryGetValue(buildingInstance, out var task)) |                     if (_buildTasks.TryGetValue(buildingInstance, out var task)) | ||||||
|                     { |                     { | ||||||
| @@ -245,6 +270,7 @@ public partial class PlacementManager : Node2D | |||||||
|                             Grid.FreeArea(_hoveredCell, building.Size, _currentRotation, building.Layer); |                             Grid.FreeArea(_hoveredCell, building.Size, _currentRotation, building.Layer); | ||||||
|                             buildingInstance.QueueFree(); |                             buildingInstance.QueueFree(); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                         task.Complete(); |                         task.Complete(); | ||||||
|                         _buildTasks.Remove(buildingInstance); |                         _buildTasks.Remove(buildingInstance); | ||||||
|                     } |                     } | ||||||
| @@ -258,9 +284,28 @@ public partial class PlacementManager : Node2D | |||||||
|             // Right click to destroy from current layer |             // Right click to destroy from current layer | ||||||
|             var building = Grid.GetBuildingAtCell(_hoveredCell); |             var building = Grid.GetBuildingAtCell(_hoveredCell); | ||||||
|             if (building == null) return; |             if (building == null) return; | ||||||
|  |              | ||||||
|             // Find all cells occupied by this building |             // Find all cells occupied by this building | ||||||
|             var buildingInfo = Grid.GetBuildingInfoAtCell(_hoveredCell, GridLayer.Building); |             var buildingInfo = Grid.GetBuildingInfoAtCell(_hoveredCell, GridLayer.Building); | ||||||
|             if (buildingInfo == null) return; |             if (buildingInfo == null) return; | ||||||
|  |              | ||||||
|  |             // Check if this building is in the build tasks (under construction) | ||||||
|  |             if (_buildTasks.TryGetValue(building, out var buildTask)) | ||||||
|  |             { | ||||||
|  |                 var buildingTile = building as BaseTile; | ||||||
|  |                 // Cancel the build task | ||||||
|  |                 buildTask.Complete(true); // Mark as cancelled | ||||||
|  |                 _buildTasks.Remove(building); | ||||||
|  |                 _canceledSound.Play(); | ||||||
|  |                 if (buildingTile == null) return; | ||||||
|  |                  | ||||||
|  |                 // Refund resources for canceled build | ||||||
|  |                 var buildingData = Registry.GetBuilding(buildingTile.TileId); | ||||||
|  |                 if (buildingData != null) | ||||||
|  |                     RefundBuildingResources(buildingTile.TileId); | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // Clean up the building and grid | ||||||
|             building.QueueFree(); |             building.QueueFree(); | ||||||
|             Grid.FreeArea(buildingInfo.Value.Position, buildingInfo.Value.Size, buildingInfo.Value.Rotation); |             Grid.FreeArea(buildingInfo.Value.Position, buildingInfo.Value.Size, buildingInfo.Value.Rotation); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ public partial class BaseTile : Node2D | |||||||
|     private Sprite2D _sprite; |     private Sprite2D _sprite; | ||||||
|     private ColorRect _progressOverlay; |     private ColorRect _progressOverlay; | ||||||
|     private Action _onConstructionComplete; |     private Action _onConstructionComplete; | ||||||
|  |     private bool _isConstructing = false; | ||||||
|  |  | ||||||
|     public override void _Ready() |     public override void _Ready() | ||||||
|     { |     { | ||||||
| @@ -26,6 +27,9 @@ public partial class BaseTile : Node2D | |||||||
|  |  | ||||||
|     public void SetGhostMode(bool canPlace) |     public void SetGhostMode(bool canPlace) | ||||||
|     { |     { | ||||||
|  |         // Don't modify collision for constructing buildings | ||||||
|  |         if (_isConstructing) return; | ||||||
|  |              | ||||||
|         if (_collisionShape != null) |         if (_collisionShape != null) | ||||||
|             _collisionShape.Disabled = true; |             _collisionShape.Disabled = true; | ||||||
|  |  | ||||||
| @@ -46,8 +50,13 @@ public partial class BaseTile : Node2D | |||||||
|     // Building progress visualization |     // Building progress visualization | ||||||
|     public void StartConstruction(float buildTime, Action onComplete = null) |     public void StartConstruction(float buildTime, Action onComplete = null) | ||||||
|     { |     { | ||||||
|  |         _isConstructing = true; | ||||||
|  |         if (_collisionShape != null) | ||||||
|  |             _collisionShape.Disabled = true; | ||||||
|  |  | ||||||
|         if (_progressOverlay == null || _sprite?.Texture == null)  |         if (_progressOverlay == null || _sprite?.Texture == null)  | ||||||
|         { |         { | ||||||
|  |             _isConstructing = false; | ||||||
|             onComplete?.Invoke(); |             onComplete?.Invoke(); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @@ -55,6 +64,10 @@ public partial class BaseTile : Node2D | |||||||
|         _onConstructionComplete = onComplete; |         _onConstructionComplete = onComplete; | ||||||
|         var texSize = new Vector2(GridUtils.TileSize, GridUtils.TileSize); |         var texSize = new Vector2(GridUtils.TileSize, GridUtils.TileSize); | ||||||
|  |  | ||||||
|  |         // Set initial transparency for construction | ||||||
|  |         if (_sprite != null) | ||||||
|  |             _sprite.Modulate = new Color(1, 1, 1, 0.8f); | ||||||
|  |  | ||||||
|         _progressOverlay.Visible = true; |         _progressOverlay.Visible = true; | ||||||
|         _progressOverlay.Modulate = Colors.White; |         _progressOverlay.Modulate = Colors.White; | ||||||
|         _progressOverlay.Color = new Color(0, 0, 1, 0.4f); // semi-transparent blue |         _progressOverlay.Color = new Color(0, 0, 1, 0.4f); // semi-transparent blue | ||||||
| @@ -80,7 +93,14 @@ public partial class BaseTile : Node2D | |||||||
|             // Fade out the overlay |             // Fade out the overlay | ||||||
|             await FadeOutOverlay(0.5f); |             await FadeOutOverlay(0.5f); | ||||||
|              |              | ||||||
|             // Notify completion |             // Construction complete - restore full opacity and enable collision | ||||||
|  |             if (_sprite != null) | ||||||
|  |                 _sprite.Modulate = Colors.White; | ||||||
|  |                  | ||||||
|  |             _isConstructing = false; | ||||||
|  |             if (_collisionShape != null) | ||||||
|  |                 _collisionShape.Disabled = false; | ||||||
|  |                  | ||||||
|             _onConstructionComplete?.Invoke(); |             _onConstructionComplete?.Invoke(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								Sounds/Events/Building.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Sounds/Events/Building.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								Sounds/Events/Building.wav.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Sounds/Events/Building.wav.import
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | [remap] | ||||||
|  |  | ||||||
|  | importer="wav" | ||||||
|  | type="AudioStreamWAV" | ||||||
|  | uid="uid://d1trbqrntmuij" | ||||||
|  | path="res://.godot/imported/Building.wav-b8766581fd25a206c63f47b13bd2e2f5.sample" | ||||||
|  |  | ||||||
|  | [deps] | ||||||
|  |  | ||||||
|  | source_file="res://Sounds/Events/Building.wav" | ||||||
|  | dest_files=["res://.godot/imported/Building.wav-b8766581fd25a206c63f47b13bd2e2f5.sample"] | ||||||
|  |  | ||||||
|  | [params] | ||||||
|  |  | ||||||
|  | force/8_bit=false | ||||||
|  | force/mono=false | ||||||
|  | force/max_rate=false | ||||||
|  | force/max_rate_hz=44100 | ||||||
|  | edit/trim=false | ||||||
|  | edit/normalize=false | ||||||
|  | edit/loop_mode=0 | ||||||
|  | edit/loop_begin=0 | ||||||
|  | edit/loop_end=-1 | ||||||
|  | compress/mode=2 | ||||||
							
								
								
									
										
											BIN
										
									
								
								Sounds/Events/Canceled.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Sounds/Events/Canceled.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								Sounds/Events/Canceled.wav.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Sounds/Events/Canceled.wav.import
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | [remap] | ||||||
|  |  | ||||||
|  | importer="wav" | ||||||
|  | type="AudioStreamWAV" | ||||||
|  | uid="uid://chn8ux4two1kd" | ||||||
|  | path="res://.godot/imported/Canceled.wav-6d441d9a898b5cd9be4c0664a1f489ed.sample" | ||||||
|  |  | ||||||
|  | [deps] | ||||||
|  |  | ||||||
|  | source_file="res://Sounds/Events/Canceled.wav" | ||||||
|  | dest_files=["res://.godot/imported/Canceled.wav-6d441d9a898b5cd9be4c0664a1f489ed.sample"] | ||||||
|  |  | ||||||
|  | [params] | ||||||
|  |  | ||||||
|  | force/8_bit=false | ||||||
|  | force/mono=false | ||||||
|  | force/max_rate=false | ||||||
|  | force/max_rate_hz=44100 | ||||||
|  | edit/trim=false | ||||||
|  | edit/normalize=false | ||||||
|  | edit/loop_mode=0 | ||||||
|  | edit/loop_begin=0 | ||||||
|  | edit/loop_end=-1 | ||||||
|  | compress/mode=2 | ||||||
							
								
								
									
										
											BIN
										
									
								
								Sounds/Events/CannotDeployHere.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Sounds/Events/CannotDeployHere.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								Sounds/Events/CannotDeployHere.wav.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Sounds/Events/CannotDeployHere.wav.import
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | [remap] | ||||||
|  |  | ||||||
|  | importer="wav" | ||||||
|  | type="AudioStreamWAV" | ||||||
|  | uid="uid://7u1gw7lt5xd1" | ||||||
|  | path="res://.godot/imported/CannotDeployHere.wav-a9ec27508654f74d03ac7b8c8037059c.sample" | ||||||
|  |  | ||||||
|  | [deps] | ||||||
|  |  | ||||||
|  | source_file="res://Sounds/Events/CannotDeployHere.wav" | ||||||
|  | dest_files=["res://.godot/imported/CannotDeployHere.wav-a9ec27508654f74d03ac7b8c8037059c.sample"] | ||||||
|  |  | ||||||
|  | [params] | ||||||
|  |  | ||||||
|  | force/8_bit=false | ||||||
|  | force/mono=false | ||||||
|  | force/max_rate=false | ||||||
|  | force/max_rate_hz=44100 | ||||||
|  | edit/trim=false | ||||||
|  | edit/normalize=false | ||||||
|  | edit/loop_mode=0 | ||||||
|  | edit/loop_begin=0 | ||||||
|  | edit/loop_end=-1 | ||||||
|  | compress/mode=2 | ||||||
							
								
								
									
										
											BIN
										
									
								
								Sounds/Events/InsufficientFunds.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Sounds/Events/InsufficientFunds.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								Sounds/Events/InsufficientFunds.wav.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Sounds/Events/InsufficientFunds.wav.import
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | [remap] | ||||||
|  |  | ||||||
|  | importer="wav" | ||||||
|  | type="AudioStreamWAV" | ||||||
|  | uid="uid://bemxvqcettqgp" | ||||||
|  | path="res://.godot/imported/InsufficientFunds.wav-7aba215cb1cd04a5285a5e9908999906.sample" | ||||||
|  |  | ||||||
|  | [deps] | ||||||
|  |  | ||||||
|  | source_file="res://Sounds/Events/InsufficientFunds.wav" | ||||||
|  | dest_files=["res://.godot/imported/InsufficientFunds.wav-7aba215cb1cd04a5285a5e9908999906.sample"] | ||||||
|  |  | ||||||
|  | [params] | ||||||
|  |  | ||||||
|  | force/8_bit=false | ||||||
|  | force/mono=false | ||||||
|  | force/max_rate=false | ||||||
|  | force/max_rate_hz=44100 | ||||||
|  | edit/trim=false | ||||||
|  | edit/normalize=false | ||||||
|  | edit/loop_mode=0 | ||||||
|  | edit/loop_begin=0 | ||||||
|  | edit/loop_end=-1 | ||||||
|  | compress/mode=2 | ||||||
							
								
								
									
										
											BIN
										
									
								
								Sounds/Events/NotReady.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Sounds/Events/NotReady.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								Sounds/Events/NotReady.wav.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								Sounds/Events/NotReady.wav.import
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | [remap] | ||||||
|  |  | ||||||
|  | importer="wav" | ||||||
|  | type="AudioStreamWAV" | ||||||
|  | uid="uid://dogbl6tfealwg" | ||||||
|  | path="res://.godot/imported/NotReady.wav-2cfa5f22feed110ca411d6478060fdea.sample" | ||||||
|  |  | ||||||
|  | [deps] | ||||||
|  |  | ||||||
|  | source_file="res://Sounds/Events/NotReady.wav" | ||||||
|  | dest_files=["res://.godot/imported/NotReady.wav-2cfa5f22feed110ca411d6478060fdea.sample"] | ||||||
|  |  | ||||||
|  | [params] | ||||||
|  |  | ||||||
|  | force/8_bit=false | ||||||
|  | force/mono=false | ||||||
|  | force/max_rate=false | ||||||
|  | force/max_rate_hz=44100 | ||||||
|  | edit/trim=false | ||||||
|  | edit/normalize=false | ||||||
|  | edit/loop_mode=0 | ||||||
|  | edit/loop_begin=0 | ||||||
|  | edit/loop_end=-1 | ||||||
|  | compress/mode=2 | ||||||
		Reference in New Issue
	
	Block a user