225 lines
7.0 KiB
C#
225 lines
7.0 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using DarkTonic.MasterAudio;
|
||
using UnityEngine;
|
||
|
||
public class Bow : MonoBehaviour
|
||
{
|
||
public Transform bowString;
|
||
public Transform bulletPoint;
|
||
public Arrow nowArrow;
|
||
[SoundGroup] public string arrowShoot;
|
||
|
||
[Header("箭矢类型管理")]
|
||
private float specialArrowTimeRemaining = 0f;
|
||
|
||
[Header("箭矢预制体")]
|
||
public GameObject normalArrowPrefab;
|
||
|
||
[Header("弓弦力度参数")]
|
||
public float minForce = 20f;//最小力度
|
||
public float maxForce = 45f;//最大力度
|
||
public float forceMultiplier = 1.2f;//力度倍增系数
|
||
public float maxPullDistance = 0.5f;//弓弦可拉最大距离
|
||
public float forceCurveExponent = 1.5f;//力度曲线指数
|
||
public float currentDrawStrength = 0f;//当前力度(0-1)
|
||
|
||
[Header("弓弦视觉反馈")]
|
||
public LineRenderer bowStringRenderer;//弓弦的LineRenderer
|
||
public Transform stringTopPoint;//弓弦顶端点
|
||
public Transform stringBottomPoint;//弓弦末端点
|
||
public Transform stringMiddlePoint;//弓弦中间点(手拉动弓弦的位置)
|
||
|
||
private Vector3 middlePointPos;//初始弓弦初始点
|
||
|
||
public virtual void Start()
|
||
{
|
||
//初始化弓弦位置
|
||
if (bowStringRenderer != null && stringTopPoint != null && stringBottomPoint != null)
|
||
{
|
||
//设置LineRenderer位置
|
||
bowStringRenderer.positionCount = 3;
|
||
bowStringRenderer.SetPosition(0, stringTopPoint.position);
|
||
bowStringRenderer.SetPosition(1, stringMiddlePoint.position);
|
||
bowStringRenderer.SetPosition(2, stringBottomPoint.position);
|
||
|
||
//保存中间点初始位置
|
||
middlePointPos = stringMiddlePoint.localPosition;
|
||
}
|
||
}
|
||
|
||
public void Update()
|
||
{
|
||
UpdateArrowStatus();
|
||
UpdateBowStringVisual();
|
||
}
|
||
|
||
//更新弓弦视觉效果
|
||
private void UpdateBowStringVisual()
|
||
{
|
||
if (bowStringRenderer != null && stringTopPoint != null && stringBottomPoint != null && stringMiddlePoint != null)
|
||
{
|
||
//更新LineRenderer
|
||
bowStringRenderer.SetPosition(0, stringTopPoint.position);
|
||
bowStringRenderer.SetPosition(1, stringMiddlePoint.position);
|
||
bowStringRenderer.SetPosition(2, stringBottomPoint.position);
|
||
}
|
||
}
|
||
|
||
//更新箭矢状态
|
||
public virtual void UpdateArrowStatus()
|
||
{
|
||
if (nowArrow != null)
|
||
{
|
||
// 箭尾固定点(通常是弓上挂箭点)
|
||
Transform tailPoint = bulletPoint; // 保证箭尾贴在弓上
|
||
|
||
// 箭头方向:从箭尾指向左手
|
||
Vector3 direction = (transform.position - tailPoint.position).normalized;
|
||
|
||
// 更新箭的位置与旋转
|
||
nowArrow.transform.position = tailPoint.position;
|
||
nowArrow.transform.rotation = Quaternion.LookRotation(direction, transform.up);
|
||
}
|
||
}
|
||
|
||
Vector3 ProjectPointOnPlane(Vector3 point, Vector3 planeOrigin, Vector3 planeNormal)
|
||
{
|
||
// 单位化法向量
|
||
planeNormal.Normalize();
|
||
|
||
// 计算点到平面上任意一点的向量
|
||
Vector3 vectorToPlane = point - planeOrigin;
|
||
|
||
// 计算投影距离
|
||
float distance = Vector3.Dot(vectorToPlane, planeNormal);
|
||
|
||
// 得到垂足(即点在平面上的投影)
|
||
Vector3 projection = point - distance * planeNormal;
|
||
|
||
return projection;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 拉弓弦(由左手位置驱动)
|
||
/// </summary>
|
||
public void Pull(Transform point)
|
||
{
|
||
Vector3 planeOrigin = bowString.position;
|
||
Vector3 planeNormal = bowString.right;
|
||
|
||
// 投影手的拉动位置到弓弦平面
|
||
Vector3 projectedPoint = ProjectPointOnPlane(point.position, planeOrigin, planeNormal);
|
||
|
||
// 转换到弓的局部坐标系
|
||
Vector3 localPos = transform.InverseTransformPoint(projectedPoint);
|
||
|
||
// 限制拉弓距离,防止超过最大拉伸范围
|
||
float pullDistance = Mathf.Clamp(localPos.z, -maxPullDistance, 0);
|
||
|
||
// 更新弓弦视觉
|
||
if (stringMiddlePoint != null)
|
||
{
|
||
Vector3 midPos = middlePointPos;
|
||
midPos.z = pullDistance;
|
||
stringMiddlePoint.localPosition = midPos;
|
||
}
|
||
|
||
// 更新箭尾点位置
|
||
if (bulletPoint != null)
|
||
{
|
||
bulletPoint.localPosition = new Vector3(0, 0, pullDistance);
|
||
}
|
||
|
||
// 力度计算
|
||
currentDrawStrength = Mathf.Clamp01(Mathf.Abs(pullDistance) / maxPullDistance);
|
||
|
||
// -------------------------
|
||
// ✅ 新增保护逻辑:超过最大拉距时自动复位
|
||
// -------------------------
|
||
// if (Mathf.Approximately(pullDistance, -maxPullDistance))
|
||
// {
|
||
// Reset();
|
||
// }
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 弓弦复位
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
// // 拉弓点归零
|
||
// if (bulletPoint != null)
|
||
// bulletPoint.localPosition = Vector3.zero;
|
||
// 弓弦归位
|
||
if (stringMiddlePoint != null)
|
||
stringMiddlePoint.localPosition = middlePointPos;
|
||
// 当前力度清零
|
||
currentDrawStrength = 0f;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 创建箭矢
|
||
/// </summary>
|
||
public void CreateArrowInHand()
|
||
{
|
||
//如果已有箭矢,先销毁
|
||
if (nowArrow != null)
|
||
{
|
||
Destroy(nowArrow.gameObject);
|
||
}
|
||
|
||
//根据当前箭矢类型选择预制体
|
||
GameObject arrowPrefab = normalArrowPrefab;
|
||
GameObject arrowObj = Instantiate(arrowPrefab, bulletPoint);
|
||
nowArrow = arrowObj.GetComponent<Arrow>();
|
||
|
||
//初始禁用物理,知道射出
|
||
if (nowArrow.TryGetComponent<Rigidbody>(out var rb))
|
||
{
|
||
rb.isKinematic = true;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 射出箭矢
|
||
/// </summary>
|
||
public void ShootArrow()
|
||
{
|
||
if (nowArrow != null)
|
||
{
|
||
MasterAudio.PlaySound(arrowShoot);
|
||
|
||
// 根据拉弓力度计算实际力度(应用非线性曲线)
|
||
float curvedStrength = Mathf.Pow(currentDrawStrength, 1.8f);
|
||
float actualForce = Mathf.Lerp(minForce, maxForce, curvedStrength) * forceMultiplier;
|
||
|
||
//发射手上已有的箭矢
|
||
nowArrow.transform.SetParent(null);
|
||
|
||
//应用物理效果
|
||
if (nowArrow.TryGetComponent<Rigidbody>(out var rb))
|
||
{
|
||
rb.isKinematic = false;//确保物理启用
|
||
rb.velocity = Vector3.zero;//重置速度
|
||
rb.angularVelocity= Vector3.zero;//重置角速度
|
||
|
||
//设置初始速度
|
||
rb.AddForce(bulletPoint.forward * actualForce, ForceMode.VelocityChange);
|
||
}
|
||
|
||
//调用箭矢初始化(传递力度值)
|
||
nowArrow.OnSpawn(bulletPoint.forward, actualForce);
|
||
|
||
//清楚引用
|
||
nowArrow = null;
|
||
|
||
Reset();
|
||
}
|
||
}
|
||
}
|