| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using DG.Tweening;
- using UnityEngine.SceneManagement;
- /* 拍摄箭飞行的摄像机 */
- public class ArrowCamera : MonoBehaviour
- {
- [System.NonSerialized] public Arrow arrow;
- [System.NonSerialized] public ArrowCameraTemplate arrowCameraTemplate;
- [System.NonSerialized] public bool isArrowSync = false;
- [System.NonSerialized] public ArrowSync arrowSync;
- public void SetArrowSync(ArrowSync arrowSync) {
- isArrowSync = true;
- this.arrowSync = arrowSync;
- }
- void Awake()
- {
- BowCamera.ins.SetArrowFollowing(true);
- }
- void Start()
- {
- if (SceneManager.GetActiveScene().name == "Game") {
- if ((isArrowSync && arrowSync.canUserLockCamera) || (!isArrowSync && arrow.canUserLockCamera))
- {
- //使用锁靶镜头
- arrowCameraTemplate = new ArrowCameraTemplate_targetLock(this, TargetBody.ins.transform);
- }
- else {
- //射空就使用之前的镜头
- //arrowCameraTemplate = new ArrowCameraTemplate1(this);
- arrowCameraTemplate = new ArrowCameraTemplate_targetLock(this, TargetBody.ins.transform,false);
- }
-
- //if ((isArrowSync && arrowSync.canUseSideCamera) || (!isArrowSync && arrow.canUseSideCamera)) {
- // arrowCameraTemplate = new ArrowCameraTemplate2(this);
- // Debug.Log("跟随镜头2");
- //} else {
- // arrowCameraTemplate = new ArrowCameraTemplate1(this);
- // Debug.Log("跟随镜头1");
- //}
- } else if (SceneManager.GetActiveScene().name == "GameChallenge") {
- arrowCameraTemplate = new ArrowCameraTemplate3(this);
- }
- }
- void OnDestroy()
- {
- try
- {
- BowCamera.ins.SetArrowFollowing(false);
- }
- catch (System.Exception) {}
- }
- void FixedUpdate()
- {
- arrowCameraTemplate.Update();
- }
- }
- /* 模板3:跟着箭飞_打猎场景 */
- class ArrowCameraTemplate3 : ArrowCameraTemplate
- {
- public ArrowCameraTemplate3(ArrowCamera arrowCamera) : base(arrowCamera) {
- if (!arrowCamera.isArrowSync) {
- this.arrowCamera.arrow.activeEffectCyclone(true);
- } else {
- this.arrowCamera.arrowSync.activeEffectCyclone(true);
- }
- Camera camera = arrowCamera.transform.GetComponent<Camera>();
- if (camera) camera.fieldOfView = 25;
- }
-
- private bool cameraMoveFinish = false;
- Vector3 cameraToRunPosition = new Vector3(0.4f, 0.5f, -1 - Mathf.Clamp(Arrow.speed / 20 * 6, 0, 6));
- Vector3 cameraFinalPosition = new Vector3(0.4f, 0.8f, -5f);
- //若有树的遮挡,则使用以下视角坐标
- Vector3 cameraFinalPosition_whenBlockByTree = new Vector3(0.15f, 0.3f, -1.2f);
- bool hasBlockByTree = false;
- Vector3 blockByTreeLookAtPoint;
- public override void Update() {
- if (cameraMoveFinish) {
- return;
- }
- Transform cameraT = this.arrowCamera.transform;
- Vector3 cameraPosition = cameraT.localPosition;
- if ((!this.arrowCamera.isArrowSync && this.arrowCamera.arrow.isHit) ||
- (this.arrowCamera.isArrowSync && this.arrowCamera.arrowSync.isHit)) {
- cameraPosition = Vector3.Lerp(cameraPosition, cameraFinalPosition, Time.deltaTime * 6);
- cameraT.localPosition = cameraPosition;
- if (hasBlockByTree) {
- cameraT.LookAt(blockByTreeLookAtPoint);
- }
- float d = Vector3.Distance(cameraPosition, cameraFinalPosition);
- if (d < 0.001f) {
- cameraMoveFinish = true;
- Sequence seq = DOTween.Sequence();
- if (!quicklyNextShoot) seq.AppendInterval(1f);
- seq.AppendCallback(delegate() {
- if (!this.arrowCamera.isArrowSync) {
- this.arrowCamera.arrow.nextShoot();
- }
- GameObject.Destroy(container?container:this.arrowCamera.gameObject);
- });
- }
- } else {
- cameraPosition = Vector3.Lerp(cameraPosition, cameraToRunPosition, Time.deltaTime * 6);
- cameraT.localPosition = cameraPosition;
- if (this.arrowCamera.isArrowSync) {
- cameraT.LookAt(this.arrowCamera.arrowSync.Head());
- } else {
- cameraT.LookAt(this.arrowCamera.arrow.Head());
- }
- }
- }
- GameObject container = null;
- public override void beforeHit() {
- //把镜头从箭中移除,放到一个固定的容器里,免得随着动物抖动
- if (!container) {
- container = new GameObject("CameraContainer");
- container.transform.position = this.arrowCamera.arrow.transform.position;
- container.transform.rotation = this.arrowCamera.arrow.transform.rotation;
- this.arrowCamera.transform.SetParent(container.transform);
- //检测有没有树遮挡
- Quaternion rot = container.transform.rotation;
- Quaternion back = rot * Quaternion.AngleAxis(180, Vector3.up); //绕本地坐标轴旋转
- for (int i = -36; i <= 36; i += 3) {
- float angle = i;
- Quaternion axis = back * Quaternion.AngleAxis(angle, Vector3.up);
- Vector3 direction = axis * Vector3.forward;
- RaycastHit[] raycastHits = Physics.RaycastAll(container.transform.position, direction, 6f);
- foreach (var raycastHit in raycastHits) {
- Transform tf = raycastHit.transform;
- if (tf && tf.name.StartsWith("TreeCollider")) {
- cameraFinalPosition = cameraFinalPosition_whenBlockByTree;
- hasBlockByTree = true;
- Arrow arrow = this.arrowCamera.arrow;
- blockByTreeLookAtPoint = arrow.Head().position - arrow.transform.forward * 0.5f;
- break;
- }
- }
- }
- }
- //记录需要同步的消息
- if (!this.arrowCamera.isArrowSync) {
- if (this.arrowCamera.arrow.outputSyncData != null) {
- this.arrowCamera.arrow.outputSyncData.SetArrowCameraTemplate3(this.hasBlockByTree, this.quicklyNextShoot);
- }
- }
- }
- public void beforHitWhenSync(bool hasBlockByTree) {
- this.hasBlockByTree = hasBlockByTree;
- container = new GameObject("CameraContainer");
- container.transform.position = this.arrowCamera.arrowSync.transform.position;
- container.transform.rotation = Quaternion.LookRotation(this.arrowCamera.arrowSync.transform.forward, Vector3.up);
- this.arrowCamera.transform.SetParent(container.transform);
- this.arrowCamera.transform.localRotation = Quaternion.identity;
- if (hasBlockByTree) {
- cameraFinalPosition = cameraFinalPosition_whenBlockByTree;
- ArrowSync arrowSync = this.arrowCamera.arrowSync;
- blockByTreeLookAtPoint = arrowSync.Head().position - arrowSync.transform.forward * 0.5f;
- }
- }
- public bool quicklyNextShoot = ChallengeGameMode.IsChallengeWolf();
- public override void SendMsg(int id, object msg) {
- if (id == 0) {
- quicklyNextShoot = true;
- }
- //记录需要同步的消息
- if (!this.arrowCamera.isArrowSync) {
- if (this.arrowCamera.arrow.outputSyncData != null) {
- this.arrowCamera.arrow.outputSyncData.SetArrowCameraTemplate3(this.hasBlockByTree, this.quicklyNextShoot);
- }
- }
- }
- }
- /* 模板2:从侧面看箭飞 */
- class ArrowCameraTemplate2 : ArrowCameraTemplate
- {
- public ArrowCameraTemplate2(ArrowCamera arrowCamera) : base(arrowCamera) {
- this.arrowCamera.transform.parent = null;
- arrowCamera.transform.localPosition = new Vector3(8.33f, 2.45f, 6.4f);
- arrowCamera.transform.localEulerAngles = new Vector3(0, -42, 0);
- }
- bool isHit = false;
- public override void Update() {
- if (arrowCamera.isArrowSync) {
- if (!isHit) {
- isHit = arrowCamera.arrowSync.isHit;
- if (isHit) {
- this.arrowCamera.transform.SetParent(this.arrowCamera.arrowSync.transform);
- arrowCamera.transform.localPosition = new Vector3(-0.3f, 0.2f, -1.3f);
- arrowCamera.transform.LookAt(this.arrowCamera.arrowSync.Head());
- Sequence seq = DOTween.Sequence();
- seq.PrependInterval(2.2f);
- seq.AppendCallback(delegate() {
- GameObject.Destroy(this.arrowCamera.gameObject);
- });
- return;
- }
- }
- if (!arrowCamera.arrowSync) {
- GameObject.Destroy(this.arrowCamera.gameObject);
- }
- } else {
- if (!isHit) {
- isHit = arrowCamera.arrow.isHit;
- if (isHit) {
- this.arrowCamera.transform.SetParent(this.arrowCamera.arrow.transform);
- arrowCamera.transform.localPosition = new Vector3(-0.3f, 0.2f, -1.3f);
- arrowCamera.transform.LookAt(this.arrowCamera.arrow.Head());
- Sequence seq = DOTween.Sequence();
- seq.PrependInterval(2.2f);
- seq.AppendCallback(delegate() {
- this.arrowCamera.arrow.nextShoot();
- GameObject.Destroy(this.arrowCamera.gameObject);
- });
- return;
- }
- }
- if (!arrowCamera.arrow) {
- GameObject.Destroy(this.arrowCamera.gameObject);
- }
- }
- }
- }
- /* 模板1:跟着箭飞 */
- class ArrowCameraTemplate1 : ArrowCameraTemplate
- {
- public ArrowCameraTemplate1(ArrowCamera arrowCamera) : base(arrowCamera) {
- if (!arrowCamera.isArrowSync) {
- this.arrowCamera.arrow.activeEffectCyclone(true);
- } else {
- this.arrowCamera.arrowSync.activeEffectCyclone(true);
- }
- }
-
- private bool cameraMoveFinish = false;
- Vector3 cameraToRunPosition = new Vector3(0.4f, 0.3f, -1 - Mathf.Clamp(Arrow.speed / 20 * 6, 0, 6));
- Vector3 cameraFinalPosition = new Vector3(-0.3f, 0.2f, -1.3f);
- public override void Update() {
- if (cameraMoveFinish) {
- return;
- }
- Transform cameraT = this.arrowCamera.transform;
- Vector3 cameraPosition = cameraT.localPosition;
- if ((!this.arrowCamera.isArrowSync && this.arrowCamera.arrow.isHit) ||
- (this.arrowCamera.isArrowSync && this.arrowCamera.arrowSync.isHit)) {
- cameraPosition = Vector3.Lerp(cameraPosition, cameraFinalPosition, Time.deltaTime * 8);
- float d = Vector3.Distance(cameraPosition, cameraFinalPosition);
- if (d < 0.001f) {
- cameraMoveFinish = true;
- Sequence seq = DOTween.Sequence();
- seq.AppendInterval(2.2f);
- seq.AppendCallback(delegate() {
- if (!arrowCamera.isArrowSync) {
- this.arrowCamera.arrow.nextShoot();
- }
- GameObject.Destroy(this.arrowCamera.gameObject);
- });
- }
- } else {
- cameraPosition = Vector3.Lerp(cameraPosition, cameraToRunPosition, Time.deltaTime * 6);
- }
- if (this.arrowCamera.isArrowSync) {
- cameraT.LookAt(this.arrowCamera.arrowSync.Head());
- } else {
- cameraT.LookAt(this.arrowCamera.arrow.Head());
- }
- cameraT.localPosition = cameraPosition;
- }
- }
- /// <summary>
- /// 箭相机模板:靶锁模式
- /// 相机会跟随箭头运动,并在靠近目标时减速停下,支持缓动曲线控制
- /// </summary>
- class ArrowCameraTemplate_targetLock : ArrowCameraTemplate
- {
- //当前操作状态,是否删除
- private bool isDeleting = false;
- public bool IsDeleting => isDeleting;
- private bool cameraStopped = false; // 标记相机是否已停止(到达目标附近后停止更新位置)
- private Transform target; // 被锁定的目标(通常是靶心)
- private bool isFollowTarget = true;
- /// <summary>
- /// 相机相对箭的偏移量
- /// x = 左右偏移(负数表示往左,正数往右)
- /// y = 高度偏移(正数表示高于箭,固定高度时候,和目标y值叠加)
- /// z = 前后偏移(负数表示在箭的后面,正数表示在箭的前面)
- /// </summary>
- private Vector3 offsetFromArrow = new Vector3(0, 0.8f, -2.2f);
- private float stopDistanceToTarget = 4f; // 相机与目标之间的最小停止距离(XZ 平面)
- private float totalDist = 0f; // 初始相机与目标之间的水平总距离(用于计算进度)
- private Vector3 lastArrowPos; // 记录箭的上一次位置
- private float arrowSpeed = 0;
- // 调节参数
- private const float extraSpeedMax = 100f; // 相机在箭方向上的额外冲击速度最大值(越大越“冲”)
- private const float minLerpSpeed = 2f; // 插值时的最小速度(进度小的时候)
- private const float maxLerpSpeed = 10f; // 插值时的最大速度(进度接近 1 时)
- public ArrowCameraTemplate_targetLock(ArrowCamera arrowCamera, Transform target,bool followTarget = true) : base(arrowCamera)
- {
- //在 ArmBow.ins 调试参数
- offsetFromArrow = followTarget? ArmBow.ins.offsetFromArrow : ArmBow.ins.offsetFromArrowTemp;
- stopDistanceToTarget = ArmBow.ins.stopDistanceToTarget;
- this.target = target;
-
- this.isFollowTarget = followTarget;
- Transform cameraT = arrowCamera.transform;
- Transform arrowT = arrowCamera.isArrowSync ? arrowCamera.arrowSync.transform : arrowCamera.arrow.transform;
- this.lastArrowPos = arrowT.position;
- // 相机初始位置(箭位置 + 偏移,锁定 Y 高度)
- Vector3 offsetPos = arrowT.position + arrowT.TransformDirection(offsetFromArrow);
- offsetPos.y = target.position.y + offsetFromArrow.y;
- offsetPos.x = target.position.x;
- cameraT.position = offsetPos;
- // 记录初始总路程(XZ 平面,不考虑高度差)
- totalDist = GetXZDistance(offsetPos, target.position);
- arrowSpeed = arrowCamera.arrow.mySpeed;
- Debug.Log("当前弓箭速度:" + arrowSpeed);
- }
- public override void Update()
- {
- if (target == null) return;
- //弓箭删除
- if ((arrowCamera.isArrowSync && arrowCamera.arrowSync == null) || (!arrowCamera.isArrowSync && arrowCamera.arrow == null))return;
- Transform cameraT = arrowCamera.transform;
- Transform arrowT = arrowCamera.isArrowSync ? arrowCamera.arrowSync.transform : arrowCamera.arrow.transform;
- if (!cameraStopped)
- {
- // 计算当前相机与目标的水平距离
- float distToTarget = GetXZDistance(cameraT.position, target.position);
- if (distToTarget <= stopDistanceToTarget)
- {
- // 到达目标附近 -> 停止跟随
- cameraStopped = true;
- cameraT.SetParent(null);
- }
- else
- {
- // progress = 相机已接近目标的进度(0 = 起点,1 = 停止点)
- float progress = Mathf.Clamp01(
- 1f - (distToTarget - stopDistanceToTarget) / (totalDist - stopDistanceToTarget)
- );
- //Vector3 arrowScreenPos = cameraT.GetComponent<Camera>().WorldToViewportPoint(arrowT.position);
- //bool isFollow = true;
- //// 如果箭接近屏幕边缘,就往后退
- //if (arrowScreenPos.x < -0.13f || arrowScreenPos.x > 1f ||
- // arrowScreenPos.y < -0.13f || arrowScreenPos.y > 1f)
- //{
- // //UnityEditor.EditorApplication.isPaused = true;
- // // offsetFromArrow.z = ArmBow.ins.offsetFromArrow.z - 2;
- // // 用 Lerp 平滑过渡
- // //float targetZ = ArmBow.ins.offsetFromArrow.z - 4f;
- // // offsetFromArrow.z = Mathf.Lerp(offsetFromArrow.z, targetZ, Time.deltaTime * 2f);
- // Debug.Log("箭离开屏幕!" + offsetFromArrow);
- // isFollow = false;
- //}
- //else
- //{
- // //offsetFromArrow.z = ArmBow.ins.offsetFromArrow.z;
- // isFollow = true;
- //}
- // 用缓动曲线计算归一化进度(决定移动节奏)
- float easedT = ArmBow.ins.customCurveCamera.Evaluate(progress);
- // 箭位置 + 偏移(相机保持与箭的相对位置,并锁定到目标的高度)
- Vector3 offsetPos = arrowT.position + arrowT.TransformDirection(offsetFromArrow);
- //offsetPos.y = target.position.y + offsetFromArrow.y;
- // offsetPos.x = target.position.x;
- if (this.isFollowTarget)
- {
- // 箭的水平前进方向(忽略x, y 分量)arrowT.forward.x
- Vector3 arrowDirXZ = new Vector3(0f, 0f, arrowT.forward.z).normalized;
- // 相机额外的位移偏移量(随 easedT 增强,越靠近目标越快)
- Vector3 extraOffset = arrowDirXZ * Mathf.Lerp(0f, extraSpeedMax, easedT) * Time.deltaTime;
- // 最终目标位置 = 箭偏移位置 + 额外速度偏移
- Vector3 targetPos = offsetPos + extraOffset;
- // 相机向目标位置平滑插值(随曲线加速)
- float speedFactor = Mathf.Lerp(minLerpSpeed, maxLerpSpeed, easedT);
- cameraT.position = Vector3.Lerp(cameraT.position, targetPos, Time.deltaTime * speedFactor);
- }
- else {
- // 最终目标位置 = 箭偏移位置
- //offsetPos.z = arrowT.position.z - 5;
- // 箭的水平前进方向(忽略 y 分量)arrowT.forward.x
- //Vector3 arrowDirXZ = new Vector3(0f, 0f, arrowT.forward.z).normalized;
- // 相机额外的位移偏移量(随 easedT 增强,越靠近目标越快)
- // Vector3 extraOffset = arrowDirXZ * Mathf.Lerp(0f, extraSpeedMax, easedT) * Time.deltaTime;
- // 最终目标位置 = 箭偏移位置 + 额外速度偏移
- //Vector3 targetPos = offsetPos + extraOffset;
- // 相机向目标位置平滑插值(随曲线加速)
- //float speedFactor = Mathf.Lerp(minLerpSpeed, maxLerpSpeed, easedT);
- //cameraT.position = offsetPos;// Vector3.Lerp(cameraT.position, targetPos, Time.deltaTime * speedFactor);
- cameraT.SetParent(null);
- // 箭的前进方向(XZ 平面)Z 分量
- float arrowSpeedZ = arrowSpeed * arrowT.forward.z; // 箭速度 * 前方向 Z 分量
- // 相机当前 Z 位置参考箭的 Z
- float targetZ = cameraT.position.z + arrowSpeedZ * Time.deltaTime;
- // 保证相机不要超过箭本身(可选)
- targetZ = Mathf.Min(targetZ, arrowT.position.z);
- // 目标位置 = 相机 X/Y 偏移不变,Z 方向用 targetZ
- Vector3 targetPos = new Vector3(
- target.position.x, // X 可以锁定到目标或保持 offsetPos.x
- offsetPos.y, // Y 维持箭高度偏移
- targetZ
- );
- // 直接插值平滑到目标位置(也可以加缓动)
- float speedFactor = 5f; // 可调节平滑程度
- cameraT.position = Vector3.Lerp(cameraT.position, targetPos, Time.deltaTime * speedFactor);
- }
- // 最后强制 y = 靶子高度,不受lerp影响
- Vector3 fixedPos = cameraT.position;
- fixedPos.y = target.position.y + offsetFromArrow.y;
- cameraT.position = fixedPos;
- //#if UNITY_EDITOR
- // Debug.Log($"progress:{progress:F2}, easedT:{easedT:F2}, speed:{speedFactor:F2}, extra:{extraOffset}");
- //#endif
- }
-
- }
- // 命中处理(箭命中目标后,1.5 秒后销毁相机对象)
- if ((!arrowCamera.isArrowSync && arrowCamera.arrow.isHit) ||
- (arrowCamera.isArrowSync && arrowCamera.arrowSync.isHit))
- {
- if (isDeleting) return;
- isDeleting = true;
- cameraStopped = true;
- Sequence seq = DOTween.Sequence();
- seq.AppendInterval(1.5f);
- seq.AppendCallback(() =>
- {
- if (!arrowCamera.isArrowSync)
- arrowCamera.arrow.nextShoot(); // 下一发准备
- GameObject.Destroy(arrowCamera.gameObject); // 销毁相机
- });
- }
- }
- /// <summary>
- /// 计算两个点在 XZ 平面的水平距离(忽略 Y 高度差)
- /// </summary>
- private float GetXZDistance(Vector3 a, Vector3 b)
- {
- float dx = a.x - b.x;
- float dz = a.z - b.z;
- return Mathf.Sqrt(dx * dx + dz * dz);
- }
- }
- public class ArrowCameraTemplate {
- public ArrowCamera arrowCamera;
- public ArrowCameraTemplate(ArrowCamera arrowCamera)
- {
- this.arrowCamera = arrowCamera;
- }
- public virtual void Update() {}
- public virtual void beforeHit() {}
- public virtual void SendMsg(int id, object msg) {}
- }
|