Destroyable chests

This commit is contained in:
MaddoScientisto 2025-03-12 22:01:45 +01:00
commit 80e0eda977
14 changed files with 253 additions and 27 deletions

View file

@ -1,8 +1,10 @@
using Godot;
using System;
using System.Diagnostics;
using System.Linq;
using Cirno.Scripts;
using Cirno.Scripts.Resources;
using Godot.Collections;
public partial class Barrel : Area2D, IDestructible
{
@ -19,6 +21,7 @@ public partial class Barrel : Area2D, IDestructible
[Export] public BulletResource ExplosionData { get; set; }
[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.None;
[Export] public Array<DamageResistance> DamageResistances { get; set; } = [];
[ExportCategory("On Death Activation")]
[Export]
@ -136,7 +139,9 @@ public partial class Barrel : Area2D, IDestructible
{
if (_isDestroyed || Indestructible) return;
_currentHealth -= damage;
var dmg = DamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, damageType));
_currentHealth -= dmg;
if (_currentHealth > 0) return;
_isDestroyed = true;
Explode();

View file

@ -1,7 +1,10 @@
[gd_scene load_steps=12 format=3 uid="uid://djf0y08ix66fn"]
[gd_scene load_steps=16 format=3 uid="uid://djf0y08ix66fn"]
[ext_resource type="Script" uid="uid://cqh7bh0s374ac" path="res://Scripts/Chest.cs" id="1_cwpn7"]
[ext_resource type="Texture2D" uid="uid://qeh4ai8h6sw5" path="res://Sprites/Chest.png" id="2_w7a1a"]
[ext_resource type="Script" uid="uid://cqwvssstkrdmw" path="res://Scripts/Components/Actors/ActorResourceProvider.cs" id="3_s8kek"]
[ext_resource type="Script" uid="uid://cq3hkweplldbr" path="res://Scripts/Components/Actors/GenericDamageReceiver.cs" id="3_u7mm1"]
[ext_resource type="PackedScene" uid="uid://b57ep58h4bs3l" path="res://Scenes/Props/Chest_Broken.tscn" id="4_7lp3q"]
[sub_resource type="CircleShape2D" id="CircleShape2D_ihal6"]
radius = 16.0
@ -74,6 +77,9 @@ animations = [{
[sub_resource type="RectangleShape2D" id="RectangleShape2D_isrvb"]
size = Vector2(12, 10)
[sub_resource type="CircleShape2D" id="CircleShape2D_7lp3q"]
radius = 7.0
[node name="Chest" type="Area2D" groups=["Interactable"]]
collision_layer = 4
collision_mask = 2
@ -96,3 +102,20 @@ gravity_scale = 0.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
position = Vector2(0, -3)
shape = SubResource("RectangleShape2D_isrvb")
[node name="DamageReceiver" type="Area2D" parent="." node_paths=PackedStringArray("HealthProvider")]
collision_layer = 64
collision_mask = 136
script = ExtResource("3_u7mm1")
HealthProvider = NodePath("Health")
Debris = ExtResource("4_7lp3q")
[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageReceiver"]
shape = SubResource("CircleShape2D_7lp3q")
[node name="Health" type="Node2D" parent="DamageReceiver"]
script = ExtResource("3_s8kek")
ResourceName = "Health"
MaxResource = 8.0
[connection signal="area_entered" from="DamageReceiver" to="DamageReceiver" method="_on_damage_hitbox_area_entered"]

View file

@ -1,8 +1,15 @@
[gd_scene load_steps=6 format=3 uid="uid://clyyl3jgpfoo7"]
[gd_scene load_steps=8 format=3 uid="uid://clyyl3jgpfoo7"]
[ext_resource type="Script" uid="uid://cpx2fxtumgmud" path="res://Scenes/Barrel.cs" id="1_gn5xq"]
[ext_resource type="Script" uid="uid://ddsqqfx1usc3j" path="res://Scripts/Resources/DamageResistance.cs" id="2_n641h"]
[ext_resource type="Texture2D" uid="uid://d2f16ke8c7vwx" path="res://Sprites/Barrel.png" id="3_c3t2t"]
[sub_resource type="Resource" id="Resource_c3bn4"]
script = ExtResource("2_n641h")
DamageType = 4
Attribute = 3
metadata/_custom_type_script = "uid://ddsqqfx1usc3j"
[sub_resource type="RectangleShape2D" id="RectangleShape2D_2ewfl"]
size = Vector2(11, 14)
@ -13,13 +20,14 @@ region = Rect2(16, 0, 16, 16)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ss2y0"]
size = Vector2(11, 14)
[node name="Barrel" type="Area2D" groups=["Destroyable"]]
[node name="BrokenBarrel" type="Area2D" groups=["Destroyable"]]
collision_layer = 64
collision_mask = 10
script = ExtResource("1_gn5xq")
Health = 2.0
ExplosionRadius = 0.0
ExplosionDamage = 0.0
DamageResistances = [SubResource("Resource_c3bn4")]
metadata/_edit_group_ = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]

View file

@ -0,0 +1,53 @@
[gd_scene load_steps=7 format=3 uid="uid://b57ep58h4bs3l"]
[ext_resource type="Script" uid="uid://cpx2fxtumgmud" path="res://Scenes/Barrel.cs" id="1_v36o1"]
[ext_resource type="Texture2D" uid="uid://qeh4ai8h6sw5" path="res://Sprites/Chest.png" id="2_v36o1"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_2ewfl"]
size = Vector2(11, 14)
[sub_resource type="AtlasTexture" id="AtlasTexture_v36o1"]
atlas = ExtResource("2_v36o1")
region = Rect2(32, 0, 16, 16)
[sub_resource type="SpriteFrames" id="SpriteFrames_ejqcg"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_v36o1")
}],
"loop": true,
"name": &"default",
"speed": 5.0
}]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ss2y0"]
size = Vector2(11, 14)
[node name="Broken Chest" type="Area2D" groups=["Destroyable"]]
collision_layer = 64
collision_mask = 10
script = ExtResource("1_v36o1")
Indestructible = true
Health = 2.0
ExplosionRadius = 0.0
ExplosionDamage = 0.0
metadata/_edit_group_ = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
visible = false
position = Vector2(0.5, -1)
shape = SubResource("RectangleShape2D_2ewfl")
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
sprite_frames = SubResource("SpriteFrames_ejqcg")
[node name="RigidBody2D" type="RigidBody2D" parent="."]
collision_layer = 64
collision_mask = 10
gravity_scale = 0.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
visible = false
position = Vector2(0.5, -1)
shape = SubResource("RectangleShape2D_ss2y0")

File diff suppressed because one or more lines are too long

View file

@ -1,8 +1,11 @@
using Godot;
using System.Linq;
using Cirno.Scripts.Resources;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.Components.Actors;
public partial class DamageReceiverActorModule : ActorModule
public partial class DamageReceiverActorModule : ActorModule, IHittable
{
protected Actor _actor;
@ -14,6 +17,8 @@ public partial class DamageReceiverActorModule : ActorModule
[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.None;
[Export] public Array<DamageResistance> DamageResistances { get; set; } = [];
public override void Init(Actor actor)
{
_actor = actor;
@ -42,14 +47,14 @@ public partial class DamageReceiverActorModule : ActorModule
if (BulletGroup is BulletOwner.None)
{
this.Hit(bullet.Damage);
this.Hit(bullet.Damage, bullet.DamageType);
bullet.RequestCollisionDestruction();
return;
}
if (bullet.BulletInfo.Owner == BulletGroup) return;
this.Hit(bullet.Damage);
this.Hit(bullet.Damage, bullet.DamageType);
bullet.RequestCollisionDestruction();
}
@ -58,7 +63,9 @@ public partial class DamageReceiverActorModule : ActorModule
if (_actor.IsDestroyed) return;
if (Invulnerable) return;
HealthProvider.CurrentResource -= damage;
var dmg = DamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, damageType));
HealthProvider.CurrentResource -= dmg;
}
protected void OnDeath()

