Optimized drag and drop of items.

优化物品的拖拽。
This commit is contained in:
Cold-Mint 2024-06-18 23:37:18 +08:00
parent c1f0e30671
commit a58ddeb039
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
5 changed files with 207 additions and 57 deletions

View File

@ -2,7 +2,7 @@
importer="csv_translation"
type="Translation"
uid="uid://bgfmprv2sm645"
uid="uid://cc0k86apkvut7"
[deps]

View File

@ -1,18 +1,17 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using ColdMint.scripts.camp;
using ColdMint.scripts.damage;
using ColdMint.scripts.debug;
using ColdMint.scripts.health;
using ColdMint.scripts.inventory;
using ColdMint.scripts.item;
using ColdMint.scripts.item.itemStacks;
using ColdMint.scripts.utils;
using ColdMint.scripts.item.weapon;
using ColdMint.scripts.loot;
using ColdMint.scripts.pickable;
using Godot;
namespace ColdMint.scripts.character;
@ -67,7 +66,9 @@ public partial class CharacterTemplate : CharacterBody2D
///<para>Update finished items</para>
///<para>更新完成后的物品</para>
/// </param>
protected virtual void WhenUpdateCurrentItem(Node2D? currentItem) { }
protected virtual void WhenUpdateCurrentItem(Node2D? currentItem)
{
}
//Define a pickup range
//定义一个拾起范围
@ -275,8 +276,8 @@ public partial class CharacterTemplate : CharacterBody2D
//Get the currently selected node
//拿到当前选择的节点
var itemSlotNode = ItemContainer.GetSelectItemSlotNode();
if (itemSlotNode == null)
var selectItemSlotNode = ItemContainer.GetSelectItemSlotNode();
if (selectItemSlotNode == null)
{
return false;
}
@ -311,7 +312,9 @@ public partial class CharacterTemplate : CharacterBody2D
pickAbleTemplate.Sleeping = true;
}
if (itemSlotNode.GetItem() != null && itemSlotNode.GetItem() == item && _currentItem == null)
var itemStack = selectItemSlotNode.GetItemStack();
var itemFromStack = itemStack?.GetItem();
if (itemFromStack != null && itemFromStack == item && _currentItem == null)
{
//If the selected item slot in the item container is a newly picked item, and there is no item in the hand, then we put the selected item into the hand.
//如果物品容器内选中的物品槽是刚刚捡到的物品,且手里没有物品持有,那么我们将选中的物品放到手上。
@ -486,7 +489,9 @@ public partial class CharacterTemplate : CharacterBody2D
_additionalForce = force;
}
protected virtual void OnHit(DamageTemplate damageTemplate) { }
protected virtual void OnHit(DamageTemplate damageTemplate)
{
}
/// <summary>
/// <para>Handle the event of character death</para>

View File

