diff --git a/scripts/character/CharacterTemplate.cs b/scripts/character/CharacterTemplate.cs
index dd7ea07..d2e1251 100644
--- a/scripts/character/CharacterTemplate.cs
+++ b/scripts/character/CharacterTemplate.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using ColdMint.scripts.camp;
using ColdMint.scripts.damage;
using ColdMint.scripts.health;
+using ColdMint.scripts.inventory;
using ColdMint.scripts.weapon;
using Godot;
@@ -29,6 +30,16 @@ public partial class CharacterTemplate : CharacterBody2D
protected string? CharacterName;
+ //Item containers are used to store items.
+ //物品容器用于存储物品。
+ protected IItemContainer? _itemContainer;
+
+
+ public IItemContainer? ItemContainer
+ {
+ get => _itemContainer;
+ set => _itemContainer = value;
+ }
//Items currently held
//当前持有的物品
@@ -167,31 +178,75 @@ public partial class CharacterTemplate : CharacterBody2D
///Whether successfully picked up
///是否成功拾起
///
- public bool PickItem(Node2D pickAbleItem)
+ public bool PickItem(Node2D? pickAbleItem)
{
- if (CurrentItem == null)
+ if (pickAbleItem == null)
{
- if (pickAbleItem is WeaponTemplate weaponTemplate)
- {
- if (weaponTemplate.Owner != null && weaponTemplate.Owner != this)
- {
- return false;
- }
-
- weaponTemplate.Owner = this;
- weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false);
- weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, false);
- weaponTemplate.EnableContactInjury = false;
- weaponTemplate.Sleeping = true;
- }
-
- pickAbleItem.Reparent(ItemMarker2D);
- pickAbleItem.Position = Vector2.Zero;
- CurrentItem = pickAbleItem;
- return true;
+ return false;
}
- return false;
+ if (_itemContainer == null)
+ {
+ return false;
+ }
+
+ //Get the currently selected node
+ //拿到当前选择的节点
+ var itemSlotNode = _itemContainer.GetSelectItemSlotNode();
+ if (itemSlotNode == null)
+ {
+ return false;
+ }
+
+ if (pickAbleItem is not IItem item)
+ {
+ return false;
+ }
+
+ //First check if we can pick up the item.
+ //先检查我们能否拾起此物品。
+ var canPick = _itemContainer.CanAddItem(item);
+ if (!canPick)
+ {
+ return false;
+ }
+
+ //Is it successfully added to the container?
+ //再检查是否成功的添加到容器内了?
+ var addSuccess = _itemContainer.AddItem(item);
+ if (!addSuccess)
+ {
+ return false;
+ }
+
+ //Set up routine handling of picked up items.
+ //设置捡起物品的常规处理。
+ //You can supplement picking up state handling for more types of objects here.
+ //您可以在这里补充更多类型对象的捡起状态处理。
+ if (pickAbleItem is WeaponTemplate weaponTemplate)
+ {
+ weaponTemplate.Owner = this;
+ weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false);
+ weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, false);
+ weaponTemplate.EnableContactInjury = false;
+ weaponTemplate.Sleeping = true;
+ }
+
+ if (itemSlotNode.GetItem() != null && itemSlotNode.GetItem() == 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.
+ //如果物品容器内选中的物品槽是刚刚捡到的物品,且手里没有物品持有,那么我们将选中的物品放到手上。
+ CurrentItem = pickAbleItem;
+ }
+ else
+ {
+ pickAbleItem.Visible = false;
+ pickAbleItem.ProcessMode = ProcessModeEnum.Disabled;
+ }
+
+ pickAbleItem.Reparent(ItemMarker2D);
+ pickAbleItem.Position = Vector2.Zero;
+ return true;
}
diff --git a/scripts/character/Player.cs b/scripts/character/Player.cs
index b4f600c..6063f68 100644
--- a/scripts/character/Player.cs
+++ b/scripts/character/Player.cs
@@ -20,6 +20,9 @@ public partial class Player : CharacterTemplate
protected Control FloatLabel;
+ //Empty object projectile
+ //空的物品抛射线
+ private Vector2[] emptyVector2Array = new[] { Vector2.Zero };
//抛物线
private Line2D Parabola;
@@ -172,39 +175,40 @@ public partial class Player : CharacterTemplate
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
{
+ //When the collision state between the platform detection ray and the platform changes
//在平台检测射线与平台碰撞状态改变时
if (PlatformDetectionRayCast2D.IsColliding() != CollidingWithPlatform)
{
+ //When the state changes, update the action hint
//当状态改变时,更新操作提示
CollidingWithPlatform = PlatformDetectionRayCast2D.IsColliding();
UpdateOperationTip();
}
+ //If the character is on the ground, give an upward velocity when the jump button is pressed
//如果角色正在地面上,按下跳跃键时,给予一个向上的速度
if (Input.IsActionJustPressed("ui_up") && IsOnFloor())
velocity.Y = JumpVelocity;
+ //Moving left and right
//左右移动
var axis = Input.GetAxis("ui_left", "ui_right");
velocity.X = axis * Speed;
+ //Use items
//使用物品
if (Input.IsActionPressed("use_item"))
{
UseItem(GetGlobalMousePosition());
}
+ //Pick up an item
//捡起物品
if (Input.IsActionJustPressed("pick_up"))
{
var success = PickItem(PickAbleItem);
if (success)
{
- if (PickAbleItem is WeaponTemplate weaponTemplate)
- {
- GameSceneNodeHolder.HotBar.AddItem(weaponTemplate);
- }
-
PickAbleItem = null;
TotalNumberOfPickups--;
if (FloatLabel != null)
@@ -221,6 +225,7 @@ public partial class Player : CharacterTemplate
{
if (CollidingWithPlatform)
{
+ //When the character stands on the platform and presses the ui_down key, we cancel the collision between the character and the platform
//当角色站在平台上按下 ui_down 键时,我们取消角色与平台的碰撞
var timer = new Timer();
AddChild(timer);
@@ -237,16 +242,23 @@ public partial class Player : CharacterTemplate
}
+ //Display a parabola when an item is thrown
//抛出物品时,显示抛物线
if (Input.IsActionPressed("throw"))
{
- if (CurrentItem != null)
+ if (CurrentItem == null)
+ {
+ Parabola.Points = emptyVector2Array;
+ }
+ else
{
Parabola.Points =
ParabolicUtils.ComputeParabolic(ItemMarker2D.Position, GetThrowVelocity(), Gravity, 0.1f);
}
}
+
+ //When you raise your hand, throw the object
//抬起手时,抛出物品
if (Input.IsActionJustReleased("throw"))
{
@@ -295,6 +307,7 @@ public partial class Player : CharacterTemplate
private Vector2 GetThrowVelocity()
{
+ //We take the mouse position, normalize it, and then multiply it by the distance the player can throw
//我们拿到鼠标的位置,将其归一化处理,然后乘以玩家可扔出的距离
return GetLocalMousePosition().Normalized() * throwingVelocity;
}
@@ -307,18 +320,21 @@ public partial class Player : CharacterTemplate
switch (axis)
{
case -1:
+ //Minus 1, we move to the left
//-1,向左移动
FacingLeft = true;
itemMarker2DPosition.X = -ReadOnlyItemMarkerOriginalX;
Flip();
break;
case 1:
+ //1, move to the right
//1,向右移动
FacingLeft = false;
itemMarker2DPosition.X = ReadOnlyItemMarkerOriginalX;
Flip();
break;
default:
+ //0, when it's not pressed
//0,没有按下时
break;
}
@@ -329,6 +345,7 @@ public partial class Player : CharacterTemplate
protected override void Flip()
{
base.Flip();
+ //If there is a weapon, flip it too
//如果有武器的话,也要翻转
if (CurrentItem != null)
{
@@ -341,6 +358,13 @@ public partial class Player : CharacterTemplate
protected override void EnterThePickingRangeBody(Node node)
{
+ if (CurrentItem == node)
+ {
+ //If the node entering the pick range is the node held by the player, then return.
+ //如果说进入拾捡范围的节点是玩家所持有的节点,那么返回。
+ return;
+ }
+
if (node is not Node2D)
{
return;
@@ -398,6 +422,7 @@ public partial class Player : CharacterTemplate
TotalNumberOfPickups--;
if (TotalNumberOfPickups == 0)
{
+ //Set to null if there are no more items to pick up
//如果没有可捡的物品了,设置为null
PickAbleItem = null;
}
diff --git a/scripts/inventory/HotBar.cs b/scripts/inventory/HotBar.cs
index d961cfa..b24d7ab 100644
--- a/scripts/inventory/HotBar.cs
+++ b/scripts/inventory/HotBar.cs
@@ -10,7 +10,7 @@ namespace ColdMint.scripts.inventory;
/// HotBar
/// 快捷物品栏
///
-public partial class HotBar : HBoxContainer
+public partial class HotBar : HBoxContainer, IItemContainer
{
private PackedScene _itemSlotPackedScene;
private List _itemSlotNodes;
@@ -30,13 +30,6 @@ public partial class HotBar : HBoxContainer
public override void _Process(double delta)
{
base._Process(delta);
- if (Input.IsActionPressed("throw"))
- {
- //Players are not allowed to switch current items while throwing them.
- //玩家在抛物品时禁止切换当前物品。
- return;
- }
-
if (Input.IsActionJustPressed("hotbar_next"))
{
var count = _itemSlotNodes.Count;
@@ -198,27 +191,39 @@ public partial class HotBar : HBoxContainer
var item = _itemSlotNodes[newSelectIndex].GetItem();
if (item == null)
{
- LogCat.Log("选择" + oldSelectIndex + "新的为" + newSelectIndex + "空对象");
- GameSceneNodeHolder.Player.CurrentItem = null;
- LogCat.Log("我是空吗" + (GameSceneNodeHolder.Player.CurrentItem == null));
+ if (GameSceneNodeHolder.Player != null)
+ {
+ GameSceneNodeHolder.Player.CurrentItem = null;
+ }
}
else
{
if (item is Node2D node2D)
{
- LogCat.Log("我是空吗" + (GameSceneNodeHolder.Player.CurrentItem == null));
- LogCat.Log("选择" + oldSelectIndex + "新的为" + newSelectIndex + "已赋值" + node2D);
node2D.ProcessMode = ProcessModeEnum.Inherit;
node2D.Show();
- GameSceneNodeHolder.Player.CurrentItem = node2D;
+ if (GameSceneNodeHolder.Player != null)
+ {
+ GameSceneNodeHolder.Player.CurrentItem = node2D;
+ }
}
else
{
- GameSceneNodeHolder.Player.CurrentItem = null;
+ if (GameSceneNodeHolder.Player != null)
+ {
+ GameSceneNodeHolder.Player.CurrentItem = null;
+ }
}
}
}
+
+ public bool CanAddItem(IItem item)
+ {
+ return Matching(item) != null;
+ }
+
+
///
/// Add an item to the HotBar
/// 在HotBar内添加一个物品
@@ -227,9 +232,54 @@ public partial class HotBar : HBoxContainer
///
public bool AddItem(IItem item)
{
- return _itemSlotNodes.Count != 0 && _itemSlotNodes.Any(itemSlotNode => itemSlotNode.SetItem(item));
+ var itemSlotNode = Matching(item);
+ if (itemSlotNode == null)
+ {
+ return false;
+ }
+ else
+ {
+ return itemSlotNode.SetItem(item);
+ }
}
+ public ItemSlotNode? GetSelectItemSlotNode()
+ {
+ if (_itemSlotNodes.Count == 0)
+ {
+ return null;
+ }
+
+ if (selectIndex < _itemSlotNodes.Count)
+ {
+ //Prevent subscripts from going out of bounds.
+ //防止下标越界。
+ return _itemSlotNodes[selectIndex];
+ }
+
+ return null;
+ }
+
+ public ItemSlotNode? Matching(IItem item)
+ {
+ if (_itemSlotNodes.Count == 0)
+ {
+ return null;
+ }
+
+
+ foreach (var itemSlotNode in _itemSlotNodes)
+ {
+ if (itemSlotNode.CanSetItem(item))
+ {
+ //If there is an item slot to put this item in, then we return it.
+ //如果有物品槽可放置此物品,那么我们返回它。
+ return itemSlotNode;
+ }
+ }
+
+ return null;
+ }
///
/// Add items tank
diff --git a/scripts/inventory/IItem.cs b/scripts/inventory/IItem.cs
index 60ad524..09811e9 100644
--- a/scripts/inventory/IItem.cs
+++ b/scripts/inventory/IItem.cs
@@ -27,7 +27,7 @@ public interface IItem
/// Items can be set with Icon
/// 物品可以设置图标
///
- Texture2D Icon { get; set; }
+ Texture2D? Icon { get; set; }
///
/// Item has a name
diff --git a/scripts/inventory/IItemContainer.cs b/scripts/inventory/IItemContainer.cs
new file mode 100644
index 0000000..01d2bff
--- /dev/null
+++ b/scripts/inventory/IItemContainer.cs
@@ -0,0 +1,46 @@
+namespace ColdMint.scripts.inventory;
+
+///
+/// item container
+/// 物品容器
+///
+///
+///Item containers can store items. Things like backpacks and Hotbars are containers with visual pages.
+///物品容器可以储存物品。像背包和hotbar是具有可视化页面的容器。
+///
+public interface IItemContainer
+{
+ ///
+ /// Can the specified item be added to the container?
+ /// 指定的物品是否可添加到容器内?
+ ///
+ ///
+ ///
+ bool CanAddItem(IItem item);
+
+ ///
+ /// Implement methods for adding items
+ /// 实现添加物品的方法
+ ///
+ ///
+ ///
+ bool AddItem(IItem item);
+
+ ///
+ /// Gets the currently selected node
+ /// 获取当前选中的节点
+ ///
+ ///
+ ItemSlotNode? GetSelectItemSlotNode();
+
+ ///
+ /// Based on the given item, match the item slots where it can be placed
+ /// 根据给定的物品,匹配可放置它的物品槽
+ ///
+ ///
+ ///
+ ///Return null if there is no slot to place the item in
+ ///若没有槽可放置此物品,则返回null
+ ///
+ ItemSlotNode? Matching(IItem item);
+}
\ No newline at end of file
diff --git a/scripts/inventory/ItemSlotNode.cs b/scripts/inventory/ItemSlotNode.cs
index 11c069a..6f4e5ab 100644
--- a/scripts/inventory/ItemSlotNode.cs
+++ b/scripts/inventory/ItemSlotNode.cs
@@ -8,189 +8,212 @@ namespace ColdMint.scripts.inventory;
///
public partial class ItemSlotNode : MarginContainer
{
- private IItem? _item;
- private TextureRect _backgroundTextureRect;
- private TextureRect _iconTextureRect;
- private Label _quantityLabel;
- private Control _control;
- private bool _isSelect;
- private Texture2D _backgroundTexture;
- private Texture2D _backgroundTextureWhenSelect;
+ private IItem? _item;
+ private TextureRect _backgroundTextureRect;
+ private TextureRect _iconTextureRect;
+ private Label _quantityLabel;
+ private Control _control;
+ private bool _isSelect;
+ private Texture2D _backgroundTexture;
+ private Texture2D _backgroundTextureWhenSelect;
- public bool IsSelect
- {
- get => _isSelect;
- set
- {
- if (value)
- {
- _backgroundTextureRect.Texture = _backgroundTextureWhenSelect;
- }
- else
- {
- _backgroundTextureRect.Texture = _backgroundTexture;
- }
+ public bool IsSelect
+ {
+ get => _isSelect;
+ set
+ {
+ if (value)
+ {
+ _backgroundTextureRect.Texture = _backgroundTextureWhenSelect;
+ }
+ else
+ {
+ _backgroundTextureRect.Texture = _backgroundTexture;
+ }
- _isSelect = value;
- }
- }
+ _isSelect = value;
+ }
+ }
- public TextureRect BackgroundTextureRect => _backgroundTextureRect;
+ public TextureRect BackgroundTextureRect => _backgroundTextureRect;
- ///
- /// Get the items in the item slot
- /// 获取物品槽内的物品
- ///
- ///
- public IItem? GetItem()
- {
- return _item;
- }
+ ///
+ /// Get the items in the item slot
+ /// 获取物品槽内的物品
+ ///
+ ///
+ public IItem? GetItem()
+ {
+ return _item;
+ }
- ///
- /// Removes the specified number of items from the item slot
- /// 在物品槽内移除指定数量的物品
- ///
- ///
- ///
- public bool RemoveItem(int number)
- {
- if (_item == null)
- {
- return false;
- }
+ ///
+ /// Removes the specified number of items from the item slot
+ /// 在物品槽内移除指定数量的物品
+ ///
+ ///
+ ///
+ public bool RemoveItem(int number)
+ {
+ if (_item == null)
+ {
+ return false;
+ }
- var newNumber = _item.Quantity - number;
- if (newNumber <= 0)
- {
- //If the specified number of items is removed, the number of items is less than or equal to 0. Then we return the removal successful and empty the inventory.
- //如果移除指定数量的物品后,物品数量小于或等于0。那么我们返回移除成功,并清空物品栏。
- ClearItem();
- return true;
- }
- else
- {
- _item.Quantity = newNumber;
- UpdateTooltipText(_item);
- UpdateQuantityLabel(_item.Quantity);
- return true;
- }
- }
+ var newNumber = _item.Quantity - number;
+ if (newNumber <= 0)
+ {
+ //If the specified number of items is removed, the number of items is less than or equal to 0. Then we return the removal successful and empty the inventory.
+ //如果移除指定数量的物品后,物品数量小于或等于0。那么我们返回移除成功,并清空物品栏。
+ ClearItem();
+ return true;
+ }
+ else
+ {
+ _item.Quantity = newNumber;
+ UpdateTooltipText(_item);
+ UpdateQuantityLabel(_item.Quantity);
+ return true;
+ }
+ }
- ///
- /// Empty the items in the item slot
- /// 清空物品槽内的物品
- ///
- ///
- ///This method does not calculate how many items should be left. If you want to remove a specified number of items, call the RemoveItem method.
- ///此方法不会计算物品应该剩余多少个。若您希望移除指定数量的物品,请调用RemoveItem方法。
- ///
- public void ClearItem()
- {
- _item = null;
- _iconTextureRect.Texture = null;
- _control.TooltipText = null;
- _quantityLabel.Visible = false;
- }
+ ///
+ /// Empty the items in the item slot
+ /// 清空物品槽内的物品
+ ///
+ ///
+ ///This method does not calculate how many items should be left. If you want to remove a specified number of items, call the RemoveItem method.
+ ///此方法不会计算物品应该剩余多少个。若您希望移除指定数量的物品,请调用RemoveItem方法。
+ ///
+ public void ClearItem()
+ {
+ _item = null;
+ _iconTextureRect.Texture = null;
+ _control.TooltipText = null;
+ _quantityLabel.Visible = false;
+ }
- ///
- /// Sets items for the item slot
- /// 为物品槽设置物品
- ///
- ///
- ///
- public bool SetItem(IItem item)
- {
- if (_item == null)
- {
- if (item.Icon != null)
- {
- _iconTextureRect.Texture = item.Icon;
- }
- _item = item;
- UpdateTooltipText(item);
- UpdateQuantityLabel(item.Quantity);
- return true;
- }
- else
- {
- //This inventory already has items, but the items in this inventory are not the same as the incoming items
- //这个物品栏已经有物品了,但是这个物品栏的物品和传入的物品不一样
- if (_item.Id != item.Id)
- {
- return false;
- }
+ ///
+ /// Can the specified item be placed in the item slot?
+ /// 指定的物品是否可设置在物品槽内?
+ ///
+ ///
+ ///
+ public bool CanSetItem(IItem item)
+ {
+ if (_item == null)
+ {
+ return true;
+ }
- var newQuantity = _item.Quantity + item.Quantity;
- if (newQuantity > item.MaxStackQuantity)
- {
- //If the amount of the current item exceeds the maximum stack amount after placing it in this inventory
- //如果将当前物品放置到这个物品栏后,数量超过了最大叠加数量
- return false;
- }
+ //This inventory already has items, but the items in this inventory are not the same as the incoming items
+ //这个物品栏已经有物品了,但是这个物品栏的物品和传入的物品不一样
+ if (_item.Id != item.Id)
+ {
+ return false;
+ }
- _item.Quantity = newQuantity;
- UpdateTooltipText(item);
- UpdateQuantityLabel(newQuantity);
- return true;
- }
- }
+ var newQuantity = _item.Quantity + item.Quantity;
+ if (newQuantity > item.MaxStackQuantity)
+ {
+ //If the amount of the current item exceeds the maximum stack amount after placing it in this inventory
+ //如果将当前物品放置到这个物品栏后,数量超过了最大叠加数量
+ return false;
+ }
- ///
- /// Update item tips
- /// 更新物品的提示内容
- ///
- ///
- private void UpdateTooltipText(IItem item)
- {
- if (Config.IsDebug())
- {
- _control.TooltipText = string.Format(TranslationServer.Translate("item_prompt_debug"), item.Id,
- TranslationServer.Translate(item.Name),
- item.Quantity, item.MaxStackQuantity, item.GetType().Name,
- TranslationServer.Translate(item.Description));
- }
- else
- {
- _control.TooltipText = TranslationServer.Translate(item.Name) + "\n" +
- TranslationServer.Translate(item.Description);
- }
- }
+ return true;
+ }
- ///
- /// Update quantity label
- /// 更新数量标签
- ///
- ///
- private void UpdateQuantityLabel(int? quantity)
- {
- switch (quantity)
- {
- case null:
- _quantityLabel.Visible = false;
- return;
- case > 1:
- //When the quantity is greater than 1, we display the quantity.
- //当数量大于1时,我们显示数量
- _quantityLabel.Text = quantity.ToString();
- _quantityLabel.Visible = true;
- break;
- default:
- _quantityLabel.Visible = false;
- break;
- }
- }
+ ///
+ /// Sets items for the item slot
+ /// 为物品槽设置物品
+ ///
+ ///
+ ///
+ public bool SetItem(IItem item)
+ {
+ if (!CanSetItem(item))
+ {
+ return false;
+ }
- public override void _Ready()
- {
- _backgroundTexture = GD.Load("res://sprites/ui/ItemBarEmpty.png");
- _backgroundTextureWhenSelect = GD.Load("res://sprites/ui/ItemBarFocus.png");
- _backgroundTextureRect =
- GetNode("BackgroundTexture");
- _iconTextureRect = GetNode("BackgroundTexture/CenterContainer/IconTextureRect");
- _quantityLabel = GetNode