Files
AceField-New-Horizon/Scripts/System/ItemPickup.cs
LittleSheep 483773f042 Merge stack
💫 Better miner tile vfx
2025-08-29 17:44:49 +08:00

187 lines
5.5 KiB
C#

using System.Collections;
using AceFieldNewHorizon.Scripts.Entities;
using Godot;
namespace AceFieldNewHorizon.Scripts.System;
public partial class ItemPickup : Area2D
{
[Signal]
public delegate void StackMergedEventHandler(string itemId, int totalQuantity);
public const string PickupGroupName = "ItemPickupTarget";
[Export] public string ItemId { get; set; } = "";
[Export] public int Quantity { get; set; } = 1;
[Export] public bool Infinite { get; set; } = false;
[Export] public float MagnetRange { get; set; } = 64f;
public int GetItemQuantity(string itemId)
{
if (itemId == ItemId)
return Quantity;
return 0;
}
public void SetItemQuantity(string itemId, int newQuantity)
{
if (itemId == ItemId)
{
Quantity = newQuantity;
// Update the quantity label if it exists
if (_quantityLabel != null)
{
if (Quantity > 1)
_quantityLabel.Text = Quantity.ToString();
else
_quantityLabel.Text = string.Empty;
}
}
}
public bool HasItem(string itemId)
{
return itemId == ItemId;
}
public void AddItem(string itemId, int amount)
{
if (itemId == ItemId)
{
Quantity += amount;
// Update the quantity label if it exists
if (_quantityLabel != null)
{
if (Quantity > 1)
_quantityLabel.Text = Quantity.ToString();
else
_quantityLabel.Text = string.Empty;
}
}
}
private Sprite2D _sprite;
private Label _quantityLabel;
private Sprite2D _shadowSprite;
private Node2D _playerTarget;
// Called when the node enters the scene tree
public override void _Ready()
{
BodyEntered += OnEntered;
AreaEntered += OnEntered;
_sprite = GetNode<Sprite2D>("Sprite2D");
UpdateTexture();
// Get the Label node for quantity
if (HasNode("Label"))
{
_quantityLabel = GetNode<Label>("Label");
if (Quantity > 1)
_quantityLabel.Text = Quantity.ToString();
else
_quantityLabel.Text = string.Empty;
}
// Add or update shadow sprite
if (HasNode("ShadowSprite"))
{
_shadowSprite = GetNode<Sprite2D>("ShadowSprite");
_shadowSprite.Texture = _sprite.Texture;
_shadowSprite.Modulate = new Color(0, 0, 0, 0.5f);
_shadowSprite.Position = _sprite.Position + new Vector2(0, 6);
_shadowSprite.ZIndex = _sprite.ZIndex - 1;
}
else
{
_shadowSprite = new Sprite2D();
_shadowSprite.Scale = _sprite.Scale;
_shadowSprite.Name = "ShadowSprite";
_shadowSprite.Texture = _sprite.Texture;
_shadowSprite.Modulate = new Color(0, 0, 0, 0.5f);
_shadowSprite.Position = _sprite.Position + new Vector2(0, 6);
_shadowSprite.ZIndex = _sprite.ZIndex - 1;
AddChild(_shadowSprite);
}
_playerTarget = GetTree().GetFirstNodeInGroup(PickupGroupName) as Node2D;
if (_playerTarget == null)
_playerTarget = GetTree().GetFirstNodeInGroup("Player") as Node2D;
}
public override void _Process(double delta)
{
if (_playerTarget != null)
{
var distance = Position.DistanceTo(_playerTarget.Position);
const float speed = 10f;
if (distance <= MagnetRange)
Position = Position.Lerp(_playerTarget.Position, (float)delta * speed);
}
}
private void UpdateTexture()
{
var file = FileAccess.Open("res://Data/ItemTextures.json", FileAccess.ModeFlags.Read);
if (file == null)
{
GD.PrintErr("Failed to open ItemTextures.json");
return;
}
var text = file.GetAsText();
file.Close();
var json = new Json();
var err = json.Parse(text);
if (err != Error.Ok)
{
GD.PrintErr(json.GetErrorMessage());
return;
}
var dict = json.Data.AsGodotDictionary();
if (!dict.TryGetValue(ItemId, out var value))
return;
var texturePath = value.AsString();
if (string.IsNullOrEmpty(texturePath))
return;
var texture = GD.Load<Texture2D>(texturePath);
if (texture == null)
return;
_sprite.Texture = texture;
}
private void OnEntered(Node body)
{
if (body is ItemPickup itemStack)
{
// Only process the merge for the item with the lower instance ID to prevent double merging
if (itemStack.ItemId != ItemId || GetInstanceId() > body.GetInstanceId())
return;
// Get current quantity and add to it
var currentQuantity = itemStack.GetItemQuantity(ItemId);
var newQuantity = currentQuantity + Quantity;
itemStack.SetItemQuantity(ItemId, newQuantity);
// Emit signal for stack merge
EmitSignal(nameof(StackMerged), ItemId, newQuantity);
QueueFree();
}
else if (body.IsInGroup(PickupGroupName))
{
if (body is Player player)
{
player.AddItem(ItemId, Quantity);
}
if (!Infinite)
QueueFree();
}
}
}