Compare commits
5 Commits
fac2047f79
...
5ca995d689
Author | SHA1 | Date | |
---|---|---|---|
5ca995d689 | |||
95515ddab2 | |||
21b3691925 | |||
f7139dd60d | |||
6adb1b057c |
|
@ -15,11 +15,6 @@ public partial class BehaviorNode : Node2D
|
||||||
InvokeBehaviorTreeNode(true, delta);
|
InvokeBehaviorTreeNode(true, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
// public override void _Process(double delta)
|
|
||||||
// {
|
|
||||||
// InvokeBehaviorTreeNode(false, delta);
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>InvokeBehaviorTreeNode</para>
|
/// <para>InvokeBehaviorTreeNode</para>
|
||||||
/// <para>调用行为树节点</para>
|
/// <para>调用行为树节点</para>
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
namespace ColdMint.scripts.behaviorTree;
|
namespace ColdMint.scripts.behaviorTree;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>IBehavior Tree</para>
|
||||||
|
/// <para>行为树</para>
|
||||||
|
/// </summary>
|
||||||
public interface IBehaviorTree
|
public interface IBehaviorTree
|
||||||
{
|
{
|
||||||
string? Id { get; }
|
string? Id { get; }
|
||||||
|
|
|
@ -3,6 +3,10 @@ using ColdMint.scripts.character;
|
||||||
|
|
||||||
namespace ColdMint.scripts.behaviorTree.ai;
|
namespace ColdMint.scripts.behaviorTree.ai;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>AI attack node</para>
|
||||||
|
/// <para>AI的攻击节点</para>
|
||||||
|
/// </summary>
|
||||||
public class AiAttackNode : BehaviorTreeNodeTemplate
|
public class AiAttackNode : BehaviorTreeNodeTemplate
|
||||||
{
|
{
|
||||||
public AiCharacter? Character { get; set; }
|
public AiCharacter? Character { get; set; }
|
||||||
|
@ -29,8 +33,11 @@ public class AiAttackNode : BehaviorTreeNodeTemplate
|
||||||
var selfCamp = CampManager.GetCamp(Character.CampId);
|
var selfCamp = CampManager.GetCamp(Character.CampId);
|
||||||
foreach (var node in nodesInTheAttackRange)
|
foreach (var node in nodesInTheAttackRange)
|
||||||
{
|
{
|
||||||
if (node is CharacterTemplate characterTemplate)
|
if (node is not CharacterTemplate characterTemplate)
|
||||||
{
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (node == Character)
|
if (node == Character)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -50,26 +57,25 @@ public class AiAttackNode : BehaviorTreeNodeTemplate
|
||||||
|
|
||||||
if (selfCamp.Id == characterCamp.Id)
|
if (selfCamp.Id == characterCamp.Id)
|
||||||
{
|
{
|
||||||
//如果是同一阵营,不攻击
|
//If it is the same side, do not attack, if allowed friend damage, this code will prevent the AI from actively attacking the player.
|
||||||
|
//如果是同一阵营,不攻击,如果允许友伤,这段代码会阻止AI主动攻击玩家。
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var distance = characterTemplate.GlobalPosition - Character.GlobalPosition;
|
var distance = characterTemplate.GlobalPosition.DistanceTo(Character.GlobalPosition);
|
||||||
var distanceLength = distance.Length();
|
if (distance < closestDistance)
|
||||||
if (distanceLength < closestDistance)
|
|
||||||
{
|
{
|
||||||
closestDistance = distanceLength;
|
closestDistance = distance;
|
||||||
closestEnemy = characterTemplate;
|
closestEnemy = characterTemplate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (closestEnemy != null && Character.AttackObstacleDetection != null)
|
if (closestEnemy != null && Character.AttackObstacleDetection != null)
|
||||||
{
|
{
|
||||||
//There are the closest enemies
|
//With the nearest enemy and no obstacles
|
||||||
//有距离最近的敌人
|
//有距离最近的敌人,且没有障碍物
|
||||||
var distance = closestEnemy.GlobalPosition - Character.GlobalPosition;
|
var distanceVector2 = closestEnemy.GlobalPosition - Character.GlobalPosition;
|
||||||
Character.AttackObstacleDetection.TargetPosition = distance;
|
Character.AttackObstacleDetection.TargetPosition = distanceVector2;
|
||||||
if (Character.AttackObstacleDetection.GetCollider() == null)
|
if (Character.AttackObstacleDetection.GetCollider() == null)
|
||||||
{
|
{
|
||||||
Character.StopMoving();
|
Character.StopMoving();
|
||||||
|
|
|
@ -4,6 +4,7 @@ using ColdMint.scripts.character;
|
||||||
namespace ColdMint.scripts.behaviorTree.ai;
|
namespace ColdMint.scripts.behaviorTree.ai;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// <para>AI patrol node</para>
|
||||||
/// <para>AI巡逻节点</para>
|
/// <para>AI巡逻节点</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AiPatrolNode : SelectorNode
|
public class AiPatrolNode : SelectorNode
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class SequenceNode : BehaviorTreeNodeTemplate
|
||||||
/// <para>Check whether all child nodes are executed in sequence</para>
|
/// <para>Check whether all child nodes are executed in sequence</para>
|
||||||
/// <para>所有子节点是否按顺序执行完毕</para>
|
/// <para>所有子节点是否按顺序执行完毕</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool _complete = true;
|
private bool _complete = true;
|
||||||
|
|
||||||
public override int Execute(bool isPhysicsProcess, double delta)
|
public override int Execute(bool isPhysicsProcess, double delta)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,12 +8,11 @@ namespace ColdMint.scripts.camp;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Camp
|
public class Camp
|
||||||
{
|
{
|
||||||
private readonly string _id;
|
|
||||||
private readonly List<string> _friendlyCampIdList;
|
private readonly List<string> _friendlyCampIdList;
|
||||||
|
|
||||||
public Camp(string id)
|
public Camp(string id)
|
||||||
{
|
{
|
||||||
_id = id;
|
Id = id;
|
||||||
_friendlyCampIdList = new List<string>();
|
_friendlyCampIdList = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +20,7 @@ public class Camp
|
||||||
/// <para>Get camp ID</para>
|
/// <para>Get camp ID</para>
|
||||||
/// <para>获取阵营ID</para>
|
/// <para>获取阵营ID</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Id => _id;
|
public string Id { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Get camp name</para>
|
/// <para>Get camp name</para>
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace ColdMint.scripts.camp;
|
||||||
/// <para>Camp manager</para>
|
/// <para>Camp manager</para>
|
||||||
/// <para>阵营管理器</para>
|
/// <para>阵营管理器</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CampManager
|
public static class CampManager
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, Camp?> Camps = new Dictionary<string, Camp?>();
|
private static readonly Dictionary<string, Camp?> Camps = new Dictionary<string, Camp?>();
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace ColdMint.scripts.character;
|
||||||
/// <para>The role played by computers</para>
|
/// <para>The role played by computers</para>
|
||||||
/// <para>由电脑扮演的角色</para>
|
/// <para>由电脑扮演的角色</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AiCharacter : CharacterTemplate
|
public sealed partial class AiCharacter : CharacterTemplate
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>How fast the character moves</para>
|
/// <para>How fast the character moves</para>
|
||||||
|
@ -67,10 +67,11 @@ public partial class AiCharacter : CharacterTemplate
|
||||||
|
|
||||||
if (_attackArea != null)
|
if (_attackArea != null)
|
||||||
{
|
{
|
||||||
|
//If true, the zone will detect objects or areas entering and leaving the zone.
|
||||||
//如果为true,该区域将检测进出该区域的物体或区域。
|
//如果为true,该区域将检测进出该区域的物体或区域。
|
||||||
_attackArea.Monitoring = true;
|
_attackArea.Monitoring = true;
|
||||||
//Other regions cannot detect our pick region
|
//Other areas can't detect our attack zone
|
||||||
//其他区域不能检测到我们的拾取区域
|
//其他区域不能检测到我们的攻击区域
|
||||||
_attackArea.Monitorable = false;
|
_attackArea.Monitorable = false;
|
||||||
_attackArea.BodyEntered += EnterTheAttackArea;
|
_attackArea.BodyEntered += EnterTheAttackArea;
|
||||||
_attackArea.BodyExited += ExitTheAttackArea;
|
_attackArea.BodyExited += ExitTheAttackArea;
|
||||||
|
@ -83,12 +84,12 @@ public partial class AiCharacter : CharacterTemplate
|
||||||
// _behaviorNode.Root = patrolBehaviorTree.Root;
|
// _behaviorNode.Root = patrolBehaviorTree.Root;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void EnterTheAttackArea(Node node)
|
private void EnterTheAttackArea(Node node)
|
||||||
{
|
{
|
||||||
_nodesInTheAttackRange?.Add(node);
|
_nodesInTheAttackRange?.Add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ExitTheAttackArea(Node node)
|
private void ExitTheAttackArea(Node node)
|
||||||
{
|
{
|
||||||
_nodesInTheAttackRange?.Remove(node);
|
_nodesInTheAttackRange?.Remove(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using ColdMint.scripts.damage;
|
||||||
using ColdMint.scripts.debug;
|
using ColdMint.scripts.debug;
|
||||||
using ColdMint.scripts.health;
|
using ColdMint.scripts.health;
|
||||||
using ColdMint.scripts.inventory;
|
using ColdMint.scripts.inventory;
|
||||||
using ColdMint.scripts.map.events;
|
|
||||||
using ColdMint.scripts.utils;
|
using ColdMint.scripts.utils;
|
||||||
using ColdMint.scripts.weapon;
|
using ColdMint.scripts.weapon;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
@ -30,6 +29,9 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
|
|
||||||
protected const float JumpVelocity = -240;
|
protected const float JumpVelocity = -240;
|
||||||
|
|
||||||
|
//物品被扔出后多长时间恢复与地面和平台的碰撞(单位:秒)
|
||||||
|
private readonly double _itemCollisionRecoveryTime = 0.045f;
|
||||||
|
|
||||||
public string? ReadOnlyCharacterName => CharacterName;
|
public string? ReadOnlyCharacterName => CharacterName;
|
||||||
|
|
||||||
protected string? CharacterName;
|
protected string? CharacterName;
|
||||||
|
@ -259,7 +261,9 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public bool PickItem(Node2D? pickAbleItem)
|
public bool PickItem(Node2D? pickAbleItem)
|
||||||
{
|
{
|
||||||
if (pickAbleItem == null)
|
//Empty reference checking is implicitly performed here.
|
||||||
|
//此处隐式的执行了空引用检查。
|
||||||
|
if (pickAbleItem is not IItem item)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -277,11 +281,6 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pickAbleItem is not IItem item)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//First check if we can pick up the item.
|
//First check if we can pick up the item.
|
||||||
//先检查我们能否拾起此物品。
|
//先检查我们能否拾起此物品。
|
||||||
var canPick = _itemContainer.CanAddItem(item);
|
var canPick = _itemContainer.CanAddItem(item);
|
||||||
|
@ -368,7 +367,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
/// <para>Update the role's health bar</para>
|
/// <para>Update the role's health bar</para>
|
||||||
/// <para>更新角色的健康条</para>
|
/// <para>更新角色的健康条</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpDataHealthBar(DamageTemplate damageTemplate)
|
private void UpDataHealthBar()
|
||||||
{
|
{
|
||||||
if (_healthBar == null)
|
if (_healthBar == null)
|
||||||
{
|
{
|
||||||
|
@ -441,7 +440,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpDataHealthBar(damageTemplate);
|
UpDataHealthBar();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,6 +528,86 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
_animatedSprite2D.FlipH = FacingLeft;
|
_animatedSprite2D.FlipH = FacingLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Throw item</para>
|
||||||
|
/// <para>抛出物品</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">
|
||||||
|
///<para>Item slot subscript in item container</para>
|
||||||
|
///<para>物品容器内的物品槽下标</para>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="number">
|
||||||
|
/// <para>How many to throw</para>
|
||||||
|
/// <para>要扔几个</para>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="velocity">
|
||||||
|
///<para>The speed to be applied to the item</para>
|
||||||
|
///<para>要施加到物品上的速度</para>
|
||||||
|
/// </param>
|
||||||
|
protected void ThrowItem(int index, int number, Vector2 velocity)
|
||||||
|
{
|
||||||
|
if (_itemContainer == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemSlotNode = _itemContainer.GetItemSlotNode(index);
|
||||||
|
if (itemSlotNode == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = itemSlotNode.GetItem();
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (item)
|
||||||
|
{
|
||||||
|
case WeaponTemplate weaponTemplate:
|
||||||
|
if (GameSceneNodeHolder.WeaponContainer == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
weaponTemplate.Reparent(GameSceneNodeHolder.WeaponContainer);
|
||||||
|
var timer = new Timer();
|
||||||
|
weaponTemplate.AddChild(timer);
|
||||||
|
timer.WaitTime = _itemCollisionRecoveryTime;
|
||||||
|
timer.OneShot = true;
|
||||||
|
timer.Timeout += () =>
|
||||||
|
{
|
||||||
|
//We cannot immediately resume the physical collision when the weapon is discharged, which will cause the weapon to collide with the ground and platform earlier, preventing the weapon from flying.
|
||||||
|
//仍出武器时,我们不能立即恢复物理碰撞,立即恢复会导致武器更早的与地面和平台碰撞,阻止武器的飞行。
|
||||||
|
weaponTemplate.EnableContactInjury = true;
|
||||||
|
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, true);
|
||||||
|
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
||||||
|
timer.QueueFree();
|
||||||
|
};
|
||||||
|
timer.Start();
|
||||||
|
weaponTemplate.Sleeping = false;
|
||||||
|
// weaponTemplate.LinearVelocity = Vector2.Zero;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//We apply force to objects.
|
||||||
|
//我们给物品施加力。
|
||||||
|
switch (CurrentItem)
|
||||||
|
{
|
||||||
|
case CharacterBody2D characterBody2D:
|
||||||
|
characterBody2D.Velocity = velocity;
|
||||||
|
break;
|
||||||
|
case RigidBody2D rigidBody2D:
|
||||||
|
rigidBody2D.LinearVelocity = velocity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove items from the item container
|
||||||
|
//在物品容器内移除物品
|
||||||
|
itemSlotNode.RemoveItem(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public sealed override void _PhysicsProcess(double delta)
|
public sealed override void _PhysicsProcess(double delta)
|
||||||
{
|
{
|
||||||
|
|
|
@ -43,9 +43,6 @@ public partial class Player : CharacterTemplate
|
||||||
//角色从平台上跳下后,多少时间后恢复与平台的碰撞(单位:秒)
|
//角色从平台上跳下后,多少时间后恢复与平台的碰撞(单位:秒)
|
||||||
private double _platformCollisionRecoveryTime = 0.2f;
|
private double _platformCollisionRecoveryTime = 0.2f;
|
||||||
|
|
||||||
//物品被扔出后多长时间恢复与地面和平台的碰撞(单位:秒)
|
|
||||||
private readonly double _itemCollisionRecoveryTime = 0.045f;
|
|
||||||
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
|
@ -255,7 +252,7 @@ public partial class Player : CharacterTemplate
|
||||||
//抬起手时,抛出物品
|
//抬起手时,抛出物品
|
||||||
if (Input.IsActionJustReleased("throw"))
|
if (Input.IsActionJustReleased("throw"))
|
||||||
{
|
{
|
||||||
if (CurrentItem == null)
|
if (ItemContainer == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -265,46 +262,8 @@ public partial class Player : CharacterTemplate
|
||||||
_parabola.Points = new[] { Vector2.Zero };
|
_parabola.Points = new[] { Vector2.Zero };
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrentItem.Reparent(GameSceneNodeHolder.WeaponContainer);
|
ThrowItem(ItemContainer.GetSelectIndex(), 1, GetThrowVelocity());
|
||||||
switch (CurrentItem)
|
|
||||||
{
|
|
||||||
case WeaponTemplate weaponTemplate:
|
|
||||||
{
|
|
||||||
var timer = new Timer();
|
|
||||||
weaponTemplate.AddChild(timer);
|
|
||||||
timer.WaitTime = _itemCollisionRecoveryTime;
|
|
||||||
timer.OneShot = true;
|
|
||||||
timer.Timeout += () =>
|
|
||||||
{
|
|
||||||
//We cannot immediately resume the physical collision when the weapon is discharged, which will cause the weapon to collide with the ground and platform earlier, preventing the weapon from flying.
|
|
||||||
//仍出武器时,我们不能立即恢复物理碰撞,立即恢复会导致武器更早的与地面和平台碰撞,阻止武器的飞行。
|
|
||||||
weaponTemplate.EnableContactInjury = true;
|
|
||||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, true);
|
|
||||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
|
||||||
timer.QueueFree();
|
|
||||||
};
|
|
||||||
timer.Start();
|
|
||||||
weaponTemplate.Sleeping = false;
|
|
||||||
weaponTemplate.LinearVelocity = Vector2.Zero;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//We apply force to objects.
|
|
||||||
//我们给物品施加力。
|
|
||||||
switch (CurrentItem)
|
|
||||||
{
|
|
||||||
case CharacterBody2D characterBody2D:
|
|
||||||
characterBody2D.Velocity = GetThrowVelocity();
|
|
||||||
break;
|
|
||||||
case RigidBody2D rigidBody2D:
|
|
||||||
rigidBody2D.LinearVelocity = GetThrowVelocity();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentItem = null;
|
CurrentItem = null;
|
||||||
var hotBar = GameSceneNodeHolder.HotBar;
|
|
||||||
hotBar?.RemoveItemFromItemSlotBySelectIndex(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,6 +272,10 @@ public partial class Player : CharacterTemplate
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>当玩家手动抛出物品时,施加到物品上的速度值</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
private Vector2 GetThrowVelocity()
|
private Vector2 GetThrowVelocity()
|
||||||
{
|
{
|
||||||
//We take the mouse position, normalize it, and then multiply it by the distance the player can throw
|
//We take the mouse position, normalize it, and then multiply it by the distance the player can throw
|
||||||
|
|
|
@ -14,6 +14,12 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
|
|
||||||
private List<ItemSlotNode>? _itemSlotNodes;
|
private List<ItemSlotNode>? _itemSlotNodes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>UnknownIndex</para>
|
||||||
|
/// <para>未知位置</para>
|
||||||
|
/// </summary>
|
||||||
|
private const int UnknownIndex = -1;
|
||||||
|
|
||||||
//_selectIndex默认为0.
|
//_selectIndex默认为0.
|
||||||
private int _selectIndex;
|
private int _selectIndex;
|
||||||
|
|
||||||
|
@ -160,17 +166,14 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = _itemSlotNodes.Count;
|
var safeIndex = GetSafeIndex(shortcutKeyIndex);
|
||||||
if (count == 0)
|
if (safeIndex == UnknownIndex)
|
||||||
{
|
{
|
||||||
//Prevents the dividend from being 0
|
|
||||||
//防止被除数为0
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newIndex = shortcutKeyIndex % count;
|
SelectItemSlot(_selectIndex, safeIndex);
|
||||||
SelectItemSlot(_selectIndex, newIndex);
|
_selectIndex = safeIndex;
|
||||||
_selectIndex = newIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,6 +188,27 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
return RemoveItemFromItemSlot(_selectIndex, number);
|
return RemoveItemFromItemSlot(_selectIndex, number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetItemSlotCount()
|
||||||
|
{
|
||||||
|
if (_itemSlotNodes == null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _itemSlotNodes.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlotNode? GetItemSlotNode(int index)
|
||||||
|
{
|
||||||
|
if (_itemSlotNodes == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var safeIndex = GetSafeIndex(index);
|
||||||
|
return _itemSlotNodes[safeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Remove items from the item slot</para>
|
/// <para>Remove items from the item slot</para>
|
||||||
/// <para>从物品槽内移除物品</para>
|
/// <para>从物品槽内移除物品</para>
|
||||||
|
@ -204,17 +228,41 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var safeIndex = GetSafeIndex(itemSlotIndex);
|
||||||
|
if (safeIndex == UnknownIndex)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemSlot = _itemSlotNodes[safeIndex];
|
||||||
|
return itemSlot.RemoveItem(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Gets a secure subscript index</para>
|
||||||
|
/// <para>获取安全的下标索引</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemSlotIndex"></param>
|
||||||
|
/// <returns>
|
||||||
|
///<para>-1 is returned on failure, and the index that does not result in an out-of-bounds subscript is returned on success</para>
|
||||||
|
///<para>失败返回-1,成功返回不会导致下标越界的索引</para>
|
||||||
|
/// </returns>
|
||||||
|
private int GetSafeIndex(int itemSlotIndex)
|
||||||
|
{
|
||||||
|
if (_itemSlotNodes == null)
|
||||||
|
{
|
||||||
|
return UnknownIndex;
|
||||||
|
}
|
||||||
|
|
||||||
var count = _itemSlotNodes.Count;
|
var count = _itemSlotNodes.Count;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
//Prevents the dividend from being 0
|
//Prevents the dividend from being 0
|
||||||
//防止被除数为0
|
//防止被除数为0
|
||||||
return false;
|
return UnknownIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
var newIndex = itemSlotIndex % count;
|
return itemSlotIndex % count;
|
||||||
var itemSlot = _itemSlotNodes[newIndex];
|
|
||||||
return itemSlot.RemoveItem(number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -223,6 +271,11 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SelectItemSlot(int oldSelectIndex, int newSelectIndex)
|
private void SelectItemSlot(int oldSelectIndex, int newSelectIndex)
|
||||||
{
|
{
|
||||||
|
if (oldSelectIndex == newSelectIndex)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_itemSlotNodes == null)
|
if (_itemSlotNodes == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -286,10 +339,12 @@ public partial class HotBar : HBoxContainer, IItemContainer
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return itemSlotNode.SetItem(item);
|
return itemSlotNode.SetItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetSelectIndex()
|
||||||
|
{
|
||||||
|
return _selectIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemSlotNode? GetSelectItemSlotNode()
|
public ItemSlotNode? GetSelectItemSlotNode()
|
||||||
|
|
|
@ -26,6 +26,13 @@ public interface IItemContainer
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
bool AddItem(IItem item);
|
bool AddItem(IItem item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Gets the selected location</para>
|
||||||
|
/// <para>获取选中的位置</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
int GetSelectIndex();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Gets the currently selected node</para>
|
/// <para>Gets the currently selected node</para>
|
||||||
/// <para>获取当前选中的节点</para>
|
/// <para>获取当前选中的节点</para>
|
||||||
|
@ -33,6 +40,38 @@ public interface IItemContainer
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ItemSlotNode? GetSelectItemSlotNode();
|
ItemSlotNode? GetSelectItemSlotNode();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Removes an item from the inventory at the currently selected location</para>
|
||||||
|
/// <para>移除当前选中位置物品栏内的物品</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="number"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool RemoveItemFromItemSlotBySelectIndex(int number);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Gets the number of item slots</para>
|
||||||
|
/// <para>获取物品槽的数量</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
int GetItemSlotCount();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Gets the item slot for the specified location</para>
|
||||||
|
/// <para>获取指定位置的物品槽</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ItemSlotNode? GetItemSlotNode(int index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>Removes an item from the item slot in the specified location</para>
|
||||||
|
/// <para>在指定位置的物品槽内移除物品</para>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="itemSlotIndex"></param>
|
||||||
|
/// <param name="number"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool RemoveItemFromItemSlot(int itemSlotIndex, int number);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Based on the given item, match the item slots where it can be placed</para>
|
/// <para>Based on the given item, match the item slots where it can be placed</para>
|
||||||
/// <para>根据给定的物品,匹配可放置它的物品槽</para>
|
/// <para>根据给定的物品,匹配可放置它的物品槽</para>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user