Drop item

This commit is contained in:
2024-09-22 14:00:52 -07:00
parent 01477b9a0e
commit 490f0d17d2
25 changed files with 401 additions and 257 deletions

View File

@@ -1,4 +0,0 @@
namespace GameJamDungeon
{
public interface IEquipable;
}

View File

@@ -0,0 +1,9 @@
namespace GameJamDungeon
{
public interface IEquipableItem : IInventoryItem
{
public void Equip();
public void Unequip();
}
}

View File

@@ -21,17 +21,11 @@ public interface IInventory : INode
public void Remove(IInventoryItem inventoryItem);
public void Equip(IEquipable equipable);
public void Equip(IEquipableItem equipable);
public void Unequip(IEquipable equipable);
public void Unequip(IEquipableItem equipable);
public bool IsEquipped(IEquipable equipable);
public void Use(IInventoryItem inventoryItem);
public void Throw(IInventoryItem inventoryItem);
public void Drop(IInventoryItem inventoryItem);
public bool IsEquipped(IEquipableItem equipable);
public void Sort();
@@ -40,8 +34,6 @@ public interface IInventory : INode
event Inventory.AccessoryUnequippedEventHandler AccessoryUnequipped;
event Inventory.RaiseStatRequestEventHandler RaiseStatRequest;
event Inventory.EquippedItemEventHandler EquippedItem;
}
public partial class Inventory : Node, IInventory
@@ -55,8 +47,6 @@ public partial class Inventory : Node, IInventory
public delegate void AccessoryUnequippedEventHandler(AccessoryStats unequippedAccessory);
[Signal]
public delegate void RaiseStatRequestEventHandler(ConsumableItemStats consumableItemStats);
[Signal]
public delegate void EquippedItemEventHandler();
public Inventory()
{
@@ -88,7 +78,7 @@ public partial class Inventory : Node, IInventory
public void Remove(IInventoryItem inventoryItem) => Items.Remove(inventoryItem);
public void Equip(IEquipable equipable)
public void Equip(IEquipableItem equipable)
{
if (equipable is Weapon weapon)
_equippedWeapon.OnNext(weapon);
@@ -98,11 +88,9 @@ public partial class Inventory : Node, IInventory
_equippedAccessory.OnNext(accessory);
else
throw new NotImplementedException("Item type is not supported.");
EmitSignal(SignalName.EquippedItem);
}
public void Unequip(IEquipable equipable)
public void Unequip(IEquipableItem equipable)
{
if (equipable is Weapon weapon)
{
@@ -121,7 +109,7 @@ public partial class Inventory : Node, IInventory
throw new NotImplementedException("Item type is not supported.");
}
public bool IsEquipped(IEquipable equipable)
public bool IsEquipped(IEquipableItem equipable)
{
if (equipable is Weapon weapon)
return _equippedWeapon.Value.Equals(weapon);
@@ -133,27 +121,6 @@ public partial class Inventory : Node, IInventory
throw new NotImplementedException("Item type is not supported.");
}
public void Use(IInventoryItem item)
{
if (item is ConsumableItem consumableItem)
{
EmitSignal(SignalName.RaiseStatRequest, consumableItem.ConsumableItemInfo);
Remove(consumableItem);
}
}
public void Throw(IInventoryItem item)
{
if (item is ThrowableItem throwable)
throwable.Throw(throwable.ThrowableItemInfo);
//Remove(item);
}
public void Drop(IInventoryItem item)
{
Remove(item);
}
public void Sort()
{
var equippedWeapon = Items.OfType<Weapon>().Where(IsEquipped);

View File

@@ -1,4 +1,5 @@
using Chickensoft.GodotNodeInterfaces;
using Godot;
using System;
namespace GameJamDungeon
@@ -6,8 +7,17 @@ namespace GameJamDungeon
public interface IInventoryItem : INode3D
{
public Guid ID { get; }
public IGameRepo GameRepo { get; }
public InventoryItemStats Info { get; }
}
public interface IUsableItem : IInventoryItem
{
public void Use();
}
public interface IThrowableItem : IInventoryItem
{
public void Throw();
}
}

View File

@@ -13,4 +13,6 @@ public partial class InventoryItemStats : Resource
[Export(PropertyHint.Range, "0, 1, 0.01")]
public float SpawnRate { get; set; } = 0.5f;
public float ThrowSpeed { get; set; } = 7.0f;
}

View File

@@ -3,16 +3,16 @@ using Chickensoft.Introspection;
using GameJamDungeon;
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
[Meta(typeof(IAutoNode))]
public partial class Accessory : Node3D, IInventoryItem, IEquipable
public partial class Accessory : Node3D, IEquipableItem, IThrowableItem
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
public InventoryItemStats Info => AccessoryStats;
[Export]
@@ -30,12 +30,17 @@ public partial class Accessory : Node3D, IInventoryItem, IEquipable
Pickup.BodyEntered += OnEntered;
}
public void Throw()
public void Equip()
{
GameRepo.PlayerData.Inventory.Remove(this);
GameEventDepot.OnEquippedAccessory(this);
}
public void Drop()
public void Unequip()
{
GameEventDepot.OnUnequippedAccessory();
}
public void Throw()
{
GameRepo.PlayerData.Inventory.Remove(this);
}

