First builds and stuff done yipewaho

This commit is contained in:
2026-02-01 05:32:22 +02:00
parent 12c1360ae7
commit d910018b7b
62 changed files with 1886 additions and 37 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ public partial class CameraController : Camera2D
[Export] private float maxX = 0f;
[Export] private float minY = 0f;
[Export] private float maxY = 0f;
private bool _dragging;
private Vector2 _grabWorldPos;
+77
View File
@@ -6,13 +6,90 @@ public partial class GameController : Node
public static GameController Instance;
[Export] private float _ShrineStartHP;
[Export] private Label _CurrencyLabel;
[Export] private Label _ShrineHealthLabel;
public int Wave { get; private set; }
public int Currency { get; private set; }
public float ShrineHealth { get; private set; }
private bool _waveOnGoing = false;
public override void _Ready()
{
GameController.Instance = this;
Wave = 0;
Currency = 300;
ShrineHealth = 100;
_CurrencyLabel.Text = Currency.ToString();
_ShrineHealthLabel.Text = $"{(100f * (ShrineHealth /_ShrineStartHP)):F1}%";
CallDeferred(nameof(DelayNextWave));
}
private void StartWave()
{
if (_waveOnGoing) return;
Wave++;
_waveOnGoing = true;
int amountToSpawn = (int)Math.Round(5 * Math.Pow(Wave, 1.05));
for (int i = 0; i < 100; i++)
{
// GD.Print((int)Math.Round(5 * Math.Pow(i + 1, 1.05)));
}
EnemySpawner.Instance.EnemiesSpawned = amountToSpawn;
float baseDelay = 0.67f;
float minDelay = 0.12f; // never go below this
float delay = Math.Max(minDelay, baseDelay * (float)Math.Pow(0.96f, Wave));
for (int i = 0; i < amountToSpawn; i++)
{
EnemySpawner.Instance.SpawnWithDelay(i * delay);
}
}
private async void DelayNextWave()
{
await ToSignal(GetTree().CreateTimer(7.5f), SceneTreeTimer.SignalName.Timeout);
CallDeferred(nameof(StartWave));
}
public void WaveComplete()
{
_waveOnGoing = false;
CallDeferred(nameof(DelayNextWave));
}
public void DamageShrine(float v)
{
v = Math.Abs(v);
ShrineHealth -= v;
_ShrineHealthLabel.Text = $"{(100f * (ShrineHealth /_ShrineStartHP)):F1}%";
if (ShrineHealth <= 0)
{
// TODO LOSE SCENARIO
}
}
public void AddCurrency(int v)
{
v = Math.Abs(v);
Currency += v;
_CurrencyLabel.Text = Currency.ToString();
}
public bool TryRemoveCurrency(int v)
{
v = Math.Abs(v);
if (Currency < v) return false;
Currency -= v;
_CurrencyLabel.Text = Currency.ToString();
return true;
}
}
+9 -2
View File
@@ -11,15 +11,20 @@ public partial class Health : Node
[Signal]
public delegate void DeathEventHandler(Node2D node);
[Signal]
public delegate void DamagedEventHandler();
public override void _EnterTree()
{
CurHP = MaxHP = _baseMaxHp * Mathf.Pow(GameController.Instance.Wave, 1.067f);
// CurHP = MaxHP = _baseMaxHp * Mathf.Pow(GameController.Instance.Wave, 1.067f);
Reset();
}
public void Substract(float v)
{
v = Mathf.Abs(v);
CurHP -= v;
EmitSignalDamaged();
if (CurHP <= 0)
{
EmitSignalDeath(_parent);
@@ -34,6 +39,8 @@ public partial class Health : Node
public void Reset()
{
CurHP = MaxHP = _baseMaxHp * Mathf.Pow(GameController.Instance.Wave, 1.067f);
CurHP = MaxHP = _baseMaxHp * Mathf.Pow(1.075f, GameController.Instance.Wave);
GD.Print("Curhp");
GD.Print(CurHP);
}
}
+13 -1
View File
@@ -5,14 +5,21 @@ public partial class Enemy : PathFollow2D
{
[Export] public EnemyType Type;
[Export] public Health Health;
[Export] private AudioStreamPlayer2D _audio;
public event Action<Enemy> Died;
public event Action<Enemy> ReachedShrine;
public override void _Ready()
{
Health.Death += _ => Died?.Invoke(this);
Health.Damaged += () =>
{
_audio?.SetPitchScale(RandomHelper.Float(0.8f, 1.2f));
_audio?.Play();
};
}
public void ResetEnemy()
{
GlobalPosition = Vector2.Zero;
@@ -23,4 +30,9 @@ public partial class Enemy : PathFollow2D
Health.Reset();
// reset velocity, animation, AI, etc here
}
public void Despawn()
{
ReachedShrine?.Invoke(this);
}
}
+9 -1
View File
@@ -3,9 +3,12 @@ using System;
public partial class EnemyMovement : Node
{
[Export] private Enemy _enemy;
[Export] private PathFollow2D _pathFollow2D;
[Export] private float _speed;
private float _finalSpeed => _speed + 0.15f * (float)Math.Log(GameController.Instance.Wave + 1);
private double _time = 0;
public override void _EnterTree()
@@ -15,6 +18,11 @@ public partial class EnemyMovement : Node
public override void _Process(double delta)
{
_pathFollow2D.ProgressRatio += (float)delta * (_speed / 1000f);
_pathFollow2D.ProgressRatio += (float)delta * (_finalSpeed / 1000f);
if (_pathFollow2D.ProgressRatio >= 1.0)
{
_enemy.Despawn();
}
}
}
+19 -1
View File
@@ -30,7 +30,8 @@ public partial class EnemyPool : Node
private Enemy CreateEnemy(EnemyType type)
{
var e = _scenes[type].Instantiate<Enemy>();
e.Died += ReturnToPool;
e.Died += Died;
e.ReachedShrine += DamageShrine;
return e;
}
@@ -44,8 +45,25 @@ public partial class EnemyPool : Node
return e;
}
private void DamageShrine(Enemy e)
{
GameController.Instance.DamageShrine(5);
ReturnToPool(e);
}
private void Died(Enemy e)
{
GameController.Instance.AddCurrency(25);
ReturnToPool(e);
}
private void ReturnToPool(Enemy e)
{
EnemySpawner.Instance.EnemiesSpawned--;
if (EnemySpawner.Instance.EnemiesSpawned <= 0)
{
GameController.Instance.WaveComplete();
}
e.GetParent()?.RemoveChild(e);
e.ProcessMode = ProcessModeEnum.Disabled;
_pool[e.Type].Enqueue(e);
+9 -3
View File
@@ -3,22 +3,28 @@ using System.Collections.Generic;
public partial class EnemySpawner : Node
{
public static EnemySpawner Instance;
[Export] private Node _pathParent;
[Export] private EnemyPool _pool;
private readonly List<Path2D> _paths = new();
public int EnemiesSpawned = 0;
public override void _Ready()
{
Instance = this;
foreach (var c in _pathParent.GetChildren())
if (c is Path2D p)
_paths.Add(p);
for (int i = 0; i < 10; i++)
SpawnWithDelay(i * 0.33f);
// for (int i = 0; i < 10; i++)
// SpawnWithDelay(i * 0.33f);
}
private async void SpawnWithDelay(float t)
public async void SpawnWithDelay(float t)
{
await ToSignal(GetTree().CreateTimer(t), SceneTreeTimer.SignalName.Timeout);
Spawn();
+16
View File
@@ -0,0 +1,16 @@
extends Node2D
@export var float_height := 2.0
@export var float_speed := 1.25
var start_y := 0.0
var time := 0.0
var phase := 0.0
func _ready():
start_y = position.y
phase = randf() * TAU # Random value between 0
func _process(delta):
time += delta * float_speed
position.y = start_y + sin(time + phase) * float_height
+1
View File
@@ -0,0 +1 @@
uid://dxcke7geb20dm
+6 -4
View File
@@ -26,14 +26,16 @@ public partial class ProjectilePool : Node
public Projectile Get()
{
var p = _pool.Count > 0 ? _pool.Dequeue() : CreateProjectile();
return p;
// var p = _pool.Count > 0 ? _pool.Dequeue() : CreateProjectile();
// return p;
return CreateProjectile();
}
private void ReturnToPool(Projectile p)
{
p.GetParent()?.RemoveChild(p);
p.ProcessMode = ProcessModeEnum.Disabled;
_pool.Enqueue(p);
p.QueueFree();
// p.ProcessMode = ProcessModeEnum.Disabled;
// _pool.Enqueue(p);
}
}
+12
View File
@@ -0,0 +1,12 @@
using Godot;
public partial class DragArea : Area2D
{
public override void _InputEvent(Viewport viewport, InputEvent @event, int shapeIdx)
{
if (@event is InputEventMouseButton mb && mb.Pressed)
{
GD.Print("Area clicked");
}
}
}
+1
View File
@@ -0,0 +1 @@
uid://bwgxw6ox8b1tq
+76
View File
@@ -0,0 +1,76 @@
using Godot;
public partial class DragMover : Node
{
[Export] public Node2D Parent; // The node that will move
[Export] public Area2D DragArea; // Click detection
[Export] public Area2D CheckArea; // Overlap validation
[Export] public Area2D ShootArea; // This gets disabled while dragging
private bool _dragging;
private Vector2 _dragOffset;
private Vector2 _originalPosition;
private bool _canMove = true;
public override void _Ready()
{
if (Parent == null || DragArea == null || CheckArea == null)
{
GD.PushError("DragMover exports are not assigned.");
return;
}
DragArea.InputEvent += OnDragAreaInputEvent;
_originalPosition = Parent.GlobalPosition;
}
private void OnDragAreaInputEvent(Node viewport, InputEvent @event, long shapeIdx)
{
if (!_canMove) return;
if (@event is not InputEventMouseButton mb) return;
if (mb.ButtonIndex != MouseButton.Left) return;
if (mb.Pressed)
{
_dragging = true;
ShootArea.Monitoring = false;
_originalPosition = Parent.GlobalPosition;
_dragOffset = Parent.GlobalPosition - Parent.GetGlobalMousePosition();
}
else
{
_dragging = false;
ShootArea.Monitoring = true;
// Check overlaps when released
if (CheckArea.HasOverlappingAreas() || CheckArea.HasOverlappingBodies())
{
Parent.GlobalPosition = _originalPosition;
}
else
{
MovementDelay();
}
}
}
public override void _Process(double delta)
{
if (!_dragging) return;
Parent.GlobalPosition = Parent.GetGlobalMousePosition() + _dragOffset;
}
private async void MovementDelay()
{
ShootArea.Monitoring = false;
_canMove = false;
Parent.SetModulate(Color.FromHtml("ffffff20"));
await ToSignal(GetTree().CreateTimer(4), SceneTreeTimer.SignalName.Timeout);
Parent.SetModulate(Color.FromHtml("ffffffff"));
ShootArea.Monitoring = true;
_canMove = true;
}
}
+1
View File
@@ -0,0 +1 @@
uid://bpqof3jshxnug
+3 -2
View File
@@ -11,6 +11,7 @@ public partial class Turret : Node
[Export] private float _fireRate;
[Export] private Node2D _parent;
[Export] private ProjectilePool _projectilePool;
[Export] private AudioStreamPlayer2D _audio;
private float _fireTimer = 0f;
private HashSet<Enemy> _enemiesInRange = new HashSet<Enemy>();
@@ -26,7 +27,6 @@ public partial class Turret : Node
if (enemyHitBox is EnemyArea earea)
{
_enemiesInRange.Add(earea.Enemy);
GD.Print(earea.Name);
}
}
@@ -35,7 +35,6 @@ public partial class Turret : Node
if (enemyHitBox is EnemyArea earea)
{
_enemiesInRange.Remove(earea.Enemy);
GD.Print(earea.Name);
}
}
@@ -45,6 +44,8 @@ public partial class Turret : Node
_fireTimer += (float)delta;
if (!(_fireTimer >= 1f / _fireRate)) return;
_fireTimer = 0;
_audio?.SetPitchScale(RandomHelper.Float(0.8f, 1.2f));
_audio?.Play();
var t = Helpers.GetClosest(_parent,_enemiesInRange.ToArray());
var dir = (t.GlobalPosition - _parent.GlobalPosition).Normalized();
var proj = _projectilePool.Get();
+73 -3
View File
@@ -1,8 +1,78 @@
using System;
using Godot;
using Godot.Collections;
namespace fgj26.Scripts.Turrets;
public enum TurretType
{
Kitsune,
Oni,
Tengu
}
public partial class TurretController : Node2D
{
}
[Export] private Dictionary<TurretType, PackedScene> _typeToPrefab;
[Export] private Dictionary<TurretType, PackedScene> _typeToPlaceholder;
[Export] private Node2D _turretParent;
[Signal]
public delegate void PlaceTurretEventHandler(TurretType t);
private bool _placingTurret = false;
private TurretPlaceholder _turretPlaceholder;
private TurretType _currentlyPlacingType;
public override void _Ready()
{
PlaceTurret += StartPlaceingTurret;
}
public override void _Input(InputEvent @event)
{
if (_turretPlaceholder == null) return;
if (!_placingTurret) return;
var mpos = GetGlobalMousePosition();
_turretPlaceholder.GlobalPosition = mpos;
if (@event is InputEventMouseButton mb)
{
switch (mb.ButtonIndex)
{
case MouseButton.Left:
if (!_turretPlaceholder.CanPlace) return;
if (!GameController.Instance.TryRemoveCurrency(_turretPlaceholder.Cost)) return;
var newT = _typeToPrefab[_currentlyPlacingType].Instantiate() as Node2D;
_turretParent.AddChild(newT);
newT.GlobalPosition = mpos;
break;
case MouseButton.Right:
break;
default:
return;
}
StopPlacingTurret();
}
}
private void StartPlaceingTurret(TurretType t)
{
if (_turretPlaceholder != null)
{
_turretPlaceholder.GetParent()?.RemoveChild(_turretPlaceholder);
_turretPlaceholder.QueueFree();
}
_turretPlaceholder = _typeToPlaceholder[t].Instantiate() as TurretPlaceholder;
_turretParent.AddChild(_turretPlaceholder);
_currentlyPlacingType = t;
_placingTurret = true;
}
private void StopPlacingTurret()
{
_turretPlaceholder.GetParent()?.RemoveChild(_turretPlaceholder);
_turretPlaceholder.QueueFree();
_turretPlaceholder = null;
_placingTurret = false;
}
}
+15
View File
@@ -0,0 +1,15 @@
using Godot;
public partial class TurretPlaceholder : Node2D
{
[Export] private Area2D _placementChecker;
[Export] public int Cost = 75;
public bool CanPlace { get; private set; }
public override void _Process(double delta)
{
CanPlace = !_placementChecker.HasOverlappingAreas() && !_placementChecker.HasOverlappingBodies();
SetModulate(CanPlace ? Color.FromHtml("ffffff80") : Color.FromHtml("ff000080"));
}
}
+1
View File
@@ -0,0 +1 @@
uid://c4764ubjc3tan