using Godot;
namespace Milimoe.GodotGame
{
public partial class CharacterBody : CharacterBody2D
{
///
/// 移动速度 (像素/秒)
///
[Export]
public float Speed = 100f;
///
/// 加速度 (像素/秒^2) - 控制从静止加速到最大速度的快慢
/// 值越大,加速越快,惯性越小。
///
[Export]
public float Acceleration = 500f;
///
/// 减速度 (像素/秒^2) - 控制从运动减速到静止的快慢
/// 值越大,减速越快,惯性越小。
/// 通常减速度可以比加速度大,让停止更迅速。
///
[Export]
public float Deceleration = 800f;
///
/// 静止图片
///
[Export]
public Texture2D IdleTexture;
///
/// 行走图片
///
[Export]
public Texture2D WalkTexture;
///
/// 精灵节点
///
[Export]
public AnimatedSprite2D AnimatedSprite2D;
///
/// 战斗开始信号
///
///
///
[Signal]
public delegate void BattleStartedEventHandler(CharacterBody2D player, CharacterBody2D enemy);
///
/// _PhysicsProcess 是 Godot 进行物理计算和运动更新的函数
///
///
public override void _PhysicsProcess(double delta)
{
if (GameConstant.Pause)
{
return;
}
// 获取输入向量
// 获取水平输入轴的值 (-1 到 1)
float inputX = Input.GetAxis("move_left", "move_right");
// 获取垂直输入轴的值 (-1 到 1)
float inputY = Input.GetAxis("move_up", "move_down");
// 创建一个表示输入方向的向量
Vector2 inputVector = new(inputX, inputY);
// 目标速度
Vector2 targetVelocity;
// 当前帧应该使用的加速度/减速度
float currentAcceleration;
if (inputVector.LengthSquared() > 0)
{
// 有输入时,目标速度是输入方向乘以最大速度
targetVelocity = inputVector.Normalized() * Speed;
// 使用加速度
currentAcceleration = Acceleration;
}
else
{
// 没有输入时,目标速度是零
targetVelocity = Vector2.Zero;
// 使用减速度
currentAcceleration = Deceleration;
}
// 使用 Mathf.MoveToward 平滑地改变当前速度到目标速度
Velocity = Velocity.MoveToward(targetVelocity, currentAcceleration * (float)delta);
// 处理与墙壁、障碍物等的碰撞,阻止角色穿过它们
MoveAndSlide();
UpdateAnimation();
for (int i = 0; i < GetSlideCollisionCount(); i++)
{
KinematicCollision2D collision = GetSlideCollision(i);
GodotObject collider = collision.GetCollider();
if (collider is EnemyBody enemy && enemy.Enabled && !enemy.Dead && enemy.CollisionLayer == 4)
{
GameConstant.Pause = true;
EmitSignal(SignalName.BattleStarted, this, enemy);
break;
}
}
}
///
/// 根据速度更新贴图
///
private void UpdateAnimation()
{
if (AnimatedSprite2D == null) return;
// 获取当前实时速度的长度
float currentSpeed = Velocity.Length();
if (currentSpeed > 0.1f) // 如果正在移动
{
// 播放行走动画
if (AnimatedSprite2D.Animation != "walk")
{
AnimatedSprite2D.Play("walk");
}
// --- 核心算法:动画速度匹配 ---
// 计算比例:当前速度越快,动画播得越快
// 1.2f 是一个“手感系数”,如果觉得脚还是打滑,就调大这个值
float speedFactor = currentSpeed / Speed;
AnimatedSprite2D.SpeedScale = speedFactor * 5f;
// 处理左右翻转
if (Velocity.X != 0)
{
AnimatedSprite2D.FlipH = Velocity.X < 0;
}
}
else // 停止移动
{
AnimatedSprite2D.Play("idle");
AnimatedSprite2D.SpeedScale = 1.0f; // 回归正常倍率
}
}
// 用于存储返回时的位置
private Vector2 _savedOverworldPosition;
///
/// 记录当前位置并传送到指定的 Tile 坐标
///
/// 目标 TileMapLayer
/// 目标格子坐标 (例如 new Vector2I(88, 4))
public void TeleportToTile(TileMapLayer targetLayer, Vector2I tileCoords)
{
// 1. 记录当前的绝对坐标 (用于战斗结束后传回来)
_savedOverworldPosition = this.GlobalPosition;
GD.Print($"已记录当前位置: {_savedOverworldPosition}");
// 2. 将 Tile 坐标转换为该图层的本地像素坐标
// MapToLocal 返回的是该格子中心的相对坐标
Vector2 localPos = targetLayer.MapToLocal(tileCoords);
// 3. 将本地坐标转换为全局绝对坐标
Vector2 globalPos = targetLayer.ToGlobal(localPos);
// 4. 设置角色的全局位置(实现瞬移)
this.GlobalPosition = globalPos;
GD.Print($"角色已传送到 Tile {tileCoords},绝对坐标为: {globalPos}");
}
///
/// 返回之前记录的位置
///
public void ReturnToSavedPosition()
{
this.GlobalPosition = _savedOverworldPosition;
}
}
}