diff --git a/Assets/Prefabs/主角/召唤师主角.prefab b/Assets/Prefabs/主角/召唤师主角.prefab index b39dcc9..e9f70dc 100644 --- a/Assets/Prefabs/主角/召唤师主角.prefab +++ b/Assets/Prefabs/主角/召唤师主角.prefab @@ -183,7 +183,7 @@ MonoBehaviour: summonSearchCount: 5 summonDepthSearchStep: 1 summonDepthSearchCount: 2 - summonAnimationTimeout: 2.5 + summonAnimationTimeout: 4 projectileSpeed: 12 projectileLifetime: 5 --- !u!114 &6516315820976732023 diff --git a/Assets/Scenes/Chapter1/SummonerDuelTest.unity b/Assets/Scenes/Chapter1/SummonerDuelTest.unity index b54356b..7be0d99 100644 Binary files a/Assets/Scenes/Chapter1/SummonerDuelTest.unity and b/Assets/Scenes/Chapter1/SummonerDuelTest.unity differ diff --git a/Assets/Script/MainCharacterCombat.cs b/Assets/Script/MainCharacterCombat.cs index 628d681..70d24e9 100644 --- a/Assets/Script/MainCharacterCombat.cs +++ b/Assets/Script/MainCharacterCombat.cs @@ -230,6 +230,13 @@ public class MainCharacterCombat : MonoBehaviour return; } + // 立即停止移动 + SummonerClickMovement clickMovement = GetComponent(); + if (clickMovement != null) + { + clickMovement.ClearTarget(); + } + pendingSummonPrefab = prefab; pendingSummonCharacterData = characterData; pendingSummonPlayerData = playerData; @@ -239,7 +246,7 @@ public class MainCharacterCombat : MonoBehaviour animator.speed = 1f; animator.SetInteger("speed", 0); animator.ResetTrigger("skill"); - animator.SetTrigger("skill"); + animator.Play("skill", 0, 0f); } public void OnSkillHit1() @@ -256,16 +263,9 @@ public class MainCharacterCombat : MonoBehaviour Vector3 spawnPosition; if (!TryFindSummonPosition(direction, out spawnPosition)) { - Debug.LogWarning("主角附近没有可用的召唤位置,本次召唤取消,退还能量"); - - // 退还能量豆 - if (ManaSystem.Instance != null && pendingSummonCharacterData != null) - { - ManaSystem.Instance.AddMana(pendingSummonCharacterData.manaCost); - } - - FinishSummon(); - return; + // 找不到合适位置时,直接在召唤师前方1.5米处生成 + spawnPosition = transform.position + direction * 1.5f; + spawnPosition.y = transform.position.y; } GameObject summoned = Instantiate( @@ -335,7 +335,9 @@ public class MainCharacterCombat : MonoBehaviour private bool TryUseSummonCandidate(Vector3 candidate, out Vector3 position) { candidate.y = transform.position.y; - if (IsInsideMovementBounds(candidate) && IsSummonPositionFree(candidate)) + + // 只检查碰撞,不检查边界(召唤师移动范围已由 SummonerClickMovement 限制) + if (IsSummonPositionFree(candidate)) { position = candidate; return true; @@ -380,28 +382,39 @@ public class MainCharacterCombat : MonoBehaviour private bool IsInsideMovementBounds(Vector3 position) { - return movement == null || movement.IsWithinLeash(position); + // 召唤师对决模式:检查新的 SummonerClickMovement 半场限制 + SummonerClickMovement summonerMovement = GetComponent(); + if (summonerMovement != null) + { + // 使用召唤师的半场范围 + return position.x >= summonerMovement.minX && position.x <= summonerMovement.maxX + && position.z >= summonerMovement.minZ && position.z <= summonerMovement.maxZ; + } + + // 旧版建筑对攻模式:使用栓绳限制 + if (movement != null) + { + return movement.IsWithinLeash(position); + } + + // 无移动组件时不限制 + return true; } private void CheckSummonFinished() { - if (summonElapsed >= summonAnimationTimeout) + AnimatorStateInfo state = animator.GetCurrentAnimatorStateInfo(0); + if (state.IsName("skill") && state.normalizedTime >= 1f) { - Debug.LogWarning("主角召唤动画超时,已解除召唤状态"); FinishSummon(); return; } - AnimatorClipInfo[] clips = animator.GetCurrentAnimatorClipInfo(0); - foreach (AnimatorClipInfo clipInfo in clips) + // skill 状态意外被其他动画打断时,才使用超时兜底,避免永久锁定召唤。 + if (summonElapsed >= summonAnimationTimeout) { - string clipName = clipInfo.clip.name.ToLowerInvariant(); - if ((clipName.Contains("skill") || clipName.Contains("召唤")) - && animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1f) - { - FinishSummon(); - return; - } + Debug.LogWarning("主角召唤动画超时,已解除召唤状态"); + FinishSummon(); } } @@ -413,6 +426,7 @@ public class MainCharacterCombat : MonoBehaviour summonElapsed = 0f; animator.speed = 1f; animator.SetInteger("speed", 0); + animator.Play("idle", 0, 0f); } private void CheckAttackFinished() diff --git a/CODELY.md b/CODELY.md index cbec3bc..1496976 100644 --- a/CODELY.md +++ b/CODELY.md @@ -21,6 +21,8 @@ - [2026-09-09 20:37:24] 用户希望提前实现数据架构而非临时方案,即使当前阶段功能简单。**Why:** 用户有 10 年后端开发经验,理解数据分层的重要性,希望逐步完善而非推倒重来。**How to apply:** 对于有明确扩展方向的功能(升级、存档、联网),优先设计可扩展架构并临时写死数据,而非等需求明确后再重构。 - [2026-09-10 18:38:45] 正交俯视视角(38-43°)下,垂直墙面几乎看不见(只能看到墙顶),因为墙面平行于视线方向被自身遮挡。适合的装饰物:高耸物体(旗帜、石柱)、有明显剪影的物体(木箱、碎石堆)、对比色强的物体;不适合:低矮平面物(矮墙、栅栏)、细长水平物(绳索)。**Why:** 这是正交俯视视角的固有盲区,无法通过调整角度完全解决(角度太平会牺牲战场全局视野)。**How to apply:** 场景装饰设计时优先使用垂直高度≥2米的物体,避免依赖水平或低矮结构。 - [2026-09-14 18:24:56] 用户认可"参考游戏是基地离得远、镜头更远、单位推进慢"的观感方向(2026-09-14 数值改慢后反馈"好多了")。**Why:** 之前双方距离近+移速快,单位两三秒就接触,战斗缺乏观察窗口。**How to apply:** 后续地图/镜头调整优先加长双方距离、拉远摄像机;数值宁慢勿快。 +- [2026-09-16 22:18:14] 召唤系统:找不到合适位置时直接在召唤师前方强制生成,不显示警告,不退还能量。**Why:** 用户要求召唤必须成功,不被取消。**How to apply:** MainCharacterCombat.cs 的召唤逻辑 +- [2026-09-16 22:18:30] 召唤打断移动:主角点击召唤时必须立即停止移动,调用 SummonerClickMovement.ClearTarget() 来实现。**Why:** 用户要求召唤时即使在移动也要立刻停下。**How to apply:** BeginSummon 开始时停止移动 ### Project - [2026-08-28 14:26:56] 弓箭手远程箭矢的设计要求:保持发射时高度水平飞行,命中目标后直接结算伤害并销毁,不产生实体物理击退。**Why:** 当前玩法希望远程攻击是命中判定而非物理推动。**How to apply:** 后续调整箭矢、Projectile 或弓箭手攻击逻辑时保持这一行为。