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.
 
 
 
 
 
 

324 lines
12 KiB

using System;
using UnityEngine;
using System.Collections.Generic;
using BansheeGz.BGSpline.Curve;
using Random = UnityEngine.Random;
namespace BansheeGz.BGSpline.Example
{
// math visual testing (for internal use)
public class BGTestCurveMath : MonoBehaviour
{
[Tooltip("Material to use with LineRenderer")] public Material LineRendererMaterial;
[Tooltip("Object to move along a curve")] public MeshRenderer ObjectToMove;
private const float Period = 3;
private const int ObjectsCount = 4;
private const float ObjectsSpeed = .3f;
private TestCurves testCurves;
private GUIStyle style;
// Use this for initialization
private void Start()
{
testCurves = new TestCurves(GetComponent<BGCurve>(), new BGCurveBaseMath.Config(BGCurveBaseMath.Fields.PositionAndTangent), ObjectToMove, LineRendererMaterial);
//Base, OptimizeStraightLines
testCurves.Add(new CurveData(testCurves, "BGBaseStraightLines", "Base, OptimizeStraightLines = true", transform.position + new Vector3(-4, 1),
new BGCurveBaseMath.Config(BGCurveBaseMath.Fields.PositionAndTangent) {OptimizeStraightLines = true}, CurveData.MathTypeEnum.Base));
//Base, UsePointPositionsToCalcTangents
testCurves.Add(new CurveData(testCurves, "BGBasePos2Tangents", "Base, UsePointPositionsToCalcTangents = true", transform.position + new Vector3(-4, 4),
new BGCurveBaseMath.Config(BGCurveBaseMath.Fields.PositionAndTangent) {UsePointPositionsToCalcTangents = true}, CurveData.MathTypeEnum.Base));
//Adaptive
testCurves.Add(new CurveData(testCurves, "BGAdaptive", "Adaptive", transform.position + new Vector3(4, 4),
new BGCurveAdaptiveMath.ConfigAdaptive(BGCurveBaseMath.Fields.PositionAndTangent) /* { Tolerance = .2f }*/, CurveData.MathTypeEnum.Adaptive));
//Formula
testCurves.Add(new CurveData(testCurves, "BGFormula", "Formula", transform.position + new Vector3(4, 1),
new BGCurveBaseMath.Config(BGCurveBaseMath.Fields.PositionAndTangent), CurveData.MathTypeEnum.Formula));
}
// Update is called once per frame
private void Update()
{
testCurves.Update();
if (Input.GetKeyDown(KeyCode.LeftArrow)) testCurves.MoveLeft();
if (Input.GetKeyDown(KeyCode.RightArrow)) testCurves.MoveRight();
}
private void OnGUI()
{
if (style == null) style = new GUIStyle(GUI.skin.label) {fontSize = 18};
GUI.Label(new Rect(0, 24, 800, 30), "Left Arrow - move left, Right Arrow - move right", style);
GUI.Label(new Rect(0, 48, 800, 30), "Comparing with: " + testCurves.CurrentToString(), style);
}
//==================================== abstract curve's data
private abstract class CurveDataAbstract
{
private readonly List<GameObject> objectsToMove = new List<GameObject>();
private readonly Material objectToMoveMaterial;
private readonly LineRenderer lineRenderer;
public readonly Material LineRendererMaterial;
protected readonly GameObject GameObject;
protected BGCurveBaseMath Math;
private BGCurve curve;
public BGCurve Curve
{
get { return curve; }
protected set
{
curve = value;
curve.Changed += (sender, args) => UpdateLineRenderer();
}
}
protected CurveDataAbstract(GameObject gameObject, Material lineRendererMaterial, Color color)
{
GameObject = gameObject;
LineRendererMaterial = lineRendererMaterial;
//change material
objectToMoveMaterial = Instantiate(lineRendererMaterial);
objectToMoveMaterial.SetColor("_TintColor", color);
//add lineRenderer
lineRenderer = gameObject.AddComponent<LineRenderer>();
lineRenderer.material = lineRendererMaterial;
#if UNITY_5_5 || UNITY_5_6
lineRenderer.startWidth = lineRenderer.endWidth = 0.05f;
lineRenderer.startColor = lineRenderer.endColor = color;
#else
lineRenderer.SetWidth(0.05f, 0.05f);
lineRenderer.SetColors(color, color);
#endif
}
//=================== line renderer
private void UpdateLineRenderer()
{
const int count = 100;
var positions = new Vector3[100];
const float countMinusOne = count - 1;
for (var i = 0; i < 100; i++)
{
var distanceRatio = i/countMinusOne;
positions[i] = Math.CalcByDistanceRatio(BGCurveBaseMath.Field.Position, distanceRatio);
}
#if UNITY_5_5 || UNITY_5_6
lineRenderer.positionCount = count;
#else
lineRenderer.SetVertexCount(count);
#endif
lineRenderer.SetPositions(positions);
}
//=================== objects
protected void AddObjects(int count, MeshRenderer pattern, Transform parent)
{
for (var i = 0; i < count; i++)
{
var clone = Instantiate(pattern.gameObject);
clone.transform.parent = parent;
AddObject(clone);
}
}
protected void AddObject(GameObject obj)
{
obj.GetComponent<MeshRenderer>().sharedMaterial = objectToMoveMaterial;
objectsToMove.Add(obj.gameObject);
}
protected void UpdateObjects(List<float> distanceRatios)
{
for (var i = 0; i < objectsToMove.Count; i++)
{
var position = Math.CalcByDistanceRatio(BGCurveBaseMath.Field.Position, distanceRatios[i]);
var tangent = Math.CalcByDistanceRatio(BGCurveBaseMath.Field.Tangent, distanceRatios[i]);
objectsToMove[i].transform.position = position;
objectsToMove[i].transform.LookAt(position + tangent);
}
}
public abstract void Update();
}
//==================================== Reference Curve
private sealed class TestCurves : CurveDataAbstract
{
public readonly List<float> DistanceRatios = new List<float>();
public readonly MeshRenderer ObjectToMove;
private readonly List<CurveData> curves = new List<CurveData>();
private float startTime = -Period*2;
private Quaternion fromRotation;
private Quaternion toRotation;
private int currentCurveIndex = -1;
public TestCurves(BGCurve curve, BGCurveBaseMath.Config config, MeshRenderer objectToMove, Material lineRendererMaterial)
: base(curve.gameObject, lineRendererMaterial, Color.green)
{
Curve = curve;
Math = new BGCurveBaseMath(curve, config);
ObjectToMove = objectToMove;
AddObject(objectToMove.gameObject);
AddObjects(ObjectsCount - 1, objectToMove, curve.transform);
const float offset = 1/(float) ObjectsCount;
for (var i = 0; i < ObjectsCount; i++) DistanceRatios.Add(i*offset);
}
public void MoveRight()
{
currentCurveIndex++;
if (currentCurveIndex == curves.Count) currentCurveIndex = 0;
}
public void MoveLeft()
{
currentCurveIndex--;
if (currentCurveIndex < 0) currentCurveIndex = curves.Count - 1;
}
public override void Update()
{
if (Time.time - startTime > Period)
{
startTime = Time.time;
fromRotation = Curve.transform.rotation;
toRotation = Quaternion.Euler(Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f));
}
var ratio = (Time.time - startTime)/Period;
Curve.transform.rotation = Quaternion.Lerp(fromRotation, toRotation, ratio);
for (var i = 0; i < DistanceRatios.Count; i++)
{
DistanceRatios[i] += ObjectsSpeed*Time.deltaTime;
if (DistanceRatios[i] > 1) DistanceRatios[i] = 0;
}
UpdateObjects(DistanceRatios);
foreach (var data in curves) data.Update();
}
public bool IsCurrent(CurveData curve)
{
return currentCurveIndex >= 0 && currentCurveIndex < curves.Count && curves[currentCurveIndex] == curve;
}
public void Add(CurveData curveData)
{
curves.Add(curveData);
}
public string CurrentToString()
{
return currentCurveIndex < 0 ? "None" : curves[currentCurveIndex].Description;
}
}
//==================================== Some Curve
private sealed class CurveData : CurveDataAbstract
{
public enum MathTypeEnum
{
Base,
Formula,
Adaptive
}
private readonly Vector3 origin;
private readonly TestCurves testCurves;
private readonly Vector3 originalScale = new Vector3(.7f, .7f, .7f);
private readonly string description;
public string Description
{
get { return description; }
}
public CurveData(TestCurves testCurves, string name, string description, Vector3 position, BGCurveBaseMath.Config config, MathTypeEnum mathType)
: base(new GameObject(name), testCurves.LineRendererMaterial, Color.magenta)
{
this.testCurves = testCurves;
this.description = description;
//game object
GameObject.transform.position = position;
origin = position;
//curve
Curve = GameObject.AddComponent<BGCurve>();
Curve.Closed = testCurves.Curve.Closed;
//add points
for (var i = 0; i < testCurves.Curve.PointsCount; i++)
{
var point = testCurves.Curve[i];
var clonePoint = new BGCurvePoint(Curve, point.PositionLocal, point.ControlType, point.ControlFirstLocal, point.ControlSecondLocal);
Curve.AddPoint(clonePoint);
}
//init math after points are added
switch (mathType)
{
case MathTypeEnum.Base:
Math = new BGCurveBaseMath(Curve, config);
break;
case MathTypeEnum.Formula:
#pragma warning disable 0618
Math = new BGCurveFormulaMath(Curve, config);
#pragma warning restore 0618
break;
case MathTypeEnum.Adaptive:
Math = new BGCurveAdaptiveMath(Curve, (BGCurveAdaptiveMath.ConfigAdaptive) config);
break;
default:
throw new ArgumentOutOfRangeException("mathType", mathType, null);
}
AddObjects(ObjectsCount, testCurves.ObjectToMove, GameObject.transform);
//scale down
GameObject.transform.localScale = originalScale;
}
public override void Update()
{
var curveTransform = Curve.gameObject.transform;
var referenceTransform = testCurves.Curve.transform;
curveTransform.rotation = referenceTransform.rotation;
var moveTime = 10*Time.deltaTime;
var current = testCurves.IsCurrent(this);
curveTransform.position = Vector3.MoveTowards(curveTransform.position, current ? referenceTransform.position : origin, moveTime);
curveTransform.localScale = Vector3.MoveTowards(curveTransform.localScale, current ? referenceTransform.transform.localScale : originalScale, moveTime/4);
UpdateObjects(testCurves.DistanceRatios);
}
}
}
}