View File

@@ -5,12 +5,14 @@ using Godot;
using System;
[Meta(typeof(IAutoNode))]
public partial class Armor : Node3D, IInventoryItem, IEquipable
public partial class Armor : Node3D, IEquipableItem, IThrowableItem
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
public InventoryItemStats Info => ArmorStats;
[Export]
@@ -28,6 +30,16 @@ public partial class Armor : Node3D, IInventoryItem, IEquipable
Pickup.BodyEntered += OnEntered;
}
public void Equip()
{
GameEventDepot.OnEquippedArmor(this);
}
public void Unequip()
{
GameEventDepot.OnUnequippedArmor();
}
public void Throw()
{
GameRepo.PlayerData.Inventory.Remove(this);

View File

@@ -5,11 +5,13 @@ using Godot;
using System;
[Meta(typeof(IAutoNode))]
public partial class ConsumableItem : Node3D, IInventoryItem
public partial class ConsumableItem : Node3D, IUsableItem, IThrowableItem
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGame Game => this.DependOn<IGame>();
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Dependency] public IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
public InventoryItemStats Info => ConsumableItemInfo;
@@ -22,6 +24,21 @@ public partial class ConsumableItem : Node3D, IInventoryItem
public Guid ID => Guid.NewGuid();
public void Use()
{
GameEventDepot.OnHealingItemConsumed(ConsumableItemInfo);
}
public void Throw()
{
var throwableScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownItem.tscn");
var throwable = throwableScene.Instantiate<ThrownItem>();
throwable.ThrownItemStats = ConsumableItemInfo;
Game.AddChild(throwable);
throwable.Throw();
GameRepo.PlayerData.Inventory.Remove(this);
}
public void OnReady()
{
Sprite.Texture = ConsumableItemInfo.Texture;

View File

@@ -0,0 +1,45 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
namespace GameJamDungeon
{
[Meta(typeof(IAutoNode))]
public partial class DroppedItem : RigidBody3D
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGameRepo GameRepo => this.DependOn<IGameRepo>();
[Dependency] public IGame Game => this.DependOn<IGame>();
[Node] public Sprite3D Sprite { get; set; } = default!;
public IInventoryItem Item { get; set; }
public void OnResolved()
{
BodyEntered += DroppedItem_BodyEntered;
GlobalPosition = Game.Player.GlobalPosition + Vector3.Up;
Sprite.Texture = Item.Info.Texture;
AddCollisionExceptionWith((Node)Game.Player);
}
public async void Drop()
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
await ToSignal(GetTree().CreateTimer(1.5), "timeout");
RemoveCollisionExceptionWith((Node)Game.Player);
}
private void DroppedItem_BodyEntered(Node body)
{
if (body is IPlayer player)
{
var isAdded = GameRepo.PlayerData.Inventory.TryAdd(Item);
if (isAdded)
QueueFree();
}
}
}
}

