@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace UnityStandardAssets.Utility
{
public class AutoMobileShaderSwitch : MonoBehaviour
{
[SerializeField] private ReplacementList m_ReplacementList;

// Use this for initialization
private void OnEnable()
{
#if UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_TIZEN || UNITY_STV
var renderers = FindObjectsOfType<Renderer>();
Debug.Log (renderers.Length+" renderers");
var oldMaterials = new List<Material>();
var newMaterials = new List<Material>();

int materialsReplaced = 0;
int materialInstancesReplaced = 0;

foreach(ReplacementDefinition replacementDef in m_ReplacementList.items)
{
foreach(var r in renderers)
{
Material[] modifiedMaterials = null;
for(int n=0; n<r.sharedMaterials.Length; ++n)
{
var material = r.sharedMaterials[n];
if (material.shader == replacementDef.original)
{
if (modifiedMaterials == null)
{
modifiedMaterials = r.materials;
}
if (!oldMaterials.Contains(material))
{
oldMaterials.Add(material);
Material newMaterial = (Material)Instantiate(material);
newMaterial.shader = replacementDef.replacement;
newMaterials.Add(newMaterial);
++materialsReplaced;
}
Debug.Log ("replacing "+r.gameObject.name+" renderer "+n+" with "+newMaterials[oldMaterials.IndexOf(material)].name);
modifiedMaterials[n] = newMaterials[oldMaterials.IndexOf(material)];
++materialInstancesReplaced;
}
}
if (modifiedMaterials != null)
{
r.materials = modifiedMaterials;
}
}
}
Debug.Log (materialInstancesReplaced+" material instances replaced");
Debug.Log (materialsReplaced+" materials replaced");
for(int n=0; n<oldMaterials.Count; ++n)
{
Debug.Log (oldMaterials[n].name+" ("+oldMaterials[n].shader.name+")"+" replaced with "+newMaterials[n].name+" ("+newMaterials[n].shader.name+")");
}
#endif
}


[Serializable]
public class ReplacementDefinition
{
public Shader original = null;
public Shader replacement = null;
}

[Serializable]
public class ReplacementList
{
public ReplacementDefinition[] items = new ReplacementDefinition[0];
}
}
}

namespace UnityStandardAssets.Utility.Inspector
{
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof (AutoMobileShaderSwitch.ReplacementList))]
public class ReplacementListDrawer : PropertyDrawer
{
const float k_LineHeight = 18;
const float k_Spacing = 4;

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);

float x = position.x;
float y = position.y;
float inspectorWidth = position.width;

// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;

var items = property.FindPropertyRelative("items");
var titles = new string[] {"Original", "Replacement", ""};
var props = new string[] {"original", "replacement", "-"};
var widths = new float[] {.45f, .45f, .1f};
const float lineHeight = 18;
bool changedLength = false;
if (items.arraySize > 0)
{
for (int i = -1; i < items.arraySize; ++i)
{
var item = items.GetArrayElementAtIndex(i);

float rowX = x;
for (int n = 0; n < props.Length; ++n)
{
float w = widths[n]*inspectorWidth;

// Calculate rects
Rect rect = new Rect(rowX, y, w, lineHeight);
rowX += w;

if (i == -1)
{
// draw title labels
EditorGUI.LabelField(rect, titles[n]);
}
else
{
if (props[n] == "-" || props[n] == "^" || props[n] == "v")
{
if (GUI.Button(rect, props[n]))
{
switch (props[n])
{
case "-":
items.DeleteArrayElementAtIndex(i);
items.DeleteArrayElementAtIndex(i);
changedLength = true;
break;
case "v":
if (i > 0)
{
items.MoveArrayElement(i, i + 1);
}
break;
case "^":
if (i < items.arraySize - 1)
{
items.MoveArrayElement(i, i - 1);
}
break;
}
}
}
else
{
SerializedProperty prop = item.FindPropertyRelative(props[n]);
EditorGUI.PropertyField(rect, prop, GUIContent.none);
}
}
}

y += lineHeight + k_Spacing;
if (changedLength)
{
break;
}
}
}

// add button
var addButtonRect = new Rect((x + position.width) - widths[widths.Length - 1]*inspectorWidth, y,
widths[widths.Length - 1]*inspectorWidth, lineHeight);
if (GUI.Button(addButtonRect, "+"))
{
items.InsertArrayElementAtIndex(items.arraySize);
}

y += lineHeight + k_Spacing;

// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}


public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty items = property.FindPropertyRelative("items");
float lineAndSpace = k_LineHeight + k_Spacing;
return 40 + (items.arraySize*lineAndSpace) + lineAndSpace;
}
}
#endif
}
@@ -0,0 +1,41 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class AutoMoveAndRotate : MonoBehaviour
{
public Vector3andSpace moveUnitsPerSecond;
public Vector3andSpace rotateDegreesPerSecond;
public bool ignoreTimescale;
private float m_LastRealTime;


private void Start()
{
m_LastRealTime = Time.realtimeSinceStartup;
}


// Update is called once per frame
private void Update()
{
float deltaTime = Time.deltaTime;
if (ignoreTimescale)
{
deltaTime = (Time.realtimeSinceStartup - m_LastRealTime);
m_LastRealTime = Time.realtimeSinceStartup;
}
transform.Translate(moveUnitsPerSecond.value*deltaTime, moveUnitsPerSecond.space);
transform.Rotate(rotateDegreesPerSecond.value*deltaTime, moveUnitsPerSecond.space);
}


[Serializable]
public class Vector3andSpace
{
public Vector3 value;
public Space space = Space.Self;
}
}
}
@@ -0,0 +1,58 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class CameraRefocus
{
public Camera Camera;
public Vector3 Lookatpoint;
public Transform Parent;

private Vector3 m_OrigCameraPos;
private bool m_Refocus;


public CameraRefocus(Camera camera, Transform parent, Vector3 origCameraPos)
{
m_OrigCameraPos = origCameraPos;
Camera = camera;
Parent = parent;
}


public void ChangeCamera(Camera camera)
{
Camera = camera;
}


public void ChangeParent(Transform parent)
{
Parent = parent;
}


public void GetFocusPoint()
{
RaycastHit hitInfo;
if (Physics.Raycast(Parent.transform.position + m_OrigCameraPos, Parent.transform.forward, out hitInfo,
100f))
{
Lookatpoint = hitInfo.point;
m_Refocus = true;
return;
}
m_Refocus = false;
}


public void SetFocusPoint()
{
if (m_Refocus)
{
Camera.transform.LookAt(Lookatpoint);
}
}
}
}
@@ -0,0 +1,54 @@
using System;
using UnityEngine;


