diff options
Diffstat (limited to 'Assets/ThirdParty/XWeaponTrail/Scripts/XWeaponTrail.cs')
-rw-r--r-- | Assets/ThirdParty/XWeaponTrail/Scripts/XWeaponTrail.cs | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/Assets/ThirdParty/XWeaponTrail/Scripts/XWeaponTrail.cs b/Assets/ThirdParty/XWeaponTrail/Scripts/XWeaponTrail.cs new file mode 100644 index 00000000..5a2de663 --- /dev/null +++ b/Assets/ThirdParty/XWeaponTrail/Scripts/XWeaponTrail.cs @@ -0,0 +1,419 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace XftWeapon { + public class XWeaponTrail : MonoBehaviour { + public class Element { + public Vector3 PointStart; + + public Vector3 PointEnd; + + public Vector3 Pos { + get { + return (PointStart + PointEnd) / 2f; + } + } + + + public Element(Vector3 start, Vector3 end) { + PointStart = start; + PointEnd = end; + } + + public Element() { + + } + } + public class ElementPool { + private readonly Stack<Element> _stack = new Stack<Element>(); + + public int CountAll { get; private set; } + public int CountActive { get { return CountAll - CountInactive; } } + public int CountInactive { get { return _stack.Count; } } + + public ElementPool(int preCount) { + for (int i = 0; i < preCount; i++) { + Element element = new Element(); + _stack.Push(element); + CountAll++; + } + } + + public Element Get() { + Element element; + if (_stack.Count == 0) { + element = new Element(); + CountAll++; + } + else { + element = _stack.Pop(); + } + + return element; + } + + public void Release(Element element) { + if (_stack.Count > 0 && ReferenceEquals(_stack.Peek(), element)) { + Debug.LogError("Internal error. Trying to destroy object that is already released to pool."); + } + _stack.Push(element); + } + } + + #region public members + + public static string Version = "1.2.0"; + + + public bool UseWith2D = false; + public string SortingLayerName; + public int SortingOrder; + public Transform PointStart; + public Transform PointEnd; + + public int MaxFrame = 14; + public int Granularity = 60; + //public float Fps = 60f; + + public Color MyColor = Color.white; + public Material MyMaterial; + #endregion + + + + #region protected members + protected float mTrailWidth = 0f; + protected Element mHeadElem = new Element(); + protected List<Element> mSnapshotList = new List<Element>(); + protected ElementPool mElemPool; + protected Spline mSpline = new Spline(); + protected float mFadeT = 1f; + protected bool mIsFading = false; + protected float mFadeTime = 1f; + protected float mElapsedTime = 0f; + protected float mFadeElapsedime = 0f; + protected GameObject mMeshObj; + protected VertexPool mVertexPool; + protected VertexPool.VertexSegment mVertexSegment; + protected bool mInited = false; + + #endregion + + #region property + //public float UpdateInterval { + // get { + // return 1f / Fps; + // } + //} + public Vector3 CurHeadPos { + get { return (PointStart.position + PointEnd.position) / 2f; } + } + public float TrailWidth { + get { + return mTrailWidth; + } + } + #endregion + + #region API + //you may pre-init the trail to save some performance. + public void Init() { + if (mInited) + return; + + mElemPool = new ElementPool(MaxFrame); + + mTrailWidth = (PointStart.position - PointEnd.position).magnitude; + + InitMeshObj(); + + InitOriginalElements(); + + InitSpline(); + + mInited = true; + } + + public void Activate() { + + Init(); + + gameObject.SetActive(true); + mVertexPool.SetMeshObjectActive(true); + + mFadeT = 1f; + mIsFading = false; + mFadeTime = 1f; + mFadeElapsedime = 0f; + mElapsedTime = 0f; + + //reset all elemts to head pos. + for (int i = 0; i < mSnapshotList.Count; i++) { + mSnapshotList[i].PointStart = PointStart.position; + mSnapshotList[i].PointEnd = PointEnd.position; + + mSpline.ControlPoints[i].Position = mSnapshotList[i].Pos; + mSpline.ControlPoints[i].Normal = mSnapshotList[i].PointEnd - mSnapshotList[i].PointStart; + } + + //reset vertex too. + RefreshSpline(); + UpdateVertex(); + } + + public void Deactivate() { + gameObject.SetActive(false); + mVertexPool.SetMeshObjectActive(false); + } + + public void StopSmoothly(float fadeTime) { + mIsFading = true; + mFadeTime = fadeTime; + } + + #endregion + + #region unity methods + void Update() { + + if (!mInited) + return; + + + UpdateHeadElem(); + + + //mElapsedTime += Time.deltaTime; + //if (mElapsedTime < UpdateInterval) { + // return; + //} + //mElapsedTime -= UpdateInterval; + + + + RecordCurElem(); + + RefreshSpline(); + + UpdateFade(); + + UpdateVertex(); + + } + + + void LateUpdate() { + if (!mInited) + return; + + + mVertexPool.LateUpdate(); + } + + void OnDestroy() { + if (!mInited || mVertexPool == null) { + return; + } + mVertexPool.Destroy(); + } + + + void Start() { + mInited = false; + Init(); + } + + void OnDrawGizmos() { + if (PointEnd == null || PointStart == null) { + return; + } + + + float dist = (PointStart.position - PointEnd.position).magnitude; + + if (dist < Mathf.Epsilon) + return; + + + Gizmos.color = Color.red; + + Gizmos.DrawSphere(PointStart.position, dist * 0.04f); + + + Gizmos.color = Color.blue; + Gizmos.DrawSphere(PointEnd.position, dist * 0.04f); + + } + + #endregion + + #region local methods + + void InitSpline() { + mSpline.Granularity = Granularity; + + mSpline.Clear(); + + for (int i = 0; i < MaxFrame; i++) { + mSpline.AddControlPoint(CurHeadPos, PointStart.position - PointEnd.position); + } + } + + void RefreshSpline() { + for (int i = 0; i < mSnapshotList.Count; i++) { + mSpline.ControlPoints[i].Position = mSnapshotList[i].Pos; + mSpline.ControlPoints[i].Normal = mSnapshotList[i].PointEnd - mSnapshotList[i].PointStart; + } + + mSpline.RefreshSpline(); + } + + void UpdateVertex() { + + VertexPool pool = mVertexSegment.Pool; + + + for (int i = 0; i < Granularity; i++) { + int baseIdx = mVertexSegment.VertStart + i * 3; + + float uvSegment = (float)i / Granularity; + + + float fadeT = uvSegment * mFadeT; + + Vector2 uvCoord = Vector2.zero; + + Vector3 pos = mSpline.InterpolateByLen(fadeT); + + //Debug.DrawRay(pos, Vector3.up, Color.red); + + Vector3 up = mSpline.InterpolateNormalByLen(fadeT); + Vector3 pos0 = pos + (up.normalized * mTrailWidth * 0.5f); + Vector3 pos1 = pos - (up.normalized * mTrailWidth * 0.5f); + + + // pos0 + pool.Vertices[baseIdx] = pos0; + pool.Colors[baseIdx] = MyColor; + uvCoord.x = 0f; + uvCoord.y = uvSegment; + pool.UVs[baseIdx] = uvCoord; + + //pos + pool.Vertices[baseIdx + 1] = pos; + pool.Colors[baseIdx + 1] = MyColor; + uvCoord.x = 0.5f; + uvCoord.y = uvSegment; + pool.UVs[baseIdx + 1] = uvCoord; + + //pos1 + pool.Vertices[baseIdx + 2] = pos1; + pool.Colors[baseIdx + 2] = MyColor; + uvCoord.x = 1f; + uvCoord.y = uvSegment; + pool.UVs[baseIdx + 2] = uvCoord; + } + + mVertexSegment.Pool.UVChanged = true; + mVertexSegment.Pool.VertChanged = true; + mVertexSegment.Pool.ColorChanged = true; + + } + + void UpdateIndices() { + + VertexPool pool = mVertexSegment.Pool; + + for (int i = 0; i < Granularity - 1; i++) { + int baseIdx = mVertexSegment.VertStart + i * 3; + int nextBaseIdx = mVertexSegment.VertStart + (i + 1) * 3; + + int iidx = mVertexSegment.IndexStart + i * 12; + + //triangle left + pool.Indices[iidx + 0] = nextBaseIdx; + pool.Indices[iidx + 1] = nextBaseIdx + 1; + pool.Indices[iidx + 2] = baseIdx; + pool.Indices[iidx + 3] = nextBaseIdx + 1; + pool.Indices[iidx + 4] = baseIdx + 1; + pool.Indices[iidx + 5] = baseIdx; + + + //triangle right + pool.Indices[iidx + 6] = nextBaseIdx + 1; + pool.Indices[iidx + 7] = nextBaseIdx + 2; + pool.Indices[iidx + 8] = baseIdx + 1; + pool.Indices[iidx + 9] = nextBaseIdx + 2; + pool.Indices[iidx + 10] = baseIdx + 2; + pool.Indices[iidx + 11] = baseIdx + 1; + + } + + pool.IndiceChanged = true; + } + + void UpdateHeadElem() { + mSnapshotList[0].PointStart = PointStart.position; + mSnapshotList[0].PointEnd = PointEnd.position; + } + + + void UpdateFade() { + if (!mIsFading) + return; + + mFadeElapsedime += Time.deltaTime; + + float t = mFadeElapsedime / mFadeTime; + + mFadeT = 1f - t; + + if (mFadeT < 0f) { + Deactivate(); + } + } + + void RecordCurElem() { + //TODO: use element pool to avoid gc alloc. + //Element elem = new Element(PointStart.position, PointEnd.position); + + Element elem = mElemPool.Get(); + elem.PointStart = PointStart.position; + elem.PointEnd = PointEnd.position; + + if (mSnapshotList.Count < MaxFrame) { + mSnapshotList.Insert(1, elem); + } + else { + mElemPool.Release(mSnapshotList[mSnapshotList.Count - 1]); + mSnapshotList.RemoveAt(mSnapshotList.Count - 1); + mSnapshotList.Insert(1, elem); + } + + } + + void InitOriginalElements() { + mSnapshotList.Clear(); + //at least add 2 original elements + mSnapshotList.Add(new Element(PointStart.position, PointEnd.position)); + mSnapshotList.Add(new Element(PointStart.position, PointEnd.position)); + } + + + + void InitMeshObj() { + //init vertexpool + mVertexPool = new VertexPool(MyMaterial, this); + mVertexSegment = mVertexPool.GetVertices(Granularity * 3, (Granularity - 1) * 12); + UpdateIndices(); + } + + #endregion + + + } + +} + + |