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; } } }