VR模拟枪支打靶,消灭鬼怪,换弹以及上弦等等硬核枪支操作。 使用HTCVive设备,开启SteamVR进行游玩。
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

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;
}
}
}
}