✨ Turret shooting and damaing
This commit is contained in:
		
							
								
								
									
										97
									
								
								Scripts/Entities/Bullet.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Scripts/Entities/Bullet.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| using Godot; | ||||
|  | ||||
| namespace AceFieldNewHorizon.Scripts.Entities; | ||||
|  | ||||
| public partial class Bullet : Area2D | ||||
| { | ||||
|     [Export] public float Speed = 400.0f; | ||||
|     [Export] public int Damage = 10; | ||||
|     [Export] public float MaxDistance = 1000.0f; | ||||
|      | ||||
|     private Vector2 _direction = Vector2.Right; | ||||
|     private Vector2 _startPosition; | ||||
|     private float _distanceTraveled = 0f; | ||||
|     private bool _hasHit = false; | ||||
|     private uint _ignoreCollisionLayer = 0; // Layer to ignore (will be set by turret) | ||||
|  | ||||
|     public void Initialize(Vector2 direction, Vector2 position, float rotation, uint ignoreLayer = 0) | ||||
|     { | ||||
|         _direction = direction.Normalized(); | ||||
|         Position = position; | ||||
|         Rotation = rotation; | ||||
|         _startPosition = position; | ||||
|         _ignoreCollisionLayer = ignoreLayer; | ||||
|          | ||||
|         // Connect the area entered signal | ||||
|         BodyEntered += OnBodyEntered; | ||||
|         AreaEntered += OnAreaEntered; | ||||
|     } | ||||
|  | ||||
|     public override void _PhysicsProcess(double delta) | ||||
|     { | ||||
|         if (_hasHit) return; | ||||
|          | ||||
|         // Move the bullet | ||||
|         var movement = _direction * Speed * (float)delta; | ||||
|         Position += movement; | ||||
|         _distanceTraveled += movement.Length(); | ||||
|          | ||||
|         // Check if bullet has traveled max distance | ||||
|         if (_distanceTraveled >= MaxDistance) | ||||
|         { | ||||
|             QueueFree(); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private void OnBodyEntered(Node2D body) | ||||
|     { | ||||
|         HandleCollision(body); | ||||
|     } | ||||
|      | ||||
|     private void OnAreaEntered(Area2D area) | ||||
|     { | ||||
|         HandleCollision(area); | ||||
|     } | ||||
|      | ||||
|     private void HandleCollision(Node2D node) | ||||
|     { | ||||
|         if (_hasHit) return; | ||||
|          | ||||
|         // Skip collision if it's on the ignore layer | ||||
|         if (node is PhysicsBody2D physicsBody &&  | ||||
|             (physicsBody.CollisionLayer & _ignoreCollisionLayer) != 0) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         _hasHit = true; | ||||
|          | ||||
|         // If we hit an enemy, deal damage | ||||
|         if (node is Enemy enemy) | ||||
|         { | ||||
|             // Get the global position where the bullet hit | ||||
|             var hitPosition = GlobalPosition; | ||||
|             enemy.TakeDamage(Damage, hitPosition); | ||||
|         } | ||||
|          | ||||
|         // Optional: Add hit effect here | ||||
|         // CreateHitEffect(); | ||||
|          | ||||
|         // Remove the bullet | ||||
|         QueueFree(); | ||||
|     } | ||||
|      | ||||
|     private void CreateHitEffect() | ||||
|     { | ||||
|         // You can add a hit effect here if desired | ||||
|         // For example, a small explosion or impact sprite | ||||
|     } | ||||
|      | ||||
|     public override void _ExitTree() | ||||
|     { | ||||
|         // Clean up signal connections | ||||
|         BodyEntered -= OnBodyEntered; | ||||
|         AreaEntered -= OnAreaEntered; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1
									
								
								Scripts/Entities/Bullet.cs.uid
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Scripts/Entities/Bullet.cs.uid
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| uid://vgx2a8gm7l8b | ||||
| @@ -11,14 +11,52 @@ public partial class Enemy : CharacterBody2D | ||||
|     [Export] public float AttackRange = 50.0f; | ||||
|     [Export] public int Damage = 10; | ||||
|     [Export] public float AttackCooldown = 1.0f; | ||||
|     [Export] public int MaxHealth = 100; | ||||
|     [Export] public bool ShowDamageNumbers = true; | ||||
|      | ||||
|     private Player _player; | ||||
|     private float _attackTimer = 0; | ||||
|     private bool _isPlayerInRange = false; | ||||
|     private Area2D _detectionArea; | ||||
|     private int _currentHealth; | ||||
|     private ProgressBar _healthBar; | ||||
|      | ||||
|     public int CurrentHealth | ||||
|     { | ||||
|         get => _currentHealth; | ||||
|         private set | ||||
|         { | ||||
|             _currentHealth = Mathf.Clamp(value, 0, MaxHealth); | ||||
|             UpdateHealthBar(); | ||||
|              | ||||
|             if (_currentHealth <= 0) | ||||
|             { | ||||
|                 Die(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public bool IsDead => _currentHealth <= 0; | ||||
|  | ||||
|     public override void _Ready() | ||||
|     { | ||||
|         _currentHealth = MaxHealth; | ||||
|          | ||||
|         // Create health bar | ||||
|         _healthBar = new ProgressBar | ||||
|         { | ||||
|             MaxValue = MaxHealth, | ||||
|             Value = _currentHealth, | ||||
|             Size = new Vector2(40, 4), | ||||
|             ShowPercentage = false, | ||||
|             Visible = false | ||||
|         }; | ||||
|          | ||||
|         var healthBarContainer = new Control(); | ||||
|         healthBarContainer.AddChild(_healthBar); | ||||
|         AddChild(healthBarContainer); | ||||
|         healthBarContainer.Position = new Vector2(-20, -20); // Adjust position as needed | ||||
|          | ||||
|         // Create detection area | ||||
|         _detectionArea = new Area2D(); | ||||
|         var collisionShape = new CollisionShape2D(); | ||||
| @@ -37,6 +75,8 @@ public partial class Enemy : CharacterBody2D | ||||
|      | ||||
|     public override void _Process(double delta) | ||||
|     { | ||||
|         if (IsDead) return; | ||||
|          | ||||
|         if (_player != null && _isPlayerInRange) | ||||
|         { | ||||
|             // Face the player | ||||
| @@ -60,8 +100,68 @@ public partial class Enemy : CharacterBody2D | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public void TakeDamage(int damage, Vector2? hitPosition = null) | ||||
|     { | ||||
|         if (IsDead) return; | ||||
|          | ||||
|         CurrentHealth -= damage; | ||||
|          | ||||
|         // Show damage number (optional) | ||||
|         if (ShowDamageNumbers) | ||||
|         { | ||||
|             var damageLabel = new Label | ||||
|             { | ||||
|                 Text = $"-{damage}", | ||||
|                 Position = hitPosition ?? GlobalPosition, | ||||
|                 ZIndex = 1000 | ||||
|             }; | ||||
|              | ||||
|             GetTree().CurrentScene.AddChild(damageLabel); | ||||
|              | ||||
|             // Animate and remove damage number | ||||
|             var tween = CreateTween(); | ||||
|             tween.TweenProperty(damageLabel, "position:y", damageLabel.Position.Y - 30, 0.5f); | ||||
|             tween.TweenCallback(Callable.From(() => damageLabel.QueueFree())).SetDelay(0.5f); | ||||
|         } | ||||
|          | ||||
|         // Visual feedback | ||||
|         var originalModulate = Modulate; | ||||
|         Modulate = new Color(1, 0.5f, 0.5f); // Flash red | ||||
|          | ||||
|         var tweenFlash = CreateTween(); | ||||
|         tweenFlash.TweenProperty(this, "modulate", originalModulate, 0.2f); | ||||
|     } | ||||
|      | ||||
|     private void UpdateHealthBar() | ||||
|     { | ||||
|         if (_healthBar != null) | ||||
|         { | ||||
|             _healthBar.Value = _currentHealth; | ||||
|             _healthBar.Visible = _currentHealth < MaxHealth; // Only show when damaged | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private void Die() | ||||
|     { | ||||
|         // Play death animation/sound | ||||
|         // You can add a death animation here | ||||
|          | ||||
|         // Disable collisions and hide | ||||
|         SetProcess(false); | ||||
|         SetPhysicsProcess(false); | ||||
|         Hide(); | ||||
|          | ||||
|         // Queue free after a delay (for any death animation/sound to play) | ||||
|         var timer = new Timer(); | ||||
|         AddChild(timer); | ||||
|         timer.Timeout += () => QueueFree(); | ||||
|         timer.Start(0.5f); | ||||
|     } | ||||
|      | ||||
|     private void TryAttackPlayer(double delta) | ||||
|     { | ||||
|         if (IsDead) return; | ||||
|          | ||||
|         _attackTimer += (float)delta; | ||||
|          | ||||
|         if (_attackTimer >= AttackCooldown) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user