@ -1,6 +1,7 @@
using ColdMint.scripts.debug;
using System;
using ColdMint.scripts.item;
using ColdMint.scripts.item.itemStacks;
using ColdMint.scripts.map.events;
using ColdMint.scripts.utils;
using Godot;
@ -20,12 +21,27 @@ public partial class ItemSlotNode : MarginContainer
private bool _isSelect;
private Texture2D? _backgroundTexture;
private Texture2D? _backgroundTextureWhenSelect;
public Action<ItemStackChangeEvent>? ItemStackChangeEvent;
public override void _Ready()
{
_backgroundTexture = GD.Load<Texture2D>("res://sprites/ui/ItemBarEmpty.png");
_backgroundTextureWhenSelect = GD.Load<Texture2D>("res://sprites/ui/ItemBarFocus.png");
_backgroundTextureRect =
GetNode<TextureRect>("BackgroundTexture");
_iconTextureRect = GetNode<TextureRect>("BackgroundTexture/IconTextureRect");
_quantityLabel = GetNode<Label>("Control/QuantityLabel");
_control = GetNode<Control>("Control");
_quantityLabel.Hide();
}
public override Variant _GetDragData(Vector2 atPosition)
{
if (_iconTextureRect == null)
if (_iconTextureRect == null || _itemStack == null)
{
return base._GetDragData(atPosition);
//Drag is not allowed if there is no icon or no pile of items.
//如果没有图标或者没有物品堆,那么不允许拖动。
return new Variant();
}
var textureRect = new TextureRect();
@ -33,20 +49,63 @@ public partial class ItemSlotNode : MarginContainer
textureRect.Size = _iconTextureRect.Size;
textureRect.Texture = _iconTextureRect.Texture;
SetDragPreview(textureRect);
return Variant.From(this);
return Variant.CreateFrom(this);
}
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
//If the preplaced slot does not have an icon, the preplaced slot is not allowed.
//如果预放置的槽位没有图标,那么不允许放置。
if (_iconTextureRect == null)
{
return false;
}
//TODO:在这里判断是否可以放置物品。物品槽必须是空的。
// var itemSlotNode = data.As<ItemSlotNode>();
// itemSlotNode._itemStack
return true;
var type = data.VariantType;
if (type == Variant.Type.Nil)
{
//The preplaced data is null.
//预放置的数据为null。
return false;
}
var itemSlotNode = data.As<ItemSlotNode>();
var itemStack = itemSlotNode.GetItemStack();
if (itemStack == null)
{
//Return null when trying to get the source item heap.
//尝试获取源物品堆时返回null。
return false;
}
//TODOThis is where we infer whether the two piles can merge.在这里推断两个物品堆是否可以融合。
return _itemStack == null;
}
public override void _DropData(Vector2 atPosition, Variant data)
{
if (_iconTextureRect == null)
{
return;
}
var type = data.VariantType;
if (type == Variant.Type.Nil)
{
//The passed variable is null.
//传入的变量为null。
return;
}
var itemSlotNode = data.As<ItemSlotNode>();
var itemStack = itemSlotNode.ReplaceItemStack(null);
if (itemStack == null)
{
//Return null when trying to get the source item heap.
//尝试获取源物品堆时返回null。
return;
}
ReplaceItemStack(itemStack);
}
public bool IsSelect
@ -74,12 +133,6 @@ public partial class ItemSlotNode : MarginContainer
/// <returns></returns>
public IItemStack? GetItemStack() => _itemStack;
/// <summary>
/// <para>If present, get the item at the top of the item stack in this slot</para>
/// <para>如果存在,获取该槽位中物品堆顶部的物品</para>
/// </summary>
public IItem? GetItem() => _itemStack?.GetItem();
/// <summary>
/// <para>If present, remove an item in this slot and return it.</para>
/// <para>如果存在,移除该槽位中的一个物品并将其返回</para>
@ -90,7 +143,11 @@ public partial class ItemSlotNode : MarginContainer
if (_itemStack is null) return null;
var result = _itemStack.PickItem();
if (_itemStack.Empty) _itemStack = null;
if (_itemStack.Empty)
{
SetItemStack(null);
}
UpdateAllDisplay();
return result;
@ -110,7 +167,11 @@ public partial class ItemSlotNode : MarginContainer
if (_itemStack is null) return null;
var result = _itemStack.PickItems(value);
if (_itemStack.Empty) _itemStack = null;
if (_itemStack.Empty)
{
SetItemStack(null);
}
UpdateAllDisplay();
return result;
@ -142,7 +203,11 @@ public partial class ItemSlotNode : MarginContainer
var result = _itemStack.RemoveItem(number);
//If the specified number of items is removed, the number of items is less than or equal to 0. Then we empty the inventory.
//如果移除指定数量的物品后物品数量小于或等于0。那么我们清空物品栏。
if (_itemStack.Empty) _itemStack = null;
if (_itemStack.Empty)
{
SetItemStack(null);
}
UpdateAllDisplay();
return result;
@ -166,8 +231,7 @@ public partial class ItemSlotNode : MarginContainer
public void ClearSlot()
{
_itemStack?.ClearStack();
_itemStack = null;
SetItemStack(null);
UpdateAllDisplay();
}
@ -185,8 +249,7 @@ public partial class ItemSlotNode : MarginContainer
public IItemStack? ReplaceItemStack(IItemStack? newItemStack)
{
var result = _itemStack;
_itemStack = newItemStack;
SetItemStack(newItemStack);
UpdateAllDisplay();
return result;
@ -213,7 +276,7 @@ public partial class ItemSlotNode : MarginContainer
bool result;
if (_itemStack is null)
{
_itemStack = IItemStack.FromItem(item);
SetItemStack(IItemStack.FromItem(item));
result = true;
}
else
@ -257,7 +320,7 @@ public partial class ItemSlotNode : MarginContainer
bool result;
if (_itemStack is null)
{
_itemStack = itemStack;
SetItemStack(itemStack);
result = false;
}
else
@ -287,10 +350,9 @@ public partial class ItemSlotNode : MarginContainer
/// </summary>
private void UpdateTooltipText()
{
if (_control == null) return;
if (_itemStack == null)
{
_control.TooltipText = null;
TooltipText = null;
return;
}
@ -299,7 +361,7 @@ public partial class ItemSlotNode : MarginContainer
var debugText = TranslationServerUtils.Translate("item_prompt_debug");
if (debugText != null)
{
_control.TooltipText = string.Format(debugText, _itemStack.GetItem()?.Id,
TooltipText = string.Format(debugText, _itemStack.GetItem()?.Id,
TranslationServerUtils.Translate(_itemStack.Name),
_itemStack.Quantity, _itemStack.MaxQuantity, _itemStack.GetType().Name,
TranslationServerUtils.Translate(_itemStack.Description));
@ -307,7 +369,7 @@ public partial class ItemSlotNode : MarginContainer
}
else
{
_control.TooltipText = TranslationServerUtils.Translate(_itemStack.Name) + "\n" +
TooltipText = TranslationServerUtils.Translate(_itemStack.Name) + "\n" +
TranslationServerUtils.Translate(_itemStack.Description);
}
}
@ -337,6 +399,25 @@ public partial class ItemSlotNode : MarginContainer
}
}
/// <summary>
/// <para>SetItemStack</para>
/// <para>设置物品堆</para>
/// </summary>
/// <remarks>
///<para>This method broadcasts changes to the stack to the outside world</para>
///<para>此方法会对外广播物品堆的变更事件</para>
/// </remarks>
/// <param name="itemStack"></param>
private void SetItemStack(IItemStack? itemStack)
{
_itemStack = itemStack;
var stackChangeEvent = new ItemStackChangeEvent
{
ItemStack = itemStack
};
ItemStackChangeEvent?.Invoke(stackChangeEvent);
}
/// <summary>
/// <para>Update texture of the icon rect</para>
/// <para>更新显示的物品图标</para>
@ -349,15 +430,5 @@ public partial class ItemSlotNode : MarginContainer
}
}
public override void _Ready()
{
_backgroundTexture = GD.Load<Texture2D>("res://sprites/ui/ItemBarEmpty.png");
_backgroundTextureWhenSelect = GD.Load<Texture2D>("res://sprites/ui/ItemBarFocus.png");
_backgroundTextureRect =
GetNode<TextureRect>("BackgroundTexture");
_iconTextureRect = GetNode<TextureRect>("BackgroundTexture/IconTextureRect");
_quantityLabel = GetNode<Label>("Control/QuantityLabel");
_control = GetNode<Control>("Control");
_quantityLabel.Hide();
}
}

