lvjincheng 4 жил өмнө
parent
commit
895c69f9f1

+ 1 - 1
Assets/BowArrow/Scripts/Game/ArmBow.cs

@@ -125,8 +125,8 @@ public class ArmBow : MonoBehaviour
 
     void shoot() {
         // 筛选出一个稳定的发射角度---start
-        Quaternion best_rotation = this.bowCamera.transform.rotation; //最终的结果包含shootBackTime处理
         Quaternion best_best_rotation = this.bowCamera.transform.rotation; //最终的结果不包含shootBackTime处理
+        Quaternion best_rotation = this.bowCamera.transform.rotation; //最终的结果包含shootBackTime处理
         if (recordCount >= recordRotations.Length) {
             int single_check_count = 6;
             float min_wave = float.MaxValue;

+ 70 - 19
Assets/BowArrow/Scripts/Game/Arrow.cs

@@ -29,21 +29,33 @@ public class Arrow : MonoBehaviour
             mySpeed *= (1 + GameAssistUI.ins.shootScaleValue);
         } 
 
-        //瞄准靶子发射时,自动调整仰角
         if (raycastHit.transform && raycastHit.transform.gameObject.name == "TargetBody") {
-            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;
-                }
-            }
-
             //把瞄准点画成红圈,渲染在靶子上
             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;
@@ -53,28 +65,32 @@ public class Arrow : MonoBehaviour
         cameraTF.gameObject.AddComponent<ArrowCamera>().arrow = this;
 
         this.activeEffectTrail(true);
+
+        //如果有自动调整发射角,则禁用物理运动
+        if (hasParabolaAngle) {
+            this.GetComponent<BoxCollider>().enabled = false;
+            Destroy(newRigidbody);
+        }
     }
 
+
+    bool hasParabolaAngle = false;
+    float parabolaAngleInRadius = 0;
     void ApplyParabolaAngle(Vector3 destination)
     {
-        Vector3 backVec = -this.transform.forward * 0.8f; //如果因为物理系统误差导致落点出现上下偏移,可以调整该参数
         float deltaX = Vector2.Distance(
             new Vector2(destination.x, destination.z), 
-            new Vector2(this.transform.position.x + backVec.x, this.transform.position.z + backVec.z)
+            new Vector2(this.transform.position.x, this.transform.position.z)
         );
-        float deltaY = destination.y - (this.transform.position.y + backVec.y);
+        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;
-        if (Mathf.Pow(b, 2) - 4 * a * c >= 0) {
+        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);
-            float angle1 = Mathf.Atan(res1) / Mathf.PI * 180;
-            float angle2 = Mathf.Atan(res2) / Mathf.PI * 180;
-            float angleX = Mathf.Min(angle1, angle2);
-            Vector3 finalAngle = this.transform.eulerAngles;
-            finalAngle = new Vector3(-angleX, finalAngle.y, finalAngle.z);
-            this.transform.localRotation = Quaternion.Euler(finalAngle);
+            parabolaAngleInRadius = Mathf.Min(Mathf.Atan(res1), Mathf.Atan(res2));
         }   
     }
 
@@ -109,6 +125,41 @@ public class Arrow : MonoBehaviour
         // 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<BoxCollider>().enabled = false;
         if (newRigidbody) {

+ 21 - 17
Assets/BowArrow/Scripts/Game/TargetBody.cs

@@ -24,25 +24,29 @@ public class TargetBody : MonoBehaviour
         Arrow arrow = collision.transform.GetComponent<Arrow>();
         if (arrow)
         {
-            arrow.transform.Find("Head").position = collision.contacts[0].point;
-            arrow.Hit();
-            AudioMgr.ins.PlayHit(AudioMgr.GetAudioSource(this.gameObject));
-            bool hitTarget = false;
-            if (arrow.armBow.validTargets.Contains(this)) {
-                float maxSize = Vector3.Distance(this.transform.Find("CenterPoint").position, this.transform.Find("SidePoint").position);
-                float radius = this.measureRadius(collision.contacts[0].point);
-                int score = 10 - Mathf.FloorToInt(radius / maxSize * 10);
-                if (score > 0) {
-                    GameMgr.ins.gameMode.HitTarget(score);
-                    AudioMgr.ins.PlayCheer(true);
-                    hitTarget = true;
-                }
-            }
-            if (!hitTarget) {
-                GameMgr.ins.gameMode.HitTarget(0);
-                AudioMgr.ins.PlayCheer(false);
+            Hit(arrow, collision.contacts[0].point);
+        }
+    }
+
+    public void Hit(Arrow arrow, Vector3 hitPosition) {
+        arrow.transform.Find("Head").position = hitPosition;
+        arrow.Hit();
+        AudioMgr.ins.PlayHit(AudioMgr.GetAudioSource(this.gameObject));
+        bool hitTarget = false;
+        if (arrow.armBow.validTargets.Contains(this)) {
+            float maxSize = Vector3.Distance(this.transform.Find("CenterPoint").position, this.transform.Find("SidePoint").position);
+            float radius = this.measureRadius(hitPosition);
+            int score = 10 - Mathf.FloorToInt(radius / maxSize * 10);
+            if (score > 0) {
+                GameMgr.ins.gameMode.HitTarget(score);
+                AudioMgr.ins.PlayCheer(true);
+                hitTarget = true;
             }
         }
+        if (!hitTarget) {
+            GameMgr.ins.gameMode.HitTarget(0);
+            AudioMgr.ins.PlayCheer(false);
+        }
     }
 
     float measureRadius(Vector3 position) {