namespace UnityStandardAssets.Utility
{
[Serializable]
public class CurveControlledBob
{
public float HorizontalBobRange = 0.33f;
public float VerticalBobRange = 0.33f;
public AnimationCurve Bobcurve = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.5f, 1f),
new Keyframe(1f, 0f), new Keyframe(1.5f, -1f),
new Keyframe(2f, 0f)); // sin curve for head bob
public float VerticaltoHorizontalRatio = 1f;

private float m_CyclePositionX;
private float m_CyclePositionY;
private float m_BobBaseInterval;
private Vector3 m_OriginalCameraPosition;
private float m_Time;


public void Setup(Camera camera, float bobBaseInterval)
{
m_BobBaseInterval = bobBaseInterval;
m_OriginalCameraPosition = camera.transform.localPosition;

// get the length of the curve in time
m_Time = Bobcurve[Bobcurve.length - 1].time;
}


public Vector3 DoHeadBob(float speed)
{
float xPos = m_OriginalCameraPosition.x + (Bobcurve.Evaluate(m_CyclePositionX)*HorizontalBobRange);
float yPos = m_OriginalCameraPosition.y + (Bobcurve.Evaluate(m_CyclePositionY)*VerticalBobRange);

m_CyclePositionX += (speed*Time.deltaTime)/m_BobBaseInterval;
m_CyclePositionY += ((speed*Time.deltaTime)/m_BobBaseInterval)*VerticaltoHorizontalRatio;

if (m_CyclePositionX > m_Time)
{
m_CyclePositionX = m_CyclePositionX - m_Time;
}
if (m_CyclePositionY > m_Time)
{
m_CyclePositionY = m_CyclePositionY - m_Time;
}

return new Vector3(xPos, yPos, 0f);
}
}
}
@@ -0,0 +1,96 @@
using System;
using System.Collections;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class DragRigidbody : MonoBehaviour
{
const float k_Spring = 50.0f;
const float k_Damper = 5.0f;
const float k_Drag = 10.0f;
const float k_AngularDrag = 5.0f;
const float k_Distance = 0.2f;
const bool k_AttachToCenterOfMass = false;

private SpringJoint m_SpringJoint;


private void Update()
{
// Make sure the user pressed the mouse down
if (!Input.GetMouseButtonDown(0))
{
return;
}

var mainCamera = FindCamera();

// We need to actually hit an object
RaycastHit hit = new RaycastHit();
if (
!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition).origin,
mainCamera.ScreenPointToRay(Input.mousePosition).direction, out hit, 100,
Physics.DefaultRaycastLayers))
{
return;
}
// We need to hit a rigidbody that is not kinematic
if (!hit.rigidbody || hit.rigidbody.isKinematic)
{
return;
}

if (!m_SpringJoint)
{
var go = new GameObject("Rigidbody dragger");
Rigidbody body = go.AddComponent<Rigidbody>();
m_SpringJoint = go.AddComponent<SpringJoint>();
body.isKinematic = true;
}

m_SpringJoint.transform.position = hit.point;
m_SpringJoint.anchor = Vector3.zero;

m_SpringJoint.spring = k_Spring;
m_SpringJoint.damper = k_Damper;
m_SpringJoint.maxDistance = k_Distance;
m_SpringJoint.connectedBody = hit.rigidbody;

StartCoroutine("DragObject", hit.distance);
}


private IEnumerator DragObject(float distance)
{
var oldDrag = m_SpringJoint.connectedBody.drag;
var oldAngularDrag = m_SpringJoint.connectedBody.angularDrag;
m_SpringJoint.connectedBody.drag = k_Drag;
m_SpringJoint.connectedBody.angularDrag = k_AngularDrag;
var mainCamera = FindCamera();
while (Input.GetMouseButton(0))
{
var ray = mainCamera.ScreenPointToRay(Input.mousePosition);
m_SpringJoint.transform.position = ray.GetPoint(distance);
yield return null;
}
if (m_SpringJoint.connectedBody)
{
m_SpringJoint.connectedBody.drag = oldDrag;
m_SpringJoint.connectedBody.angularDrag = oldAngularDrag;
m_SpringJoint.connectedBody = null;
}
}