View File

@ -234,6 +234,32 @@ public class UniversalItemContainer : IItemContainer
itemSlotNode.IsSelect = (_itemSlotNodes.Count) == _selectIndex;
_itemSlotNodes.Add(itemSlotNode);
// itemSlotNode.ItemStackChangeEvent += @event =>
// {
// if (_itemSlotNodes == null)
// {
// return;
// }
//
// var index = _itemSlotNodes.IndexOf(itemSlotNode);
// // LogCat.Log("位于" + index + "的堆改变了。" + _selectIndex + "空的吗" + (@event.ItemStack == null));
// if (index == -1)
// {
// return;
// }
//
// if (index == _selectIndex)
// {
// if (@event.ItemStack == null)
// {
// HideItem(index);
// }
// else
// {
// DisplayItem(index);
// }
// }
// };
return itemSlotNode;
}
@ -317,14 +343,48 @@ public class UniversalItemContainer : IItemContainer
_itemSlotNodes[oldSelectIndex].IsSelect = false;
_itemSlotNodes[newSelectIndex].IsSelect = true;
var oldItem = _itemSlotNodes[oldSelectIndex].GetItem();
HideItem(oldSelectIndex);
DisplayItem(newSelectIndex);
_selectIndex = newSelectIndex;
}
/// <summary>
/// <para>HideItem</para>
/// <para>隐藏某个物品</para>
/// </summary>
/// <param name="index"></param>
private void HideItem(int index)
{
if (_itemSlotNodes == null)
{
return;
}
var oldItem = _itemSlotNodes[index].GetItemStack()?.GetItem();
if (oldItem is Node2D oldNode2D)
{
oldNode2D.ProcessMode = Node.ProcessModeEnum.Disabled;
oldNode2D.Hide();
}
}
var item = _itemSlotNodes[newSelectIndex].GetItem();
/// <summary>
/// <para>Displays the items in an item slot</para>
/// <para>显示某个物品槽内的物品</para>
/// </summary>
/// <remarks>
///<para>This method can also be used to refresh items held by the character, for example when a new item is dragged to the current display location, then call this method to refresh items held by the character.</para>
///<para>此方法也可用于刷新角色手上持有的物品,例如当新的物品被拖动到当前显示位置,那么请调用此方法刷新角色持有的物品。</para>
/// </remarks>
/// <param name="index"></param>
private void DisplayItem(int index)
{
if (_itemSlotNodes == null)
{
return;
}
var item = _itemSlotNodes[index].GetItemStack()?.GetItem();
switch (item)
{
case null:
@ -357,8 +417,6 @@ public class UniversalItemContainer : IItemContainer
break;
}
}
_selectIndex = newSelectIndex;
}

View File

@ -0,0 +1,16 @@
using ColdMint.scripts.item.itemStacks;
namespace ColdMint.scripts.map.events;
/// <summary>
/// <para>ItemStackChangeEvent</para>
/// <para>物品堆改变事件</para>
/// </summary>
public class ItemStackChangeEvent
{
/// <summary>
/// <para>Changed ItemStack</para>
/// <para>改变后的物品堆</para>
/// </summary>
public IItemStack? ItemStack { get; set; }
}