/************************************************************************************
|
|
|
|
Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
|
|
|
|
See SampleFramework license.txt for license terms. Unless required by applicable law
|
|
or agreed to in writing, the sample code is provided “AS IS” WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied. See the license for specific
|
|
language governing permissions and limitations under the license.
|
|
|
|
************************************************************************************/
|
|
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
|
|
namespace OculusSampleFramework
|
|
{
|
|
public class TrackSegment : MonoBehaviour
|
|
{
|
|
public enum SegmentType
|
|
{
|
|
Straight = 0,
|
|
LeftTurn,
|
|
RightTurn,
|
|
Switch
|
|
}
|
|
|
|
[SerializeField] private SegmentType _segmentType = SegmentType.Straight;
|
|
[SerializeField] private MeshFilter _straight = null;
|
|
[SerializeField] private MeshFilter _leftTurn = null;
|
|
[SerializeField] private MeshFilter _rightTurn = null;
|
|
private float _gridSize = 0.8f;
|
|
private int _subDivCount = 20;
|
|
private const float _originalGridSize = 0.8f;
|
|
private const float _trackWidth = 0.15f;
|
|
private GameObject _mesh = null;
|
|
public float StartDistance { get; set; }
|
|
|
|
// create variables here to avoid realtime allocation
|
|
private Pose _p1 = new Pose();
|
|
private Pose _p2 = new Pose();
|
|
|
|
public float GridSize
|
|
{
|
|
get
|
|
{
|
|
return _gridSize;
|
|
}
|
|
private set
|
|
{
|
|
_gridSize = value;
|
|
}
|
|
}
|
|
|
|
public int SubDivCount
|
|
{
|
|
get
|
|
{
|
|
return _subDivCount;
|
|
}
|
|
set
|
|
{
|
|
_subDivCount = value;
|
|
}
|
|
}
|
|
|
|
public SegmentType Type
|
|
{
|
|
get
|
|
{
|
|
return _segmentType;
|
|
}
|
|
}
|
|
|
|
private Pose _endPose = new Pose();
|
|
public Pose EndPose
|
|
{
|
|
get
|
|
{
|
|
UpdatePose(SegmentLength, _endPose);
|
|
return _endPose;
|
|
}
|
|
}
|
|
public float Radius
|
|
{
|
|
get
|
|
{
|
|
return 0.5f * GridSize;
|
|
}
|
|
}
|
|
|
|
public float setGridSize(float size)
|
|
{
|
|
GridSize = size;
|
|
return GridSize / _originalGridSize;
|
|
}
|
|
|
|
public float SegmentLength
|
|
{
|
|
get
|
|
{
|
|
switch (Type)
|
|
{
|
|
case SegmentType.Straight:
|
|
return GridSize;
|
|
case SegmentType.LeftTurn:
|
|
case SegmentType.RightTurn:
|
|
// return quarter of circumference.
|
|
return 0.5f * Mathf.PI * Radius;
|
|
}
|
|
|
|
return 1f;
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
Assert.IsNotNull(_straight);
|
|
Assert.IsNotNull(_leftTurn);
|
|
Assert.IsNotNull(_rightTurn);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates pose given distance into segment. While this mutates a value,
|
|
/// it avoids generating a new object.
|
|
/// </summary>
|
|
public void UpdatePose(float distanceIntoSegment, Pose pose)
|
|
{
|
|
if (Type == SegmentType.Straight)
|
|
{
|
|
pose.Position = transform.position + distanceIntoSegment * transform.forward;
|
|
pose.Rotation = transform.rotation;
|
|
}
|
|
else if (Type == SegmentType.LeftTurn)
|
|
{
|
|
float normalizedDistanceIntoSegment = distanceIntoSegment / SegmentLength;
|
|
// the turn is 90 degrees, so find out how far we are into it
|
|
float angle = 0.5f * Mathf.PI * normalizedDistanceIntoSegment;
|
|
// unity is left handed so the rotations go the opposite directions in X for left turns --
|
|
// invert that by subtracting by radius. also note the angle negation below
|
|
Vector3 localPosition = new Vector3(Radius * Mathf.Cos(angle) - Radius, 0, Radius * Mathf.Sin(angle));
|
|
Quaternion localRotation = Quaternion.Euler(0, -angle * Mathf.Rad2Deg, 0);
|
|
pose.Position = transform.TransformPoint(localPosition);
|
|
pose.Rotation = transform.rotation * localRotation;
|
|
}
|
|
else if (Type == SegmentType.RightTurn)
|
|
{
|
|
// when going to right, start from PI (180) and go toward 90
|
|
float angle = Mathf.PI - 0.5f * Mathf.PI * distanceIntoSegment / SegmentLength;
|
|
// going right means we start at radius distance away, and decrease toward zero
|
|
Vector3 localPosition = new Vector3(Radius * Mathf.Cos(angle) + Radius, 0, Radius * Mathf.Sin(angle));
|
|
Quaternion localRotation = Quaternion.Euler(0, (Mathf.PI - angle) * Mathf.Rad2Deg, 0);
|
|
pose.Position = transform.TransformPoint(localPosition);
|
|
pose.Rotation = transform.rotation * localRotation;
|
|
}
|
|
else
|
|
{
|
|
pose.Position = Vector3.zero;
|
|
pose.Rotation = Quaternion.identity;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// uncomment to debug the track path
|
|
//DrawDebugLines();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
Destroy(_mesh);
|
|
}
|
|
|
|
private void DrawDebugLines()
|
|
{
|
|
for (int i = 1; i < SubDivCount + 1; i++)
|
|
{
|
|
float len = SegmentLength / SubDivCount;
|
|
UpdatePose((i - 1) * len, _p1);
|
|
UpdatePose(i * len, _p2);
|
|
// right segment from p1 to p2
|
|
var halfTrackWidth = 0.5f * _trackWidth;
|
|
Debug.DrawLine(_p1.Position + halfTrackWidth * (_p1.Rotation * Vector3.right),
|
|
_p2.Position + halfTrackWidth * (_p2.Rotation * Vector3.right));
|
|
// left segment from p1 to p2
|
|
Debug.DrawLine(_p1.Position - halfTrackWidth * (_p1.Rotation * Vector3.right),
|
|
_p2.Position - halfTrackWidth * (_p2.Rotation * Vector3.right));
|
|
}
|
|
|
|
// bottom bound
|
|
Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right,
|
|
transform.position + 0.5f * GridSize * transform.right, Color.yellow);
|
|
// left bound
|
|
Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right,
|
|
transform.position - 0.5f * GridSize * transform.right + GridSize * transform.forward, Color.yellow);
|
|
// right bound
|
|
Debug.DrawLine(transform.position + 0.5f * GridSize * transform.right,
|
|
transform.position + 0.5f * GridSize * transform.right + GridSize * transform.forward, Color.yellow);
|
|
// top bound
|
|
Debug.DrawLine(transform.position - 0.5f * GridSize * transform.right +
|
|
GridSize * transform.forward, transform.position +
|
|
0.5f * GridSize * transform.right + GridSize * transform.forward,
|
|
Color.yellow);
|
|
}
|
|
|
|
public void RegenerateTrackAndMesh()
|
|
{
|
|
if (transform.childCount > 0 && !_mesh)
|
|
{
|
|
_mesh = transform.GetChild(0).gameObject;
|
|
}
|
|
|
|
if (_mesh)
|
|
{
|
|
DestroyImmediate(_mesh);
|
|
}
|
|
|
|
if (_segmentType == SegmentType.LeftTurn)
|
|
{
|
|
_mesh = Instantiate(_leftTurn.gameObject);
|
|
}
|
|
else if (_segmentType == SegmentType.RightTurn)
|
|
{
|
|
_mesh = Instantiate(_rightTurn.gameObject);
|
|
}
|
|
else
|
|
{
|
|
_mesh = Instantiate(_straight.gameObject);
|
|
}
|
|
|
|
_mesh.transform.SetParent(transform, false);
|
|
_mesh.transform.position += GridSize / 2.0f * transform.forward;
|
|
_mesh.transform.localScale = new Vector3(GridSize / _originalGridSize, GridSize / _originalGridSize,
|
|
GridSize / _originalGridSize);
|
|
}
|
|
}
|
|
}
|