Debug stats and nonfunctional bursts

This commit is contained in:
Marco 2024-11-11 15:41:34 +01:00
commit e6448c7f0a
6 changed files with 258 additions and 34 deletions

11
Scenes/debug_stats.tscn Normal file
View file

@ -0,0 +1,11 @@
[gd_scene load_steps=2 format=3 uid="uid://cio2gclfs7s37"]
[ext_resource type="Script" path="res://Scripts/DebugStats.cs" id="1_22s7t"]
[node name="DebugStats" type="MarginContainer"]
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_22s7t")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2

View file

@ -1,9 +1,10 @@
[gd_scene load_steps=6 format=3 uid="uid://cwfaxgr8pgfga"]
[gd_scene load_steps=7 format=3 uid="uid://cwfaxgr8pgfga"]
[ext_resource type="Script" path="res://Scenes/game.gd" id="1_s0gpj"]
[ext_resource type="Script" path="res://Scenes/PixelPerfectRendering.gd" id="2_gdejn"]
[ext_resource type="PackedScene" uid="uid://bv451a8wgty4u" path="res://Scenes/test.tscn" id="3_l2ygy"]
[ext_resource type="Script" path="res://Scenes/SubViewportSprite.gd" id="4_adb7a"]
[ext_resource type="PackedScene" uid="uid://cio2gclfs7s37" path="res://Scenes/debug_stats.tscn" id="5_ixk64"]
[sub_resource type="ViewportTexture" id="ViewportTexture_m5h5j"]
viewport_path = NodePath("PixelPerfectRendering/SubViewport")
@ -30,3 +31,5 @@ position = Vector2(960, 540)
scale = Vector2(6, 6)
texture = SubResource("ViewportTexture_m5h5j")
script = ExtResource("4_adb7a")
[node name="DebugStats" parent="." instance=ExtResource("5_ixk64")]

109
Scripts/DebugStats.cs Normal file
View file

@ -0,0 +1,109 @@
using Godot;
using System;
using System.Collections.Generic;
public partial class DebugStats : Node
{
//public DebugStats Stats => GetNode<DebugStats>("VBoxContainer");
private class Property
{
public string NumFormat { get; set; } = "%4.2f";
public Node Object { get; set; } // The object being tracked.
public string PropertyPath { get; set; } // The property to display (NodePath).
public Label LabelRef { get; set; } // A reference to the Label.
public string Display { get; set; } // Display option (rounded, etc.)
public Property(Node obj, string property, Label label, string display)
{
Object = obj;
PropertyPath = property;
LabelRef = label;
Display = display;
}
public void SetLabel()
{
// Sets the label's text.
string s = $"{Object.Name}/{PropertyPath} : ";
var p = Object.GetIndexed(PropertyPath);
switch (Display)
{
case "":
s += p.ToString();
break;
case "length":
// Handle length for Vector2 and Vector3
if (p.VariantType == Variant.Type.Vector2)
{
Vector2 v2 = p.As<Vector2>();
s += string.Format(NumFormat, v2.Length());
}
else if (p.VariantType == Variant.Type.Vector3)
{
Vector3 v3 = p.As<Vector3>();
s += string.Format(NumFormat, v3.Length());
}
else
{
s += "N/A"; // Handle non-applicable types
}
break;
case "round":
// For handling numbers (int and float)
if (p.VariantType == Variant.Type.Float || p.VariantType == Variant.Type.Int)
{
s += string.Format(NumFormat, p.As<float>());
}
else if (p.VariantType == Variant.Type.Vector2)
{
Vector2 v2Round = p.As<Vector2>();
s += v2Round.Round().ToString();
}
else if (p.VariantType == Variant.Type.Vector3)
{
Vector3 v3Round = p.As<Vector3>();
s += v3Round.Round().ToString();
}
break;
}
LabelRef.Text = s;
}
}
private List<Property> props = new List<Property>(); // An array of the tracked properties.
public static DebugStats Instance { get; private set; }
public override void _Ready()
{
Instance = this;
}
public override void _Process(double delta)
{
// if (!Visible)
// return;
foreach (var prop in props)
{
prop.SetLabel();
}
}
public void AddProperty(Node obj, string property, string display)
{
Label label = new Label();
label.Set("custom_fonts/font", GD.Load<Font>("res://fonts/Xolonium-Regular.ttf"));
GetNode<VBoxContainer>("VBoxContainer").AddChild(label);
props.Add(new Property(obj, property, label, display));
}
public void RemoveProperty(Node obj, string property)
{
props.RemoveAll(prop => prop.Object == obj && prop.PropertyPath == property);
}
}

View file

