Autopickup for player

This commit is contained in:
MaddoScientisto 2026-03-01 20:59:11 +01:00
commit 8d52b49e57
6 changed files with 242 additions and 62 deletions

View file

@ -17,8 +17,14 @@ metadata/_custom_type_script = "uid://ddsqqfx1usc3j"
[sub_resource type="Resource" id="Resource_fkd2x"]
script = ExtResource("4_hlryi")
Item = ExtResource("5_r3p83")
Chance = 100.0
Count = 4
Chance = 70.0
metadata/_custom_type_script = "uid://cq65aed620ijo"
[sub_resource type="Resource" id="Resource_hlryi"]
script = ExtResource("4_hlryi")
Item = ExtResource("5_r3p83")
Chance = 40.0
Count = 2
metadata/_custom_type_script = "uid://cq65aed620ijo"
[sub_resource type="BoxShape3D" id="BoxShape3D_hsg1w"]
@ -34,7 +40,7 @@ script = ExtResource("1_kvqx7")
Health = 8.0
ExplosionData = ExtResource("2_jolck")
DamageResistances = Array[ExtResource("3_7px86")]([SubResource("Resource_7px86")])
LootDrops = Array[ExtResource("4_hlryi")]([SubResource("Resource_fkd2x")])
LootDrops = Array[ExtResource("4_hlryi")]([SubResource("Resource_fkd2x"), SubResource("Resource_hlryi")])
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=169677373]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00549316, 0.0253752, -0.000488281)

View file

