2024-06-04 14:23:06 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
using ColdMint.scripts.damage;
|
2024-06-04 14:23:06 +00:00
|
|
|
|
using ColdMint.scripts.deathInfo;
|
2024-06-25 14:11:19 +00:00
|
|
|
|
using ColdMint.scripts.debug;
|
2024-06-19 16:02:32 +00:00
|
|
|
|
using ColdMint.scripts.inventory;
|
2024-06-03 14:58:59 +00:00
|
|
|
|
using ColdMint.scripts.map.events;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
using ColdMint.scripts.utils;
|
2024-06-16 07:28:16 +00:00
|
|
|
|
using ColdMint.scripts.pickable;
|
2024-05-07 11:36:06 +00:00
|
|
|
|
using Godot;
|
|
|
|
|
|
|
|
|
|
namespace ColdMint.scripts.character;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>玩家角色</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
public partial class Player : CharacterTemplate
|
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Empty object projectile
|
|
|
|
|
//空的物品抛射线
|
2024-06-16 07:28:16 +00:00
|
|
|
|
private readonly Vector2[] _emptyVector2Array = [Vector2.Zero];
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
//抛物线
|
2024-05-07 11:36:06 +00:00
|
|
|
|
private Line2D? _parabola;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
//用于检测玩家是否站在平台上的射线
|
2024-10-10 08:29:54 +00:00
|
|
|
|
[Export] private RayCast2D[]? _platformDetectionRayCast2DList;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
//抛出物品的飞行速度
|
2024-05-07 11:36:06 +00:00
|
|
|
|
private float _throwingVelocity = Config.CellSize * 13;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
//射线是否与平台碰撞
|
2024-05-07 11:36:06 +00:00
|
|
|
|
private bool _collidingWithPlatform;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
2024-10-10 06:11:34 +00:00
|
|
|
|
private bool _canUseItem;
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//How long does it take for the character to recover from a collision with the platform after jumping off the platform (in seconds)
|
|
|
|
|
//角色从平台上跳下后,多少时间后恢复与平台的碰撞(单位:秒)
|
2024-05-07 11:36:06 +00:00
|
|
|
|
private double _platformCollisionRecoveryTime = 0.2f;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public override void _Ready()
|
|
|
|
|
{
|
|
|
|
|
base._Ready();
|
2024-10-10 08:29:54 +00:00
|
|
|
|
if (_platformDetectionRayCast2DList == null || _platformDetectionRayCast2DList.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
LogCat.LogError("no_platform_detection_raycast_found");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-05-24 14:58:52 +00:00
|
|
|
|
CharacterName = TranslationServerUtils.Translate("default_player_name");
|
2024-10-11 09:59:47 +00:00
|
|
|
|
LogCat.LogWithFormat("player_spawn_debug", LogCat.LogLabel.Default, ReadOnlyCharacterName,
|
2024-07-02 15:16:04 +00:00
|
|
|
|
GlobalPosition);
|
2024-05-07 11:36:06 +00:00
|
|
|
|
_parabola = GetNode<Line2D>("Parabola");
|
2024-09-01 15:24:35 +00:00
|
|
|
|
var healthBarUi = GameSceneDepend.HealthBarUi;
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (healthBarUi != null)
|
|
|
|
|
{
|
|
|
|
|
healthBarUi.MaxHp = MaxHp;
|
|
|
|
|
healthBarUi.CurrentHp = CurrentHp;
|
|
|
|
|
}
|
2024-08-24 14:49:59 +00:00
|
|
|
|
|
|
|
|
|
//Mount the camera.
|
|
|
|
|
//挂载相机。
|
2024-10-09 02:49:10 +00:00
|
|
|
|
var mainCameraPackedScene = ResourceLoader.Load<PackedScene>("res://prefab/MainCamera.tscn");
|
2024-08-24 14:49:59 +00:00
|
|
|
|
var camera2D = NodeUtils.InstantiatePackedScene<Camera2D>(mainCameraPackedScene);
|
|
|
|
|
if (camera2D != null)
|
|
|
|
|
{
|
|
|
|
|
NodeUtils.CallDeferredAddChild(this, camera2D);
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 16:02:32 +00:00
|
|
|
|
protected override void WhenBindItemContainer(IItemContainer? itemContainer)
|
|
|
|
|
{
|
|
|
|
|
if (itemContainer == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Subscribe to events when the item container is bound to the player.
|
|
|
|
|
//在物品容器与玩家绑定时订阅事件。
|
2024-09-22 08:51:42 +00:00
|
|
|
|
itemContainer.SelectedItemChangeEvent += SelectedItemChangeEvent;
|
2024-06-19 16:02:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void _ExitTree()
|
|
|
|
|
{
|
|
|
|
|
base._ExitTree();
|
|
|
|
|
if (ProtectedItemContainer != null)
|
|
|
|
|
{
|
|
|
|
|
//Unsubscribe to events when this object is destroyed.
|
|
|
|
|
//此节点被销毁时,取消订阅事件。
|
2024-09-22 08:51:42 +00:00
|
|
|
|
ProtectedItemContainer.SelectedItemChangeEvent -= SelectedItemChangeEvent;
|
2024-06-19 16:02:32 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-22 08:51:42 +00:00
|
|
|
|
private void SelectedItemChangeEvent(SelectedItemChangeEvent selectedItemChangeEvent)
|
2024-06-19 16:02:32 +00:00
|
|
|
|
{
|
2024-09-22 08:51:42 +00:00
|
|
|
|
var item = selectedItemChangeEvent.NewItem;
|
2024-06-19 16:02:32 +00:00
|
|
|
|
if (item is Node2D node2D)
|
|
|
|
|
{
|
|
|
|
|
CurrentItem = node2D;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CurrentItem = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-20 14:17:07 +00:00
|
|
|
|
public override void _MouseEnter()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void _MouseExit()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-10 08:29:54 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>UpdateCollidingWithPlatform</para>
|
|
|
|
|
/// <para>更新与平台发生碰撞的状态</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateCollidingWithPlatform()
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//When the collision state between the platform detection ray and the platform changes
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//在平台检测射线与平台碰撞状态改变时
|
2024-10-10 08:29:54 +00:00
|
|
|
|
if (_platformDetectionRayCast2DList is not { Length: > 0 }) return;
|
|
|
|
|
foreach (var rayCast2D in _platformDetectionRayCast2DList)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-10-10 08:29:54 +00:00
|
|
|
|
if (!rayCast2D.IsColliding()) continue;
|
|
|
|
|
_collidingWithPlatform = true;
|
|
|
|
|
return;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
2024-10-10 08:29:54 +00:00
|
|
|
|
_collidingWithPlatform = false;
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
2024-10-10 08:29:54 +00:00
|
|
|
|
protected override void HookPhysicsProcess(ref Vector2 velocity, double delta)
|
|
|
|
|
{
|
|
|
|
|
UpdateCollidingWithPlatform();
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//If the character is on the ground, give an upward velocity when the jump button is pressed
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//如果角色正在地面上,按下跳跃键时,给予一个向上的速度
|
|
|
|
|
if (Input.IsActionJustPressed("ui_up") && IsOnFloor())
|
|
|
|
|
velocity.Y = JumpVelocity;
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Moving left and right
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//左右移动
|
|
|
|
|
var axis = Input.GetAxis("ui_left", "ui_right");
|
2024-07-07 15:10:25 +00:00
|
|
|
|
velocity.X = axis * Speed * Config.CellSize * ProtectedSpeedScale;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
|
2024-10-10 06:11:34 +00:00
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("use_item"))
|
|
|
|
|
{
|
|
|
|
|
_canUseItem = !GameSceneDepend.IsMouseOverFurnitureGui && !GameSceneDepend.IsMouseOverItemSlotNode;
|
|
|
|
|
}
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Use items
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//使用物品
|
|
|
|
|
if (Input.IsActionPressed("use_item"))
|
|
|
|
|
{
|
2024-10-10 06:11:34 +00:00
|
|
|
|
if (_canUseItem)
|
|
|
|
|
{
|
|
|
|
|
UseItem(GetGlobalMousePosition());
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Pick up an item
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//捡起物品
|
|
|
|
|
if (Input.IsActionJustPressed("pick_up"))
|
|
|
|
|
{
|
2024-05-09 13:07:14 +00:00
|
|
|
|
var pickAbleItem = FindTheNearestItem();
|
|
|
|
|
var success = PickItem(pickAbleItem);
|
2024-04-29 15:25:03 +00:00
|
|
|
|
if (success)
|
|
|
|
|
{
|
2024-05-09 13:07:14 +00:00
|
|
|
|
if (pickAbleItem != null)
|
|
|
|
|
{
|
|
|
|
|
PickingRangeBodiesList?.Remove(pickAbleItem);
|
|
|
|
|
}
|
2024-04-29 15:25:03 +00:00
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Input.IsActionJustPressed("ui_down"))
|
|
|
|
|
{
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (_collidingWithPlatform)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//When the character stands on the platform and presses the ui_down key, we cancel the collision between the character and the platform
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//当角色站在平台上按下 ui_down 键时,我们取消角色与平台的碰撞
|
|
|
|
|
var timer = new Timer();
|
|
|
|
|
AddChild(timer);
|
2024-05-07 11:36:06 +00:00
|
|
|
|
timer.WaitTime = _platformCollisionRecoveryTime;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
timer.OneShot = true;
|
|
|
|
|
timer.Start();
|
|
|
|
|
timer.Timeout += () =>
|
|
|
|
|
{
|
|
|
|
|
SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
|
|
|
|
timer.QueueFree();
|
|
|
|
|
};
|
|
|
|
|
SetCollisionMaskValue(Config.LayerNumber.Platform, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Display a parabola when an item is thrown
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//抛出物品时,显示抛物线
|
|
|
|
|
if (Input.IsActionPressed("throw"))
|
|
|
|
|
{
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (_parabola == null)
|
2024-05-06 10:59:39 +00:00
|
|
|
|
{
|
2024-05-07 11:36:06 +00:00
|
|
|
|
return;
|
2024-05-06 10:59:39 +00:00
|
|
|
|
}
|
2024-05-07 11:36:06 +00:00
|
|
|
|
|
|
|
|
|
if (ItemMarker2D == null)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-05-07 11:36:06 +00:00
|
|
|
|
//Cannot get the marked location of the item, then do not draw a line
|
|
|
|
|
//无法获取物品的标记位置,那么不绘制线
|
|
|
|
|
return;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
2024-05-07 11:36:06 +00:00
|
|
|
|
|
|
|
|
|
_parabola.Points = CurrentItem == null
|
2024-06-19 16:02:32 +00:00
|
|
|
|
? _emptyVector2Array
|
|
|
|
|
: ParabolicUtils.ComputeParabolic(ItemMarker2D.Position, GetThrowVelocity(), Gravity, 0.1f);
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-06 10:59:39 +00:00
|
|
|
|
|
|
|
|
|
//When you raise your hand, throw the object
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//抬起手时,抛出物品
|
|
|
|
|
if (Input.IsActionJustReleased("throw"))
|
|
|
|
|
{
|
2024-06-06 14:43:07 +00:00
|
|
|
|
if (ItemContainer == null)
|
2024-05-08 10:22:04 +00:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-05-09 13:07:14 +00:00
|
|
|
|
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (_parabola != null)
|
|
|
|
|
{
|
2024-07-05 14:56:24 +00:00
|
|
|
|
_parabola.Points = [Vector2.Zero];
|
2024-05-07 11:36:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
ThrowItem(ItemContainer.GetSelectIndex(), 1, GetThrowVelocity());
|
2024-05-07 11:36:06 +00:00
|
|
|
|
CurrentItem = null;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-10 06:11:34 +00:00
|
|
|
|
|
2024-06-06 14:43:07 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>当玩家手动抛出物品时,施加到物品上的速度值</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2024-04-28 13:55:19 +00:00
|
|
|
|
private Vector2 GetThrowVelocity()
|
|
|
|
|
{
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//We take the mouse position, normalize it, and then multiply it by the distance the player can throw
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//我们拿到鼠标的位置,将其归一化处理,然后乘以玩家可扔出的距离
|
2024-05-07 11:36:06 +00:00
|
|
|
|
return GetLocalMousePosition().Normalized() * _throwingVelocity;
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void _Process(double delta)
|
|
|
|
|
{
|
2024-06-04 14:23:06 +00:00
|
|
|
|
if (!Visible)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
AimTheCurrentItemAtAPoint(GetGlobalMousePosition());
|
2024-05-07 11:36:06 +00:00
|
|
|
|
var itemMarker2DPosition = Vector2.Zero;
|
|
|
|
|
if (ItemMarker2D != null)
|
|
|
|
|
{
|
|
|
|
|
itemMarker2DPosition = ItemMarker2D.Position;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
var axis = Input.GetAxis("ui_left", "ui_right");
|
|
|
|
|
switch (axis)
|
|
|
|
|
{
|
|
|
|
|
case -1:
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//Minus 1, we move to the left
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//-1,向左移动
|
|
|
|
|
FacingLeft = true;
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (ItemMarker2D != null)
|
|
|
|
|
{
|
|
|
|
|
itemMarker2DPosition.X = -ReadOnlyItemMarkerOriginalX;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
Flip();
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//1, move to the right
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//1,向右移动
|
|
|
|
|
FacingLeft = false;
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (ItemMarker2D != null)
|
|
|
|
|
{
|
|
|
|
|
itemMarker2DPosition.X = ReadOnlyItemMarkerOriginalX;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
Flip();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-07 11:36:06 +00:00
|
|
|
|
if (ItemMarker2D != null)
|
|
|
|
|
{
|
|
|
|
|
ItemMarker2D.Position = itemMarker2DPosition;
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Flip()
|
|
|
|
|
{
|
|
|
|
|
base.Flip();
|
2024-05-06 10:59:39 +00:00
|
|
|
|
//If there is a weapon, flip it too
|
2024-04-28 13:55:19 +00:00
|
|
|
|
//如果有武器的话,也要翻转
|
2024-06-16 07:28:16 +00:00
|
|
|
|
if (CurrentItem is PickAbleTemplate pickAbleTemplate)
|
2024-04-28 13:55:19 +00:00
|
|
|
|
{
|
2024-06-16 07:28:16 +00:00
|
|
|
|
pickAbleTemplate.Flip(FacingLeft);
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 14:15:23 +00:00
|
|
|
|
public override void Revive(int newHp)
|
|
|
|
|
{
|
|
|
|
|
base.Revive(newHp);
|
2024-09-01 15:24:35 +00:00
|
|
|
|
var healthBarUi = GameSceneDepend.HealthBarUi;
|
2024-06-06 14:43:07 +00:00
|
|
|
|
if (healthBarUi != null)
|
2024-06-05 14:15:23 +00:00
|
|
|
|
{
|
|
|
|
|
//The purpose of setting Hp to the current Hp is to cause the life bar to refresh.
|
|
|
|
|
//将Hp设置为当前Hp的目的是,使生命条刷新。
|
|
|
|
|
healthBarUi.CurrentHp = CurrentHp;
|
|
|
|
|
}
|
2024-08-25 10:49:48 +00:00
|
|
|
|
ProcessMode = ProcessModeEnum.Inherit;
|
|
|
|
|
Show();
|
2024-06-05 14:15:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-08 15:59:24 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// <para>When the player dies</para>
|
|
|
|
|
/// <para>当玩家死亡的时候</para>
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="damageTemplate"></param>
|
2024-06-04 14:23:06 +00:00
|
|
|
|
protected override async Task OnDie(DamageTemplate damageTemplate)
|
2024-06-03 14:58:59 +00:00
|
|
|
|
{
|
2024-06-08 15:59:24 +00:00
|
|
|
|
Hide();
|
|
|
|
|
ProcessMode = ProcessModeEnum.Disabled;
|
2024-09-06 15:36:21 +00:00
|
|
|
|
if (EventBus.GameOverEvent == null)
|
2024-06-03 14:58:59 +00:00
|
|
|
|
{
|
2024-06-04 14:23:06 +00:00
|
|
|
|
return;
|
2024-06-03 14:58:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 14:23:06 +00:00
|
|
|
|
var gameOverEvent = new GameOverEvent();
|
|
|
|
|
if (damageTemplate.Attacker != null)
|
|
|
|
|
{
|
|
|
|
|
gameOverEvent.DeathInfo = await DeathInfoGenerator.GenerateDeathInfo(this, damageTemplate.Attacker);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-06 15:36:21 +00:00
|
|
|
|
EventBus.GameOverEvent.Invoke(gameOverEvent);
|
2024-06-03 14:58:59 +00:00
|
|
|
|
}
|
2024-10-10 06:11:34 +00:00
|
|
|
|
|
2024-07-11 15:06:47 +00:00
|
|
|
|
|
2024-04-28 13:55:19 +00:00
|
|
|
|
protected override void OnHit(DamageTemplate damageTemplate)
|
|
|
|
|
{
|
|
|
|
|
base.OnHit(damageTemplate);
|
2024-09-01 15:24:35 +00:00
|
|
|
|
var healthBarUi = GameSceneDepend.HealthBarUi;
|
2024-05-08 10:22:04 +00:00
|
|
|
|
if (healthBarUi != null)
|
|
|
|
|
{
|
|
|
|
|
healthBarUi.CurrentHp = CurrentHp;
|
|
|
|
|
}
|
2024-04-28 13:55:19 +00:00
|
|
|
|
}
|
|
|
|
|
}
|