feat(gameplay): 实现召唤师对决模式核心功能 - 新增召唤师对决管理模式,支持点卡片直接召唤单位 - 添加召唤师点地移动控制,移动时不攻击、站定时自动攻击 - 实现召唤师模式开关,单位不再自动追击远处敌人 - 更新卡牌按钮逻辑,对决模式下按能量消耗直接召唤 - 修改单位基础行为,支持移动中不攻击的召唤师模式 - 更新核心玩法文档,从建筑生产模式转向召唤师对决模式 - 添加召唤师对决测试场景,整合新的战斗逻辑 ```
158 lines
4.0 KiB
C#
158 lines
4.0 KiB
C#
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
|
|
/// <summary>
|
|
/// 召唤师对决:召唤师点地移动操控(直线移动,无寻路)。
|
|
/// 点击己方区域地面 → 直线走到目标点(clamp 在己方带内)。
|
|
/// 移动时不攻击;站定后自动攻击射程内目标。
|
|
/// </summary>
|
|
public class SummonerClickMovement : MonoBehaviour
|
|
{
|
|
[Header("己方半场 clamp(世界坐标)")]
|
|
public float minX = -9f;
|
|
public float maxX = 9f;
|
|
public float minZ = -29f;
|
|
public float maxZ = -11f;
|
|
|
|
[Header("移动速度")]
|
|
public float moveSpeed = 5f;
|
|
public float stopDistance = 0.2f;
|
|
|
|
[Header("地面射线")]
|
|
public LayerMask groundMask = ~0;
|
|
|
|
private Camera mainCamera;
|
|
private MainCharacterCombat combat;
|
|
private Animator animator;
|
|
private Vector3 targetPosition;
|
|
private bool hasTarget;
|
|
|
|
private void Awake()
|
|
{
|
|
combat = GetComponent<MainCharacterCombat>();
|
|
animator = GetComponent<Animator>();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
mainCamera = Camera.main;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
HandleClickToMove();
|
|
HandleMovement();
|
|
}
|
|
|
|
// 点地移动:点击地面即设置目标点(EventSystem 判定不在 UI 上时才生效)。
|
|
private void HandleClickToMove()
|
|
{
|
|
if (Input.GetMouseButtonDown(0) && !IsPointerOverUI())
|
|
{
|
|
if (RaycastGround(out Vector3 groundPoint))
|
|
{
|
|
Vector3 clamped = ClampToOwnHalf(groundPoint);
|
|
MoveTo(clamped);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 执行直线移动
|
|
private void HandleMovement()
|
|
{
|
|
if (!hasTarget) return;
|
|
|
|
Vector3 currentPos = transform.position;
|
|
Vector3 direction = targetPosition - currentPos;
|
|
direction.y = 0f;
|
|
float distance = direction.magnitude;
|
|
|
|
// 到达目标
|
|
if (distance <= stopDistance)
|
|
{
|
|
ClearTarget();
|
|
return;
|
|
}
|
|
|
|
// 移动
|
|
direction.Normalize();
|
|
transform.position += direction * moveSpeed * Time.deltaTime;
|
|
|
|
// 朝向移动方向
|
|
if (direction.sqrMagnitude > 0.001f)
|
|
{
|
|
transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
|
|
}
|
|
|
|
// 播放走路动画
|
|
if (animator != null)
|
|
{
|
|
animator.SetInteger("speed", 1);
|
|
}
|
|
}
|
|
|
|
// 外部入口:把召唤师移动到某点(clamp 后设置目标)。
|
|
public void MoveTo(Vector3 worldPosition)
|
|
{
|
|
Vector3 clamped = ClampToOwnHalf(worldPosition);
|
|
targetPosition = clamped;
|
|
targetPosition.y = transform.position.y; // 保持 Y 不变
|
|
hasTarget = true;
|
|
|
|
// 移动中暂停攻击(防风筝规则)
|
|
if (combat != null)
|
|
{
|
|
combat.enabled = false;
|
|
}
|
|
}
|
|
|
|
public void ClearTarget()
|
|
{
|
|
hasTarget = false;
|
|
|
|
// 停止动画
|
|
if (animator != null)
|
|
{
|
|
animator.SetInteger("speed", 0);
|
|
}
|
|
|
|
// 站定后恢复自动攻击
|
|
if (combat != null)
|
|
{
|
|
combat.enabled = true;
|
|
}
|
|
}
|
|
|
|
// 半场 clamp:X 与 Z 均限制在己方带内。
|
|
private Vector3 ClampToOwnHalf(Vector3 position)
|
|
{
|
|
return new Vector3(
|
|
Mathf.Clamp(position.x, minX, maxX),
|
|
position.y,
|
|
Mathf.Clamp(position.z, minZ, maxZ));
|
|
}
|
|
|
|
private bool RaycastGround(out Vector3 point)
|
|
{
|
|
point = Vector3.zero;
|
|
if (mainCamera == null)
|
|
{
|
|
mainCamera = Camera.main;
|
|
if (mainCamera == null) return false;
|
|
}
|
|
|
|
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
|
|
if (Physics.Raycast(ray, out RaycastHit hit, 200f, groundMask.value))
|
|
{
|
|
point = hit.point;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool IsPointerOverUI()
|
|
{
|
|
return EventSystem.current != null && EventSystem.current.IsPointerOverGameObject();
|
|
}
|
|
}
|