private Camera FindCamera()
{
if (GetComponent<Camera>())
{
return GetComponent<Camera>();
}

return Camera.main;
}
}
}
@@ -0,0 +1,51 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class DynamicShadowSettings : MonoBehaviour
{
public Light sunLight;
public float minHeight = 10;
public float minShadowDistance = 80;
public float minShadowBias = 1;
public float maxHeight = 1000;
public float maxShadowDistance = 10000;
public float maxShadowBias = 0.1f;
public float adaptTime = 1;

private float m_SmoothHeight;
private float m_ChangeSpeed;
private float m_OriginalStrength = 1;


private void Start()
{
m_OriginalStrength = sunLight.shadowStrength;
}


// Update is called once per frame
private void Update()
{
Ray ray = new Ray(Camera.main.transform.position, -Vector3.up);
RaycastHit hit;
float height = transform.position.y;
if (Physics.Raycast(ray, out hit))
{
height = hit.distance;
}

if (Mathf.Abs(height - m_SmoothHeight) > 1)
{
m_SmoothHeight = Mathf.SmoothDamp(m_SmoothHeight, height, ref m_ChangeSpeed, adaptTime);
}

float i = Mathf.InverseLerp(minHeight, maxHeight, m_SmoothHeight);

QualitySettings.shadowDistance = Mathf.Lerp(minShadowDistance, maxShadowDistance, i);
sunLight.shadowBias = Mathf.Lerp(minShadowBias, maxShadowBias, 1 - ((1 - i)*(1 - i)));
sunLight.shadowStrength = Mathf.Lerp(m_OriginalStrength, 0, i);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;

public class EventSystemChecker : MonoBehaviour
{
//public GameObject eventSystem;

// Use this for initialization
void Awake ()
{
if(!FindObjectOfType<EventSystem>())
{
//Instantiate(eventSystem);
GameObject obj = new GameObject("EventSystem");
obj.AddComponent<EventSystem>();
obj.AddComponent<StandaloneInputModule>().forceModuleActive = true;
}
}
}
@@ -0,0 +1,73 @@
using System;
using System.Collections;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
[Serializable]
public class FOVKick
{
public Camera Camera; // optional camera setup, if null the main camera will be used
[HideInInspector] public float originalFov; // the original fov
public float FOVIncrease = 3f; // the amount the field of view increases when going into a run
public float TimeToIncrease = 1f; // the amount of time the field of view will increase over
public float TimeToDecrease = 1f; // the amount of time the field of view will take to return to its original size
public AnimationCurve IncreaseCurve;


public void Setup(Camera camera)
{
CheckStatus(camera);

Camera = camera;
originalFov = camera.fieldOfView;
}


private void CheckStatus(Camera camera)
{
if (camera == null)
{
throw new Exception("FOVKick camera is null, please supply the camera to the constructor");
}

if (IncreaseCurve == null)
{
throw new Exception(
"FOVKick Increase curve is null, please define the curve for the field of view kicks");
}
}


public void ChangeCamera(Camera camera)
{
Camera = camera;
}


public IEnumerator FOVKickUp()
{
float t = Mathf.Abs((Camera.fieldOfView - originalFov)/FOVIncrease);
while (t < TimeToIncrease)
{
Camera.fieldOfView = originalFov + (IncreaseCurve.Evaluate(t/TimeToIncrease)*FOVIncrease);
t += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
}


public IEnumerator FOVKickDown()
{
float t = Mathf.Abs((Camera.fieldOfView - originalFov)/FOVIncrease);
while (t > 0)
{
Camera.fieldOfView = originalFov + (IncreaseCurve.Evaluate(t/TimeToDecrease)*FOVIncrease);
t -= Time.deltaTime;
yield return new WaitForEndOfFrame();
}
//make sure that fov returns to the original size
Camera.fieldOfView = originalFov;
}
}
}
@@ -0,0 +1,38 @@
using System;
using UnityEngine;
using UnityEngine.UI;

namespace UnityStandardAssets.Utility
{
[RequireComponent(typeof (Text))]
public class FPSCounter : MonoBehaviour
{
const float fpsMeasurePeriod = 0.5f;
private int m_FpsAccumulator = 0;
private float m_FpsNextPeriod = 0;
private int m_CurrentFps;
const string display = "{0} FPS";
private Text m_Text;


private void Start()
{
m_FpsNextPeriod = Time.realtimeSinceStartup + fpsMeasurePeriod;
m_Text = GetComponent<Text>();
}


private void Update()
{
// measure average frames per second
m_FpsAccumulator++;
if (Time.realtimeSinceStartup > m_FpsNextPeriod)
{
m_CurrentFps = (int) (m_FpsAccumulator/fpsMeasurePeriod);
m_FpsAccumulator = 0;
m_FpsNextPeriod += fpsMeasurePeriod;
m_Text.text = string.Format(display, m_CurrentFps);
}
}
}
}
@@ -0,0 +1,18 @@
using System;
using UnityEngine;


namespace UnityStandardAssets.Utility
{
public class FollowTarget : MonoBehaviour
{
public Transform target;
public Vector3 offset = new Vector3(0f, 7.5f, 0f);


private void LateUpdate()
{
transform.position = target.position + offset;
}
}
}
@@ -0,0 +1,18 @@
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityStandardAssets.CrossPlatformInput;

[RequireComponent(typeof (GUITexture))]
public class ForcedReset : MonoBehaviour
{
private void Update()
{
// if we have forced a reset ...
if (CrossPlatformInputManager.GetButtonDown("ResetObject"))
{
//... reload the scene
SceneManager.LoadScene(SceneManager.GetSceneAt(0).name);
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Collections;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
[Serializable]
public class LerpControlledBob
{
public float BobDuration;
public float BobAmount;

private float m_Offset = 0f;


// provides the offset that can be used
public float Offset()
{
return m_Offset;
}


public IEnumerator DoBobCycle()
{
// make the camera move down slightly
float t = 0f;
while (t < BobDuration)
{
m_Offset = Mathf.Lerp(0f, BobAmount, t/BobDuration);
t += Time.deltaTime;
yield return new WaitForFixedUpdate();
}

// make it move back to neutral
t = 0f;
while (t < BobDuration)
{
m_Offset = Mathf.Lerp(BobAmount, 0f, t/BobDuration);
t += Time.deltaTime;
yield return new WaitForFixedUpdate();
}
m_Offset = 0f;
}
}
}
@@ -0,0 +1,57 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class ObjectResetter : MonoBehaviour
{
private Vector3 originalPosition;
private Quaternion originalRotation;
private List<Transform> originalStructure;

private Rigidbody Rigidbody;

// Use this for initialization
private void Start()
{
originalStructure = new List<Transform>(GetComponentsInChildren<Transform>());
originalPosition = transform.position;
originalRotation = transform.rotation;

Rigidbody = GetComponent<Rigidbody>();
}


public void DelayedReset(float delay)
{
StartCoroutine(ResetCoroutine(delay));
}


public IEnumerator ResetCoroutine(float delay)
{
yield return new WaitForSeconds(delay);

// remove any gameobjects added (fire, skid trails, etc)
foreach (var t in GetComponentsInChildren<Transform>())
{
if (!originalStructure.Contains(t))
{
t.parent = null;
}
}

transform.position = originalPosition;
transform.rotation = originalRotation;
if (Rigidbody)
{
Rigidbody.velocity = Vector3.zero;
Rigidbody.angularVelocity = Vector3.zero;
}

SendMessage("Reset");
}
}
}
@@ -0,0 +1,62 @@
using System;
using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;

namespace UnityStandardAssets.Utility
{
public class ParticleSystemDestroyer : MonoBehaviour
{
// allows a particle system to exist for a specified duration,
// then shuts off emission, and waits for all particles to expire
// before destroying the gameObject

public float minDuration = 8;
public float maxDuration = 10;

private float m_MaxLifetime;
private bool m_EarlyStop;


private IEnumerator Start()
{
var systems = GetComponentsInChildren<ParticleSystem>();

// find out the maximum lifetime of any particles in this effect
foreach (var system in systems)
{
m_MaxLifetime = Mathf.Max(system.main.startLifetime.constant, m_MaxLifetime);
}

// wait for random duration

float stopTime = Time.time + Random.Range(minDuration, maxDuration);

while (Time.time < stopTime || m_EarlyStop)
{
yield return null;
}
Debug.Log("stopping " + name);

// turn off emission
foreach (var system in systems)
{
var emission = system.emission;
emission.enabled = false;
}
BroadcastMessage("Extinguish", SendMessageOptions.DontRequireReceiver);

// wait for any remaining particles to expire
yield return new WaitForSeconds(m_MaxLifetime);

Destroy(gameObject);
}


public void Stop()
{
// stops the particle system early
m_EarlyStop = true;
}
}
}
@@ -0,0 +1,107 @@
using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace UnityStandardAssets.Utility
{
#if UNITY_EDITOR

[ExecuteInEditMode]
#endif
public class PlatformSpecificContent : MonoBehaviour
{
private enum BuildTargetGroup
{
Standalone,
Mobile
}

[SerializeField] private BuildTargetGroup m_BuildTargetGroup;
[SerializeField] private GameObject[] m_Content = new GameObject[0];
[SerializeField] private MonoBehaviour[] m_MonoBehaviours = new MonoBehaviour[0];
[SerializeField] private bool m_ChildrenOfThisObject;

#if !UNITY_EDITOR
void OnEnable()
{
CheckEnableContent();
}
#endif

#if UNITY_EDITOR

private void OnEnable()
{
EditorApplication.update += Update;
EditorUserBuildSettings.activeBuildTargetChanged += Update;
}


private void OnDisable()
{
EditorApplication.update -= Update;
EditorUserBuildSettings.activeBuildTargetChanged -= Update;
}

private void Update()
{
CheckEnableContent();
}
#endif


private void CheckEnableContent()
{
#if (UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_TIZEN || UNITY_STV )
if (m_BuildTargetGroup == BuildTargetGroup.Mobile)
{
EnableContent(true);
} else {
EnableContent(false);
}
#endif

#if !(UNITY_IPHONE || UNITY_ANDROID || UNITY_WP8 || UNITY_TIZEN || UNITY_STV )
if (m_BuildTargetGroup == BuildTargetGroup.Mobile)
{
EnableContent(false);
}
else
{
EnableContent(true);
}
#endif
}


private void EnableContent(bool enabled)
{
if (m_Content.Length > 0)
{
foreach (var g in m_Content)
{
if (g != null)
{
g.SetActive(enabled);
}
}
}
if (m_ChildrenOfThisObject)
{
foreach (Transform t in transform)
{
t.gameObject.SetActive(enabled);
}
}
if (m_MonoBehaviours.Length > 0)
{
foreach (var monoBehaviour in m_MonoBehaviours)
{
monoBehaviour.enabled = enabled;
}
}
}
}
}
@@ -0,0 +1,183 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &100000
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 4
m_Component:
- 224: {fileID: 22409990}
- 223: {fileID: 22323452}
- 114: {fileID: 11403178}
- 114: {fileID: 11448042}
m_Layer: 5
m_Name: FramerateCounter
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &167734
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 4
m_Component:
- 224: {fileID: 22488988}
- 222: {fileID: 22250932}
- 114: {fileID: 11410038}
- 114: {fileID: 11400482}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &11400482
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 167734}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 22bbf57ec543cee42a5aa0ec2dd9e457, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &11403178
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1980459831, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_UiScaleMode: 0
m_ReferencePixelsPerUnit: 100
m_ScaleFactor: 1
m_ReferenceResolution: {x: 800, y: 600}
m_ScreenMatchMode: 0
m_MatchWidthOrHeight: 0
m_PhysicalUnit: 3
m_FallbackScreenDPI: 96
m_DefaultSpriteDPI: 96
m_DynamicPixelsPerUnit: 1
--- !u!114 &11410038
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 167734}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: .196078435, g: .196078435, b: .196078435, a: 1}
m_FontData:
m_Font: {fileID: 12800000, guid: b51a3e520f9164da198dc59c8acfccd6, type: 3}
m_FontSize: 18
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 4
m_RichText: 0
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 'FPS
'
--- !u!114 &11448042
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1301386320, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!222 &22250932
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 167734}
--- !u!223 &22323452
Canvas:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_Enabled: 1
serializedVersion: 2
m_RenderMode: 0
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingLayerID: 0
m_SortingOrder: 0
--- !u!224 &22409990
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 100000}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 0, y: 0, z: 0}
m_Children:
- {fileID: 22488988}
m_Father: {fileID: 0}
m_RootOrder: 0
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!224 &22488988
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 167734}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 22409990}
m_RootOrder: 0
m_AnchorMin: {x: .5, y: 1}
m_AnchorMax: {x: .5, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: .5, y: 1}
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 100000}
m_IsPrefabParent: 1
@@ -0,0 +1,38 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class SimpleActivatorMenu : MonoBehaviour
{
// An incredibly simple menu which, when given references
// to gameobjects in the scene
public GUIText camSwitchButton;
public GameObject[] objects;


private int m_CurrentActiveObject;


private void OnEnable()
{
// active object starts from first in array
m_CurrentActiveObject = 0;
camSwitchButton.text = objects[m_CurrentActiveObject].name;
}


public void NextCamera()
{
int nextactiveobject = m_CurrentActiveObject + 1 >= objects.Length ? 0 : m_CurrentActiveObject + 1;

for (int i = 0; i < objects.Length; i++)
{
objects[i].SetActive(i == nextactiveobject);
}

m_CurrentActiveObject = nextactiveobject;
camSwitchButton.text = objects[m_CurrentActiveObject].name;
}
}
}
@@ -0,0 +1,113 @@
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Utility
{
public class SimpleMouseRotator : MonoBehaviour
{
// A mouselook behaviour with constraints which operate relative to
// this gameobject's initial rotation.
// Only rotates around local X and Y.
// Works in local coordinates, so if this object is parented
// to another moving gameobject, its local constraints will
// operate correctly
// (Think: looking out the side window of a car, or a gun turret
// on a moving spaceship with a limited angular range)
// to have no constraints on an axis, set the rotationRange to 360 or greater.
public Vector2 rotationRange = new Vector3(70, 70);
public float rotationSpeed = 10;
public float dampingTime = 0.2f;
public bool autoZeroVerticalOnMobile = true;
public bool autoZeroHorizontalOnMobile = false;
public bool relative = true;


private Vector3 m_TargetAngles;
private Vector3 m_FollowAngles;
private Vector3 m_FollowVelocity;
private Quaternion m_OriginalRotation;


private void Start()
{
m_OriginalRotation = transform.localRotation;
}


private void Update()
{
// we make initial calculations from the original local rotation
transform.localRotation = m_OriginalRotation;

// read input from mouse or mobile controls
float inputH;
float inputV;
if (relative)
{
inputH = CrossPlatformInputManager.GetAxis("Mouse X");
inputV = CrossPlatformInputManager.GetAxis("Mouse Y");

// wrap values to avoid springing quickly the wrong way from positive to negative
if (m_TargetAngles.y > 180)
{
m_TargetAngles.y -= 360;
m_FollowAngles.y -= 360;
}
if (m_TargetAngles.x > 180)
{
m_TargetAngles.x -= 360;
m_FollowAngles.x -= 360;
}
if (m_TargetAngles.y < -180)
{
m_TargetAngles.y += 360;
m_FollowAngles.y += 360;
}
if (m_TargetAngles.x < -180)
{
m_TargetAngles.x += 360;
m_FollowAngles.x += 360;
}

#if MOBILE_INPUT
// on mobile, sometimes we want input mapped directly to tilt value,
// so it springs back automatically when the look input is released.
if (autoZeroHorizontalOnMobile) {
m_TargetAngles.y = Mathf.Lerp (-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH * .5f + .5f);
} else {
m_TargetAngles.y += inputH * rotationSpeed;
}
if (autoZeroVerticalOnMobile) {
m_TargetAngles.x = Mathf.Lerp (-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV * .5f + .5f);
} else {
m_TargetAngles.x += inputV * rotationSpeed;
}
#else
// with mouse input, we have direct control with no springback required.
m_TargetAngles.y += inputH*rotationSpeed;
m_TargetAngles.x += inputV*rotationSpeed;
#endif

// clamp values to allowed range
m_TargetAngles.y = Mathf.Clamp(m_TargetAngles.y, -rotationRange.y*0.5f, rotationRange.y*0.5f);
m_TargetAngles.x = Mathf.Clamp(m_TargetAngles.x, -rotationRange.x*0.5f, rotationRange.x*0.5f);
}
else
{
inputH = Input.mousePosition.x;
inputV = Input.mousePosition.y;

// set values to allowed range
m_TargetAngles.y = Mathf.Lerp(-rotationRange.y*0.5f, rotationRange.y*0.5f, inputH/Screen.width);
m_TargetAngles.x = Mathf.Lerp(-rotationRange.x*0.5f, rotationRange.x*0.5f, inputV/Screen.height);
}

// smoothly interpolate current values to target angles
m_FollowAngles = Vector3.SmoothDamp(m_FollowAngles, m_TargetAngles, ref m_FollowVelocity, dampingTime);

// update the actual gameobject's rotation
transform.localRotation = m_OriginalRotation*Quaternion.Euler(-m_FollowAngles.x, m_FollowAngles.y, 0);
}
}
}
@@ -0,0 +1,61 @@
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class SmoothFollow : MonoBehaviour
{

// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target
[SerializeField]
private float distance = 10.0f;
// the height we want the camera to be above the target
[SerializeField]
private float height = 5.0f;

[SerializeField]
private float rotationDamping;
[SerializeField]
private float heightDamping;

// Use this for initialization
void Start() { }

// Update is called once per frame
void LateUpdate()
{
// Early out if we don't have a target
if (!target)
return;

// Calculate the current rotation angles
var wantedRotationAngle = target.eulerAngles.y;
var wantedHeight = target.position.y + height;

var currentRotationAngle = transform.eulerAngles.y;
var currentHeight = transform.position.y;

// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);

// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;

// Set the height of the camera
transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);

// Always look at the target
transform.LookAt(target);
}
}
}
@@ -0,0 +1,216 @@
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace UnityStandardAssets.Utility
{
public class TimedObjectActivator : MonoBehaviour
{
public enum Action
{
Activate,
Deactivate,
Destroy,
ReloadLevel,
Call,
}


[Serializable]
public class Entry
{
public GameObject target;
public Action action;
public float delay;
}


[Serializable]
public class Entries
{
public Entry[] entries;
}


public Entries entries = new Entries();


private void Awake()
{
foreach (Entry entry in entries.entries)
{
switch (entry.action)
{
case Action.Activate:
StartCoroutine(Activate(entry));
break;
case Action.Deactivate:
StartCoroutine(Deactivate(entry));
break;
case Action.Destroy:
Destroy(entry.target, entry.delay);
break;

case Action.ReloadLevel:
StartCoroutine(ReloadLevel(entry));
break;
}
}
}


private IEnumerator Activate(Entry entry)
{
yield return new WaitForSeconds(entry.delay);
entry.target.SetActive(true);
}


private IEnumerator Deactivate(Entry entry)
{
yield return new WaitForSeconds(entry.delay);
entry.target.SetActive(false);
}


private IEnumerator ReloadLevel(Entry entry)
{
yield return new WaitForSeconds(entry.delay);
SceneManager.LoadScene(SceneManager.GetSceneAt(0).name);
}
}
}