View file

@ -0,0 +1,65 @@
using System.Linq;
using Cirno.Scripts.Resources;
using Godot;
using Godot.Collections;
namespace Cirno.Scripts.Components.Actors;
public partial class GenericDamageReceiver : Area2D, IHittable
{
[Export] public ActorResourceProvider HealthProvider { get; private set; }
[Export] public bool Invulnerable { get; private set; } = false;
[Export] public BulletOwner BulletGroup { get; set; } = BulletOwner.None;
[Export] public PackedScene Debris { get; set; }
[Export] public Array<DamageResistance> DamageResistances { get; set; } = [];
private Node2D _parent;
public override void _Ready()
{
_parent = GetParent<Node2D>();
HealthProvider.FillResource();
HealthProvider.ResourceDepleted += OnDeath;
}
private void _on_damage_hitbox_area_entered(Area2D area)
{
if (Invulnerable) return;
if (area is not Bullet bullet) return;
if (BulletGroup is BulletOwner.None)
{
this.Hit(bullet.Damage, bullet.DamageType);
bullet.RequestCollisionDestruction();
return;
}
if (bullet.BulletInfo.Owner == BulletGroup) return;
this.Hit(bullet.Damage, bullet.DamageType);
bullet.RequestCollisionDestruction();
}
public void Hit(float damage, DamageType damageType = DamageType.Neutral)
{
if (Invulnerable) return;
var dmg = DamageResistances.Aggregate(damage, (current, resistance) => current * resistance.CalculateDamage(current, damageType));
HealthProvider.CurrentResource -= dmg;
}
private void OnDeath()
{
if (Debris is not null)
{
_parent.CreateSibling<Node2D>(Debris);
}
_parent.QueueFree();
}
}

View file

@ -0,0 +1 @@
uid://cq3hkweplldbr

View file

@ -0,0 +1,6 @@
namespace Cirno.Scripts.Components.Actors;
public interface IHittable
{
public void Hit(float damage, DamageType damageType = DamageType.Neutral);
}

View file

@ -0,0 +1,9 @@
namespace Cirno.Scripts.Enums;
public enum DamageAttribute
{
Neutral,
Resist,
Weak,
Immune,
}

View file

@ -0,0 +1,37 @@
using System;
using Cirno.Scripts.Enums;
using Godot;
namespace Cirno.Scripts.Resources;
[GlobalClass]
public partial class DamageResistance : Resource
{
[Export]
public DamageType DamageType { get; set; } = DamageType.Neutral;
[Export]
public DamageAttribute Attribute { get; set; } = DamageAttribute.Neutral;
public float CalculateDamage(float damage, DamageType incomingDamageType)
{
if (DamageType != incomingDamageType) return 1;
switch (Attribute)
{
case DamageAttribute.Neutral:
return 1;
break;
case DamageAttribute.Resist:
return 0.5f;
break;
case DamageAttribute.Weak:
return 2;
break;
case DamageAttribute.Immune:
return 0;
break;
}
return 1;
}
}

View file

@ -0,0 +1 @@
uid://ddsqqfx1usc3j

BIN
Sprites/Chest.aseprite (Stored with Git LFS)

Binary file not shown.

BIN
Sprites/Chest.png (Stored with Git LFS)

Binary file not shown.