@ -28,6 +28,8 @@
[ext_resource type="PackedScene" uid="uid://cfgc6ik8vb08c" path="res://Scenes/Weapons/BaseWeapon_3D.tscn" id="17_olwak"]
[ext_resource type="Script" uid="uid://cqyr8mko8oo5" path="res://Scripts/Components/FSM/3DPlayer/PlayerAcidDeathModule.cs" id="19_7selo"]
[ext_resource type="PackedScene" uid="uid://cwnyegefc8o6q" path="res://Scenes/HUD/WorldSelector3D.tscn" id="24_j6bpw"]
[ext_resource type="Script" uid="uid://s4xt80pu6lgl" path="res://Scripts/Components/FSM/3DPlayer/AutoPickupModule3D.cs" id="25_j6bpw"]
[ext_resource type="AudioStream" uid="uid://b3rm0vj6x54k4" path="res://SFX/th_knockoff_sfx/click_collect.wav" id="26_10kkd"]
[ext_resource type="Script" uid="uid://hdw15b6fi7de" path="res://Scripts/Components/Actors/3D/PlayerDamageReceiver3D.cs" id="26_ok6gd"]
[ext_resource type="Script" uid="uid://ddsqqfx1usc3j" path="res://Scripts/Resources/DamageResistance.cs" id="27_5v3dv"]
[ext_resource type="Script" uid="uid://cqwvssstkrdmw" path="res://Scripts/Components/Actors/ActorResourceProvider.cs" id="28_b3jpo"]
@ -51,6 +53,8 @@ height = 0.679688
height = 1.18042
radius = 1.20117
[sub_resource type="SphereShape3D" id="SphereShape3D_10kkd"]
[sub_resource type="SphereShape3D" id="SphereShape3D_ok250"]
[sub_resource type="Resource" id="Resource_c4ide"]
@ -224,7 +228,7 @@ script = ExtResource("3_cc7e7")
_inputProvider = NodePath("../../InputProvider")
AnimationProvider = NodePath("../../AnimationProvider")
DamageReceiver = NodePath("../../DamageReceiver")
_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), null, NodePath("../../InteractionController"), NodePath("../../ActivationProvider"), NodePath("../../WeaponModule"), NodePath("../../CrosshairModule"), NodePath("../../GrazingModule")]
_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), null, NodePath("../../InteractionController"), NodePath("../../ActivationProvider"), NodePath("../../WeaponModule"), NodePath("../../CrosshairModule"), NodePath("../../GrazingModule"), NodePath("../../AutoPickupModule")]
[node name="Dead" type="Node" parent="StateMachine" unique_id=316659315]
script = ExtResource("5_ok250")
@ -253,7 +257,7 @@ material_override = ExtResource("7_yarib")
pixel_size = 0.05
texture_filter = 0
sprite_frames = ExtResource("12_j6bpw")
animation = &"walk_up"
animation = &"Drowning"
script = ExtResource("9_yarib")
[node name="Legs" type="AnimatedSprite3D" parent="AnimationProvider" unique_id=995566769]
@ -329,6 +333,17 @@ script = ExtResource("11_4cdxq")
stream = ExtResource("13_2ffwi")
bus = &"Effects"
[node name="AutoPickupModule" type="Area3D" parent="." unique_id=1006870778]
collision_layer = 0
collision_mask = 32
script = ExtResource("25_j6bpw")
[node name="CollisionShape3D" type="CollisionShape3D" parent="AutoPickupModule" unique_id=543949155]
shape = SubResource("SphereShape3D_10kkd")
[node name="PickupSound" type="AudioStreamPlayer3D" parent="AutoPickupModule" unique_id=1774707395]
stream = ExtResource("26_10kkd")
[node name="AudioListener3D" type="AudioListener3D" parent="." unique_id=1967851684]
current = true

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=41 format=3 uid="uid://dkwi1hu1bixoe"]
[gd_scene format=3 uid="uid://dkwi1hu1bixoe"]
[ext_resource type="Script" uid="uid://baf6pxbvhqmjk" path="res://Scripts/Hud.cs" id="1_m0hb0"]
[ext_resource type="PackedScene" uid="uid://dsaj5dx82brsg" path="res://Scenes/HUD/UiSelector.tscn" id="2_jidad"]
@ -97,7 +97,7 @@ shader_parameter/x_curve = 10.0
shader_parameter/y_curve = 10.0
shader_parameter/aberration_strength = 0.6140002666650002
[node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("_healthLabel", "_healthBar", "_shieldLabel", "_shieldBar", "_motivationLabel", "_itemsContainer", "_gameOverPanel", "_fairyTerminatedPanel", "_hudInfoPanel", "NotificationsContainer", "WeaponContainer", "PauseMenuContainer", "DebugMenuHolder")]
[node name="HUD" type="CanvasLayer" unique_id=71145519 node_paths=PackedStringArray("_healthLabel", "_healthBar", "_shieldLabel", "_shieldBar", "_motivationLabel", "_itemsContainer", "_gameOverPanel", "_fairyTerminatedPanel", "_hudInfoPanel", "NotificationsContainer", "WeaponContainer", "PauseMenuContainer", "DebugMenuHolder")]
process_mode = 3
script = ExtResource("1_m0hb0")
SelectorScene = ExtResource("2_jidad")
@ -120,82 +120,82 @@ PauseMenuScene = ExtResource("3_hxmxt")
DebugMenuTemplate = ExtResource("4_gd1k6")
DebugMenuHolder = NodePath("DebugContainer")
[node name="FairyTerminated" type="PanelContainer" parent="."]
[node name="FairyTerminated" type="PanelContainer" parent="." unique_id=1026530899]
visible = false
offset_left = -3.0
offset_top = 34.0
offset_right = 323.0
offset_bottom = 88.0
offset_right = 387.0
offset_bottom = 106.0
[node name="VBoxContainer2" type="VBoxContainer" parent="FairyTerminated"]
[node name="VBoxContainer2" type="VBoxContainer" parent="FairyTerminated" unique_id=1249429394]
layout_mode = 2
size_flags_vertical = 4
theme_override_constants/separation = -4
[node name="GameOver" type="Label" parent="FairyTerminated/VBoxContainer2"]
[node name="GameOver" type="Label" parent="FairyTerminated/VBoxContainer2" unique_id=547746558]
visible = false
layout_mode = 2
text = "FAIRY: TERMINATED"
label_settings = SubResource("LabelSettings_a7f6n")
horizontal_alignment = 1
[node name="TextureRect" type="TextureRect" parent="FairyTerminated/VBoxContainer2"]
[node name="TextureRect" type="TextureRect" parent="FairyTerminated/VBoxContainer2" unique_id=989090588]
layout_mode = 2
size_flags_horizontal = 4
texture = ExtResource("8_3523e")
stretch_mode = 2
[node name="Label" type="Label" parent="FairyTerminated/VBoxContainer2"]
[node name="Label" type="Label" parent="FairyTerminated/VBoxContainer2" unique_id=1144362125]
visible = false
layout_mode = 2
text = "Press Shoot button to reform"
label_settings = SubResource("LabelSettings_5na8k")
horizontal_alignment = 1
[node name="GameOver" type="PanelContainer" parent="."]
[node name="GameOver" type="PanelContainer" parent="." unique_id=1424509047]
visible = false
offset_left = -3.0
offset_top = 34.0
offset_right = 323.0
offset_bottom = 88.0
[node name="VBoxContainer2" type="VBoxContainer" parent="GameOver"]
[node name="VBoxContainer2" type="VBoxContainer" parent="GameOver" unique_id=1979473657]
layout_mode = 2
size_flags_vertical = 4
theme_override_constants/separation = -4
[node name="GameOver" type="Label" parent="GameOver/VBoxContainer2"]
[node name="GameOver" type="Label" parent="GameOver/VBoxContainer2" unique_id=1203229580]
visible = false
layout_mode = 2
text = "FAIRY: TERMINATED"
label_settings = SubResource("LabelSettings_a7f6n")
horizontal_alignment = 1
[node name="TextureRect" type="TextureRect" parent="GameOver/VBoxContainer2"]
[node name="TextureRect" type="TextureRect" parent="GameOver/VBoxContainer2" unique_id=2045152992]
layout_mode = 2
size_flags_horizontal = 4
texture = ExtResource("10_s015s")
stretch_mode = 2
[node name="Label" type="Label" parent="GameOver/VBoxContainer2"]
[node name="Label" type="Label" parent="GameOver/VBoxContainer2" unique_id=290816364]
visible = false
layout_mode = 2
text = "Press Shoot button to reform"
label_settings = SubResource("LabelSettings_5na8k")
horizontal_alignment = 1
[node name="MessageTimer" type="Timer" parent="."]
[node name="MessageTimer" type="Timer" parent="." unique_id=308504005]
wait_time = 2.0
one_shot = true
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=465828645]
visible = false
position = Vector2(67, 47)
sprite_frames = SubResource("SpriteFrames_78fwv")
frame = 1
frame_progress = 0.8514
[node name="HudInfo" type="VBoxContainer" parent="."]
[node name="HudInfo" type="VBoxContainer" parent="." unique_id=1663735786]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
@ -209,10 +209,10 @@ size_flags_horizontal = 3
size_flags_vertical = 3
theme_override_constants/separation = 0
[node name="HealthBarContainer" type="HBoxContainer" parent="HudInfo"]
[node name="HealthBarContainer" type="HBoxContainer" parent="HudInfo" unique_id=1485920073]
layout_mode = 2
[node name="HealthBar" type="ProgressBar" parent="HudInfo/HealthBarContainer"]
[node name="HealthBar" type="ProgressBar" parent="HudInfo/HealthBarContainer" unique_id=937426877]
custom_minimum_size = Vector2(34, 8)
layout_mode = 2
size_flags_vertical = 4
@ -222,16 +222,16 @@ value = 50.0
rounded = true
show_percentage = false
[node name="HealthLabel" type="Label" parent="HudInfo/HealthBarContainer"]
[node name="HealthLabel" type="Label" parent="HudInfo/HealthBarContainer" unique_id=768460674]
layout_mode = 2
text = "100/100"
label_settings = ExtResource("2_x7kl7")
vertical_alignment = 1
[node name="ShieldBarContainer" type="HBoxContainer" parent="HudInfo"]
[node name="ShieldBarContainer" type="HBoxContainer" parent="HudInfo" unique_id=1668694771]
layout_mode = 2
[node name="ShieldBar" type="ProgressBar" parent="HudInfo/ShieldBarContainer"]
[node name="ShieldBar" type="ProgressBar" parent="HudInfo/ShieldBarContainer" unique_id=1137386812]
custom_minimum_size = Vector2(34, 8)
layout_mode = 2
size_flags_vertical = 4
@ -240,38 +240,38 @@ theme_override_styles/fill = SubResource("StyleBoxTexture_5cvcb")
value = 50.0
show_percentage = false
[node name="ShieldLabel" type="Label" parent="HudInfo/ShieldBarContainer"]
[node name="ShieldLabel" type="Label" parent="HudInfo/ShieldBarContainer" unique_id=1805514884]
layout_mode = 2
text = "100/100"
label_settings = ExtResource("2_x7kl7")
vertical_alignment = 1
[node name="MotivationContainer" type="HBoxContainer" parent="HudInfo"]
[node name="MotivationContainer" type="HBoxContainer" parent="HudInfo" unique_id=327806189]
layout_mode = 2
[node name="Label" type="Label" parent="HudInfo/MotivationContainer"]
[node name="Label" type="Label" parent="HudInfo/MotivationContainer" unique_id=1088378433]
layout_mode = 2
text = "Motivation:"
label_settings = ExtResource("2_x7kl7")
[node name="Motivationlabel" type="Label" parent="HudInfo/MotivationContainer"]
[node name="Motivationlabel" type="Label" parent="HudInfo/MotivationContainer" unique_id=617537863]
layout_mode = 2
text = "100%"
label_settings = ExtResource("2_x7kl7")
vertical_alignment = 1
[node name="ItemsContainer" type="VBoxContainer" parent="HudInfo"]
[node name="ItemsContainer" type="VBoxContainer" parent="HudInfo" unique_id=29990649]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/separation = 0
[node name="NotificationsContainer" type="VBoxContainer" parent="."]
[node name="NotificationsContainer" type="VBoxContainer" parent="." unique_id=1410590531]
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -156.0
offset_left = -113.0
offset_top = -34.0
grow_horizontal = 0
grow_vertical = 0
@ -279,7 +279,7 @@ size_flags_vertical = 3
theme_override_constants/separation = 0
alignment = 2
[node name="WeaponContainer" type="VBoxContainer" parent="."]
[node name="WeaponContainer" type="VBoxContainer" parent="." unique_id=613768405]
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
@ -291,21 +291,21 @@ grow_vertical = 0
theme_override_constants/separation = 0
metadata/_edit_group_ = true
[node name="Label" type="Label" parent="WeaponContainer"]
[node name="Label" type="Label" parent="WeaponContainer" unique_id=1544331200]
layout_mode = 2
text = "Weapon"
label_settings = ExtResource("2_x7kl7")
[node name="WeaponContainer" type="PanelContainer" parent="WeaponContainer"]
[node name="WeaponContainer" type="PanelContainer" parent="WeaponContainer" unique_id=1330746632]
layout_mode = 2
size_flags_vertical = 3
theme = ExtResource("9_sx5r0")
theme_override_styles/panel = ExtResource("17_bljno")
[node name="BossHud" parent="." instance=ExtResource("5_vmict")]
[node name="BossHud" parent="." unique_id=1635516703 instance=ExtResource("5_vmict")]
visible = false
[node name="DebugContainer" type="PanelContainer" parent="."]
[node name="DebugContainer" type="PanelContainer" parent="." unique_id=2004128887]
visible = false
anchors_preset = 15
anchor_right = 1.0
@ -313,21 +313,21 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="PauseMenuContainer" type="PanelContainer" parent="."]
[node name="PauseMenuContainer" type="PanelContainer" parent="." unique_id=2045387146]
visible = false
offset_left = 106.0
offset_top = 26.0
offset_right = 226.0
offset_bottom = 144.0
[node name="Control" type="Panel" parent="."]
[node name="Control" type="Panel" parent="." unique_id=941994087]
offset_left = 30.0
offset_top = 24.0
offset_right = 354.0
offset_bottom = 198.0
theme_override_styles/panel = ExtResource("20_0ncp3")
[node name="InventoryMenu" type="TabContainer" parent="Control" node_paths=PackedStringArray("ParentContainer")]
[node name="InventoryMenu" type="TabContainer" parent="Control" unique_id=1439629064 node_paths=PackedStringArray("ParentContainer")]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
@ -348,7 +348,7 @@ script = ExtResource("11_7pulb")
ParentContainer = NodePath("..")
metadata/_edit_group_ = true
[node name="Weapons" type="ItemList" parent="Control/InventoryMenu"]
[node name="Weapons" type="ItemList" parent="Control/InventoryMenu" unique_id=932926637]
visible = false
layout_mode = 2
theme = ExtResource("9_sx5r0")
@ -360,7 +360,7 @@ script = ExtResource("10_oflr6")
ItemsFilter = Array[int]([9])
metadata/_tab_index = 0
[node name="Consumables" type="ItemList" parent="Control/InventoryMenu"]
[node name="Consumables" type="ItemList" parent="Control/InventoryMenu" unique_id=610897193]
visible = false
layout_mode = 2
theme = ExtResource("9_sx5r0")
@ -372,7 +372,7 @@ script = ExtResource("10_oflr6")
ItemsFilter = Array[int]([4, 5, 8, 7, 6])
metadata/_tab_index = 1
[node name="Ammo" type="ItemList" parent="Control/InventoryMenu"]
[node name="Ammo" type="ItemList" parent="Control/InventoryMenu" unique_id=1227461482]
visible = false
layout_mode = 2
theme = ExtResource("9_sx5r0")
@ -384,7 +384,7 @@ script = ExtResource("10_oflr6")
ItemsFilter = Array[int]([3])
metadata/_tab_index = 2
[node name="Key" type="ItemList" parent="Control/InventoryMenu"]
[node name="Key" type="ItemList" parent="Control/InventoryMenu" unique_id=1623766474]
visible = false
layout_mode = 2
theme = ExtResource("9_sx5r0")
@ -396,7 +396,7 @@ script = ExtResource("10_oflr6")
ItemsFilter = Array[int]([0, 1, 2, 13, 10, 11, 12])
metadata/_tab_index = 3
[node name="Status" type="PanelContainer" parent="Control/InventoryMenu" node_paths=PackedStringArray("HealthExpansionCounter", "ShieldExpansionCounter", "WeaponButton")]
[node name="Status" type="PanelContainer" parent="Control/InventoryMenu" unique_id=266629319 node_paths=PackedStringArray("HealthExpansionCounter", "ShieldExpansionCounter", "WeaponButton")]
layout_mode = 2
theme = ExtResource("9_sx5r0")
theme_override_styles/panel = ExtResource("13_sjdna")
@ -408,32 +408,32 @@ ShieldExpansionCounter = NodePath("MarginContainer/HBoxContainer/VBoxContainer3/
WeaponButton = NodePath("MarginContainer/HBoxContainer/VBoxContainer2/EquippedWeapon")
metadata/_tab_index = 4
[node name="MarginContainer" type="MarginContainer" parent="Control/InventoryMenu/Status"]
[node name="MarginContainer" type="MarginContainer" parent="Control/InventoryMenu/Status" unique_id=1419887516]
layout_mode = 2
theme_override_constants/margin_left = 32
theme_override_constants/margin_right = 32
[node name="HBoxContainer" type="HBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer"]
[node name="HBoxContainer" type="HBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer" unique_id=260671629]
layout_mode = 2
alignment = 1
[node name="VBoxContainer2" type="VBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer"]
[node name="VBoxContainer2" type="VBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer" unique_id=1376371555]
layout_mode = 2
size_flags_horizontal = 2
alignment = 1
[node name="EquippedWeapon" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer2"]
[node name="EquippedWeapon" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer2" unique_id=1982020961]
layout_mode = 2
text = "IC-9
"
icon = ExtResource("19_h6xwv")
[node name="VBoxContainer3" type="VBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer"]
[node name="VBoxContainer3" type="VBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer" unique_id=153340910]
layout_mode = 2
size_flags_horizontal = 10
alignment = 1
[node name="Shield" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3"]
[node name="Shield" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3" unique_id=28187213]
layout_mode = 2
theme_override_constants/line_spacing = -4
text = "Ice
@ -441,42 +441,42 @@ Crystal"
icon = ExtResource("22_jefn6")
alignment = 0
[node name="HBoxContainer" type="HBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3"]
[node name="HBoxContainer" type="HBoxContainer" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3" unique_id=805702230]
layout_mode = 2
[node name="HealthExtensions" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3/HBoxContainer"]
[node name="HealthExtensions" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3/HBoxContainer" unique_id=1491820858]
layout_mode = 2
text = "x2"
icon = ExtResource("19_j6myr")
alignment = 0
[node name="ShieldExtensions" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3/HBoxContainer"]
[node name="ShieldExtensions" type="Button" parent="Control/InventoryMenu/Status/MarginContainer/HBoxContainer/VBoxContainer3/HBoxContainer" unique_id=622876464]
layout_mode = 2
text = "x1"
icon = ExtResource("22_5cvcb")
alignment = 0
[node name="VBoxContainer" type="VBoxContainer" parent="Control/InventoryMenu/Status"]
[node name="VBoxContainer" type="VBoxContainer" parent="Control/InventoryMenu/Status" unique_id=936621407]
custom_minimum_size = Vector2(96, 0)
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 3
[node name="Label" type="Label" parent="Control/InventoryMenu/Status/VBoxContainer"]
[node name="Label" type="Label" parent="Control/InventoryMenu/Status/VBoxContainer" unique_id=768148166]
layout_mode = 2
size_flags_horizontal = 4
size_flags_vertical = 0
text = "CIRNO"
label_settings = SubResource("LabelSettings_bkqle")
[node name="TextureRect" type="TextureRect" parent="Control/InventoryMenu/Status/VBoxContainer"]
[node name="TextureRect" type="TextureRect" parent="Control/InventoryMenu/Status/VBoxContainer" unique_id=307448839]
layout_mode = 2
size_flags_vertical = 3
texture = ExtResource("19_n0pka")
expand_mode = 1
stretch_mode = 3
[node name="ColorRect" type="ColorRect" parent="Control"]
[node name="ColorRect" type="ColorRect" parent="Control" unique_id=1220058668]
material = SubResource("ShaderMaterial_0ncp3")
layout_mode = 1
anchors_preset = 15
@ -490,7 +490,7 @@ grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="FPS" type="Label" parent="."]
[node name="FPS" type="Label" parent="." unique_id=259143833]
z_index = 20
z_as_relative = false
anchors_preset = 1

View file

@ -0,0 +1,152 @@
using System.Collections.Generic;
using System.Linq;
using Cirno.Scripts.Interactables;
using Godot;
namespace Cirno.Scripts.Components.FSM._3DPlayer;
/// <summary>
/// Detects nearby <see cref="ItemPickup3D"/> items whose loot table contains at least one
/// auto-pickup entry and magnets them toward the player. Items are only formally collected
/// (inventory added, node freed) once they physically reach the player's position.
///
/// Radius can be increased at runtime via equipment or upgrade systems — just write to
/// <see cref="Radius"/> and the underlying collision shape is updated automatically.
/// </summary>
public partial class AutoPickupModule3D : Area3D, IModule<PlayerState, CharacterBody3D>
{
// Speed at which attracted items move toward the player (units/second).
private const float AttractionSpeed = 12f;
// Squared distance threshold at which an item is considered "collected".
private const float CollectDistanceSq = 0.15f * 0.15f;
[Export]
private float _radius = 3f;
/// <summary>
/// The radius of the auto-pickup detection sphere.
/// Assigning a new value resizes the underlying collision shape immediately.
/// </summary>
public float Radius
{
get => _radius;
set
{
_radius = value;
UpdateCollisionRadius();
}
}
private bool _enabled;
private CollisionShape3D _collisionShape;
private AudioStreamPlayer3D _pickupSound;
// Items currently being attracted toward the player.
private readonly HashSet<ItemPickup3D> _trackedItems = [];
public IStateMachine<PlayerState, CharacterBody3D> StateMachine { get; private set; }
public void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
{
StateMachine = machine;
_collisionShape = GetNodeOrNull<CollisionShape3D>("CollisionShape3D") ?? CreateCollisionShape();
_pickupSound = GetNodeOrNull<AudioStreamPlayer3D>("PickupSound");
UpdateCollisionRadius();
}
private CollisionShape3D CreateCollisionShape()
{
var shape = new CollisionShape3D { Shape = new SphereShape3D { Radius = _radius } };
AddChild(shape);
return shape;
}
public void EnterState(PlayerState state)
{
_enabled = true;
AreaEntered += OnAreaEntered;
AreaExited += OnAreaExited;
}
public void ExitState(PlayerState state)
{
_enabled = false;
AreaEntered -= OnAreaEntered;
AreaExited -= OnAreaExited;
_trackedItems.Clear();
}
public void Process(double delta) { }
public void PhysicsProcess(double delta)
{
if (!_enabled || _trackedItems.Count == 0) return;
var playerPos = StateMachine.MainObject.GlobalPosition;
var toRemove = new List<ItemPickup3D>();
foreach (var item in _trackedItems)
{
if (!IsInstanceValid(item))
{
toRemove.Add(item);
continue;
}
var direction = playerPos - item.GlobalPosition;
var distanceSq = direction.LengthSquared();
if (distanceSq <= CollectDistanceSq)
{
item.Collect();
_pickupSound?.Play();
toRemove.Add(item);
continue;
}
// Move the item toward the player, scaling speed so it feels snappy at any distance.
item.GlobalPosition += direction.Normalized() * AttractionSpeed * (float)delta;
}
foreach (var item in toRemove)
{
_trackedItems.Remove(item);
}
}
private void OnAreaEntered(Area3D area)
{
if (!_enabled) return;
if (area is not ItemPickup3D pickup) return;
if (!pickup.AutoPickup) return;
// Only attract items whose inventory can still accept them to avoid a
// looping autopickup situation when the inventory slot is full.
var canAdd = pickup.LootTable.Aggregate(false,
(current, item) => current || InventoryManager.Instance.CanAddItem(item.ItemKey));
if (canAdd)
{
_trackedItems.Add(pickup);
}
}
private void OnAreaExited(Area3D area)
{
if (area is ItemPickup3D pickup)
{
_trackedItems.Remove(pickup);
}
}
private void UpdateCollisionRadius()
{
if (_collisionShape?.Shape is SphereShape3D sphere)
{
sphere.Radius = _radius;
}
}
}

View file

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

View file

@ -107,10 +107,16 @@ public partial class ItemPickup3D : Interactable3D
QueueFree();
}
/// <summary>
/// Auto-pickup items are handled exclusively by <c>AutoPickupModule3D</c>.
/// Returning <c>false</c> here prevents them from entering the normal
/// interaction selector, so they cannot be manually activated by the player.
/// </summary>
public override bool CanActivate() => !_autoPickup;
public void Collect()
{
AddItemsToInventory();
}
public void SetSprite(Texture2D sprite)