namespace UnityStandardAssets.Utility.Inspector
{
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof (TimedObjectActivator.Entries))]
public class EntriesDrawer : PropertyDrawer
{
private const float k_LineHeight = 18;
private const float k_Spacing = 4;


public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);

float x = position.x;
float y = position.y;
float width = position.width;

// Draw label
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);

// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;

var entries = property.FindPropertyRelative("entries");

if (entries.arraySize > 0)
{
float actionWidth = .25f*width;
float targetWidth = .6f*width;
float delayWidth = .1f*width;
float buttonWidth = .05f*width;

for (int i = 0; i < entries.arraySize; ++i)
{
y += k_LineHeight + k_Spacing;

var entry = entries.GetArrayElementAtIndex(i);

float rowX = x;

// Calculate rects
Rect actionRect = new Rect(rowX, y, actionWidth, k_LineHeight);
rowX += actionWidth;

Rect targetRect = new Rect(rowX, y, targetWidth, k_LineHeight);
rowX += targetWidth;

Rect delayRect = new Rect(rowX, y, delayWidth, k_LineHeight);
rowX += delayWidth;

Rect buttonRect = new Rect(rowX, y, buttonWidth, k_LineHeight);
rowX += buttonWidth;

// Draw fields - passs GUIContent.none to each so they are drawn without labels

if (entry.FindPropertyRelative("action").enumValueIndex !=
(int) TimedObjectActivator.Action.ReloadLevel)
{
EditorGUI.PropertyField(actionRect, entry.FindPropertyRelative("action"), GUIContent.none);
EditorGUI.PropertyField(targetRect, entry.FindPropertyRelative("target"), GUIContent.none);
}
else
{
actionRect.width = actionRect.width + targetRect.width;
EditorGUI.PropertyField(actionRect, entry.FindPropertyRelative("action"), GUIContent.none);
}

EditorGUI.PropertyField(delayRect, entry.FindPropertyRelative("delay"), GUIContent.none);
if (GUI.Button(buttonRect, "-"))
{
entries.DeleteArrayElementAtIndex(i);
break;
}
}
}

