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