256 lines
7.8 KiB
C#
256 lines
7.8 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using DarkTonic.MasterAudio;
|
||
using UnityEngine;
|
||
|
||
public class Bow : Launcher
|
||
{
|
||
public Transform bowString;
|
||
|
||
public GameObject arrowPre;
|
||
private Arrow _nowArrow;
|
||
[SoundGroup] public string arrowShoot;
|
||
|
||
[Header("箭矢类型管理")]
|
||
public BulletType currentArrowType = BulletType.Arrow;
|
||
private float specialArrowTimeRemaining = 0f;
|
||
|
||
[Header("箭矢预制体")]
|
||
public GameObject normalArrowPrefab;
|
||
public GameObject fireArrowPrefab;
|
||
|
||
[Header("弓弦力度参数")]
|
||
public float minForce = 20f;//最小力度
|
||
public float maxForce = 45f;//最大力度
|
||
public float forceMultiplier = 1.2f;//力度倍增系数
|
||
public float maxPullDistance = 0.5f;//弓弦可拉最大距离
|
||
public float forceCurveExponent = 1.5f;//力度曲线指数
|
||
private float currentDrawStrength = 0f;//当前力度(0-1)
|
||
|
||
[Header("弓弦视觉反馈")]
|
||
public LineRenderer bowStringRenderer;//弓弦的LineRenderer
|
||
public Transform stringTopPoint;//弓弦顶端点
|
||
public Transform stringBottomPoint;//弓弦末端点
|
||
public Transform stringMiddlePoint;//弓弦中间点(手拉动弓弦的位置)
|
||
|
||
private Vector3 middlePointPos;//初始弓弦初始点
|
||
|
||
|
||
|
||
public void Start()
|
||
{
|
||
type = GunType.Bow;
|
||
GunInfo gunInfo = GameManager.Ins.GunInfos[GunType.Bow][1];
|
||
shootRate = gunInfo.ShootRate;
|
||
recoil = maxForce;//使用最大力度作为基础后坐力
|
||
|
||
//初始化弓弦位置
|
||
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);
|
||
}
|
||
}
|
||
|
||
//更新箭矢状态
|
||
private void UpdateArrowStatus()
|
||
{
|
||
if (specialArrowTimeRemaining > 0)
|
||
{
|
||
specialArrowTimeRemaining -= Time.deltaTime;
|
||
if (specialArrowTimeRemaining <= 0)
|
||
{
|
||
currentArrowType = BulletType.Arrow;
|
||
//TODO:UI特殊箭矢已失效(或不做)
|
||
}
|
||
}
|
||
}
|
||
|
||
//激活特殊箭矢
|
||
//public void ActivateSpecialArrow(ArrowPickup.ArrowType arrowType, float duration)
|
||
//{
|
||
// switch (arrowType)
|
||
// {
|
||
// case ArrowPickup.ArrowType.Fire:
|
||
// currentArrowType = BulletType.FireArrow;
|
||
// specialArrowTimeRemaining = duration;
|
||
// //TODO:UI获得火焰箭(或不做)
|
||
// break;
|
||
// //TODO:添加其他特殊箭矢类型
|
||
// }
|
||
//}
|
||
|
||
|
||
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 = bowString.InverseTransformPoint(projectedPoint);
|
||
|
||
//限制拉弓距离
|
||
float pullDistance = Mathf.Clamp(localPos.z, -maxPullDistance, 0);
|
||
bulletPoint.localPosition = new Vector3(0, 0, localPos.z);
|
||
|
||
//更新中间点位置(弓弦弯曲效果)
|
||
if (stringMiddlePoint != null)
|
||
{
|
||
Vector3 midPos = middlePointPos;
|
||
midPos.z = pullDistance;
|
||
stringMiddlePoint.localPosition = midPos;
|
||
}
|
||
|
||
// 计算拉弓力度 (0-1)
|
||
currentDrawStrength = Mathf.Clamp01(Mathf.Abs(pullDistance) / maxPullDistance);
|
||
|
||
// 应用非线性曲线(初始松,后段紧)
|
||
float curvedStrength = Mathf.Pow(currentDrawStrength, 1.8f);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 弓弦复位
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
bulletPoint.localPosition = Vector3.zero;
|
||
currentDrawStrength = 0f;
|
||
|
||
//重置中间点位置
|
||
if (stringMiddlePoint != null)
|
||
{
|
||
stringMiddlePoint.localPosition = middlePointPos;
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建箭矢
|
||
/// </summary>
|
||
public void CreateArrowInHand()
|
||
{
|
||
//如果已有箭矢,先销毁
|
||
if (_nowArrow != null)
|
||
{
|
||
Destroy(_nowArrow.gameObject);
|
||
}
|
||
|
||
//根据当前箭矢类型选择预制体
|
||
GameObject arrowPrefab = GetCurrentArrowPrefab();
|
||
GameObject arrowObj = Instantiate(arrowPrefab, bulletPoint);
|
||
_nowArrow = arrowObj.GetComponent<Arrow>();
|
||
|
||
//初始禁用物理,知道射出
|
||
if (_nowArrow.TryGetComponent<Rigidbody>(out var rb))
|
||
{
|
||
rb.isKinematic = true;
|
||
}
|
||
}
|
||
|
||
//获取当前箭矢预制体
|
||
private GameObject GetCurrentArrowPrefab()
|
||
{
|
||
switch (currentArrowType)
|
||
{
|
||
case BulletType.FireArrow:
|
||
return fireArrowPrefab;
|
||
default:
|
||
return normalArrowPrefab;
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 射出箭矢
|
||
/// </summary>
|
||
public void ShootArrow()
|
||
{
|
||
//Shoot();
|
||
//Reset();
|
||
if (_nowArrow != null)
|
||
{
|
||
//检查游戏状态
|
||
if (GameManager.Ins.gameState == GameState.Introduce)
|
||
{
|
||
GameManager.Ins.GameStart();
|
||
}
|
||
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.type = currentArrowType;
|
||
|
||
//调用箭矢初始化(传递力度值)
|
||
_nowArrow.OnSpawn(bulletPoint.forward, actualForce);
|
||
|
||
//清楚引用
|
||
_nowArrow = null;
|
||
|
||
Reset();
|
||
}
|
||
}
|
||
}
|