// add & sort buttons
y += k_LineHeight + k_Spacing;

var addButtonRect = new Rect(position.x + position.width - 120, y, 60, k_LineHeight);
if (GUI.Button(addButtonRect, "Add"))
{
entries.InsertArrayElementAtIndex(entries.arraySize);
}

var sortButtonRect = new Rect(position.x + position.width - 60, y, 60, k_LineHeight);
if (GUI.Button(sortButtonRect, "Sort"))
{
bool changed = true;
while (entries.arraySize > 1 && changed)
{
changed = false;
for (int i = 0; i < entries.arraySize - 1; ++i)
{
var e1 = entries.GetArrayElementAtIndex(i);
var e2 = entries.GetArrayElementAtIndex(i + 1);

if (e1.FindPropertyRelative("delay").floatValue > e2.FindPropertyRelative("delay").floatValue)
{
entries.MoveArrayElement(i + 1, i);
changed = true;
break;
}
}
}
}


// Set indent back to what it was
EditorGUI.indentLevel = indent;
//


EditorGUI.EndProperty();
}


public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty entries = property.FindPropertyRelative("entries");
float lineAndSpace = k_LineHeight + k_Spacing;
return 40 + (entries.arraySize*lineAndSpace) + lineAndSpace;
}
}
#endif
}
@@ -0,0 +1,27 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class TimedObjectDestructor : MonoBehaviour
{
[SerializeField] private float m_TimeOut = 1.0f;
[SerializeField] private bool m_DetachChildren = false;


private void Awake()
{
Invoke("DestroyNow", m_TimeOut);
}


private void DestroyNow()
{
if (m_DetachChildren)
{
transform.DetachChildren();
}
DestroyObject(gameObject);
}
}
}
@@ -0,0 +1,384 @@
using System;
using System.Collections;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;

