怪物可以捡起武器打玩家了。
This commit is contained in:
parent
7812d9c570
commit
e4583aed3c
|
@ -84,3 +84,7 @@ log_no_weapon_detected,没有检测到武器。,No weapon detected.,武器が検
|
||||||
log_weapon_lost,武器丢失。,Weapon lost.,武器が失われました。
|
log_weapon_lost,武器丢失。,Weapon lost.,武器が失われました。
|
||||||
log_nearest_node_is_null,最近的节点为空。,The nearest node is null.,最も近いノードが空です。
|
log_nearest_node_is_null,最近的节点为空。,The nearest node is null.,最も近いノードが空です。
|
||||||
log_node_is_not_WeaponTemplate,节点不是WeaponTemplate。,The node is not a WeaponTemplate.,ノードはWeaponTemplateではありません。
|
log_node_is_not_WeaponTemplate,节点不是WeaponTemplate。,The node is not a WeaponTemplate.,ノードはWeaponTemplateではありません。
|
||||||
|
log_weapon_not_in_pickup_range,武器不在拾取范围内。,The weapon is not within the pickup range.,武器は拾い取り範囲内にありません。
|
||||||
|
log_weapon_picked_up,武器被拾取。,Weapon picked up.,武器が拾い取られました。
|
||||||
|
log_weapon_pickup_failed,武器拾取失败。,Weapon pickup failed.,武器の拾い取りに失敗しました。
|
||||||
|
log_enter_the_picking_range_body,进入拾取范围。,Enter the picking range.,拾い取り範囲に入ります。
|
|
|
@ -26,7 +26,6 @@ animations = [{
|
||||||
collision_layer = 4
|
collision_layer = 4
|
||||||
collision_mask = 34
|
collision_mask = 34
|
||||||
script = ExtResource("1_1dlls")
|
script = ExtResource("1_1dlls")
|
||||||
LootListId = null
|
|
||||||
metadata/CampId = "Default"
|
metadata/CampId = "Default"
|
||||||
metadata/MaxHp = 32
|
metadata/MaxHp = 32
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ radius = 20.0
|
||||||
height = 52.0
|
height = 52.0
|
||||||
|
|
||||||
[sub_resource type="CircleShape2D" id="CircleShape2D_vmqbt"]
|
[sub_resource type="CircleShape2D" id="CircleShape2D_vmqbt"]
|
||||||
radius = 34.5398
|
radius = 65.3758
|
||||||
|
|
||||||
[sub_resource type="SpriteFrames" id="SpriteFrames_qumby"]
|
[sub_resource type="SpriteFrames" id="SpriteFrames_qumby"]
|
||||||
animations = [{
|
animations = [{
|
||||||
|
|
|
@ -8,19 +8,6 @@ namespace ColdMint.scripts;
|
||||||
|
|
||||||
public static class Config
|
public static class Config
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// <para>ID of the behavior tree</para>
|
|
||||||
/// <para>行为树的ID</para>
|
|
||||||
/// </summary>
|
|
||||||
public static class BehaviorTreeId
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <para>巡逻</para>
|
|
||||||
/// <para>Patrol</para>
|
|
||||||
/// </summary>
|
|
||||||
public const string Patrol = "Patrol";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Loot table ID</para>
|
/// <para>Loot table ID</para>
|
||||||
/// <para>战利品表ID</para>
|
/// <para>战利品表ID</para>
|
||||||
|
@ -34,31 +21,6 @@ public static class Config
|
||||||
public const string Test = "test";
|
public const string Test = "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>BehaviorTreeResult</para>
|
|
||||||
/// <para>行为树的结果</para>
|
|
||||||
/// </summary>
|
|
||||||
public static class BehaviorTreeResult
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Running</para>
|
|
||||||
/// <para>运行中</para>
|
|
||||||
/// </summary>
|
|
||||||
public const int Running = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Success</para>
|
|
||||||
/// <para>成功</para>
|
|
||||||
/// </summary>
|
|
||||||
public const int Success = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <para>Failure</para>
|
|
||||||
/// <para>失败</para>
|
|
||||||
/// </summary>
|
|
||||||
public const int Failure = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Camp ID</para>
|
/// <para>Camp ID</para>
|
||||||
|
|
|
@ -16,472 +16,475 @@ namespace ColdMint.scripts.character;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class AiCharacter : CharacterTemplate
|
public sealed partial class AiCharacter : CharacterTemplate
|
||||||
{
|
{
|
||||||
//Used to detect rays on walls
|
//Used to detect rays on walls
|
||||||
//用于检测墙壁的射线
|
//用于检测墙壁的射线
|
||||||
private RayCast2D? _wallDetection;
|
private RayCast2D? _wallDetection;
|
||||||
|
|
||||||
public RayCast2D? WallDetection => _wallDetection;
|
public RayCast2D? WallDetection => _wallDetection;
|
||||||
private Vector2 _wallDetectionOrigin;
|
private Vector2 _wallDetectionOrigin;
|
||||||
private Area2D? _attackArea;
|
private Area2D? _attackArea;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Reconnaissance area</para>
|
/// <para>Reconnaissance area</para>
|
||||||
/// <para>侦察区域</para>
|
/// <para>侦察区域</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
///<para>Most of the time, when the enemy enters the reconnaissance area, the character will issue a "question mark" and try to move slowly towards the event point.</para>
|
///<para>Most of the time, when the enemy enters the reconnaissance area, the character will issue a "question mark" and try to move slowly towards the event point.</para>
|
||||||
///<para>大多数情况下,当敌人进入侦察区域后,角色会发出“疑问(问号)”,并尝试向事件点缓慢移动。</para>
|
///<para>大多数情况下,当敌人进入侦察区域后,角色会发出“疑问(问号)”,并尝试向事件点缓慢移动。</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private Area2D? _scoutArea;
|
private Area2D? _scoutArea;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>All enemies within striking distance</para>
|
/// <para>All enemies within striking distance</para>
|
||||||
/// <para>在攻击范围内的所有敌人</para>
|
/// <para>在攻击范围内的所有敌人</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<CharacterTemplate>? _enemyInTheAttackRange;
|
private List<CharacterTemplate>? _enemyInTheAttackRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Scout all enemies within range</para>
|
/// <para>Scout all enemies within range</para>
|
||||||
/// <para>在侦察范围内所有的敌人</para>
|
/// <para>在侦察范围内所有的敌人</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<CharacterTemplate>? _enemyInTheScoutRange;
|
private List<CharacterTemplate>? _enemyInTheScoutRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Every weapon in the recon area</para>
|
/// <para>Every weapon in the recon area</para>
|
||||||
/// <para>在侦察范围内所有的武器</para>
|
/// <para>在侦察范围内所有的武器</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<WeaponTemplate>? _weaponInTheScoutRange;
|
private List<WeaponTemplate>? _weaponInTheScoutRange;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Obstacle detection ray during attack</para>
|
/// <para>Obstacle detection ray during attack</para>
|
||||||
/// <para>攻击时的障碍物检测射线</para>
|
/// <para>攻击时的障碍物检测射线</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
///<para></para>
|
///<para></para>
|
||||||
///<para>检测与目标点直接是否间隔墙壁</para>
|
///<para>检测与目标点直接是否间隔墙壁</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private RayCast2D? _attackObstacleDetection;
|
private RayCast2D? _attackObstacleDetection;
|
||||||
|
|
||||||
|
|
||||||
private VisibleOnScreenEnabler2D? _screenEnabler2D;
|
private VisibleOnScreenEnabler2D? _screenEnabler2D;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Navigation agent</para>
|
/// <para>Navigation agent</para>
|
||||||
/// <para>导航代理</para>
|
/// <para>导航代理</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NavigationAgent2D? NavigationAgent2D { get; set; }
|
public NavigationAgent2D? NavigationAgent2D { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public IStateMachine? StateMachine { get; set; }
|
public IStateMachine? StateMachine { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public RayCast2D? AttackObstacleDetection => _attackObstacleDetection;
|
public RayCast2D? AttackObstacleDetection => _attackObstacleDetection;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Exclamation bubble Id</para>
|
/// <para>Exclamation bubble Id</para>
|
||||||
/// <para>感叹气泡Id</para>
|
/// <para>感叹气泡Id</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int plaintBubbleId = 0;
|
private const int plaintBubbleId = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Query bubble Id</para>
|
/// <para>Query bubble Id</para>
|
||||||
/// <para>疑问气泡Id</para>
|
/// <para>疑问气泡Id</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int queryBubbleId = 1;
|
private const int queryBubbleId = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>BubbleMarker</para>
|
/// <para>BubbleMarker</para>
|
||||||
/// <para>气泡标记</para>
|
/// <para>气泡标记</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
///<para>Subsequent production of dialogue bubbles can be put into the parent class for players to use.</para>
|
///<para>Subsequent production of dialogue bubbles can be put into the parent class for players to use.</para>
|
||||||
///<para>后续制作对话泡时可进其放到父类,供玩家使用。</para>
|
///<para>后续制作对话泡时可进其放到父类,供玩家使用。</para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private BubbleMarker? _bubbleMarker;
|
private BubbleMarker? _bubbleMarker;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>The initial weapons scene</para>
|
/// <para>The initial weapons scene</para>
|
||||||
/// <para>初始的武器场景</para>
|
/// <para>初始的武器场景</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Export] public string? InitWeaponRes;
|
[Export] public string? InitWeaponRes;
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
base._Ready();
|
base._Ready();
|
||||||
|
|
||||||
_enemyInTheAttackRange = new List<CharacterTemplate>();
|
_enemyInTheAttackRange = new List<CharacterTemplate>();
|
||||||
_enemyInTheScoutRange = new List<CharacterTemplate>();
|
_enemyInTheScoutRange = new List<CharacterTemplate>();
|
||||||
_weaponInTheScoutRange = new List<WeaponTemplate>();
|
_weaponInTheScoutRange = new List<WeaponTemplate>();
|
||||||
_screenEnabler2D = GetNode<VisibleOnScreenEnabler2D>("VisibleOnScreenEnabler2D");
|
_screenEnabler2D = GetNode<VisibleOnScreenEnabler2D>("VisibleOnScreenEnabler2D");
|
||||||
_screenEnabler2D.ScreenEntered += () =>
|
_screenEnabler2D.ScreenEntered += () =>
|
||||||
{
|
{
|
||||||
//When the character enters the screen.
|
//When the character enters the screen.
|
||||||
//当角色进入屏幕。
|
//当角色进入屏幕。
|
||||||
ProcessMode = ProcessModeEnum.Disabled;
|
ProcessMode = ProcessModeEnum.Disabled;
|
||||||
};
|
};
|
||||||
_screenEnabler2D.ScreenExited += () =>
|
_screenEnabler2D.ScreenExited += () =>
|
||||||
{
|
{
|
||||||
//When the character leaves the screen.
|
//When the character leaves the screen.
|
||||||
//当角色离开屏幕。
|
//当角色离开屏幕。
|
||||||
ProcessMode = ProcessModeEnum.Inherit;
|
ProcessMode = ProcessModeEnum.Inherit;
|
||||||
};
|
};
|
||||||
_bubbleMarker = GetNode<BubbleMarker>("BubbleMarker");
|
_bubbleMarker = GetNode<BubbleMarker>("BubbleMarker");
|
||||||
if (_bubbleMarker != null)
|
if (_bubbleMarker != null)
|
||||||
{
|
{
|
||||||
using var plaintScene = GD.Load<PackedScene>("res://prefab/ui/plaint.tscn");
|
using var plaintScene = GD.Load<PackedScene>("res://prefab/ui/plaint.tscn");
|
||||||
var plaint = NodeUtils.InstantiatePackedScene<Control>(plaintScene);
|
var plaint = NodeUtils.InstantiatePackedScene<Control>(plaintScene);
|
||||||
if (plaint != null)
|
if (plaint != null)
|
||||||
{
|
{
|
||||||
_bubbleMarker.AddBubble(plaintBubbleId, plaint);
|
_bubbleMarker.AddBubble(plaintBubbleId, plaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
using var queryScene = GD.Load<PackedScene>("res://prefab/ui/query.tscn");
|
using var queryScene = GD.Load<PackedScene>("res://prefab/ui/query.tscn");
|
||||||
var query = NodeUtils.InstantiatePackedScene<Control>(queryScene);
|
var query = NodeUtils.InstantiatePackedScene<Control>(queryScene);
|
||||||
if (query != null)
|
if (query != null)
|
||||||
{
|
{
|
||||||
_bubbleMarker.AddBubble(queryBubbleId, query);
|
_bubbleMarker.AddBubble(queryBubbleId, query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_wallDetection = GetNode<RayCast2D>("WallDetection");
|
_wallDetection = GetNode<RayCast2D>("WallDetection");
|
||||||
_attackArea = GetNode<Area2D>("AttackArea2D");
|
_attackArea = GetNode<Area2D>("AttackArea2D");
|
||||||
_scoutArea = GetNode<Area2D>("ScoutArea2D");
|
_scoutArea = GetNode<Area2D>("ScoutArea2D");
|
||||||
NavigationAgent2D = GetNode<NavigationAgent2D>("NavigationAgent2D");
|
NavigationAgent2D = GetNode<NavigationAgent2D>("NavigationAgent2D");
|
||||||
if (ItemMarker2D != null)
|
if (ItemMarker2D != null)
|
||||||
{
|
{
|
||||||
_attackObstacleDetection = ItemMarker2D.GetNode<RayCast2D>("AttackObstacleDetection");
|
_attackObstacleDetection = ItemMarker2D.GetNode<RayCast2D>("AttackObstacleDetection");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_attackArea != null)
|
if (_attackArea != null)
|
||||||
{
|
{
|
||||||
//If true, the zone will detect objects or areas entering and leaving the zone.
|
//If true, the zone will detect objects or areas entering and leaving the zone.
|
||||||
//如果为true,该区域将检测进出该区域的物体或区域。
|
//如果为true,该区域将检测进出该区域的物体或区域。
|
||||||
_attackArea.Monitoring = true;
|
_attackArea.Monitoring = true;
|
||||||
//Other areas can't detect our attack zone
|
//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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_scoutArea != null)
|
if (_scoutArea != null)
|
||||||
{
|
{
|
||||||
_scoutArea.Monitoring = true;
|
_scoutArea.Monitoring = true;
|
||||||
_scoutArea.Monitorable = false;
|
_scoutArea.Monitorable = false;
|
||||||
_scoutArea.BodyEntered += EnterTheScoutArea;
|
_scoutArea.BodyEntered += EnterTheScoutArea;
|
||||||
_scoutArea.BodyExited += ExitTheScoutArea;
|
_scoutArea.BodyExited += ExitTheScoutArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
_wallDetectionOrigin = _wallDetection.TargetPosition;
|
_wallDetectionOrigin = _wallDetection.TargetPosition;
|
||||||
StateMachine = new PatrolStateMachine();
|
StateMachine = new PatrolStateMachine();
|
||||||
StateMachine.Context = new StateContext
|
StateMachine.Context = new StateContext
|
||||||
{
|
{
|
||||||
CurrentState = State.Patrol,
|
CurrentState = State.Patrol,
|
||||||
Owner = this
|
Owner = this
|
||||||
};
|
};
|
||||||
if (StateMachine != null)
|
if (StateMachine != null)
|
||||||
{
|
{
|
||||||
StateMachine.Start();
|
StateMachine.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//You must create an item container for the character before you can pick up the item.
|
//You must create an item container for the character before you can pick up the item.
|
||||||
//必须为角色创建物品容器后才能拾起物品。
|
//必须为角色创建物品容器后才能拾起物品。
|
||||||
var universalItemContainer = new UniversalItemContainer();
|
var universalItemContainer = new UniversalItemContainer();
|
||||||
var itemSlotNode = universalItemContainer.AddItemSlot(this);
|
var itemSlotNode = universalItemContainer.AddItemSlot(this);
|
||||||
itemSlotNode?.Hide();
|
itemSlotNode?.Hide();
|
||||||
ProtectedItemContainer = universalItemContainer;
|
ProtectedItemContainer = universalItemContainer;
|
||||||
//Add initial weapon
|
//Add initial weapon
|
||||||
//添加初始武器
|
//添加初始武器
|
||||||
AddInitialWeapon(InitWeaponRes);
|
AddInitialWeapon(InitWeaponRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Adds an initial weapon to the character</para>
|
/// <para>Adds an initial weapon to the character</para>
|
||||||
/// <para>为角色添加初始的武器</para>
|
/// <para>为角色添加初始的武器</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void AddInitialWeapon(string? initWeaponRes)
|
private void AddInitialWeapon(string? initWeaponRes)
|
||||||
{
|
{
|
||||||
if (initWeaponRes == null)
|
if (initWeaponRes == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the resource path of the initial weapon and try to create the object of the initial weapon.
|
//Set the resource path of the initial weapon and try to create the object of the initial weapon.
|
||||||
//设置了初始武器的资源路径,尝试创建初始武器的对象。
|
//设置了初始武器的资源路径,尝试创建初始武器的对象。
|
||||||
var packedScene = GD.Load<PackedScene>(initWeaponRes);
|
var packedScene = GD.Load<PackedScene>(initWeaponRes);
|
||||||
var weaponTemplate = NodeUtils.InstantiatePackedScene<WeaponTemplate>(packedScene);
|
var weaponTemplate = NodeUtils.InstantiatePackedScene<WeaponTemplate>(packedScene);
|
||||||
if (weaponTemplate == null)
|
if (weaponTemplate == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeUtils.CallDeferredAddChild(this, weaponTemplate);
|
NodeUtils.CallDeferredAddChild(this, weaponTemplate);
|
||||||
PickItem(weaponTemplate);
|
PickItem(weaponTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Display exclamation marks</para>
|
/// <para>Display exclamation marks</para>
|
||||||
/// <para>显示感叹号</para>
|
/// <para>显示感叹号</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void DispladyPlaint()
|
public void DispladyPlaint()
|
||||||
{
|
{
|
||||||
_bubbleMarker?.ShowBubble(plaintBubbleId);
|
_bubbleMarker?.ShowBubble(plaintBubbleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HidePlaint()
|
public void HidePlaint()
|
||||||
{
|
{
|
||||||
_bubbleMarker?.HideBubble(plaintBubbleId);
|
_bubbleMarker?.HideBubble(plaintBubbleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Displady Query</para>
|
/// <para>Displady Query</para>
|
||||||
/// <para>显示疑问</para>
|
/// <para>显示疑问</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void DispladyQuery()
|
public void DispladyQuery()
|
||||||
{
|
{
|
||||||
_bubbleMarker?.ShowBubble(queryBubbleId);
|
_bubbleMarker?.ShowBubble(queryBubbleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HideQuery()
|
public void HideQuery()
|
||||||
{
|
{
|
||||||
_bubbleMarker?.HideBubble(queryBubbleId);
|
_bubbleMarker?.HideBubble(queryBubbleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Whether the enemy has been detected in the reconnaissance area</para>
|
/// <para>Whether the enemy has been detected in the reconnaissance area</para>
|
||||||
/// <para>侦察范围是否发现敌人</para>
|
/// <para>侦察范围是否发现敌人</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
///<para>Have you spotted the enemy?</para>
|
///<para>Have you spotted the enemy?</para>
|
||||||
///<para>是否发现敌人</para>
|
///<para>是否发现敌人</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public bool ScoutEnemyDetected()
|
public bool ScoutEnemyDetected()
|
||||||
{
|
{
|
||||||
if (_enemyInTheScoutRange == null)
|
if (_enemyInTheScoutRange == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _enemyInTheScoutRange.Count > 0;
|
return _enemyInTheScoutRange.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Any weapons found in the recon area</para>
|
/// <para>Any weapons found in the recon area</para>
|
||||||
/// <para>侦察范围内是否发现武器</para>
|
/// <para>侦察范围内是否发现武器</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool ScoutWeaponDetected()
|
public bool ScoutWeaponDetected()
|
||||||
{
|
{
|
||||||
if (_weaponInTheScoutRange == null)
|
if (_weaponInTheScoutRange == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _weaponInTheScoutRange.Count > 0;
|
return _weaponInTheScoutRange.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Get weapons in the recon area</para>
|
/// <para>Get weapons in the recon area</para>
|
||||||
/// <para>获取侦察范围内的武器</para>
|
/// <para>获取侦察范围内的武器</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public WeaponTemplate[]? GetWeaponInScoutArea()
|
public WeaponTemplate[]? GetWeaponInScoutArea()
|
||||||
{
|
{
|
||||||
if (_weaponInTheScoutRange == null)
|
if (_weaponInTheScoutRange == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _weaponInTheScoutRange.ToArray();
|
return _weaponInTheScoutRange.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Get the first enemy in range</para>
|
/// <para>Get the first enemy in range</para>
|
||||||
/// <para>获取第一个进入侦察范围的敌人</para>
|
/// <para>获取第一个进入侦察范围的敌人</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CharacterTemplate? GetFirstEnemyInScoutArea()
|
public CharacterTemplate? GetFirstEnemyInScoutArea()
|
||||||
{
|
{
|
||||||
if (_enemyInTheScoutRange == null || _enemyInTheScoutRange.Count == 0)
|
if (_enemyInTheScoutRange == null || _enemyInTheScoutRange.Count == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _enemyInTheScoutRange[0];
|
return _enemyInTheScoutRange[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Get the first enemy within striking range</para>
|
/// <para>Get the first enemy within striking range</para>
|
||||||
/// <para>获取第一个进入攻击范围的敌人</para>
|
/// <para>获取第一个进入攻击范围的敌人</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public CharacterTemplate? GetFirstEnemyInAttackArea()
|
public CharacterTemplate? GetFirstEnemyInAttackArea()
|
||||||
{
|
{
|
||||||
if (_enemyInTheAttackRange == null || _enemyInTheAttackRange.Count == 0)
|
if (_enemyInTheAttackRange == null || _enemyInTheAttackRange.Count == 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _enemyInTheAttackRange[0];
|
return _enemyInTheAttackRange[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
|
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
|
||||||
{
|
{
|
||||||
StateMachine?.Execute();
|
StateMachine?.Execute();
|
||||||
if (NavigationAgent2D != null && IsOnFloor())
|
if (NavigationAgent2D != null && IsOnFloor())
|
||||||
{
|
{
|
||||||
var nextPathPosition = NavigationAgent2D.GetNextPathPosition();
|
var nextPathPosition = NavigationAgent2D.GetNextPathPosition();
|
||||||
var direction = (nextPathPosition - GlobalPosition).Normalized();
|
var direction = (nextPathPosition - GlobalPosition).Normalized();
|
||||||
velocity = direction * Config.CellSize * Speed * ProtectedSpeedScale;
|
velocity = direction * Config.CellSize * Speed * ProtectedSpeedScale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>When the node enters the reconnaissance area</para>
|
/// <para>When the node enters the reconnaissance area</para>
|
||||||
/// <para>当节点进入侦察区域后</para>
|
/// <para>当节点进入侦察区域后</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
private void EnterTheScoutArea(Node node)
|
private void EnterTheScoutArea(Node node)
|
||||||
{
|
{
|
||||||
if (node is WeaponTemplate weaponTemplate)
|
if (node is WeaponTemplate weaponTemplate)
|
||||||
{
|
{
|
||||||
_weaponInTheScoutRange?.Add(weaponTemplate);
|
if (CanPickItem(weaponTemplate))
|
||||||
}
|
{
|
||||||
|
_weaponInTheScoutRange?.Add(weaponTemplate);
|
||||||
CanCauseHarmNode(node, (canCause, characterTemplate) =>
|
}
|
||||||
{
|
}
|
||||||
if (canCause && characterTemplate != null)
|
|
||||||
{
|
CanCauseHarmNode(node, (canCause, characterTemplate) =>
|
||||||
_enemyInTheScoutRange?.Add(characterTemplate);
|
{
|
||||||
}
|
if (canCause && characterTemplate != null)
|
||||||
});
|
{
|
||||||
}
|
_enemyInTheScoutRange?.Add(characterTemplate);
|
||||||
|
}
|
||||||
/// <summary>
|
});
|
||||||
/// <para>When the node exits the reconnaissance area</para>
|
}
|
||||||
/// <para>当节点退出侦察区域后</para>
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="node"></param>
|
/// <para>When the node exits the reconnaissance area</para>
|
||||||
private void ExitTheScoutArea(Node node)
|
/// <para>当节点退出侦察区域后</para>
|
||||||
{
|
/// </summary>
|
||||||
if (node == this)
|
/// <param name="node"></param>
|
||||||
{
|
private void ExitTheScoutArea(Node node)
|
||||||
return;
|
{
|
||||||
}
|
if (node == this)
|
||||||
|
{
|
||||||
if (node is WeaponTemplate weaponTemplate)
|
return;
|
||||||
{
|
}
|
||||||
_weaponInTheScoutRange?.Remove(weaponTemplate);
|
|
||||||
}
|
if (node is WeaponTemplate weaponTemplate)
|
||||||
|
{
|
||||||
if (node is CharacterTemplate characterTemplate)
|
_weaponInTheScoutRange?.Remove(weaponTemplate);
|
||||||
{
|
}
|
||||||
_enemyInTheScoutRange?.Remove(characterTemplate);
|
|
||||||
}
|
if (node is CharacterTemplate characterTemplate)
|
||||||
}
|
{
|
||||||
|
_enemyInTheScoutRange?.Remove(characterTemplate);
|
||||||
/// <summary>
|
}
|
||||||
/// <para>When a node enters the attack zone</para>
|
}
|
||||||
/// <para>当节点进入攻击区域后</para>
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="node"></param>
|
/// <para>When a node enters the attack zone</para>
|
||||||
private void EnterTheAttackArea(Node node)
|
/// <para>当节点进入攻击区域后</para>
|
||||||
{
|
/// </summary>
|
||||||
CanCauseHarmNode(node, (canCause, characterTemplate) =>
|
/// <param name="node"></param>
|
||||||
{
|
private void EnterTheAttackArea(Node node)
|
||||||
if (canCause && characterTemplate != null)
|
{
|
||||||
{
|
CanCauseHarmNode(node, (canCause, characterTemplate) =>
|
||||||
_enemyInTheAttackRange?.Add(characterTemplate);
|
{
|
||||||
}
|
if (canCause && characterTemplate != null)
|
||||||
});
|
{
|
||||||
}
|
_enemyInTheAttackRange?.Add(characterTemplate);
|
||||||
|
}
|
||||||
/// <summary>
|
});
|
||||||
/// <para>CanCauseHarmNode</para>
|
}
|
||||||
/// <para>是否可伤害某个节点</para>
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="node"></param>
|
/// <para>CanCauseHarmNode</para>
|
||||||
/// <param name="action"></param>
|
/// <para>是否可伤害某个节点</para>
|
||||||
private void CanCauseHarmNode(Node node, Action<bool, CharacterTemplate?> action)
|
/// </summary>
|
||||||
{
|
/// <param name="node"></param>
|
||||||
if (node == this)
|
/// <param name="action"></param>
|
||||||
{
|
private void CanCauseHarmNode(Node node, Action<bool, CharacterTemplate?> action)
|
||||||
//The target can't be yourself.
|
{
|
||||||
//攻击目标不能是自己。
|
if (node == this)
|
||||||
action.Invoke(false, null);
|
{
|
||||||
return;
|
//The target can't be yourself.
|
||||||
}
|
//攻击目标不能是自己。
|
||||||
|
action.Invoke(false, null);
|
||||||
if (node is not CharacterTemplate characterTemplate)
|
return;
|
||||||
{
|
}
|
||||||
action.Invoke(false, null);
|
|
||||||
return;
|
if (node is not CharacterTemplate characterTemplate)
|
||||||
}
|
{
|
||||||
|
action.Invoke(false, null);
|
||||||
//Determine if damage can be done between factions
|
return;
|
||||||
//判断阵营间是否可造成伤害
|
}
|
||||||
var camp = CampManager.GetCamp(CampId);
|
|
||||||
var enemyCamp = CampManager.GetCamp(characterTemplate.CampId);
|
//Determine if damage can be done between factions
|
||||||
if (enemyCamp != null && camp != null)
|
//判断阵营间是否可造成伤害
|
||||||
{
|
var camp = CampManager.GetCamp(CampId);
|
||||||
action.Invoke(CampManager.CanCauseHarm(camp, enemyCamp), characterTemplate);
|
var enemyCamp = CampManager.GetCamp(characterTemplate.CampId);
|
||||||
return;
|
if (enemyCamp != null && camp != null)
|
||||||
}
|
{
|
||||||
|
action.Invoke(CampManager.CanCauseHarm(camp, enemyCamp), characterTemplate);
|
||||||
action.Invoke(false, characterTemplate);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExitTheAttackArea(Node node)
|
action.Invoke(false, characterTemplate);
|
||||||
{
|
}
|
||||||
if (node == this)
|
|
||||||
{
|
private void ExitTheAttackArea(Node node)
|
||||||
return;
|
{
|
||||||
}
|
if (node == this)
|
||||||
|
{
|
||||||
if (node is CharacterTemplate characterTemplate)
|
return;
|
||||||
{
|
}
|
||||||
_enemyInTheAttackRange?.Remove(characterTemplate);
|
|
||||||
}
|
if (node is CharacterTemplate characterTemplate)
|
||||||
}
|
{
|
||||||
|
_enemyInTheAttackRange?.Remove(characterTemplate);
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// <para>Set target location</para>
|
|
||||||
/// <para>设置目标位置</para>
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="targetPosition"></param>
|
/// <para>Set target location</para>
|
||||||
public void SetTargetPosition(Vector2 targetPosition)
|
/// <para>设置目标位置</para>
|
||||||
{
|
/// </summary>
|
||||||
if (NavigationAgent2D == null)
|
/// <param name="targetPosition"></param>
|
||||||
{
|
public void SetTargetPosition(Vector2 targetPosition)
|
||||||
return;
|
{
|
||||||
}
|
if (NavigationAgent2D == null)
|
||||||
|
{
|
||||||
NavigationAgent2D.TargetPosition = targetPosition;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NavigationAgent2D.TargetPosition = targetPosition;
|
||||||
public override void _ExitTree()
|
}
|
||||||
{
|
|
||||||
base._ExitTree();
|
|
||||||
if (_attackArea != null)
|
public override void _ExitTree()
|
||||||
{
|
{
|
||||||
_attackArea.BodyEntered -= EnterTheAttackArea;
|
base._ExitTree();
|
||||||
_attackArea.BodyExited -= ExitTheAttackArea;
|
if (_attackArea != null)
|
||||||
}
|
{
|
||||||
|
_attackArea.BodyEntered -= EnterTheAttackArea;
|
||||||
if (_scoutArea != null)
|
_attackArea.BodyExited -= ExitTheAttackArea;
|
||||||
{
|
}
|
||||||
_scoutArea.BodyEntered -= EnterTheScoutArea;
|
|
||||||
_scoutArea.BodyExited -= ExitTheScoutArea;
|
if (_scoutArea != null)
|
||||||
}
|
{
|
||||||
|
_scoutArea.BodyEntered -= EnterTheScoutArea;
|
||||||
if (StateMachine != null)
|
_scoutArea.BodyExited -= ExitTheScoutArea;
|
||||||
{
|
}
|
||||||
StateMachine.Stop();
|
|
||||||
}
|
if (StateMachine != null)
|
||||||
}
|
{
|
||||||
|
StateMachine.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -240,14 +240,12 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
foreach (var pickingRangeBody in PickingRangeBodies)
|
foreach (var pickingRangeBody in PickingRangeBodies)
|
||||||
{
|
{
|
||||||
if (pickingRangeBody is not WeaponTemplate weaponTemplate) continue;
|
if (pickingRangeBody is not WeaponTemplate weaponTemplate) continue;
|
||||||
if (weaponTemplate.Owner != null)
|
if (weaponTemplate.Picked)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
weaponTemplates.Add(weaponTemplate);
|
weaponTemplates.Add(weaponTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return weaponTemplates.ToArray();
|
return weaponTemplates.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +306,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool CanPickItem(Node node)
|
protected bool CanPickItem(Node node)
|
||||||
{
|
{
|
||||||
if (_currentItem != null && node == _currentItem)
|
if (_currentItem != null && node == _currentItem)
|
||||||
{
|
{
|
||||||
|
@ -336,7 +334,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
///<para>Whether successfully picked up</para>
|
///<para>Whether successfully picked up</para>
|
||||||
///<para>是否成功拾起</para>
|
///<para>是否成功拾起</para>
|
||||||
/// </returns>
|
/// </returns>
|
||||||
protected bool PickItem(Node2D? pickAbleItemNode2D)
|
public bool PickItem(Node2D? pickAbleItemNode2D)
|
||||||
{
|
{
|
||||||
//Empty reference checking is implicitly performed here.
|
//Empty reference checking is implicitly performed here.
|
||||||
//此处隐式的执行了空引用检查。
|
//此处隐式的执行了空引用检查。
|
||||||
|
@ -585,12 +583,12 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
if (damageTemplate.Attacker is CharacterTemplate characterTemplate &&
|
if (damageTemplate.Attacker is CharacterTemplate characterTemplate &&
|
||||||
!string.IsNullOrEmpty(characterTemplate.CharacterName))
|
!string.IsNullOrEmpty(characterTemplate.CharacterName))
|
||||||
{
|
{
|
||||||
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName,
|
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat, CharacterName,
|
||||||
characterTemplate.CharacterName);
|
characterTemplate.CharacterName);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat,CharacterName,
|
LogCat.LogWithFormat("death_info", LogCat.LogLabel.Default, LogCat.UploadFormat, CharacterName,
|
||||||
damageTemplate.Attacker.Name);
|
damageTemplate.Attacker.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,6 +610,7 @@ public partial class CharacterTemplate : CharacterBody2D
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogCat.Log("enter_the_picking_range_body");
|
||||||
PickingRangeBodiesList?.Add(node);
|
PickingRangeBodiesList?.Add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,498 +17,498 @@ namespace ColdMint.scripts.character;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class Player : CharacterTemplate
|
public partial class Player : CharacterTemplate
|
||||||
{
|
{
|
||||||
private Control? _floatLabel;
|
private Control? _floatLabel;
|
||||||
|
|
||||||
//Empty object projectile
|
//Empty object projectile
|
||||||
//空的物品抛射线
|
//空的物品抛射线
|
||||||
private readonly Vector2[] _emptyVector2Array = [Vector2.Zero];
|
private readonly Vector2[] _emptyVector2Array = [Vector2.Zero];
|
||||||
|
|
||||||
//抛物线
|
//抛物线
|
||||||
private Line2D? _parabola;
|
private Line2D? _parabola;
|
||||||
|
|
||||||
//用于检测玩家是否站在平台上的射线
|
//用于检测玩家是否站在平台上的射线
|
||||||
private RayCast2D? _platformDetectionRayCast2D;
|
private RayCast2D? _platformDetectionRayCast2D;
|
||||||
|
|
||||||
|
|
||||||
private const float PromptTextDistance = 50;
|
private const float PromptTextDistance = 50;
|
||||||
|
|
||||||
|
|
||||||
//抛出物品的飞行速度
|
//抛出物品的飞行速度
|
||||||
private float _throwingVelocity = Config.CellSize * 13;
|
private float _throwingVelocity = Config.CellSize * 13;
|
||||||
|
|
||||||
//射线是否与平台碰撞
|
//射线是否与平台碰撞
|
||||||
private bool _collidingWithPlatform;
|
private bool _collidingWithPlatform;
|
||||||
|
|
||||||
//How long does it take for the character to recover from a collision with the platform after jumping off the platform (in seconds)
|
//How long does it take for the character to recover from a collision with the platform after jumping off the platform (in seconds)
|
||||||
//角色从平台上跳下后,多少时间后恢复与平台的碰撞(单位:秒)
|
//角色从平台上跳下后,多少时间后恢复与平台的碰撞(单位:秒)
|
||||||
private double _platformCollisionRecoveryTime = 0.2f;
|
private double _platformCollisionRecoveryTime = 0.2f;
|
||||||
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
base._Ready();
|
base._Ready();
|
||||||
CharacterName = TranslationServerUtils.Translate("default_player_name");
|
CharacterName = TranslationServerUtils.Translate("default_player_name");
|
||||||
LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,ReadOnlyCharacterName,
|
LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, LogCat.UploadFormat,ReadOnlyCharacterName,
|
||||||
GlobalPosition);
|
GlobalPosition);
|
||||||
var floatLabelPackedScene = GD.Load<PackedScene>("res://prefab/ui/FloatLabel.tscn");
|
var floatLabelPackedScene = GD.Load<PackedScene>("res://prefab/ui/FloatLabel.tscn");
|
||||||
//Initializes the float label.
|
//Initializes the float label.
|
||||||
//初始化悬浮标签。
|
//初始化悬浮标签。
|
||||||
_floatLabel = NodeUtils.InstantiatePackedScene<Control>(floatLabelPackedScene);
|
_floatLabel = NodeUtils.InstantiatePackedScene<Control>(floatLabelPackedScene);
|
||||||
if (_floatLabel == null)
|
if (_floatLabel == null)
|
||||||
{
|
{
|
||||||
throw new NullReferenceException(TranslationServer.Translate("float_label_instantiate_failed"));
|
throw new NullReferenceException(TranslationServer.Translate("float_label_instantiate_failed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
_floatLabel.Hide();
|
_floatLabel.Hide();
|
||||||
NodeUtils.CallDeferredAddChild(this, _floatLabel);
|
NodeUtils.CallDeferredAddChild(this, _floatLabel);
|
||||||
_parabola = GetNode<Line2D>("Parabola");
|
_parabola = GetNode<Line2D>("Parabola");
|
||||||
_platformDetectionRayCast2D = GetNode<RayCast2D>("PlatformDetectionRayCast");
|
_platformDetectionRayCast2D = GetNode<RayCast2D>("PlatformDetectionRayCast");
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
||||||
if (healthBarUi != null)
|
if (healthBarUi != null)
|
||||||
{
|
{
|
||||||
healthBarUi.MaxHp = MaxHp;
|
healthBarUi.MaxHp = MaxHp;
|
||||||
healthBarUi.CurrentHp = CurrentHp;
|
healthBarUi.CurrentHp = CurrentHp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WhenBindItemContainer(IItemContainer? itemContainer)
|
protected override void WhenBindItemContainer(IItemContainer? itemContainer)
|
||||||
{
|
{
|
||||||
if (itemContainer == null)
|
if (itemContainer == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Subscribe to events when the item container is bound to the player.
|
//Subscribe to events when the item container is bound to the player.
|
||||||
//在物品容器与玩家绑定时订阅事件。
|
//在物品容器与玩家绑定时订阅事件。
|
||||||
itemContainer.SelectedItemSlotChangeEvent += SelectedItemSlotChangeEvent;
|
itemContainer.SelectedItemSlotChangeEvent += SelectedItemSlotChangeEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _ExitTree()
|
public override void _ExitTree()
|
||||||
{
|
{
|
||||||
base._ExitTree();
|
base._ExitTree();
|
||||||
if (ProtectedItemContainer != null)
|
if (ProtectedItemContainer != null)
|
||||||
{
|
{
|
||||||
//Unsubscribe to events when this object is destroyed.
|
//Unsubscribe to events when this object is destroyed.
|
||||||
//此节点被销毁时,取消订阅事件。
|
//此节点被销毁时,取消订阅事件。
|
||||||
ProtectedItemContainer.SelectedItemSlotChangeEvent -= SelectedItemSlotChangeEvent;
|
ProtectedItemContainer.SelectedItemSlotChangeEvent -= SelectedItemSlotChangeEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectedItemSlotChangeEvent(SelectedItemSlotChangeEvent selectedItemSlotChangeEvent)
|
private void SelectedItemSlotChangeEvent(SelectedItemSlotChangeEvent selectedItemSlotChangeEvent)
|
||||||
{
|
{
|
||||||
var item = selectedItemSlotChangeEvent.NewItemSlotNode?.GetItem();
|
var item = selectedItemSlotChangeEvent.NewItemSlotNode?.GetItem();
|
||||||
GameSceneNodeHolder.HideBackpackUiContainerIfVisible();
|
GameSceneNodeHolder.HideBackpackUiContainerIfVisible();
|
||||||
if (item is Node2D node2D)
|
if (item is Node2D node2D)
|
||||||
{
|
{
|
||||||
CurrentItem = node2D;
|
CurrentItem = node2D;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentItem = null;
|
CurrentItem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Update operation prompt</para>
|
/// <para>Update operation prompt</para>
|
||||||
/// <para>更新操作提示</para>
|
/// <para>更新操作提示</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateOperationTip()
|
private void UpdateOperationTip()
|
||||||
{
|
{
|
||||||
var operationTipLabel = GameSceneNodeHolder.OperationTipLabel;
|
var operationTipLabel = GameSceneNodeHolder.OperationTipLabel;
|
||||||
if (operationTipLabel == null)
|
if (operationTipLabel == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var operationTipBuilder = new StringBuilder();
|
var operationTipBuilder = new StringBuilder();
|
||||||
|
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_left")[0].AsText()));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_left")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_move_left"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_move_left"));
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_right")[0].AsText()));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_right")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_move_right"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_move_right"));
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_up")[0].AsText()));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_up")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_jump"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_jump"));
|
||||||
if (_collidingWithPlatform)
|
if (_collidingWithPlatform)
|
||||||
{
|
{
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(
|
operationTipBuilder.Append(
|
||||||
TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_down")[0].AsText()));
|
TranslationServerUtils.Translate(InputMap.ActionGetEvents("ui_down")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_jump_down"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_jump_down"));
|
||||||
}
|
}
|
||||||
|
|
||||||
var nearestItem = FindTheNearestItem();
|
var nearestItem = FindTheNearestItem();
|
||||||
if (nearestItem != null)
|
if (nearestItem != null)
|
||||||
{
|
{
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(
|
operationTipBuilder.Append(
|
||||||
TranslationServerUtils.Translate(InputMap.ActionGetEvents("pick_up")[0].AsText()));
|
TranslationServerUtils.Translate(InputMap.ActionGetEvents("pick_up")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_pick_up"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_pick_up"));
|
||||||
if (nearestItem is IItem item)
|
if (nearestItem is IItem item)
|
||||||
{
|
{
|
||||||
operationTipBuilder.Append(item.Name);
|
operationTipBuilder.Append(item.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
operationTipLabel.Text = operationTipBuilder.ToString();
|
operationTipLabel.Text = operationTipBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CurrentItem != null)
|
if (CurrentItem != null)
|
||||||
{
|
{
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("throw")[0].AsText()));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(InputMap.ActionGetEvents("throw")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_throw"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_throw"));
|
||||||
if (CurrentItem is IItem item)
|
if (CurrentItem is IItem item)
|
||||||
{
|
{
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(item.Name));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(item.Name));
|
||||||
operationTipBuilder.Append(' ');
|
operationTipBuilder.Append(' ');
|
||||||
operationTipBuilder.Append("[color=");
|
operationTipBuilder.Append("[color=");
|
||||||
operationTipBuilder.Append(Config.OperationTipActionColor);
|
operationTipBuilder.Append(Config.OperationTipActionColor);
|
||||||
operationTipBuilder.Append(']');
|
operationTipBuilder.Append(']');
|
||||||
operationTipBuilder.Append(
|
operationTipBuilder.Append(
|
||||||
TranslationServerUtils.Translate(InputMap.ActionGetEvents("use_item")[0].AsText()));
|
TranslationServerUtils.Translate(InputMap.ActionGetEvents("use_item")[0].AsText()));
|
||||||
operationTipBuilder.Append("[/color]");
|
operationTipBuilder.Append("[/color]");
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate("action_use_item"));
|
operationTipBuilder.Append(TranslationServerUtils.Translate("action_use_item"));
|
||||||
operationTipBuilder.Append(TranslationServerUtils.Translate(item.Name));
|
operationTipBuilder.Append(TranslationServerUtils.Translate(item.Name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operationTipLabel.Text = operationTipBuilder.ToString();
|
operationTipLabel.Text = operationTipBuilder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
|
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
|
||||||
{
|
{
|
||||||
//When the collision state between the platform detection ray and the platform changes
|
//When the collision state between the platform detection ray and the platform changes
|
||||||
//在平台检测射线与平台碰撞状态改变时
|
//在平台检测射线与平台碰撞状态改变时
|
||||||
if (_platformDetectionRayCast2D != null && _platformDetectionRayCast2D.IsColliding() != _collidingWithPlatform)
|
if (_platformDetectionRayCast2D != null && _platformDetectionRayCast2D.IsColliding() != _collidingWithPlatform)
|
||||||
{
|
{
|
||||||
//When the state changes, update the action hint
|
//When the state changes, update the action hint
|
||||||
//当状态改变时,更新操作提示
|
//当状态改变时,更新操作提示
|
||||||
_collidingWithPlatform = _platformDetectionRayCast2D.IsColliding();
|
_collidingWithPlatform = _platformDetectionRayCast2D.IsColliding();
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
//If the character is on the ground, give an upward velocity when the jump button is pressed
|
//If the character is on the ground, give an upward velocity when the jump button is pressed
|
||||||
//如果角色正在地面上,按下跳跃键时,给予一个向上的速度
|
//如果角色正在地面上,按下跳跃键时,给予一个向上的速度
|
||||||
if (Input.IsActionJustPressed("ui_up") && IsOnFloor())
|
if (Input.IsActionJustPressed("ui_up") && IsOnFloor())
|
||||||
velocity.Y = JumpVelocity;
|
velocity.Y = JumpVelocity;
|
||||||
|
|
||||||
//Moving left and right
|
//Moving left and right
|
||||||
//左右移动
|
//左右移动
|
||||||
var axis = Input.GetAxis("ui_left", "ui_right");
|
var axis = Input.GetAxis("ui_left", "ui_right");
|
||||||
velocity.X = axis * Speed * Config.CellSize * ProtectedSpeedScale;
|
velocity.X = axis * Speed * Config.CellSize * ProtectedSpeedScale;
|
||||||
|
|
||||||
//Use items
|
//Use items
|
||||||
//使用物品
|
//使用物品
|
||||||
if (Input.IsActionPressed("use_item"))
|
if (Input.IsActionPressed("use_item"))
|
||||||
{
|
{
|
||||||
UseItem(GetGlobalMousePosition());
|
UseItem(GetGlobalMousePosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pick up an item
|
//Pick up an item
|
||||||
//捡起物品
|
//捡起物品
|
||||||
if (Input.IsActionJustPressed("pick_up"))
|
if (Input.IsActionJustPressed("pick_up"))
|
||||||
{
|
{
|
||||||
var pickAbleItem = FindTheNearestItem();
|
var pickAbleItem = FindTheNearestItem();
|
||||||
var success = PickItem(pickAbleItem);
|
var success = PickItem(pickAbleItem);
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
if (pickAbleItem != null)
|
if (pickAbleItem != null)
|
||||||
{
|
{
|
||||||
PickingRangeBodiesList?.Remove(pickAbleItem);
|
PickingRangeBodiesList?.Remove(pickAbleItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
RecycleFloatLabel();
|
RecycleFloatLabel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Input.IsActionJustPressed("ui_down"))
|
if (Input.IsActionJustPressed("ui_down"))
|
||||||
{
|
{
|
||||||
if (_collidingWithPlatform)
|
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
|
//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 键时,我们取消角色与平台的碰撞
|
//当角色站在平台上按下 ui_down 键时,我们取消角色与平台的碰撞
|
||||||
var timer = new Timer();
|
var timer = new Timer();
|
||||||
AddChild(timer);
|
AddChild(timer);
|
||||||
timer.WaitTime = _platformCollisionRecoveryTime;
|
timer.WaitTime = _platformCollisionRecoveryTime;
|
||||||
timer.OneShot = true;
|
timer.OneShot = true;
|
||||||
timer.Start();
|
timer.Start();
|
||||||
timer.Timeout += () =>
|
timer.Timeout += () =>
|
||||||
{
|
{
|
||||||
SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
||||||
timer.QueueFree();
|
timer.QueueFree();
|
||||||
};
|
};
|
||||||
SetCollisionMaskValue(Config.LayerNumber.Platform, false);
|
SetCollisionMaskValue(Config.LayerNumber.Platform, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Display a parabola when an item is thrown
|
//Display a parabola when an item is thrown
|
||||||
//抛出物品时,显示抛物线
|
//抛出物品时,显示抛物线
|
||||||
if (Input.IsActionPressed("throw"))
|
if (Input.IsActionPressed("throw"))
|
||||||
{
|
{
|
||||||
if (_parabola == null)
|
if (_parabola == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ItemMarker2D == null)
|
if (ItemMarker2D == null)
|
||||||
{
|
{
|
||||||
//Cannot get the marked location of the item, then do not draw a line
|
//Cannot get the marked location of the item, then do not draw a line
|
||||||
//无法获取物品的标记位置,那么不绘制线
|
//无法获取物品的标记位置,那么不绘制线
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_parabola.Points = CurrentItem == null
|
_parabola.Points = CurrentItem == null
|
||||||
? _emptyVector2Array
|
? _emptyVector2Array
|
||||||
: ParabolicUtils.ComputeParabolic(ItemMarker2D.Position, GetThrowVelocity(), Gravity, 0.1f);
|
: ParabolicUtils.ComputeParabolic(ItemMarker2D.Position, GetThrowVelocity(), Gravity, 0.1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//When you raise your hand, throw the object
|
//When you raise your hand, throw the object
|
||||||
//抬起手时,抛出物品
|
//抬起手时,抛出物品
|
||||||
if (Input.IsActionJustReleased("throw"))
|
if (Input.IsActionJustReleased("throw"))
|
||||||
{
|
{
|
||||||
if (ItemContainer == null)
|
if (ItemContainer == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parabola != null)
|
if (_parabola != null)
|
||||||
{
|
{
|
||||||
_parabola.Points = [Vector2.Zero];
|
_parabola.Points = [Vector2.Zero];
|
||||||
}
|
}
|
||||||
|
|
||||||
ThrowItem(ItemContainer.GetSelectIndex(), 1, GetThrowVelocity());
|
ThrowItem(ItemContainer.GetSelectIndex(), 1, GetThrowVelocity());
|
||||||
GameSceneNodeHolder.HideBackpackUiContainerIfVisible();
|
GameSceneNodeHolder.HideBackpackUiContainerIfVisible();
|
||||||
CurrentItem = null;
|
CurrentItem = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WhenUpdateCurrentItem(Node2D? currentItem)
|
protected override void WhenUpdateCurrentItem(Node2D? currentItem)
|
||||||
{
|
{
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>当玩家手动抛出物品时,施加到物品上的速度值</para>
|
/// <para>当玩家手动抛出物品时,施加到物品上的速度值</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <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
|
||||||
//我们拿到鼠标的位置,将其归一化处理,然后乘以玩家可扔出的距离
|
//我们拿到鼠标的位置,将其归一化处理,然后乘以玩家可扔出的距离
|
||||||
return GetLocalMousePosition().Normalized() * _throwingVelocity;
|
return GetLocalMousePosition().Normalized() * _throwingVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process(double delta)
|
public override void _Process(double delta)
|
||||||
{
|
{
|
||||||
if (!Visible)
|
if (!Visible)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AimTheCurrentItemAtAPoint(GetGlobalMousePosition());
|
AimTheCurrentItemAtAPoint(GetGlobalMousePosition());
|
||||||
var itemMarker2DPosition = Vector2.Zero;
|
var itemMarker2DPosition = Vector2.Zero;
|
||||||
if (ItemMarker2D != null)
|
if (ItemMarker2D != null)
|
||||||
{
|
{
|
||||||
itemMarker2DPosition = ItemMarker2D.Position;
|
itemMarker2DPosition = ItemMarker2D.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
var axis = Input.GetAxis("ui_left", "ui_right");
|
var axis = Input.GetAxis("ui_left", "ui_right");
|
||||||
switch (axis)
|
switch (axis)
|
||||||
{
|
{
|
||||||
case -1:
|
case -1:
|
||||||
//Minus 1, we move to the left
|
//Minus 1, we move to the left
|
||||||
//-1,向左移动
|
//-1,向左移动
|
||||||
FacingLeft = true;
|
FacingLeft = true;
|
||||||
if (ItemMarker2D != null)
|
if (ItemMarker2D != null)
|
||||||
{
|
{
|
||||||
itemMarker2DPosition.X = -ReadOnlyItemMarkerOriginalX;
|
itemMarker2DPosition.X = -ReadOnlyItemMarkerOriginalX;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flip();
|
Flip();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//1, move to the right
|
//1, move to the right
|
||||||
//1,向右移动
|
//1,向右移动
|
||||||
FacingLeft = false;
|
FacingLeft = false;
|
||||||
if (ItemMarker2D != null)
|
if (ItemMarker2D != null)
|
||||||
{
|
{
|
||||||
itemMarker2DPosition.X = ReadOnlyItemMarkerOriginalX;
|
itemMarker2DPosition.X = ReadOnlyItemMarkerOriginalX;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flip();
|
Flip();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ItemMarker2D != null)
|
if (ItemMarker2D != null)
|
||||||
{
|
{
|
||||||
ItemMarker2D.Position = itemMarker2DPosition;
|
ItemMarker2D.Position = itemMarker2DPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Flip()
|
protected override void Flip()
|
||||||
{
|
{
|
||||||
base.Flip();
|
base.Flip();
|
||||||
//If there is a weapon, flip it too
|
//If there is a weapon, flip it too
|
||||||
//如果有武器的话,也要翻转
|
//如果有武器的话,也要翻转
|
||||||
if (CurrentItem is PickAbleTemplate pickAbleTemplate)
|
if (CurrentItem is PickAbleTemplate pickAbleTemplate)
|
||||||
{
|
{
|
||||||
pickAbleTemplate.Flip(FacingLeft);
|
pickAbleTemplate.Flip(FacingLeft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Revive(int newHp)
|
public override void Revive(int newHp)
|
||||||
{
|
{
|
||||||
base.Revive(newHp);
|
base.Revive(newHp);
|
||||||
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
||||||
if (healthBarUi != null)
|
if (healthBarUi != null)
|
||||||
{
|
{
|
||||||
//The purpose of setting Hp to the current Hp is to cause the life bar to refresh.
|
//The purpose of setting Hp to the current Hp is to cause the life bar to refresh.
|
||||||
//将Hp设置为当前Hp的目的是,使生命条刷新。
|
//将Hp设置为当前Hp的目的是,使生命条刷新。
|
||||||
healthBarUi.CurrentHp = CurrentHp;
|
healthBarUi.CurrentHp = CurrentHp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>When the player dies</para>
|
/// <para>When the player dies</para>
|
||||||
/// <para>当玩家死亡的时候</para>
|
/// <para>当玩家死亡的时候</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="damageTemplate"></param>
|
/// <param name="damageTemplate"></param>
|
||||||
protected override async Task OnDie(DamageTemplate damageTemplate)
|
protected override async Task OnDie(DamageTemplate damageTemplate)
|
||||||
{
|
{
|
||||||
Hide();
|
Hide();
|
||||||
ProcessMode = ProcessModeEnum.Disabled;
|
ProcessMode = ProcessModeEnum.Disabled;
|
||||||
if (EventManager.GameOverEvent == null)
|
if (EventManager.GameOverEvent == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameOverEvent = new GameOverEvent();
|
var gameOverEvent = new GameOverEvent();
|
||||||
if (damageTemplate.Attacker != null)
|
if (damageTemplate.Attacker != null)
|
||||||
{
|
{
|
||||||
gameOverEvent.DeathInfo = await DeathInfoGenerator.GenerateDeathInfo(this, damageTemplate.Attacker);
|
gameOverEvent.DeathInfo = await DeathInfoGenerator.GenerateDeathInfo(this, damageTemplate.Attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventManager.GameOverEvent.Invoke(gameOverEvent);
|
EventManager.GameOverEvent.Invoke(gameOverEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void EnterThePickingRangeBody(Node node)
|
protected override void EnterThePickingRangeBody(Node node)
|
||||||
{
|
{
|
||||||
base.EnterThePickingRangeBody(node);
|
base.EnterThePickingRangeBody(node);
|
||||||
if (CurrentItem == node)
|
if (CurrentItem == node)
|
||||||
{
|
{
|
||||||
//If the node entering the pick range is the node held by the player, then return.
|
//If the node entering the pick range is the node held by the player, then return.
|
||||||
//如果说进入拾捡范围的节点是玩家所持有的节点,那么返回。
|
//如果说进入拾捡范围的节点是玩家所持有的节点,那么返回。
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node is not Node2D node2D)
|
if (node is not Node2D node2D)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_floatLabel != null)
|
if (_floatLabel != null)
|
||||||
{
|
{
|
||||||
if (node is not PickAbleTemplate pickAbleTemplate)
|
if (node is not PickAbleTemplate pickAbleTemplate)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pickAbleTemplate.Picked)
|
if (pickAbleTemplate.Picked)
|
||||||
{
|
{
|
||||||
//If the pickables are picked up, the label is not displayed.
|
//If the pickables are picked up, the label is not displayed.
|
||||||
//如果可拾捡物被捡起了,那么不显示标签。
|
//如果可拾捡物被捡起了,那么不显示标签。
|
||||||
LogCat.LogWarning("pickable_picked_up");
|
LogCat.LogWarning("pickable_picked_up");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeUtils.CallDeferredReparent(node, _floatLabel);
|
NodeUtils.CallDeferredReparent(node, _floatLabel);
|
||||||
var rotationDegreesNode2D = node2D.RotationDegrees;
|
var rotationDegreesNode2D = node2D.RotationDegrees;
|
||||||
var rotationDegreesNode2DAbs = Math.Abs(rotationDegreesNode2D);
|
var rotationDegreesNode2DAbs = Math.Abs(rotationDegreesNode2D);
|
||||||
_floatLabel.GlobalPosition = node2D.GlobalPosition;
|
_floatLabel.GlobalPosition = node2D.GlobalPosition;
|
||||||
_floatLabel.Position = rotationDegreesNode2DAbs > 90
|
_floatLabel.Position = rotationDegreesNode2DAbs > 90
|
||||||
? new Vector2(0, PromptTextDistance)
|
? new Vector2(0, PromptTextDistance)
|
||||||
: new Vector2(0, -PromptTextDistance);
|
: new Vector2(0, -PromptTextDistance);
|
||||||
_floatLabel.RotationDegrees = 0 - rotationDegreesNode2D;
|
_floatLabel.RotationDegrees = 0 - rotationDegreesNode2D;
|
||||||
var label = _floatLabel.GetNode<Label>("Label");
|
var label = _floatLabel.GetNode<Label>("Label");
|
||||||
|
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
if (pickAbleTemplate.Owner is CharacterTemplate characterTemplate)
|
if (pickAbleTemplate.Owner is CharacterTemplate characterTemplate)
|
||||||
{
|
{
|
||||||
stringBuilder.Append(characterTemplate.ReadOnlyCharacterName);
|
stringBuilder.Append(characterTemplate.ReadOnlyCharacterName);
|
||||||
stringBuilder.Append(TranslationServerUtils.Translate("de"));
|
stringBuilder.Append(TranslationServerUtils.Translate("de"));
|
||||||
}
|
}
|
||||||
|
|
||||||
stringBuilder.Append(TranslationServerUtils.Translate(pickAbleTemplate.Name));
|
stringBuilder.Append(TranslationServerUtils.Translate(pickAbleTemplate.Name));
|
||||||
label.Text = stringBuilder.ToString();
|
label.Text = stringBuilder.ToString();
|
||||||
_floatLabel.Show();
|
_floatLabel.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ExitThePickingRangeBody(Node node)
|
protected override void ExitThePickingRangeBody(Node node)
|
||||||
{
|
{
|
||||||
base.ExitThePickingRangeBody(node);
|
base.ExitThePickingRangeBody(node);
|
||||||
if (node is not Node2D)
|
if (node is not Node2D)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecycleFloatLabel();
|
RecycleFloatLabel();
|
||||||
UpdateOperationTip();
|
UpdateOperationTip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Recycle Float Label</para>
|
/// <para>Recycle Float Label</para>
|
||||||
/// <para>回收悬浮标签</para>
|
/// <para>回收悬浮标签</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void RecycleFloatLabel()
|
private void RecycleFloatLabel()
|
||||||
{
|
{
|
||||||
if (_floatLabel == null)
|
if (_floatLabel == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_floatLabel.Hide();
|
_floatLabel.Hide();
|
||||||
NodeUtils.CallDeferredReparent(this, _floatLabel);
|
NodeUtils.CallDeferredReparent(this, _floatLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHit(DamageTemplate damageTemplate)
|
protected override void OnHit(DamageTemplate damageTemplate)
|
||||||
{
|
{
|
||||||
base.OnHit(damageTemplate);
|
base.OnHit(damageTemplate);
|
||||||
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
var healthBarUi = GameSceneNodeHolder.HealthBarUi;
|
||||||
if (healthBarUi != null)
|
if (healthBarUi != null)
|
||||||
{
|
{
|
||||||
healthBarUi.CurrentHp = CurrentHp;
|
healthBarUi.CurrentHp = CurrentHp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,100 +20,100 @@ namespace ColdMint.scripts.loader.uiLoader;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class SplashScreenLoader : UiLoaderTemplate
|
public partial class SplashScreenLoader : UiLoaderTemplate
|
||||||
{
|
{
|
||||||
private Label? _loadingLabel;
|
private Label? _loadingLabel;
|
||||||
private PackedScene? _mainMenuScene;
|
private PackedScene? _mainMenuScene;
|
||||||
private AnimationPlayer? _animationPlayer;
|
private AnimationPlayer? _animationPlayer;
|
||||||
private string _startup = "startup";
|
private string _startup = "startup";
|
||||||
private Label? _nameLabel;
|
private Label? _nameLabel;
|
||||||
|
|
||||||
public override void InitializeData()
|
public override void InitializeData()
|
||||||
{
|
{
|
||||||
_mainMenuScene = GD.Load<PackedScene>("res://scenes/mainMenu.tscn");
|
_mainMenuScene = GD.Load<PackedScene>("res://scenes/mainMenu.tscn");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void InitializeUi()
|
public override void InitializeUi()
|
||||||
{
|
{
|
||||||
_nameLabel = GetNode<Label>("NameLabel");
|
_nameLabel = GetNode<Label>("NameLabel");
|
||||||
_loadingLabel = GetNode<Label>("loadingStateLabel");
|
_loadingLabel = GetNode<Label>("loadingStateLabel");
|
||||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||||
//Disable animation in Debug mode.
|
//Disable animation in Debug mode.
|
||||||
//在Debug模式禁用动画。
|
//在Debug模式禁用动画。
|
||||||
if (Config.IsDebug())
|
if (Config.IsDebug())
|
||||||
{
|
{
|
||||||
_loadingLabel.Modulate = Colors.White;
|
_loadingLabel.Modulate = Colors.White;
|
||||||
_nameLabel.Modulate = Colors.White;
|
_nameLabel.Modulate = Colors.White;
|
||||||
AnimationFinished(_startup);
|
AnimationFinished(_startup);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_animationPlayer.Play(_startup);
|
_animationPlayer.Play(_startup);
|
||||||
_animationPlayer.AnimationFinished += AnimationFinished;
|
_animationPlayer.AnimationFinished += AnimationFinished;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void AnimationFinished(StringName name)
|
private async void AnimationFinished(StringName name)
|
||||||
{
|
{
|
||||||
await LoadingGlobalData();
|
await LoadingGlobalData();
|
||||||
if (_mainMenuScene == null)
|
if (_mainMenuScene == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetTree().ChangeSceneToPacked(_mainMenuScene);
|
GetTree().ChangeSceneToPacked(_mainMenuScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <para>Load the game's global data</para>
|
/// <para>Load the game's global data</para>
|
||||||
/// <para>加载游戏的全局数据</para>
|
/// <para>加载游戏的全局数据</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task LoadingGlobalData()
|
private async Task LoadingGlobalData()
|
||||||
{
|
{
|
||||||
//Loading App configuration
|
//Loading App configuration
|
||||||
//加载App配置
|
//加载App配置
|
||||||
var appConfigData = AppConfig.LoadFromFile();
|
var appConfigData = AppConfig.LoadFromFile();
|
||||||
if (appConfigData != null)
|
if (appConfigData != null)
|
||||||
{
|
{
|
||||||
AppConfig.ApplyAppConfig(appConfigData);
|
AppConfig.ApplyAppConfig(appConfigData);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set the minimum log level to Info in debug mode.(Print all logs)
|
//Set the minimum log level to Info in debug mode.(Print all logs)
|
||||||
//在调试模式下将最小日志等级设置为Info。(打印全部日志)
|
//在调试模式下将最小日志等级设置为Info。(打印全部日志)
|
||||||
//Disable all logs in the release version.
|
//Disable all logs in the release version.
|
||||||
//在发行版禁用所有日志。
|
//在发行版禁用所有日志。
|
||||||
LogCat.MinLogLevel = Config.IsDebug() ? LogCat.InfoLogLevel : LogCat.DisableAllLogLevel;
|
LogCat.MinLogLevel = Config.IsDebug() ? LogCat.InfoLogLevel : LogCat.DisableAllLogLevel;
|
||||||
ContributorDataManager.RegisterAllContributorData();
|
ContributorDataManager.RegisterAllContributorData();
|
||||||
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
|
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
|
||||||
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
|
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
|
||||||
MapGenerator.RegisterRoomInjectionProcessor(new TimeIntervalRoomInjectorProcessor());
|
MapGenerator.RegisterRoomInjectionProcessor(new TimeIntervalRoomInjectorProcessor());
|
||||||
//Register the corresponding encoding provider to solve the problem of garbled Chinese path of the compressed package
|
//Register the corresponding encoding provider to solve the problem of garbled Chinese path of the compressed package
|
||||||
//注册对应的编码提供程序,解决压缩包中文路径乱码问题
|
//注册对应的编码提供程序,解决压缩包中文路径乱码问题
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
//创建游戏数据文件夹
|
//创建游戏数据文件夹
|
||||||
var dataPath = Config.GetGameDataDirectory();
|
var dataPath = Config.GetGameDataDirectory();
|
||||||
if (!Directory.Exists(dataPath))
|
if (!Directory.Exists(dataPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(dataPath);
|
Directory.CreateDirectory(dataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Registered camp
|
//Registered camp
|
||||||
//注册阵营
|
//注册阵营
|
||||||
var defaultCamp = new Camp(Config.CampId.Default)
|
var defaultCamp = new Camp(Config.CampId.Default)
|
||||||
{
|
{
|
||||||
FriendInjury = true
|
FriendInjury = true
|
||||||
};
|
};
|
||||||
CampManager.SetDefaultCamp(defaultCamp);
|
CampManager.SetDefaultCamp(defaultCamp);
|
||||||
var mazoku = new Camp(Config.CampId.Mazoku);
|
var mazoku = new Camp(Config.CampId.Mazoku);
|
||||||
CampManager.AddCamp(mazoku);
|
CampManager.AddCamp(mazoku);
|
||||||
var aborigines = new Camp(Config.CampId.Aborigines);
|
var aborigines = new Camp(Config.CampId.Aborigines);
|
||||||
CampManager.AddCamp(aborigines);
|
CampManager.AddCamp(aborigines);
|
||||||
//Register ItemTypes from file
|
//Register ItemTypes from file
|
||||||
//从文件注册物品类型
|
//从文件注册物品类型
|
||||||
ItemTypeRegister.RegisterFromFile();
|
ItemTypeRegister.RegisterFromFile();
|
||||||
//Hardcoded ItemTypes Register
|
//Hardcoded ItemTypes Register
|
||||||
//硬编码注册物品类型
|
//硬编码注册物品类型
|
||||||
ItemTypeRegister.StaticRegister();
|
ItemTypeRegister.StaticRegister();
|
||||||
//静态注册掉落表
|
//静态注册掉落表
|
||||||
LootRegister.StaticRegister();
|
LootRegister.StaticRegister();
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(500));
|
await Task.Delay(TimeSpan.FromMilliseconds(500));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,7 +27,51 @@ public class LookForWeaponProcessor : StateProcessorTemplate
|
||||||
{
|
{
|
||||||
//If the nearest weapon is found, move the character to the weapon.
|
//If the nearest weapon is found, move the character to the weapon.
|
||||||
//如果有最近的武器被找到了,那么将角色移动到武器旁边。
|
//如果有最近的武器被找到了,那么将角色移动到武器旁边。
|
||||||
aiCharacter.SetTargetPosition(TargetWeapon.GlobalPosition);
|
var weaponTemplates = aiCharacter.GetCanPickedWeapon();
|
||||||
|
//Weapons are not in the range of the pickup.
|
||||||
|
//武器没在拾捡范围内。
|
||||||
|
if (weaponTemplates.Length == 0)
|
||||||
|
{
|
||||||
|
LogCat.Log("weapon_not_in_pickup_range", LogCat.LogLabel.LookForWeaponProcessor);
|
||||||
|
aiCharacter.SetTargetPosition(TargetWeapon.GlobalPosition);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var haveWeapon = false;
|
||||||
|
foreach (var weaponTemplate in weaponTemplates)
|
||||||
|
{
|
||||||
|
if (weaponTemplate == TargetWeapon)
|
||||||
|
{
|
||||||
|
haveWeapon = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (haveWeapon)
|
||||||
|
{
|
||||||
|
var pickResult = aiCharacter.PickItem(TargetWeapon);
|
||||||
|
if (pickResult)
|
||||||
|
{
|
||||||
|
context.CurrentState = context.PreviousState;
|
||||||
|
//Successfully picked up the weapon.
|
||||||
|
//成功拾起武器。
|
||||||
|
LogCat.Log("weapon_picked_up", LogCat.LogLabel.LookForWeaponProcessor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TargetWeapon = null;
|
||||||
|
//Weapon failed to pick up.
|
||||||
|
//武器捡起时失败。
|
||||||
|
LogCat.Log("weapon_pickup_failed", LogCat.LogLabel.LookForWeaponProcessor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//No weapons are included in the pickup area.
|
||||||
|
//拾捡范围内不包含武器。
|
||||||
|
LogCat.Log("weapon_not_in_pickup_range", LogCat.LogLabel.LookForWeaponProcessor);
|
||||||
|
aiCharacter.SetTargetPosition(TargetWeapon.GlobalPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user