You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
5.2 KiB
162 lines
5.2 KiB
3 years ago
|
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. ===========
|
||
|
|
||
|
using UnityEngine;
|
||
|
using HTC.UnityPlugin.Utility;
|
||
|
|
||
|
namespace HTC.UnityPlugin.Pointer3D
|
||
|
{
|
||
|
public class ProjectileGenerator : BaseRaySegmentGenerator
|
||
|
{
|
||
|
public float velocity = 2f;
|
||
|
public Vector3 gravity = Vector3.down;
|
||
|
|
||
|
private float m_velocity;
|
||
|
private Vector3 m_gravity;
|
||
|
|
||
|
private float maxHalfJourney;// maximum distance if projectile angle equals to 45 degree using given velocity
|
||
|
private float accY;// vertical accelerate
|
||
|
|
||
|
private Vector3 systemY;
|
||
|
private Vector3 systemX;
|
||
|
|
||
|
private Vector3 v0;// initial velocity vector
|
||
|
private float v0X;// initial horizontal velocity
|
||
|
private float v0Y;// initial vertical velocity
|
||
|
private bool isHeighPeek;// if included angle between v0 and systemX is larger then 45 degree
|
||
|
private float halfJourney;// half maximum distance of projectile
|
||
|
|
||
|
private float contactPointTime;
|
||
|
private float nextContactPointTime;
|
||
|
private float rayDistance;
|
||
|
private float nextRayDistance;
|
||
|
|
||
|
private void CalculateAcc()
|
||
|
{
|
||
|
accY = -gravity.magnitude;
|
||
|
}
|
||
|
|
||
|
private void CalculatePeekDistanceMax()
|
||
|
{
|
||
|
maxHalfJourney = 0.5f * velocity * velocity / Mathf.Abs(accY);
|
||
|
}
|
||
|
|
||
|
protected override void Start()
|
||
|
{
|
||
|
base.Start();
|
||
|
CalculateAcc();
|
||
|
CalculatePeekDistanceMax();
|
||
|
}
|
||
|
|
||
|
public override void ResetSegments()
|
||
|
{
|
||
|
var velocityChanged = ChangeProp.Set(ref m_velocity, velocity);
|
||
|
var gravityChanged = ChangeProp.Set(ref m_gravity, gravity);
|
||
|
|
||
|
if (gravityChanged)
|
||
|
{
|
||
|
CalculateAcc();
|
||
|
}
|
||
|
|
||
|
if (velocityChanged || gravityChanged)
|
||
|
{
|
||
|
CalculatePeekDistanceMax();
|
||
|
}
|
||
|
|
||
|
systemY = -gravity;
|
||
|
systemX = transform.forward;
|
||
|
Vector3.OrthoNormalize(ref systemY, ref systemX);
|
||
|
|
||
|
v0 = transform.forward * velocity;
|
||
|
v0X = Vector3.Dot(v0, systemX);
|
||
|
v0Y = Vector3.Dot(v0, systemY);
|
||
|
isHeighPeek = Mathf.Abs(v0Y) > Mathf.Abs(v0X);
|
||
|
|
||
|
contactPointTime = v0Y / accY;
|
||
|
halfJourney = Mathf.Abs(contactPointTime);
|
||
|
|
||
|
rayDistance = nextRayDistance = 0f;
|
||
|
}
|
||
|
|
||
|
public override bool NextSegment(out Vector3 direction, out float distance)
|
||
|
{
|
||
|
if (isHeighPeek)
|
||
|
{
|
||
|
if (contactPointTime < 0f)
|
||
|
{
|
||
|
nextContactPointTime = 0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextContactPointTime = contactPointTime + halfJourney;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (contactPointTime < 0f)
|
||
|
{
|
||
|
nextContactPointTime = 0f;
|
||
|
}
|
||
|
else if (contactPointTime == 0f)
|
||
|
{
|
||
|
if (halfJourney == 0f)
|
||
|
{
|
||
|
nextContactPointTime = contactPointTime + maxHalfJourney * 0.3f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextContactPointTime = contactPointTime + halfJourney;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// cap to maxHalfJourney to avoid small segment
|
||
|
//nextContactPointTime = contactPointTime + maxHalfJourney;
|
||
|
nextContactPointTime = contactPointTime + Mathf.Lerp(halfJourney, maxHalfJourney, 0.3f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var lastDistance = rayDistance;
|
||
|
GetTangentLineIntersectDistance(contactPointTime, nextContactPointTime, out rayDistance, out nextRayDistance, out direction);
|
||
|
distance = rayDistance + lastDistance;
|
||
|
|
||
|
// shift for next iteration
|
||
|
rayDistance = nextRayDistance;
|
||
|
contactPointTime = nextContactPointTime;
|
||
|
|
||
|
if (distance <= Pointer3DRaycaster.MIN_SEGMENT_DISTANCE)
|
||
|
{
|
||
|
distance = Pointer3DRaycaster.MIN_SEGMENT_DISTANCE;
|
||
|
//NextSegment(out direction, out distance);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private void GetTangentLineIntersectDistance(float tA, float tB, out float dA, out float dB, out Vector3 directionA)
|
||
|
{
|
||
|
if (tA == tB)
|
||
|
{
|
||
|
dA = dB = 0f;
|
||
|
|
||
|
directionA = (systemY * (accY * tA / v0X) + systemX).normalized;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var vA = new Vector2(v0X * tA, 0.5f * accY * tA * tA);
|
||
|
var vB = new Vector2(v0X * tB, 0.5f * accY * tB * tB);
|
||
|
var mA = accY * tA / v0X;
|
||
|
var mB = accY * tB / v0X;
|
||
|
|
||
|
// C is intersect point between line through A and line through B
|
||
|
var vC = default(Vector2);
|
||
|
vC.x = (mA * vA.x - mB * vB.x - vA.y + vB.y) / (mA - mB);
|
||
|
vC.y = mA * (vC.x - vA.x) + vA.y;
|
||
|
|
||
|
dA = (vC - vA).magnitude;
|
||
|
dB = (vC - vB).magnitude;
|
||
|
|
||
|
directionA = (systemY * mA + systemX).normalized;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|