#endif

namespace UnityStandardAssets.Utility
{
public class WaypointCircuit : MonoBehaviour
{
public WaypointList waypointList = new WaypointList();
[SerializeField] private bool smoothRoute = true;
private int numPoints;
private Vector3[] points;
private float[] distances;

public float editorVisualisationSubsteps = 100;
public float Length { get; private set; }

public Transform[] Waypoints
{
get { return waypointList.items; }
}

//this being here will save GC allocs
private int p0n;
private int p1n;
private int p2n;
private int p3n;

private float i;
private Vector3 P0;
private Vector3 P1;
private Vector3 P2;
private Vector3 P3;

// Use this for initialization
private void Awake()
{
if (Waypoints.Length > 1)
{
CachePositionsAndDistances();
}
numPoints = Waypoints.Length;
}


public RoutePoint GetRoutePoint(float dist)
{
// position and direction
Vector3 p1 = GetRoutePosition(dist);
Vector3 p2 = GetRoutePosition(dist + 0.1f);
Vector3 delta = p2 - p1;
return new RoutePoint(p1, delta.normalized);
}


public Vector3 GetRoutePosition(float dist)
{
int point = 0;

if (Length == 0)
{
Length = distances[distances.Length - 1];
}

dist = Mathf.Repeat(dist, Length);

while (distances[point] < dist)
{
++point;
}


// get nearest two points, ensuring points wrap-around start & end of circuit
p1n = ((point - 1) + numPoints)%numPoints;
p2n = point;

// found point numbers, now find interpolation value between the two middle points

i = Mathf.InverseLerp(distances[p1n], distances[p2n], dist);

if (smoothRoute)
{
// smooth catmull-rom calculation between the two relevant points


// get indices for the surrounding 2 points, because
// four points are required by the catmull-rom function
p0n = ((point - 2) + numPoints)%numPoints;
p3n = (point + 1)%numPoints;

// 2nd point may have been the 'last' point - a dupe of the first,
// (to give a value of max track distance instead of zero)
// but now it must be wrapped back to zero if that was the case.
p2n = p2n%numPoints;

P0 = points[p0n];
P1 = points[p1n];
P2 = points[p2n];
P3 = points[p3n];

return CatmullRom(P0, P1, P2, P3, i);
}
else
{
// simple linear lerp between the two points:

p1n = ((point - 1) + numPoints)%numPoints;
p2n = point;

return Vector3.Lerp(points[p1n], points[p2n], i);
}
}


private Vector3 CatmullRom(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float i)
{
// comments are no use here... it's the catmull-rom equation.
// Un-magic this, lord vector!
return 0.5f*
((2*p1) + (-p0 + p2)*i + (2*p0 - 5*p1 + 4*p2 - p3)*i*i +
(-p0 + 3*p1 - 3*p2 + p3)*i*i*i);
}


private void CachePositionsAndDistances()
{
// transfer the position of each point and distances between points to arrays for
// speed of lookup at runtime
points = new Vector3[Waypoints.Length + 1];
distances = new float[Waypoints.Length + 1];

float accumulateDistance = 0;
for (int i = 0; i < points.Length; ++i)
{
var t1 = Waypoints[(i)%Waypoints.Length];
var t2 = Waypoints[(i + 1)%Waypoints.Length];
if (t1 != null && t2 != null)
{
Vector3 p1 = t1.position;
Vector3 p2 = t2.position;
points[i] = Waypoints[i%Waypoints.Length].position;
distances[i] = accumulateDistance;
accumulateDistance += (p1 - p2).magnitude;
}
}
}


private void OnDrawGizmos()
{
DrawGizmos(false);
}


private void OnDrawGizmosSelected()
{
DrawGizmos(true);
}


private void DrawGizmos(bool selected)
{
waypointList.circuit = this;
if (Waypoints.Length > 1)
{
numPoints = Waypoints.Length;

CachePositionsAndDistances();
Length = distances[distances.Length - 1];

Gizmos.color = selected ? Color.yellow : new Color(1, 1, 0, 0.5f);
Vector3 prev = Waypoints[0].position;
if (smoothRoute)
{
for (float dist = 0; dist < Length; dist += Length/editorVisualisationSubsteps)
{
Vector3 next = GetRoutePosition(dist + 1);
Gizmos.DrawLine(prev, next);
prev = next;
}
Gizmos.DrawLine(prev, Waypoints[0].position);
}
else
{
for (int n = 0; n < Waypoints.Length; ++n)
{
Vector3 next = Waypoints[(n + 1)%Waypoints.Length].position;
Gizmos.DrawLine(prev, next);
prev = next;
}
}
}
}


[Serializable]
public class WaypointList
{
public WaypointCircuit circuit;
public Transform[] items = new Transform[0];
}

public struct RoutePoint
{
public Vector3 position;
public Vector3 direction;


public RoutePoint(Vector3 position, Vector3 direction)
{
this.position = position;
this.direction = direction;
}
}
}
}