View File

@@ -0,0 +1,25 @@
[gd_scene load_steps=4 format=3 uid="uid://brq11lswpqxei"]
[ext_resource type="Script" path="res://src/items/dropped/DroppedItem.cs" id="1_67jk4"]
[ext_resource type="Texture2D" uid="uid://mi70lolgtf3n" path="res://src/items/throwable/textures/GEOMANCER-DICE.png" id="2_cu1v3"]
[sub_resource type="SphereShape3D" id="SphereShape3D_28r8g"]
[node name="DroppedItem" type="RigidBody3D"]
collision_layer = 4
axis_lock_angular_x = true
axis_lock_angular_y = true
axis_lock_angular_z = true
mass = 10.0
contact_monitor = true
max_contacts_reported = 50
script = ExtResource("1_67jk4")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("SphereShape3D_28r8g")
[node name="Sprite" type="Sprite3D" parent="."]
unique_name_in_owner = true
pixel_size = 0.0005
billboard = 2
texture = ExtResource("2_cu1v3")

View File

@@ -5,7 +5,7 @@ using Godot;
using System;
[Meta(typeof(IAutoNode))]
public partial class ThrowableItem : Node3D, IInventoryItem
public partial class ThrowableItem : Node3D, IThrowableItem
{
public override void _Notification(int what) => this.Notify(what);
@@ -32,16 +32,13 @@ public partial class ThrowableItem : Node3D, IInventoryItem
Pickup.BodyEntered += OnEntered;
}
public void Throw(ThrowableItemStats throwableItemStats)
public void Throw()
{
var throwableScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownGeometricDice.tscn");
var throwableScene = GD.Load<PackedScene>("res://src/items/thrown/ThrownItem.tscn");
var throwable = throwableScene.Instantiate<ThrownItem>();
throwable.ThrownItemStats = ThrowableItemInfo;
Game.AddChild(throwable);
throwable.Throw(throwableItemStats);
}
public void Drop()
{
throwable.Throw();
GameRepo.PlayerData.Inventory.Remove(this);
}

View File

@@ -1,42 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://b1twcuneob5kt"]
[ext_resource type="Script" path="res://src/items/thrown/ThrownItem.cs" id="1_ig3yn"]
[ext_resource type="Texture2D" uid="uid://mi70lolgtf3n" path="res://src/items/throwable/textures/GEOMANCER-DICE.png" id="2_ia1qk"]
[sub_resource type="BoxShape3D" id="BoxShape3D_s4ym5"]
size = Vector3(0.288967, 0.302734, 0.28064)
[sub_resource type="ViewportTexture" id="ViewportTexture_vebu3"]
viewport_path = NodePath("Sprite3D/SubViewport")
[node name="Hitbox" type="RigidBody3D"]
collision_layer = 17
collision_mask = 16
mass = 0.001
gravity_scale = 0.0
contact_monitor = true
max_contacts_reported = 1
script = ExtResource("1_ig3yn")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00739601, 0.0986328, 0.137878)
shape = SubResource("BoxShape3D_s4ym5")
[node name="Sprite3D" type="Sprite3D" parent="."]
billboard = 2
double_sided = false
texture = SubResource("ViewportTexture_vebu3")
[node name="SubViewport" type="SubViewport" parent="Sprite3D"]
disable_3d = true
transparent_bg = true
handle_input_locally = false
size = Vector2i(100, 100)
[node name="Sprite" type="Sprite2D" parent="Sprite3D/SubViewport"]
unique_name_in_owner = true
z_index = 100
scale = Vector2(0.1, 0.1)
texture = ExtResource("2_ia1qk")
centered = false
flip_h = true

