|
|
@@ -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) {
|