namespace UnityStandardAssets.Utility.Inspector
{
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof (WaypointCircuit.WaypointList))]
public class WaypointListDrawer : PropertyDrawer
{
private float lineHeight = 18;
private float spacing = 4;


public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);

float x = position.x;
float y = position.y;
float inspectorWidth = position.width;

// Draw label


// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;

var items = property.FindPropertyRelative("items");
var titles = new string[] {"Transform", "", "", ""};
var props = new string[] {"transform", "^", "v", "-"};
var widths = new float[] {.7f, .1f, .1f, .1f};
float lineHeight = 18;
bool changedLength = false;
if (items.arraySize > 0)
{
for (int i = -1; i < items.arraySize; ++i)
{
var item = items.GetArrayElementAtIndex(i);

float rowX = x;
for (int n = 0; n < props.Length; ++n)
{
float w = widths[n]*inspectorWidth;

// Calculate rects
Rect rect = new Rect(rowX, y, w, lineHeight);
rowX += w;

if (i == -1)
{
EditorGUI.LabelField(rect, titles[n]);
}
else
{
if (n == 0)
{
EditorGUI.ObjectField(rect, item.objectReferenceValue, typeof (Transform), true);
}
else
{
if (GUI.Button(rect, props[n]))
{
switch (props[n])
{
case "-":
items.DeleteArrayElementAtIndex(i);
items.DeleteArrayElementAtIndex(i);
changedLength = true;
break;
case "v":
if (i > 0)
{
items.MoveArrayElement(i, i + 1);
}
break;
case "^":
if (i < items.arraySize - 1)
{
items.MoveArrayElement(i, i - 1);
}
break;
}
}
}
}
}

y += lineHeight + spacing;
if (changedLength)
{
break;
}
}
}
else
{
// add button
var addButtonRect = new Rect((x + position.width) - widths[widths.Length - 1]*inspectorWidth, y,
widths[widths.Length - 1]*inspectorWidth, lineHeight);
if (GUI.Button(addButtonRect, "+"))
{
items.InsertArrayElementAtIndex(items.arraySize);
}

y += lineHeight + spacing;
}

