312 lines
11 KiB
C#
312 lines
11 KiB
C#
|
//======= Copyright (c) Valve Corporation, All rights reserved. ===============
|
|||
|
//
|
|||
|
// Purpose: Displays the arc lines for teleporting and does the traces
|
|||
|
//
|
|||
|
//=============================================================================
|
|||
|
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace Valve.VR.InteractionSystem
|
|||
|
{
|
|||
|
//-------------------------------------------------------------------------
|
|||
|
public class TeleportArc : MonoBehaviour
|
|||
|
{
|
|||
|
public int segmentCount = 60;
|
|||
|
public float thickness = 0.01f;
|
|||
|
|
|||
|
[Tooltip("The amount of time in seconds to predict the motion of the projectile.")]
|
|||
|
public float arcDuration = 3.0f;
|
|||
|
|
|||
|
[Tooltip("The amount of time in seconds between each segment of the projectile.")]
|
|||
|
public float segmentBreak = 0.025f;
|
|||
|
|
|||
|
[Tooltip("The speed at which the line segments of the arc move.")]
|
|||
|
public float arcSpeed = 0.2f;
|
|||
|
|
|||
|
public Material material;
|
|||
|
|
|||
|
[HideInInspector]
|
|||
|
public int traceLayerMask = 0;
|
|||
|
|
|||
|
//Private data
|
|||
|
private LineRenderer[] lineRenderers;
|
|||
|
private float arcTimeOffset = 0.0f;
|
|||
|
private float prevThickness = 0.0f;
|
|||
|
private int prevSegmentCount = 0;
|
|||
|
private bool showArc = true;
|
|||
|
private Vector3 startPos;
|
|||
|
private Vector3 projectileVelocity;
|
|||
|
private bool useGravity = true;
|
|||
|
private Transform arcObjectsTransfrom;
|
|||
|
private bool arcInvalid = false;
|
|||
|
private float scale = 1;
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
void Start()
|
|||
|
{
|
|||
|
arcTimeOffset = Time.time;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
void Update()
|
|||
|
{
|
|||
|
//scale arc to match player scale
|
|||
|
scale = Player.instance.transform.lossyScale.x;
|
|||
|
if (thickness != prevThickness || segmentCount != prevSegmentCount)
|
|||
|
{
|
|||
|
CreateLineRendererObjects();
|
|||
|
prevThickness = thickness;
|
|||
|
prevSegmentCount = segmentCount;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
private void CreateLineRendererObjects()
|
|||
|
{
|
|||
|
//Destroy any existing line renderer objects
|
|||
|
if (arcObjectsTransfrom != null)
|
|||
|
{
|
|||
|
Destroy(arcObjectsTransfrom.gameObject);
|
|||
|
}
|
|||
|
|
|||
|
GameObject arcObjectsParent = new GameObject("ArcObjects");
|
|||
|
arcObjectsTransfrom = arcObjectsParent.transform;
|
|||
|
arcObjectsTransfrom.SetParent(this.transform);
|
|||
|
|
|||
|
//Create new line renderer objects
|
|||
|
lineRenderers = new LineRenderer[segmentCount];
|
|||
|
for (int i = 0; i < segmentCount; ++i)
|
|||
|
{
|
|||
|
GameObject newObject = new GameObject("LineRenderer_" + i);
|
|||
|
newObject.transform.SetParent(arcObjectsTransfrom);
|
|||
|
|
|||
|
lineRenderers[i] = newObject.AddComponent<LineRenderer>();
|
|||
|
|
|||
|
lineRenderers[i].receiveShadows = false;
|
|||
|
lineRenderers[i].reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
|
|||
|
lineRenderers[i].lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
|
|||
|
lineRenderers[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
|||
|
lineRenderers[i].material = material;
|
|||
|
#if (UNITY_5_4)
|
|||
|
lineRenderers[i].SetWidth(thickness, thickness);
|
|||
|
#else
|
|||
|
lineRenderers[i].startWidth = thickness * scale;
|
|||
|
lineRenderers[i].endWidth = thickness * scale;
|
|||
|
#endif
|
|||
|
lineRenderers[i].enabled = false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
public void SetArcData(Vector3 position, Vector3 velocity, bool gravity, bool pointerAtBadAngle)
|
|||
|
{
|
|||
|
startPos = position;
|
|||
|
projectileVelocity = velocity;
|
|||
|
useGravity = gravity;
|
|||
|
|
|||
|
if (arcInvalid && !pointerAtBadAngle)
|
|||
|
{
|
|||
|
arcTimeOffset = Time.time;
|
|||
|
}
|
|||
|
arcInvalid = pointerAtBadAngle;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
public void Show()
|
|||
|
{
|
|||
|
showArc = true;
|
|||
|
if (lineRenderers == null)
|
|||
|
{
|
|||
|
CreateLineRendererObjects();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
public void Hide()
|
|||
|
{
|
|||
|
//Hide the line segments if they were previously being shown
|
|||
|
if (showArc)
|
|||
|
{
|
|||
|
HideLineSegments(0, segmentCount);
|
|||
|
}
|
|||
|
showArc = false;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
// Draws each segment of the arc individually
|
|||
|
//-------------------------------------------------
|
|||
|
public bool DrawArc(out RaycastHit hitInfo)
|
|||
|
{
|
|||
|
float timeStep = arcDuration / segmentCount;
|
|||
|
|
|||
|
float currentTimeOffset = (Time.time - arcTimeOffset) * arcSpeed;
|
|||
|
|
|||
|
//Reset the arc time offset when it has gone beyond a segment length
|
|||
|
if (currentTimeOffset > (timeStep + segmentBreak))
|
|||
|
{
|
|||
|
arcTimeOffset = Time.time;
|
|||
|
currentTimeOffset = 0.0f;
|
|||
|
}
|
|||
|
|
|||
|
float segmentStartTime = currentTimeOffset;
|
|||
|
|
|||
|
float arcHitTime = FindProjectileCollision(out hitInfo);
|
|||
|
|
|||
|
if (arcInvalid)
|
|||
|
{
|
|||
|
//Only draw first segment
|
|||
|
lineRenderers[0].enabled = true;
|
|||
|
lineRenderers[0].SetPosition(0, GetArcPositionAtTime(0.0f));
|
|||
|
lineRenderers[0].SetPosition(1, GetArcPositionAtTime(arcHitTime < timeStep ? arcHitTime : timeStep));
|
|||
|
|
|||
|
HideLineSegments(1, segmentCount);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//Draw the first segment outside the loop if needed
|
|||
|
int loopStartSegment = 0;
|
|||
|
if (segmentStartTime > segmentBreak)
|
|||
|
{
|
|||
|
float firstSegmentEndTime = currentTimeOffset - segmentBreak;
|
|||
|
if (arcHitTime < firstSegmentEndTime)
|
|||
|
{
|
|||
|
firstSegmentEndTime = arcHitTime;
|
|||
|
}
|
|||
|
DrawArcSegment(0, 0.0f, firstSegmentEndTime);
|
|||
|
|
|||
|
loopStartSegment = 1;
|
|||
|
}
|
|||
|
|
|||
|
bool stopArc = false;
|
|||
|
int currentSegment = 0;
|
|||
|
if (segmentStartTime < arcHitTime)
|
|||
|
{
|
|||
|
for (currentSegment = loopStartSegment; currentSegment < segmentCount; ++currentSegment)
|
|||
|
{
|
|||
|
//Clamp the segment end time to the arc duration
|
|||
|
float segmentEndTime = segmentStartTime + timeStep;
|
|||
|
if (segmentEndTime >= arcDuration)
|
|||
|
{
|
|||
|
segmentEndTime = arcDuration;
|
|||
|
stopArc = true;
|
|||
|
}
|
|||
|
|
|||
|
if (segmentEndTime >= arcHitTime)
|
|||
|
{
|
|||
|
segmentEndTime = arcHitTime;
|
|||
|
stopArc = true;
|
|||
|
}
|
|||
|
|
|||
|
DrawArcSegment(currentSegment, segmentStartTime, segmentEndTime);
|
|||
|
|
|||
|
segmentStartTime += timeStep + segmentBreak;
|
|||
|
|
|||
|
//If the previous end time or the next start time is beyond the duration then stop the arc
|
|||
|
if (stopArc || segmentStartTime >= arcDuration || segmentStartTime >= arcHitTime)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
currentSegment--;
|
|||
|
}
|
|||
|
|
|||
|
//Hide the rest of the line segments
|
|||
|
HideLineSegments(currentSegment + 1, segmentCount);
|
|||
|
}
|
|||
|
|
|||
|
return arcHitTime != float.MaxValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
private void DrawArcSegment(int index, float startTime, float endTime)
|
|||
|
{
|
|||
|
lineRenderers[index].enabled = true;
|
|||
|
lineRenderers[index].SetPosition(0, GetArcPositionAtTime(startTime));
|
|||
|
lineRenderers[index].SetPosition(1, GetArcPositionAtTime(endTime));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
public void SetColor(Color color)
|
|||
|
{
|
|||
|
for (int i = 0; i < segmentCount; ++i)
|
|||
|
{
|
|||
|
#if (UNITY_5_4)
|
|||
|
lineRenderers[i].SetColors(color, color);
|
|||
|
#else
|
|||
|
lineRenderers[i].startColor = color;
|
|||
|
lineRenderers[i].endColor = color;
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
private float FindProjectileCollision(out RaycastHit hitInfo)
|
|||
|
{
|
|||
|
float timeStep = arcDuration / segmentCount;
|
|||
|
float segmentStartTime = 0.0f;
|
|||
|
|
|||
|
hitInfo = new RaycastHit();
|
|||
|
|
|||
|
Vector3 segmentStartPos = GetArcPositionAtTime(segmentStartTime);
|
|||
|
for (int i = 0; i < segmentCount; ++i)
|
|||
|
{
|
|||
|
float segmentEndTime = segmentStartTime + timeStep;
|
|||
|
Vector3 segmentEndPos = GetArcPositionAtTime(segmentEndTime);
|
|||
|
|
|||
|
if (Physics.Linecast(segmentStartPos, segmentEndPos, out hitInfo, traceLayerMask))
|
|||
|
{
|
|||
|
if (hitInfo.collider.GetComponent<IgnoreTeleportTrace>() == null)
|
|||
|
{
|
|||
|
Util.DrawCross(hitInfo.point, Color.red, 0.5f);
|
|||
|
float segmentDistance = Vector3.Distance(segmentStartPos, segmentEndPos);
|
|||
|
float hitTime = segmentStartTime + (timeStep * (hitInfo.distance / segmentDistance));
|
|||
|
return hitTime;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
segmentStartTime = segmentEndTime;
|
|||
|
segmentStartPos = segmentEndPos;
|
|||
|
}
|
|||
|
|
|||
|
return float.MaxValue;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
public Vector3 GetArcPositionAtTime(float time)
|
|||
|
{
|
|||
|
Vector3 gravity = useGravity ? Physics.gravity : Vector3.zero;
|
|||
|
|
|||
|
Vector3 arcPos = startPos + ((projectileVelocity * time) + (0.5f * time * time) * gravity) * scale;
|
|||
|
return arcPos;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//-------------------------------------------------
|
|||
|
private void HideLineSegments(int startSegment, int endSegment)
|
|||
|
{
|
|||
|
if (lineRenderers != null)
|
|||
|
{
|
|||
|
for (int i = startSegment; i < endSegment; ++i)
|
|||
|
{
|
|||
|
lineRenderers[i].enabled = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|