|
@@ -57,49 +57,64 @@ public class Arrow : MonoBehaviour
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**在箭飞行前初始化&如果瞄准射线的落点在靶子上时,才调用该函数 */
|
|
|
void SetUpBeforFly()
|
|
void SetUpBeforFly()
|
|
|
{
|
|
{
|
|
|
|
|
+ //看能否通过调整发射角让箭落在靶子的瞄准点上
|
|
|
CalculateParabolaAngle(absoluteRay.point);
|
|
CalculateParabolaAngle(absoluteRay.point);
|
|
|
|
|
|
|
|
- if (!hasParabolaAngle) {
|
|
|
|
|
|
|
+ if (!hasParabolaAngle) { //发射角无解,就提示用户
|
|
|
if (AimLoadChecker.ins) AimLoadChecker.ins.ShowOutTip();
|
|
if (AimLoadChecker.ins) AimLoadChecker.ins.ShowOutTip();
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+ //来到这里,证明发射角有解,该解姑且叫它绝对角
|
|
|
|
|
|
|
|
|
|
+ //因为Unity引擎的规则,向上时359~270度,向下是0~90度
|
|
|
|
|
+ //为了方便数学运算,换算成 向上时0~90度,向下是0~-90度
|
|
|
float baseAngleX = this.transform.eulerAngles.x;
|
|
float baseAngleX = this.transform.eulerAngles.x;
|
|
|
if (baseAngleX > 180) baseAngleX = baseAngleX - 360;
|
|
if (baseAngleX > 180) baseAngleX = baseAngleX - 360;
|
|
|
baseAngleX *= -1;
|
|
baseAngleX *= -1;
|
|
|
|
|
|
|
|
|
|
+ //绝对角
|
|
|
float absoluteAngleX = parabolaAngleInRadian / Mathf.PI * 180;
|
|
float absoluteAngleX = parabolaAngleInRadian / Mathf.PI * 180;
|
|
|
|
|
|
|
|
|
|
+ //客户要求绝对角跟原本角度相差不能超过 maxDeltaAngleX
|
|
|
float deltaAngleX = absoluteAngleX - baseAngleX;
|
|
float deltaAngleX = absoluteAngleX - baseAngleX;
|
|
|
float maxDeltaAngleX = 5;
|
|
float maxDeltaAngleX = 5;
|
|
|
|
|
|
|
|
|
|
+ //最终的角还要加上偏移角度,偏移角也是客户要求加,单纯是为了增加误差,简单模式偏移角度为0
|
|
|
float finalAngleX = this.offsetAngle;
|
|
float finalAngleX = this.offsetAngle;
|
|
|
|
|
+ //如果绝对角跟原本角度相差超过 maxDeltaAngleX,就不能用绝对角了,直接在原本角度上加上最大差角
|
|
|
if (Mathf.Abs(deltaAngleX) > maxDeltaAngleX) {
|
|
if (Mathf.Abs(deltaAngleX) > maxDeltaAngleX) {
|
|
|
finalAngleX += baseAngleX;
|
|
finalAngleX += baseAngleX;
|
|
|
finalAngleX += deltaAngleX > 0 ? maxDeltaAngleX : -maxDeltaAngleX;
|
|
finalAngleX += deltaAngleX > 0 ? maxDeltaAngleX : -maxDeltaAngleX;
|
|
|
if (AimLoadChecker.ins) AimLoadChecker.ins.ShowOutTip();
|
|
if (AimLoadChecker.ins) AimLoadChecker.ins.ShowOutTip();
|
|
|
- } else {
|
|
|
|
|
|
|
+ } else {//不超过就最好,直接用绝对角
|
|
|
finalAngleX += absoluteAngleX;
|
|
finalAngleX += absoluteAngleX;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ //拆分两轴的速度
|
|
|
float vy = Mathf.Sin(finalAngleX / 180 * Mathf.PI) * this.mySpeed;
|
|
float vy = Mathf.Sin(finalAngleX / 180 * Mathf.PI) * this.mySpeed;
|
|
|
float vx = Mathf.Cos(finalAngleX / 180 * Mathf.PI) * this.mySpeed;
|
|
float vx = Mathf.Cos(finalAngleX / 180 * Mathf.PI) * this.mySpeed;
|
|
|
|
|
+ //x轴距离
|
|
|
float deltaX = Mathf.Sqrt(
|
|
float deltaX = Mathf.Sqrt(
|
|
|
Mathf.Pow(absoluteRay.point.x - this.shootOutPosition.x, 2) +
|
|
Mathf.Pow(absoluteRay.point.x - this.shootOutPosition.x, 2) +
|
|
|
Mathf.Pow(absoluteRay.point.z - this.shootOutPosition.z, 2)
|
|
Mathf.Pow(absoluteRay.point.z - this.shootOutPosition.z, 2)
|
|
|
);
|
|
);
|
|
|
|
|
+ //x方向的耗时
|
|
|
float tx = deltaX / vx;
|
|
float tx = deltaX / vx;
|
|
|
|
|
+ //最终y轴的位移
|
|
|
float dy = vy * tx + 0.5f * Physics.gravity.y * tx * tx;
|
|
float dy = vy * tx + 0.5f * Physics.gravity.y * tx * tx;
|
|
|
|
|
|
|
|
- if (Mathf.Abs(dy) < 0.62f) { //在靶子范围内,则用update运算物理
|
|
|
|
|
|
|
+ float tbRadius = 0.62f;//靶子半径
|
|
|
|
|
+ //之所以这样比较,是因为发射位置跟靶子中心是等高的,靶子半径是已知的
|
|
|
|
|
+ if (Mathf.Abs(dy) < tbRadius) { //在靶子范围内,则用update运算物理
|
|
|
finalPoint = absoluteRay.point;
|
|
finalPoint = absoluteRay.point;
|
|
|
finalPoint.y = absoluteRay.transform.parent.position.y + dy;
|
|
finalPoint.y = absoluteRay.transform.parent.position.y + dy;
|
|
|
useUpdatePhysics = true;
|
|
useUpdatePhysics = true;
|
|
|
parabolaAngleInRadian = finalAngleX / 180 * Mathf.PI;
|
|
parabolaAngleInRadian = finalAngleX / 180 * Mathf.PI;
|
|
|
RandomUseSideCamera();
|
|
RandomUseSideCamera();
|
|
|
- } else {
|
|
|
|
|
|
|
+ } else { //否则,调下角度就好,到时候用unity物理运算
|
|
|
Vector3 eulerAngle = this.transform.eulerAngles;
|
|
Vector3 eulerAngle = this.transform.eulerAngles;
|
|
|
eulerAngle.x = -finalAngleX;
|
|
eulerAngle.x = -finalAngleX;
|
|
|
this.transform.eulerAngles = eulerAngle;
|
|
this.transform.eulerAngles = eulerAngle;
|
|
@@ -114,8 +129,34 @@ public class Arrow : MonoBehaviour
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**发射角有无解 */
|
|
|
bool hasParabolaAngle = false;
|
|
bool hasParabolaAngle = false;
|
|
|
|
|
+ /**发射角弧度解 */
|
|
|
float parabolaAngleInRadian = 0;
|
|
float parabolaAngleInRadian = 0;
|
|
|
|
|
+ /**
|
|
|
|
|
+ 求弓箭发射到指定坐标所需要的角度。
|
|
|
|
|
+ 已知初速度大小V,重力g,起始坐标(a1,a2),目标坐标(b1,b2)。
|
|
|
|
|
+ 解:
|
|
|
|
|
+ 1、列出关系式
|
|
|
|
|
+ Δx = b1 - a1;
|
|
|
|
|
+ Δy = b2 - a2;
|
|
|
|
|
+ Vx = V * cos(angle)
|
|
|
|
|
+ Vy = V * sin(angle)
|
|
|
|
|
+ Vy * t + 1/2 * g * t^2 = Δy
|
|
|
|
|
+ Vx * t = Δx
|
|
|
|
|
+ t = Δx / Vx
|
|
|
|
|
+ 2、推导过程
|
|
|
|
|
+ (V * sin(angle)) * Δx / (V * cos(angle)) + 1/2 * g * Δx^2 / (V^2*cos(angle)^2) = Δy
|
|
|
|
|
+ tan(angle) * Δx + 1/2 * g * Δx^2 / (V^2*cos(angle)^2) = Δy
|
|
|
|
|
+ tan(angle) * Δx + 1/2 * g * (Δx^2 / V^2) * (1 + tan(angle)^2) = Δy
|
|
|
|
|
+ 3、根据求根公式得出结论
|
|
|
|
|
+ a = 1/2 * g * Δx^2 / V^2
|
|
|
|
|
+ b = Δx
|
|
|
|
|
+ c = a - Δy
|
|
|
|
|
+ d = tan(angle) = (-b ± (b^2 - 4*a*c)^0.5) / (2*a)
|
|
|
|
|
+ angle = atan(d)
|
|
|
|
|
+ 有无根的判别式,有根则b^2-4*a*c>=0
|
|
|
|
|
+ */
|
|
|
void CalculateParabolaAngle(Vector3 destination)
|
|
void CalculateParabolaAngle(Vector3 destination)
|
|
|
{
|
|
{
|
|
|
float deltaX = Vector2.Distance(
|
|
float deltaX = Vector2.Distance(
|
|
@@ -142,9 +183,6 @@ public class Arrow : MonoBehaviour
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Vector3 position;
|
|
|
|
|
- Quaternion rotation;
|
|
|
|
|
-
|
|
|
|
|
void FixedUpdate()
|
|
void FixedUpdate()
|
|
|
{
|
|
{
|
|
|
if (newRigidbody) {
|
|
if (newRigidbody) {
|
|
@@ -152,8 +190,6 @@ public class Arrow : MonoBehaviour
|
|
|
}
|
|
}
|
|
|
if (!isHit && flyTime >= 0) {
|
|
if (!isHit && flyTime >= 0) {
|
|
|
flyTime += Time.deltaTime;
|
|
flyTime += Time.deltaTime;
|
|
|
- this.position = this.transform.position;
|
|
|
|
|
- this.rotation = this.transform.rotation;
|
|
|
|
|
if (flyTime > 14) {
|
|
if (flyTime > 14) {
|
|
|
Destroy(gameObject);
|
|
Destroy(gameObject);
|
|
|
GameMgr.ins.gameMode.HitTarget(0);
|
|
GameMgr.ins.gameMode.HitTarget(0);
|
|
@@ -172,6 +208,7 @@ public class Arrow : MonoBehaviour
|
|
|
bool useUpdatePhysics = false;
|
|
bool useUpdatePhysics = false;
|
|
|
float flyTimeWithoutPhysics = 0;
|
|
float flyTimeWithoutPhysics = 0;
|
|
|
Vector3 finalPoint = default;
|
|
Vector3 finalPoint = default;
|
|
|
|
|
+ /**更新箭的飞行轨迹(非Unity物理运算)*/
|
|
|
void UpdateFlyWithoutPhysics() {
|
|
void UpdateFlyWithoutPhysics() {
|
|
|
if (!useUpdatePhysics || isHit) return;
|
|
if (!useUpdatePhysics || isHit) return;
|
|
|
flyTimeWithoutPhysics += Time.deltaTime;
|
|
flyTimeWithoutPhysics += Time.deltaTime;
|