// add all button
var addAllButtonRect = new Rect(x, y, inspectorWidth, lineHeight);
if (GUI.Button(addAllButtonRect, "Assign using all child objects"))
{
var circuit = property.FindPropertyRelative("circuit").objectReferenceValue as WaypointCircuit;
var children = new Transform[circuit.transform.childCount];
int n = 0;
foreach (Transform child in circuit.transform)
{
children[n++] = child;
}
Array.Sort(children, new TransformNameComparer());
circuit.waypointList.items = new Transform[children.Length];
for (n = 0; n < children.Length; ++n)
{
circuit.waypointList.items[n] = children[n];
}
}
y += lineHeight + spacing;

// rename all button
var renameButtonRect = new Rect(x, y, inspectorWidth, lineHeight);
if (GUI.Button(renameButtonRect, "Auto Rename numerically from this order"))
{
var circuit = property.FindPropertyRelative("circuit").objectReferenceValue as WaypointCircuit;
int n = 0;
foreach (Transform child in circuit.waypointList.items)
{
child.name = "Waypoint " + (n++).ToString("000");
}
}
y += lineHeight + spacing;

// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}


public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
SerializedProperty items = property.FindPropertyRelative("items");
float lineAndSpace = lineHeight + spacing;
return 40 + (items.arraySize*lineAndSpace) + lineAndSpace;
}


// comparer for check distances in ray cast hits
public class TransformNameComparer : IComparer
{
public int Compare(object x, object y)
{
return ((Transform) x).name.CompareTo(((Transform) y).name);
}
}
}
#endif
}
@@ -0,0 +1,152 @@
using System;
using UnityEngine;

namespace UnityStandardAssets.Utility
{
public class WaypointProgressTracker : MonoBehaviour
{
// This script can be used with any object that is supposed to follow a
// route marked out by waypoints.

// This script manages the amount to look ahead along the route,
// and keeps track of progress and laps.

[SerializeField] private WaypointCircuit circuit; // A reference to the waypoint-based route we should follow

[SerializeField] private float lookAheadForTargetOffset = 5;
// The offset ahead along the route that the we will aim for

[SerializeField] private float lookAheadForTargetFactor = .1f;
// A multiplier adding distance ahead along the route to aim for, based on current speed

[SerializeField] private float lookAheadForSpeedOffset = 10;
// The offset ahead only the route for speed adjustments (applied as the rotation of the waypoint target transform)

[SerializeField] private float lookAheadForSpeedFactor = .2f;
// A multiplier adding distance ahead along the route for speed adjustments

[SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
// whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.

[SerializeField] private float pointToPointThreshold = 4;
// proximity to waypoint which must be reached to switch target to next waypoint : only used in PointToPoint mode.

public enum ProgressStyle
{
SmoothAlongRoute,
PointToPoint,
}

// these are public, readable by other objects - i.e. for an AI to know where to head!
public WaypointCircuit.RoutePoint targetPoint { get; private set; }
public WaypointCircuit.RoutePoint speedPoint { get; private set; }
public WaypointCircuit.RoutePoint progressPoint { get; private set; }

public Transform target;

private float progressDistance; // The progress round the route, used in smooth mode.
private int progressNum; // the current waypoint number, used in point-to-point mode.
private Vector3 lastPosition; // Used to calculate current speed (since we may not have a rigidbody component)
private float speed; // current speed of this object (calculated from delta since last frame)

// setup script properties
private void Start()
{
// we use a transform to represent the point to aim for, and the point which
// is considered for upcoming changes-of-speed. This allows this component
// to communicate this information to the AI without requiring further dependencies.

// You can manually create a transform and assign it to this component *and* the AI,
// then this component will update it, and the AI can read it.
if (target == null)
{
target = new GameObject(name + " Waypoint Target").transform;
}

Reset();
}


// reset the object to sensible values
public void Reset()
{
progressDistance = 0;
progressNum = 0;
if (progressStyle == ProgressStyle.PointToPoint)
{
target.position = circuit.Waypoints[progressNum].position;
target.rotation = circuit.Waypoints[progressNum].rotation;
}
}


private void Update()
{
if (progressStyle == ProgressStyle.SmoothAlongRoute)
{
// determine the position we should currently be aiming for
// (this is different to the current progress position, it is a a certain amount ahead along the route)
// we use lerp as a simple way of smoothing out the speed over time.
if (Time.deltaTime > 0)
{
speed = Mathf.Lerp(speed, (lastPosition - transform.position).magnitude/Time.deltaTime,
Time.deltaTime);
}
target.position =
circuit.GetRoutePoint(progressDistance + lookAheadForTargetOffset + lookAheadForTargetFactor*speed)
.position;
target.rotation =
Quaternion.LookRotation(
circuit.GetRoutePoint(progressDistance + lookAheadForSpeedOffset + lookAheadForSpeedFactor*speed)
.direction);


// get our current progress along the route
progressPoint = circuit.GetRoutePoint(progressDistance);
Vector3 progressDelta = progressPoint.position - transform.position;
if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
{
progressDistance += progressDelta.magnitude*0.5f;
}

lastPosition = transform.position;
}
else
{
// point to point mode. Just increase the waypoint if we're close enough:

Vector3 targetDelta = target.position - transform.position;
if (targetDelta.magnitude < pointToPointThreshold)
{
progressNum = (progressNum + 1)%circuit.Waypoints.Length;
}


target.position = circuit.Waypoints[progressNum].position;
target.rotation = circuit.Waypoints[progressNum].rotation;

// get our current progress along the route
progressPoint = circuit.GetRoutePoint(progressDistance);
Vector3 progressDelta = progressPoint.position - transform.position;
if (Vector3.Dot(progressDelta, progressPoint.direction) < 0)
{
progressDistance += progressDelta.magnitude;
}
lastPosition = transform.position;
}
}


private void OnDrawGizmos()
{
if (Application.isPlaying)
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, target.position);
Gizmos.DrawWireSphere(circuit.GetRoutePosition(progressDistance), 1);
Gizmos.color = Color.yellow;
Gizmos.DrawLine(target.position, target.position + target.forward);
}
}
}
}