View File

@@ -10,27 +10,55 @@ public partial class ThrownItem : RigidBody3D
[Dependency] public IGame Game => this.DependOn<IGame>();
[Node] public Sprite2D Sprite { get; set; } = default!;
public InventoryItemStats ThrownItemStats;
private int _damage = 0;
[Node] public Sprite3D Sprite { get; set; } = default!;
public void OnResolved()
{
BodyEntered += ThrownItem_BodyEntered;
GlobalPosition = Game.Player.GlobalPosition + Vector3.Up;
Sprite.Texture = ThrownItemStats.Texture;
AddCollisionExceptionWith((Node)Game.Player);
}
private void ThrownItem_BodyEntered(Node body)
{
if (body is IEnemy enemy)
enemy.EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(_damage));
{
if (ThrownItemStats is ThrowableItemStats throwableItemStats)
enemy.EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(throwableItemStats.Damage));
}
QueueFree();
}
public void Throw(ThrowableItemStats throwableItemStats)
public void Throw()
{
_damage = throwableItemStats.Damage;
ApplyCentralImpulse(Game.Player.GlobalBasis.Z.Normalized() * -20.0f);
ThrowInternal((dynamic)ThrownItemStats);
}
private void ThrowInternal(WeaponStats weaponStats)
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
}
private void ThrowInternal(ArmorStats armorStats)
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
}
private void ThrowInternal(AccessoryStats accessoryStats)
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
}
private void ThrowInternal(ConsumableItemStats consumableItemStats)
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 5.0f);
}
private void ThrowInternal(ThrowableItemStats throwableItemStats)
{
ApplyCentralImpulse(-Game.Player.GlobalBasis.Z.Normalized() * 20.0f);
}
}

View File

@@ -0,0 +1,26 @@
[gd_scene load_steps=4 format=3 uid="uid://b1twcuneob5kt"]
[ext_resource type="Script" path="res://src/items/thrown/ThrownItem.cs" id="1_wlplc"]
[ext_resource type="Texture2D" uid="uid://mi70lolgtf3n" path="res://src/items/throwable/textures/GEOMANCER-DICE.png" id="2_alcjn"]
[sub_resource type="BoxShape3D" id="BoxShape3D_s4ym5"]
size = Vector3(0.288967, 0.302734, 0.28064)
[node name="Hitbox" type="RigidBody3D"]
collision_layer = 17
collision_mask = 16
mass = 0.001
gravity_scale = 0.0
contact_monitor = true
max_contacts_reported = 1
script = ExtResource("1_wlplc")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00739601, 0.0986328, 0.137878)
shape = SubResource("BoxShape3D_s4ym5")
[node name="Sprite" type="Sprite3D" parent="."]
unique_name_in_owner = true
pixel_size = 0.001
billboard = 2
texture = ExtResource("2_alcjn")

View File

@@ -5,7 +5,7 @@ using Godot;
using System;
[Meta(typeof(IAutoNode))]
public partial class Weapon : Node3D, IInventoryItem, IEquipable
public partial class Weapon : Node3D, IInventoryItem, IEquipableItem
{
public override void _Notification(int what) => this.Notify(what);
@@ -13,6 +13,9 @@ public partial class Weapon : Node3D, IInventoryItem, IEquipable
public InventoryItemStats Info => WeaponStats;
[Signal]
public delegate void EquippedItemEventHandler(Weapon equippedWeapon);
[Export]
public WeaponStats WeaponStats { get; set; } = new WeaponStats();
@@ -28,6 +31,16 @@ public partial class Weapon : Node3D, IInventoryItem, IEquipable
Pickup.BodyEntered += OnEntered;
}
public void Equip()
{
EmitSignal(SignalName.EquippedItem, this);
}
public void Unequip()
{
}
public void Throw()
{
GameRepo.PlayerData.Inventory.Remove(this);