using System.Collections.Generic; using UnityEngine; using DG.Tweening; public class Arrow : MonoBehaviour { private Rigidbody newRigidbody; public Vector3 shootOutPosition; public float flyTime = 0; public bool isHit = false; public RaycastHit raycastHit; public RaycastHit raycastHit1; private float mySpeed = 0; public bool simulatedParabola = false; //模拟抛物线 public ArmBow armBow; public static float speed = GameMgr.RealSizeToGameSize(60); void Awake() { GameMgr.ins.gameMode.PauseTimeCounting(this); } void Start() { newRigidbody = this.gameObject.AddComponent(); mySpeed = speed; if (GameAssistUI.ins) { mySpeed *= (1 + GameAssistUI.ins.shootScaleValue); } if (raycastHit.transform && raycastHit.transform.gameObject.name == "TargetBody") { //把瞄准点画成红圈,渲染在靶子上 Transform redCircle = TargetBody.ins.transform.Find("RedCircle"); redCircle.gameObject.SetActive(true); redCircle.transform.position = -redCircle.transform.forward * 0.001f + raycastHit.point; } //目标落点在靶子时,调整仰角,走Update模式 if (raycastHit1.transform && raycastHit1.transform.gameObject.name == "TargetBody") { ApplyParabolaAngle(raycastHit1.point); //有几率进入抛物线观看镜头 float distance = TargetBody.ins.GetDistance(); if (Mathf.RoundToInt(distance) >= 50) { if (Random.value < 0.5) simulatedParabola = true; } } else { //目标落点不在靶子,瞄准点在靶子时,调整仰角,走物理模式 if (raycastHit.transform && raycastHit.transform.gameObject.name == "TargetBody") { ApplyParabolaAngle(raycastHit.point); if (hasParabolaAngle) { hasParabolaAngle = false; float angleX = parabolaAngleInRadius / Mathf.PI * 180; Vector3 eulerAngle = this.transform.eulerAngles; eulerAngle.x = -angleX; this.transform.eulerAngles = eulerAngle; } } } newRigidbody.velocity = this.transform.forward * mySpeed; newRigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; Transform cameraTF = this.transform.Find("Camera"); cameraTF.gameObject.SetActive(true); cameraTF.gameObject.AddComponent().arrow = this; this.activeEffectTrail(true); //如果有自动调整发射角,则禁用物理运动 if (hasParabolaAngle) { this.GetComponent().enabled = false; Destroy(newRigidbody); } } bool hasParabolaAngle = false; float parabolaAngleInRadius = 0; void ApplyParabolaAngle(Vector3 destination) { float deltaX = Vector2.Distance( new Vector2(destination.x, destination.z), new Vector2(this.transform.position.x, this.transform.position.z) ); float deltaY = destination.y - this.transform.position.y; float a = 0.5f * Physics.gravity.y * Mathf.Pow(deltaX, 2) / Mathf.Pow(this.mySpeed, 2); float b = deltaX; float c = a - deltaY; hasParabolaAngle = Mathf.Pow(b, 2) - 4 * a * c >= 0; if (hasParabolaAngle) { float res1 = (-b + Mathf.Pow(Mathf.Pow(b, 2) - 4*a*c, 0.5f)) / (2 * a); float res2 = (-b - Mathf.Pow(Mathf.Pow(b, 2) - 4*a*c, 0.5f)) / (2 * a); parabolaAngleInRadius = Mathf.Min(Mathf.Atan(res1), Mathf.Atan(res2)); } } void OnDestroy() { GameMgr.ins.gameMode.ResumeTimeCounting(this); if (this.newRigidbody) { Destroy(this.newRigidbody); } } Vector3 position; Quaternion rotation; void FixedUpdate() { if (newRigidbody) { transform.forward = newRigidbody.velocity.normalized; } if (!isHit && flyTime >= 0) { flyTime += Time.deltaTime; this.position = this.transform.position; this.rotation = this.transform.rotation; if (flyTime > 14) { Destroy(gameObject); GameMgr.ins.gameMode.HitTarget(0); AudioMgr.ins.PlayCheer(false); nextShoot(); } this.UpdateRotate(); } // this.UpdateShake(); } void Update() { UpdateFlyWithoutPhysics(); } float flyTimeWithoutPhysics = 0; void UpdateFlyWithoutPhysics() { if (!hasParabolaAngle || isHit) return; flyTimeWithoutPhysics += Time.deltaTime; Vector3 destination = raycastHit1.point; float deltaX = Mathf.Sqrt( Mathf.Pow(destination.x - shootOutPosition.x, 2) + Mathf.Pow(destination.z - shootOutPosition.z, 2) ); float vx = Mathf.Cos(parabolaAngleInRadius) * mySpeed; float t = deltaX / vx; if (flyTimeWithoutPhysics < t) { t = flyTimeWithoutPhysics; } float vy = Mathf.Sin(parabolaAngleInRadius) * mySpeed + Physics.gravity.y * t; float dy = Mathf.Sin(parabolaAngleInRadius) * mySpeed * t + 0.5f * Physics.gravity.y * Mathf.Pow(t, 2); float dx = vx * t; Vector3 nextPosition = new Vector3(destination.x - shootOutPosition.x, 0, destination.z - shootOutPosition.z); nextPosition = nextPosition.normalized * dx; nextPosition.y = shootOutPosition.y + dy; this.transform.position = nextPosition; Vector3 eulerAngles = this.transform.eulerAngles; float angleX = Mathf.Atan(vy / vx) / Mathf.PI * 180; eulerAngles.x = -angleX; this.transform.eulerAngles = eulerAngles; //箭头到达目标点时,触发碰撞(之所以用以下,是因为箭的锚点在尾部,而箭的长度接近1.1) if (Vector3.Distance(nextPosition, destination) < 1.1f) { TargetBody.ins.Hit(this, destination); } } public void Hit() { gameObject.GetComponent().enabled = false; if (newRigidbody) { newRigidbody.useGravity = false; newRigidbody.velocity = Vector3.zero; Destroy(newRigidbody); newRigidbody = null; } isHit = true; // this.Shake(); this.activeEffectCyclone(false); this.activeEffectBomb(true); this.activeEffectTrail(false); //最新一箭击中后会发光标记 ArrowLightSick.RecoveryAll(); this.GetComponentInChildren().Hit(); } public Vector3 getHeadPosition() { return this.transform.Find("Head").position; } /**箭矢旋转 */ private Vector3 rotateV3 = new Vector3(0, 0, 1400); private void UpdateRotate() { this.transform.Find("Head").Rotate(rotateV3 * Time.deltaTime, Space.Self); } /**箭矢震动 */ private bool shaking = false; private float shakeTime = 0; private float shakeTimeMax = 0.5f; private float shakeRange = 5; private int shakeDirection = 1; private Vector3 shakeAngles = new Vector3(); private void Shake() { this.shaking = true; this.shakeTime = 0; this.shakeDirection = 1; } private void UpdateShake() { if (!this.shaking) { return; } Transform transform = this.transform.Find("Head").transform; float shakeRangeNow = (1 - this.shakeTime / this.shakeTimeMax) * this.shakeRange; if (shakeRangeNow <= 0) {//震动结束 this.shaking = false; this.shakeAngles.x = 0; } else { this.shakeAngles.x = -this.shakeDirection * shakeRangeNow; this.shakeDirection *= -1; } transform.localEulerAngles = this.shakeAngles; this.shakeTime += Time.deltaTime; } //进入下一轮射击 bool hasDoneNextShoot = false; public void nextShoot() { if (hasDoneNextShoot) return; hasDoneNextShoot = true; GameMgr.ins.gameMode.ResumeTimeCounting(this); if (!GameMgr.ins.gameMode.DoNextShoot()) return; this.armBow.readyShoot(); //把瞄准点画成红圈,渲染在靶子上(取消) Transform redCircle = TargetBody.ins.transform.Find("RedCircle"); redCircle.gameObject.SetActive(false); //最新一箭击中后会发光标记(取消) ArrowLightSick.RecoveryAll(); } void OnCollisionEnter(Collision collision) { if ((1 << collision.gameObject.layer) != LayerMask.GetMask("Target")) { this.Hit(); GameMgr.ins.gameMode.HitTarget(0); AudioMgr.ins.PlayCheer(false); } this.transform.SetParent(collision.transform.parent); } public void activeEffectCyclone(bool value) { this.transform.Find("Head/EF_kuosanquan").gameObject.SetActive(value); if (!value) return; ParticleSystemRenderer ps = this.transform.Find("Head/EF_kuosanquan/kuosan").GetComponent(); ParticleSystemRenderer ps1 = this.transform.Find("Head/EF_kuosanquan/kuosan (1)").GetComponent(); DOTween.To(() => ps.minParticleSize, value => { ps.minParticleSize = value; ps.maxParticleSize = value; }, 0.4f, 0.6f); DOTween.To(() => ps1.minParticleSize, value => { ps1.minParticleSize = value; ps1.maxParticleSize = value; }, 0.8f, 0.6f); } void activeEffectBomb(bool value) { this.transform.Find("Head/EF_baodian").gameObject.SetActive(value); } void activeEffectTrail(bool value) { this.transform.Find("EF_tuowei").gameObject.SetActive(value); this.transform.Find("EF_tuowei/Trail").GetComponent().time = 1.6f / mySpeed; } }