diff --git a/BoundingBoxes/Hitbox.cs b/BoundingBoxes/Hitbox.cs new file mode 100644 index 0000000..9ac8ea4 --- /dev/null +++ b/BoundingBoxes/Hitbox.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Godot; +using SupaLidlGame.Characters; + +namespace SupaLidlGame.BoundingBoxes +{ + public partial class Hitbox : Area2D + { + private HashSet _ignoreList = new HashSet(); + + [Export] + public float Damage { get; set; } = 0; + + [Export] + public bool IsEnabled { get; set; } + + [Export] + public float Knockback { get; set; } + + public Character Inflictor { get; set; } + + public void _on_area_entered(Area2D area) + { + if (!IsEnabled) + { + return; + } + + if (area is Hurtbox hurtbox) + { + if (!_ignoreList.Contains(hurtbox)) + { + _ignoreList.Add(hurtbox); + hurtbox.InflictDamage(Damage, Inflictor, Knockback); + } + } + } + + public void ResetIgnoreList() => _ignoreList.Clear(); + } +} diff --git a/BoundingBoxes/Hitbox.tscn b/BoundingBoxes/Hitbox.tscn new file mode 100644 index 0000000..e9a60a2 --- /dev/null +++ b/BoundingBoxes/Hitbox.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=3 format=3 uid="uid://du5vhccg75nrq"] + +[ext_resource type="Script" path="res://BoundingBoxes/Hitbox.cs" id="1_44i8j"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_3w20g"] + +[node name="Hitbox" type="Area2D"] +script = ExtResource("1_44i8j") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("RectangleShape2D_3w20g") +debug_color = Color(0.701961, 0.490196, 0, 0.419608) + +[connection signal="area_entered" from="." to="." method="_on_area_entered"] diff --git a/BoundingBoxes/Hurtbox.cs b/BoundingBoxes/Hurtbox.cs new file mode 100644 index 0000000..22fbcea --- /dev/null +++ b/BoundingBoxes/Hurtbox.cs @@ -0,0 +1,26 @@ +using Godot; +using SupaLidlGame.Characters; + +namespace SupaLidlGame.BoundingBoxes +{ + public partial class Hurtbox : Area2D + { + [Signal] + public delegate void ReceivedDamageEventHandler(float damage); + + public void InflictDamage( + float damage, + Character inflictor, + float knockback, + Vector2 knockbackOrigin = default, + Vector2 knockbackVector = default) + { + EmitSignal( + "ReceivedDamage", + damage, + inflictor, + knockback, + knockbackOrigin, knockbackVector); + } + } +} diff --git a/BoundingBoxes/Hurtbox.tscn b/BoundingBoxes/Hurtbox.tscn new file mode 100644 index 0000000..a8a2eae --- /dev/null +++ b/BoundingBoxes/Hurtbox.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://cjgxyhgcyvsv7"] + +[ext_resource type="Script" path="res://BoundingBoxes/Hurtbox.cs" id="1_ov1ss"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_2rki1"] + +[node name="Hurtbox" type="Area2D"] +script = ExtResource("1_ov1ss") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("RectangleShape2D_2rki1") +debug_color = Color(0.996078, 0, 0.129412, 0.419608) diff --git a/Characters/Character.cs b/Characters/Character.cs index 247c921..8cf725b 100644 --- a/Characters/Character.cs +++ b/Characters/Character.cs @@ -7,18 +7,31 @@ namespace SupaLidlGame.Characters [Export] public float Speed { get; protected set; } = 128.0f; + [Export] + public float Mass + { + get => _mass; + set + { + if (value > 0) + _mass = value; + } + } + + protected float _mass = 1.0f; + public float JumpVelocity { get; protected set; } = -400.0f; + public float AccelerationMagnitude { get; protected set; } = 256.0f; public Vector2 Acceleration => Direction * AccelerationMagnitude; - // Get the gravity from the project settings to be synced with RigidBody nodes. - public float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle(); - public Vector2 Direction { get; set; } = Vector2.Zero; public Vector2 Target { get; set; } = Vector2.Zero; + public float Health { get; set; } + [Export] public State.Machine StateMachine { get; set; } @@ -45,5 +58,18 @@ namespace SupaLidlGame.Characters StateMachine.PhysicsProcess(delta); } } + + public void ApplyImpulse(Vector2 impulse, bool resetVelocity = false) + { + // delta p = F delta t + if (resetVelocity) + Velocity = Vector2.Zero; + Velocity += impulse / Mass; + } + + public void _on_hurtbox_received_damage(float damage) + { + Health -= damage; + } } } diff --git a/Characters/ExampleEnemy.tscn b/Characters/ExampleEnemy.tscn index 2563266..31c160b 100644 --- a/Characters/ExampleEnemy.tscn +++ b/Characters/ExampleEnemy.tscn @@ -1,14 +1,18 @@ -[gd_scene load_steps=7 format=3 uid="uid://dymwd5ihpwyqm"] +[gd_scene load_steps=9 format=3 uid="uid://dymwd5ihpwyqm"] [ext_resource type="Script" path="res://Characters/NPC.cs" id="1_4x3dm"] [ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_ujqd7"] [ext_resource type="Script" path="res://Characters/States/Machine.cs" id="3_k4ypw"] [ext_resource type="Script" path="res://Characters/States/NPCIdleState.cs" id="4_8r2qn"] [ext_resource type="Script" path="res://Characters/States/NPCMoveState.cs" id="5_utogm"] +[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="6_jo0cg"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"] size = Vector2(32, 16) +[sub_resource type="RectangleShape2D" id="RectangleShape2D_8lxmf"] +size = Vector2(32, 32) + [node name="ExampleEnemy" type="CharacterBody2D" node_paths=PackedStringArray("StateMachine")] script = ExtResource("1_4x3dm") Speed = 32.0 @@ -34,3 +38,12 @@ MoveState = NodePath("../Move") [node name="Move" type="Node" parent="StateMachine" node_paths=PackedStringArray("IdleState")] script = ExtResource("5_utogm") IdleState = NodePath("../Idle") + +[node name="Hurtbox" parent="." instance=ExtResource("6_jo0cg")] + +[node name="CollisionShape2D" parent="Hurtbox" index="0"] +shape = SubResource("RectangleShape2D_8lxmf") + +[connection signal="ReceivedDamage" from="Hurtbox" to="." method="_on_hurtbox_received_damage"] + +[editable path="Hurtbox"] diff --git a/Characters/Items/Inventory.cs b/Characters/Items/Inventory.cs new file mode 100644 index 0000000..b27ad25 --- /dev/null +++ b/Characters/Items/Inventory.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Godot; +using SupaLidlGame.Characters; + +namespace SupaLidlGame.Items +{ + public partial class Inventory : Node2D + { + public Character Character { get; private set; } + + public List Items { get; private set; } = new List(); + + public const int MaxCapacity = 32; + + private Item _selectedItem; + + public Item SelectedItem + { + get => _selectedItem; + set + { + if (!Items.Contains(value)) + { + GD.PrintErr("Tried to equip an item not in the inventory."); + return; + } + + if (_selectedItem is not null) + { + _selectedItem.Unequip(Character); + } + + _selectedItem = value; + + _selectedItem.Equip(Character); + } + } + + public Item AddItem(Item item) + { + if (Items.Count >= MaxCapacity) + { + return null; + } + + Items.Add(item); + return item; + } + + public Item DropItem(Item item) + { + throw new System.NotImplementedException(); + } + + public override void _Ready() + { + Owner = GetParent(); + base._Ready(); + } + } +} diff --git a/Characters/Items/Item.cs b/Characters/Items/Item.cs new file mode 100644 index 0000000..af78ec6 --- /dev/null +++ b/Characters/Items/Item.cs @@ -0,0 +1,19 @@ +using Godot; +using SupaLidlGame.Characters; + +namespace SupaLidlGame.Items +{ + public abstract partial class Item : Node2D + { + [Export] + public string Description { get; set; } + + public abstract void Equip(Character character); + + public abstract void Unequip(Character character); + + public abstract void Use(); + + public abstract void Deuse(); + } +} diff --git a/Characters/Items/Weapon.cs b/Characters/Items/Weapon.cs new file mode 100644 index 0000000..62815ae --- /dev/null +++ b/Characters/Items/Weapon.cs @@ -0,0 +1,54 @@ +using Godot; +using SupaLidlGame.Characters; + +namespace SupaLidlGame.Items +{ + public abstract partial class Weapon : Item + { + public double RemainingUseTime { get; protected set; } = 0; + + public bool CanStartAttack => RemainingUseTime <= 0; + + /// + /// How much damage in HP that this weapon deals. + /// + [Export] + public float Damage { get; set; } = 0; + + /// + /// The time in seconds it takes for this weapon to become available + /// again after using. + /// + [Export] + public double UseTime { get; set; } = 0; + + /// + /// The magnitude of the knockback force of the weapon. + /// + [Export] + public float Knockback { get; set; } = 0; + + /// + /// The initial velocity of any projectile the weapon may spawn. + /// + [Export] + public float InitialVelocity { get; set; } = 0; + + public Character Character { get; set; } + + public override void Equip(Character character) + { + Character = character; + } + + public override void Unequip(Character character) + { + Character = null; + } + + public override void Deuse() + { + + } + } +} diff --git a/Characters/Items/Weapons/Sword.cs b/Characters/Items/Weapons/Sword.cs new file mode 100644 index 0000000..1725292 --- /dev/null +++ b/Characters/Items/Weapons/Sword.cs @@ -0,0 +1,20 @@ +using SupaLidlGame.Characters; + +namespace SupaLidlGame.Items.Weapons +{ + public partial class Sword : Weapon + { + //[Export] + //public Damagebox + + public override void Equip(Character character) + { + base.Equip(character); + } + + public override void Use() + { + //base.Use(); + } + } +} diff --git a/Characters/NPC.cs b/Characters/NPC.cs index 282fee4..970957d 100644 --- a/Characters/NPC.cs +++ b/Characters/NPC.cs @@ -12,9 +12,9 @@ namespace SupaLidlGame.Characters public float[] Weights => _weights; - float[] _weights = new float[16]; - Vector2[] _weightDirs = new Vector2[16]; - int _bestWeightIdx; + protected float[] _weights = new float[16]; + protected Vector2[] _weightDirs = new Vector2[16]; + protected int _bestWeightIdx; protected double _thinkTimeElapsed = 0; public override void _Ready() diff --git a/Characters/Player.tscn b/Characters/Player.tscn index 0754ceb..66c9aaa 100644 --- a/Characters/Player.tscn +++ b/Characters/Player.tscn @@ -62,3 +62,5 @@ label_settings = SubResource("LabelSettings_q5h1n") horizontal_alignment = 1 [node name="Node" type="Node" parent="."] + +[node name="Inventory" type="Node2D" parent="."] diff --git a/Prototyping/ContextBasedSteeringTest.tscn b/Prototyping/ContextBasedSteeringTest.tscn deleted file mode 100644 index 2622ca7..0000000 --- a/Prototyping/ContextBasedSteeringTest.tscn +++ /dev/null @@ -1,9 +0,0 @@ -[gd_scene load_steps=2 format=3 uid="uid://dmbgefwamg0u7"] - -[ext_resource type="Script" path="res://Prototyping/ContextBasedSteering.cs" id="1_t0k7y"] - -[node name="ContextBasedSteeringTest" type="Node2D"] - -[node name="ContextBasedSteering" type="Node2D" parent="."] -position = Vector2(410, 242) -script = ExtResource("1_t0k7y") diff --git a/Sprites/knife.ase b/Sprites/knife.ase new file mode 100644 index 0000000..8d024a4 Binary files /dev/null and b/Sprites/knife.ase differ diff --git a/Sprites/knife.png b/Sprites/knife.png new file mode 100644 index 0000000..6dc1368 Binary files /dev/null and b/Sprites/knife.png differ diff --git a/Sprites/knife.png.import b/Sprites/knife.png.import new file mode 100644 index 0000000..e44bffb --- /dev/null +++ b/Sprites/knife.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dt6u8p4h6g7le" +path="res://.godot/imported/knife.png-95e39b161a14477923b7daae97a5ccae.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Sprites/knife.png" +dest_files=["res://.godot/imported/knife.png-95e39b161a14477923b7daae97a5ccae.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/Prototyping/ContextBasedSteering.cs b/Tests/ContextBasedSteering.cs similarity index 100% rename from Prototyping/ContextBasedSteering.cs rename to Tests/ContextBasedSteering.cs diff --git a/Tests/ContextBasedSteeringTest.tscn b/Tests/ContextBasedSteeringTest.tscn new file mode 100644 index 0000000..a075f47 --- /dev/null +++ b/Tests/ContextBasedSteeringTest.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://c2d4dmf4yg481"] + +[ext_resource type="Script" path="res://Tests/ContextBasedSteering.cs" id="1_g16e3"] + +[node name="ContextBasedSteeringTest" type="Node2D"] + +[node name="ContextBasedSteering" type="Node2D" parent="."] +position = Vector2(410, 242) +script = ExtResource("1_g16e3") diff --git a/Tests/HitboxTest.tscn b/Tests/HitboxTest.tscn new file mode 100644 index 0000000..aafb0e9 --- /dev/null +++ b/Tests/HitboxTest.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=6 format=3 uid="uid://8ewc46esswdo"] + +[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="1_jh0yt"] +[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="2_gtebh"] +[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="2_konpx"] +[ext_resource type="Script" path="res://Tests/OscillatingBody.cs" id="3_exvxj"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_bvv0o"] +size = Vector2(128, 128) + +[node name="HItboxTest" type="Node2D"] +position = Vector2(377, 214) + +[node name="Node2D" type="Node2D" parent="."] + +[node name="Sprite2D" type="Sprite2D" parent="Node2D"] +texture = ExtResource("1_jh0yt") + +[node name="Hitbox" parent="Node2D" instance=ExtResource("2_gtebh")] +IsEnabled = true + +[node name="OscillatingBody" type="CharacterBody2D" parent="."] +script = ExtResource("3_exvxj") + +[node name="Sprite2D" type="Sprite2D" parent="OscillatingBody"] +position = Vector2(230, 7) +texture = ExtResource("1_jh0yt") + +[node name="Hurtbox" parent="OscillatingBody" instance=ExtResource("2_konpx")] + +[node name="CollisionShape2D" parent="OscillatingBody/Hurtbox" index="0"] +shape = SubResource("RectangleShape2D_bvv0o") + +[connection signal="ReceivedDamage" from="OscillatingBody/Hurtbox" to="OscillatingBody" method="_on_hurtbox_received_damage"] + +[editable path="Node2D/Hitbox"] +[editable path="OscillatingBody/Hurtbox"] diff --git a/Tests/OscillatingBody.cs b/Tests/OscillatingBody.cs new file mode 100644 index 0000000..cd6cc75 --- /dev/null +++ b/Tests/OscillatingBody.cs @@ -0,0 +1,22 @@ +using Godot; +using SupaLidlGame.Characters; +using System; + +public partial class OscillatingBody : CharacterBody2D +{ + private double _time = 0; + + public override void _PhysicsProcess(double delta) + { + _time += delta; + // move along the path sin(x) whose derivative is cos(x) + Velocity = Vector2.Left * Mathf.Cos((float)_time) * 256; + MoveAndSlide(); + } + + public void _on_hurtbox_received_damage(float damage, Character attacker, + float knockback, Vector2 _, Vector2 __) + { + GD.Print($"took {damage} dmg"); + } +} diff --git a/Tests/StaticMovement.cs b/Tests/StaticMovement.cs new file mode 100644 index 0000000..ef04ba1 --- /dev/null +++ b/Tests/StaticMovement.cs @@ -0,0 +1,39 @@ +using Godot; +using System; + +public partial class StaticMovement : CharacterBody2D +{ + public const float Speed = 300.0f; + public const float JumpVelocity = -400.0f; + + // Get the gravity from the project settings to be synced with RigidBody nodes. + public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle(); + + public override void _PhysicsProcess(double delta) + { + Vector2 velocity = Velocity; + + // Add the gravity. + if (!IsOnFloor()) + velocity.y += gravity * (float)delta; + + // Handle Jump. + if (Input.IsActionJustPressed("ui_accept") && IsOnFloor()) + velocity.y = JumpVelocity; + + // Get the input direction and handle the movement/deceleration. + // As good practice, you should replace UI actions with custom gameplay actions. + Vector2 direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); + if (direction != Vector2.Zero) + { + velocity.x = direction.x * Speed; + } + else + { + velocity.x = Mathf.MoveToward(Velocity.x, 0, Speed); + } + + Velocity = velocity; + MoveAndSlide(); + } +}