From 286dfb8061d60ab15efe524e59e746e101d6de89 Mon Sep 17 00:00:00 2001 From: copygirl Date: Tue, 18 May 2021 14:51:47 +0200 Subject: [PATCH] Implement health, death & respawn - Add Health HUD element - Add Damage to weapons - Bullet does damage to players - Players die and respawn - Hit decal spawned by server - Disable various processing when player is not alive --- scene/ClientScene.tscn | 10 ++-- scene/Player.tscn | 4 ++ src/HUD/Health.cs | 94 +++++++++++++++++++++++++++++++++++ src/HUD/RadialMenu.cs | 32 +++++------- src/Items/CreativeBuilding.cs | 9 ++-- src/Items/Weapon.cs | 25 +++++++--- src/Objects/Bullet.cs | 24 ++++++--- src/Objects/HitDecal.cs | 1 - src/Objects/LocalPlayer.cs | 2 +- src/Objects/Player.cs | 47 ++++++++++++++++-- src/World.cs | 10 ++++ 11 files changed, 213 insertions(+), 45 deletions(-) create mode 100644 src/HUD/Health.cs diff --git a/scene/ClientScene.tscn b/scene/ClientScene.tscn index 70cc1d7..9ec383a 100644 --- a/scene/ClientScene.tscn +++ b/scene/ClientScene.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=16 format=2] +[gd_scene load_steps=17 format=2] [ext_resource path="res://scene/GameScene.tscn" type="PackedScene" id=1] [ext_resource path="res://src/HUD/Cursor.cs" type="Script" id=2] @@ -12,6 +12,7 @@ [ext_resource path="res://ui_theme.tres" type="Theme" id=10] [ext_resource path="res://src/HUD/RadialMenu.cs" type="Script" id=11] [ext_resource path="res://src/HUD/WeaponInfo.cs" type="Script" id=12] +[ext_resource path="res://src/HUD/Health.cs" type="Script" id=13] [sub_resource type="StyleBoxFlat" id=1] bg_color = Color( 0, 0, 0, 0.752941 ) @@ -63,7 +64,10 @@ __meta__ = { [node name="HUD" type="CanvasLayer" parent="." index="4"] -[node name="RadialMenu" type="Node2D" parent="HUD" index="0"] +[node name="Health" type="Node2D" parent="HUD" index="0"] +script = ExtResource( 13 ) + +[node name="RadialMenu" type="Node2D" parent="HUD" index="1"] visible = false script = ExtResource( 11 ) @@ -84,7 +88,7 @@ __meta__ = { "_edit_use_anchors_": false } -[node name="EscapeMenu" parent="HUD" index="1" instance=ExtResource( 7 )] +[node name="EscapeMenu" parent="HUD" index="2" instance=ExtResource( 7 )] visible = false [node name="CursorLayer" type="CanvasLayer" parent="." index="5"] diff --git a/scene/Player.tscn b/scene/Player.tscn index cd74a8a..e70697a 100644 --- a/scene/Player.tscn +++ b/scene/Player.tscn @@ -76,6 +76,7 @@ SpreadIncrease = 1.0 RecoilMin = 3.0 RecoilMax = 5.0 BulletVelocity = 1200 +Damage = 0.22 [node name="Tip" type="Node2D" parent="Items/Revolver"] position = Vector2( 15, -2.5 ) @@ -99,6 +100,7 @@ EffectiveRange = 240 MaximumRange = 360 BulletVelocity = 1000 BulletsPerShot = 6 +Damage = 0.6 BulletOpacity = 0.1 [node name="Tip" type="Node2D" parent="Items/Shotgun"] @@ -121,6 +123,7 @@ RecoilMax = 8.0 EffectiveRange = 480 MaximumRange = 920 BulletVelocity = 4000 +Damage = 0.8 BulletOpacity = 0.4 [node name="Tip" type="Node2D" parent="Items/Rifle"] @@ -143,6 +146,7 @@ Spread = 0.6 SpreadIncrease = 0.8 RecoilMin = 1.0 RecoilMax = 2.5 +Damage = 0.12 BulletOpacity = 0.15 [node name="Tip" type="Node2D" parent="Items/Assault Rifle"] diff --git a/src/HUD/Health.cs b/src/HUD/Health.cs new file mode 100644 index 0000000..c8a8654 --- /dev/null +++ b/src/HUD/Health.cs @@ -0,0 +1,94 @@ +using System; +using Godot; + +public class Health : Node2D +{ + private static readonly TimeSpan VISIBLE_TIME = TimeSpan.FromSeconds(1.0); + private static readonly TimeSpan FADE_TIME = TimeSpan.FromSeconds(1.5); + + [Export] public int Segments { get; set; } = 6; + [Export] public int InnerRadius { get; set; } = 14; + [Export] public int OuterRadius { get; set; } = 24; + [Export] public float Separation { get; set; } = 2.0F; + + private float _startAngle; + private float _health; + private float _visibilityTimer; + + public override void _Ready() + { + _startAngle = (-Mathf.Tau / 4) - (Mathf.Tau / Segments / 2); + Visible = false; + } + + public override void _Process(float delta) + { + if (!(this.GetClient().LocalPlayer is Player player)) + { Visible = false; return; } + + if (player.Health >= 1.0F) { + if (!Visible) return; + _visibilityTimer += delta; + if (_visibilityTimer > (VISIBLE_TIME + FADE_TIME).TotalSeconds) + { Visible = false; return; } + else if (_visibilityTimer > VISIBLE_TIME.TotalSeconds) + Modulate = new Color(Colors.White, 1.0F - (float)( + (_visibilityTimer - VISIBLE_TIME.TotalSeconds) / FADE_TIME.TotalSeconds)); + } else { + Visible = true; + Modulate = Colors.White; + _visibilityTimer = 0.0F; + } + + Position = player.GetGlobalTransformWithCanvas().origin; + _health = player.Health; + + Update(); + } + + public override void _Draw() + { + var vertices = new Vector2[6]; + + for (var i = 0; i < Segments; i++) { + var angle1 = _startAngle + Mathf.Tau * ( i / (float)Segments); + var angle3 = _startAngle + Mathf.Tau * ((i + 1) / (float)Segments); + var angle2 = (angle1 + angle3) / 2; + + var sep1 = Mathf.Polar2Cartesian(Separation, angle1 + Mathf.Tau / 4); + var sep2 = Mathf.Polar2Cartesian(Separation, angle3 - Mathf.Tau / 4); + + vertices[0] = Mathf.Polar2Cartesian(InnerRadius, angle2); + vertices[1] = Mathf.Polar2Cartesian(InnerRadius, angle1) + sep1; + vertices[2] = Mathf.Polar2Cartesian(OuterRadius, angle1) + sep1; + vertices[3] = Mathf.Polar2Cartesian(OuterRadius, angle2); + vertices[4] = Mathf.Polar2Cartesian(OuterRadius, angle3) + sep2; + vertices[5] = Mathf.Polar2Cartesian(InnerRadius, angle3) + sep2; + + DrawColoredPolygon(vertices, new Color(Colors.Black, 0.4F), antialiased: true); + } + + for (var i = 0; i < Segments; i++) { + var fullness = Mathf.Clamp((_health * Segments) - i, 0.0F, 1.0F); + if (fullness <= 0.1) return; + + var angle1 = _startAngle + Mathf.Tau * ( i / (float)Segments); + var angle3 = _startAngle + Mathf.Tau * ((i + 1) / (float)Segments); + var angle2 = (angle1 + angle3) / 2; + + var sep1 = Mathf.Polar2Cartesian(Separation + 1, angle1 + Mathf.Tau / 4); + var sep2 = Mathf.Polar2Cartesian(Separation + 1, angle3 - Mathf.Tau / 4); + + var outerRadius = Mathf.Lerp(InnerRadius, OuterRadius, fullness); + + vertices[0] = Mathf.Polar2Cartesian(InnerRadius + 1, angle2); + vertices[1] = Mathf.Polar2Cartesian(InnerRadius + 1, angle1) + sep1; + vertices[2] = Mathf.Polar2Cartesian(outerRadius - 1, angle1) + sep1; + vertices[3] = Mathf.Polar2Cartesian(outerRadius - 1, angle2); + vertices[4] = Mathf.Polar2Cartesian(outerRadius - 1, angle3) + sep2; + vertices[5] = Mathf.Polar2Cartesian(InnerRadius + 1, angle3) + sep2; + + DrawColoredPolygon(vertices, new Color(Colors.Red, 0.5F), antialiased: true); + } + } +} diff --git a/src/HUD/RadialMenu.cs b/src/HUD/RadialMenu.cs index bb5a644..6f37982 100644 --- a/src/HUD/RadialMenu.cs +++ b/src/HUD/RadialMenu.cs @@ -4,9 +4,9 @@ using Godot; // TODO: Display number of rounds for weapons? Add an even smaller font for this? public class RadialMenu : Node2D { + [Export] public int MinSegments { get; set; } = 8; [Export] public int InnerRadius { get; set; } = 32; [Export] public int OuterRadius { get; set; } = 64; - [Export] public int MinElements { get; set; } = 8; [Export] public float Separation { get; set; } = 2F; public Cursor Cursor { get; private set; } @@ -18,7 +18,7 @@ public class RadialMenu : Node2D public override void _Ready() { - _startAngle = (-Mathf.Tau / 4) - (Mathf.Tau / MinElements / 2); + _startAngle = (-Mathf.Tau / 4) - (Mathf.Tau / MinSegments / 2); Cursor = this.GetClient()?.Cursor; ActiveName = GetNode