@ -13,40 +13,59 @@ public partial class Enemy : Area2D, IDestructible
[Export] public float Health = 4f;
[Export] public double RateOfFire = 0.4f;
[Export] public double RateOfFire = 0.4f; // Time between shots within a burst
[Export] public float BulletSpeed = 100f;
[Export] public int BurstCount = 3; // Number of shots per burst
[Export] public float BurstCooldown = 1f; // Time between bursts
[Export] public bool AimAtPlayer = true; // Whether to aim at player or shoot straight
private float _currentHealth = 0f;
private bool _isDestroyed = false;
private Timer _cooldownTimer;
private Timer _burstTimer;
private Timer _shotTimer;
private int _shotsFired = 0;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
_currentHealth = Health;
_cooldownTimer = GetNode<Timer>("./ShootTimer");
// Initialize timers
_burstTimer = new Timer();
_shotTimer = new Timer();
AddChild(_burstTimer);
AddChild(_shotTimer);
_burstTimer.WaitTime = BurstCooldown;
_burstTimer.OneShot = true;
_shotTimer.WaitTime = RateOfFire;
_shotTimer.OneShot = true;
_shotTimer.Timeout += OnShotTimerTimeout;
_burstTimer.Timeout += OnBurstTimerTimeout;
// Debug
DebugStats.Instance.AddProperty(this, "_currentHealth", "");
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
switch (_currentState)
{
case EnemyState.Idle:
break;
case EnemyState.Primed:
// Have the raycast follow the player and shoot if visible
//HandlePlayerDetection();
break;
//case EnemyState.Shooting:
// Shoot
//break;
default:
break;
}
@ -64,36 +83,67 @@ public partial class Enemy : Area2D, IDestructible
return;
}
if (_cooldownTimer.IsStopped() && IsPlayerInSight())
if (_burstTimer.IsStopped() && !_shotTimer.IsStopped() && IsPlayerInSight())
{
// SHOOT
var bullet = this.CreateChild<Bullet>(BulletScene);
// var bullet = BulletScene.Instantiate<Bullet>();
// Owner.AddChild(bullet);
// bullet.Transform = this.GlobalTransform;
// bullet.Position = this.Position;
bullet.SetDirection((_cachedPlayer.GlobalPosition - this.GlobalPosition).Normalized());
bullet.Speed = BulletSpeed;
_cooldownTimer.Start(RateOfFire);
StartBurst();
}
}
private void StartBurst()
{
_shotsFired = 0;
_shotTimer.Start();
}
private void OnShotTimerTimeout()
{
if (_shotsFired < BurstCount)
{
Shoot();
_shotsFired++;
if (_shotsFired < BurstCount)
{
_shotTimer.Start(); // Restart for the next shot in the burst
}
}
else
{
_burstTimer.Start(); // Start cooldown between bursts
}
}
private void OnBurstTimerTimeout()
{
// Cooldown complete, can start new burst when conditions are met
}
private void Shoot()
{
var bullet = this.CreateChild<Bullet>(BulletScene);
if (AimAtPlayer)
{
bullet.SetDirection((_cachedPlayer.GlobalPosition - this.GlobalPosition).Normalized());
}
else
{
bullet.SetDirection(Vector2.Right.Rotated(this.Rotation));
}
bullet.Speed = BulletSpeed;
}
private bool IsPlayerInSight()
{
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(this.GlobalPosition, _cachedPlayer.GlobalPosition, CollisionMask, new Godot.Collections.Array<Rid> { GetRid() });
var result = spaceState.IntersectRay(query);
// If count is 0 then the player is in sight, otherwise there is level geometry in the way
return result.Count == 0;
// if (result.Count > 0)
// GD.Print("Hit at point: ", result["position"]);
return result.Count == 0; // True if no obstacles between enemy and player
}
private void _on_player_detection_area_entered(Area2D area)
{
// Assume area is player for now
if (area is InteractionController player)
{
Debug.WriteLine("Enemy detection area Entered by interaction controller");
@ -114,24 +164,21 @@ public partial class Enemy : Area2D, IDestructible
}
}
// Bullets collision
private void _on_area_entered(Area2D area)
{
// Collision handling
}
private void Explode()
{
Debug.WriteLine("Ded");
//CreateParticles();
//CreateDebris();
QueueFree();
}
public void Hit(float damage)
{
if (_isDestroyed) return;
_currentHealth -= damage;
if (!(_currentHealth <= 0)) return;
_isDestroyed = true;

50
Scripts/debug_stats.gd Normal file
View file

@ -0,0 +1,50 @@
extends MarginContainer
class Property:
var num_format = "%4.2f"
var object # The object being tracked.
var property # The property to display (NodePath).
var label_ref # A reference to the Label.
var display # Display option (rounded, etc.)
func _init(_object, _property, _label, _display):
object = _object
property = _property
label_ref = _label
display = _display
func set_label():
# Sets the label's text.
var s = object.name + "/" + property + " : "
var p = object.get_indexed(property)
match display:
"":
s += str(p)
"length":
s += num_format % p.length()
"round":
match typeof(p):
TYPE_INT, TYPE_FLOAT:
s += num_format % p
TYPE_VECTOR2, TYPE_VECTOR3:
s += str(p.round())
label_ref.text = s
var props = [] # An array of the tracked properties.
func _process(_delta):
if not visible:
return
for prop in props:
prop.set_label()
func add_property(object, property, display):
var label = Label.new()
label.set("custom_fonts/font", load("res://debug/roboto_16.tres"))
$VBoxContainer.add_child(label)
props.append(Property.new(object, property, label, display))
func remove_property(object, property):
for prop in props:
if prop.object == object and prop.property == property:
props.erase(prop)

View file

@ -15,6 +15,10 @@ run/main_scene="res://Scenes/game.tscn"
config/features=PackedStringArray("4.3", "C#", "GL Compatibility")
config/icon="res://icon.svg"
[autoload]
DebugStats="*res://Scenes/debug_stats.tscn"
[display]
window/size/viewport_width=1920