505 lines
14 KiB
Plaintext
505 lines
14 KiB
Plaintext
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class BackGroundRollerWithMemory : MonoBehaviour
|
|
{
|
|
#region Defines
|
|
|
|
public enum RollTypes { RandomPool, SequencePool };
|
|
|
|
private const int MAX_MEMORY_COUNT = 10000;
|
|
private const int PRE_GENRERATE_COUNT = 1000;
|
|
|
|
[System.Serializable]
|
|
public struct BackGroundObject
|
|
{
|
|
public GameObject GameObject;
|
|
public float Length;
|
|
|
|
public void AutoLength()
|
|
{
|
|
Length = GameObject.transform.localScale.x;
|
|
}
|
|
}
|
|
|
|
private struct ActiveBackGround
|
|
{
|
|
public int CountPosition;
|
|
public GameObject GameObject;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Interface
|
|
|
|
#region Func
|
|
|
|
public System.Func<int, float> Func_GetObjectLengthAtCountPos;
|
|
public System.Func<int, GameObject> Func_GetSpawnObjectInstanceAtCountPos;
|
|
|
|
#endregion
|
|
|
|
public RollTypes RollType
|
|
{
|
|
get
|
|
{
|
|
return m_rollType;
|
|
}
|
|
|
|
set
|
|
{
|
|
m_rollType = value;
|
|
}
|
|
}
|
|
|
|
public Transform RollerTarget
|
|
{
|
|
get
|
|
{
|
|
return m_rollerTarget;
|
|
}
|
|
}
|
|
|
|
public BackGroundObject[] BackGroundPool
|
|
{
|
|
get
|
|
{
|
|
return m_backGroundPool;
|
|
}
|
|
|
|
set
|
|
{
|
|
m_backGroundPool = value;
|
|
}
|
|
}
|
|
|
|
public int GetObjectIDAtCountPos(int countPos)
|
|
{
|
|
switch (m_rollType)
|
|
{
|
|
case RollTypes.RandomPool:
|
|
GenerateEnoughIDs(countPos);
|
|
return m_generatedObjectID_Distances[countPos].Key;
|
|
case RollTypes.SequencePool:
|
|
return countPos;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public void SetBackGroundPool(GameObject[] gameObjects)
|
|
{
|
|
int poolLength = gameObjects.Length;
|
|
BackGroundObject[] pool = new BackGroundObject[poolLength];
|
|
for (int i = 0; i < poolLength; i++)
|
|
{
|
|
pool[i].GameObject = gameObjects[i];
|
|
pool[i].AutoLength();
|
|
}
|
|
}
|
|
|
|
public int GetCountPositionWithRelativeX(float x)
|
|
{
|
|
int result = 0;
|
|
int moveDelta = 0;
|
|
IsCorrectLastEnding(x, result, out moveDelta);
|
|
while (moveDelta != 0)
|
|
{
|
|
result += moveDelta;
|
|
IsCorrectLastEnding(x, result, out moveDelta);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public int GetCountPositionWithTransform(Transform targetTransform)
|
|
{
|
|
Vector4 targetPos = targetTransform.position;
|
|
targetPos.w = 1.0f;
|
|
Vector3 relativePos = transform.worldToLocalMatrix * targetPos;
|
|
return GetCountPositionWithRelativeX(relativePos.x);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Debug
|
|
|
|
private Vector3[] m_debugRenderArea;
|
|
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (m_rollerTarget == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Gizmos.color = Color.blue;
|
|
CalculateCameraArea();
|
|
MoreGizmos.DrawMultiLine(m_debugRenderArea);
|
|
}
|
|
|
|
private void CalculateCameraArea()
|
|
{
|
|
if (m_debugRenderArea == null || m_debugRenderArea.Length != 4)
|
|
{
|
|
m_debugRenderArea = new Vector3[4];
|
|
}
|
|
|
|
float half_width = m_renderLength / 2.0f;
|
|
float half_height = 2.5f;
|
|
Vector3 up = transform.up;
|
|
Vector3 right = transform.right;
|
|
|
|
Vector3 pos = m_rollerTarget.position;
|
|
|
|
m_debugRenderArea[0] = pos + up * half_height - right * half_width;
|
|
m_debugRenderArea[1] = pos + up * half_height + right * half_width;
|
|
m_debugRenderArea[2] = pos - up * half_height + right * half_width;
|
|
m_debugRenderArea[3] = pos - up * half_height - right * half_width;
|
|
}
|
|
|
|
#endregion
|
|
|
|
[SerializeField]
|
|
private RollTypes m_rollType;
|
|
|
|
[SerializeField]
|
|
private Transform m_rollerTarget;
|
|
|
|
[SerializeField]
|
|
private BackGroundObject[] m_backGroundPool;
|
|
|
|
[SerializeField]
|
|
private string m_randomSeed;
|
|
private System.Random m_randomer;
|
|
|
|
[SerializeField]
|
|
private float m_renderLength;
|
|
private int m_possibleRenderEndingPosition;
|
|
|
|
private List<KeyValuePair<int, float>> m_generatedObjectID_Distances;
|
|
private List<ActiveBackGround> m_activeBackGrounds;
|
|
|
|
private int GetRandomIDforCountNum(int countNum)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
private KeyValuePair<int, float> GetIDLengthPairAtCountPos(int countPos, float lastEnding)
|
|
{
|
|
switch (m_rollType)
|
|
{
|
|
case RollTypes.RandomPool:
|
|
{
|
|
int nextObjectID = m_randomer.Next(0, m_backGroundPool.Length);
|
|
float newEnding = lastEnding + m_backGroundPool[nextObjectID].Length;
|
|
return new KeyValuePair<int, float>(nextObjectID, newEnding);
|
|
}
|
|
case RollTypes.SequencePool:
|
|
{
|
|
float newEnding = lastEnding + Func_GetObjectLengthAtCountPos(countPos);
|
|
return new KeyValuePair<int, float>(0, newEnding);
|
|
}
|
|
default:
|
|
return new KeyValuePair<int, float>(0, 0);
|
|
}
|
|
}
|
|
|
|
private void GenerateOneID()
|
|
{
|
|
// Generate next id
|
|
int count = m_generatedObjectID_Distances.Count;
|
|
float lastEnding = 0.0f;
|
|
if (count != 0)
|
|
{
|
|
lastEnding = m_generatedObjectID_Distances[count - 1].Value;
|
|
}
|
|
|
|
m_generatedObjectID_Distances.Add(GetIDLengthPairAtCountPos(count, lastEnding));
|
|
}
|
|
|
|
private void PreGenerateIDs()
|
|
{
|
|
if (m_rollType != RollTypes.RandomPool)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < PRE_GENRERATE_COUNT; i++)
|
|
{
|
|
GenerateOneID();
|
|
}
|
|
}
|
|
|
|
private void GenerateEnoughIDs(float offsetLength)
|
|
{
|
|
float minEnding = offsetLength + m_renderLength / 2.0f;
|
|
|
|
if (m_generatedObjectID_Distances.Count == 0)
|
|
{
|
|
GenerateOneID();
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
int count = m_generatedObjectID_Distances.Count;
|
|
float lastEnding = m_generatedObjectID_Distances[count - 1].Value;
|
|
if (lastEnding > minEnding)
|
|
{
|
|
break;
|
|
}
|
|
|
|
GenerateOneID();
|
|
}
|
|
}
|
|
|
|
private void GenerateEnoughIDs(int countPos)
|
|
{
|
|
int count = m_generatedObjectID_Distances.Count;
|
|
while (count <= countPos)
|
|
{
|
|
GenerateOneID();
|
|
count = m_generatedObjectID_Distances.Count;
|
|
}
|
|
}
|
|
|
|
private void IsCorrectLastEnding(float lastEnding, int possiblePosition, out int moveDelta)
|
|
{
|
|
if (possiblePosition < 0)
|
|
{
|
|
moveDelta = 0;
|
|
return;
|
|
}
|
|
|
|
float endingLength = m_generatedObjectID_Distances[possiblePosition].Value;
|
|
if (endingLength < lastEnding)
|
|
{
|
|
moveDelta = 1;
|
|
}
|
|
else
|
|
{
|
|
if (possiblePosition == 0)
|
|
{
|
|
endingLength = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
endingLength = m_generatedObjectID_Distances[possiblePosition - 1].Value;
|
|
}
|
|
|
|
if (endingLength < lastEnding)
|
|
{
|
|
moveDelta = 0;
|
|
}
|
|
else
|
|
{
|
|
moveDelta = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int FindRenderStartPosition(float offsetLength, int renderLastPosition)
|
|
{
|
|
int result = renderLastPosition;
|
|
float starting = offsetLength - m_renderLength / 2.0f;
|
|
int moveDelta;
|
|
IsCorrectLastEnding(starting, result, out moveDelta);
|
|
while (moveDelta != 0)
|
|
{
|
|
result += moveDelta;
|
|
IsCorrectLastEnding(starting, result, out moveDelta);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private int FindRenderLastPosition(float offsetLength)
|
|
{
|
|
int result = m_possibleRenderEndingPosition;
|
|
float lastEnding = offsetLength + m_renderLength / 2.0f;
|
|
int moveDelta;
|
|
IsCorrectLastEnding(lastEnding, result, out moveDelta);
|
|
while (moveDelta != 0)
|
|
{
|
|
result += moveDelta;
|
|
IsCorrectLastEnding(lastEnding, result, out moveDelta);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private GameObject CreateGameObjectAtCountPos(int countPosition)
|
|
{
|
|
BackGroundObject result;
|
|
if (Func_GetSpawnObjectInstanceAtCountPos != null)
|
|
{
|
|
result.Length = Func_GetObjectLengthAtCountPos.Invoke(countPosition);
|
|
result.GameObject = Func_GetSpawnObjectInstanceAtCountPos.Invoke(countPosition);
|
|
result.GameObject.transform.SetParent(transform);
|
|
}
|
|
else
|
|
{
|
|
result = m_backGroundPool[GetObjectIDAtCountPos(countPosition)];
|
|
result.GameObject = Instantiate(result.GameObject, transform);
|
|
}
|
|
|
|
float relativeOffset = m_generatedObjectID_Distances[countPosition].Value;
|
|
float reltaivePosition = relativeOffset - result.Length / 2.0f;
|
|
result.GameObject.transform.localPosition = new Vector3(reltaivePosition, 0.0f, 0.0f);
|
|
|
|
//print($"Active object {result.GameObject.name}, created at countpos:{countPosition}");
|
|
return result.GameObject;
|
|
}
|
|
|
|
private void SpawnGameObjectWithRange(int start, int end, bool doAppend)
|
|
{
|
|
if (end < 0 || start >= m_generatedObjectID_Distances.Count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (start < 0)
|
|
{
|
|
start = 0;
|
|
}
|
|
|
|
if (doAppend)
|
|
{
|
|
for (int i = start; i <= end; i++)
|
|
{
|
|
ActiveBackGround newActiveBackGround;
|
|
newActiveBackGround.CountPosition = i;
|
|
newActiveBackGround.GameObject = CreateGameObjectAtCountPos( i);
|
|
|
|
m_activeBackGrounds.Add(newActiveBackGround);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = end; i >= start; i--)
|
|
{
|
|
ActiveBackGround newActiveBackGround;
|
|
newActiveBackGround.CountPosition = i;
|
|
newActiveBackGround.GameObject = CreateGameObjectAtCountPos(i);
|
|
|
|
m_activeBackGrounds.Insert(0, newActiveBackGround);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DetermineActiveObjects(float offsetLength)
|
|
{
|
|
int renderLastPosition = FindRenderLastPosition(offsetLength);
|
|
int renderStartPosition = FindRenderStartPosition(offsetLength, renderLastPosition);
|
|
|
|
// Delete old ones
|
|
int activeCount = m_activeBackGrounds.Count;
|
|
for (int i = activeCount - 1; i >= 0; i--)
|
|
{
|
|
ActiveBackGround activeBackGround = m_activeBackGrounds[i];
|
|
int countPosition = activeBackGround.CountPosition;
|
|
if (countPosition >= renderStartPosition && countPosition <= renderLastPosition)
|
|
{
|
|
// Leave it as it is
|
|
}
|
|
else
|
|
{
|
|
//print($"Active object with countpos:{countPosition} is destoryed");
|
|
Destroy(activeBackGround.GameObject);
|
|
m_activeBackGrounds.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
// Create new ones
|
|
if (m_activeBackGrounds.Count != 0)
|
|
{
|
|
int activeStartPosition = m_activeBackGrounds[0].CountPosition;
|
|
int activeLastPosition = m_activeBackGrounds[m_activeBackGrounds.Count - 1].CountPosition;
|
|
if (renderStartPosition < activeStartPosition)
|
|
{
|
|
if (renderLastPosition < activeStartPosition)
|
|
{
|
|
SpawnGameObjectWithRange(renderStartPosition, renderLastPosition, false);
|
|
}
|
|
else
|
|
{
|
|
SpawnGameObjectWithRange(renderStartPosition, activeStartPosition - 1, false);
|
|
}
|
|
}
|
|
|
|
if (renderLastPosition > activeLastPosition)
|
|
{
|
|
if (renderStartPosition > activeLastPosition)
|
|
{
|
|
SpawnGameObjectWithRange(renderStartPosition, renderLastPosition, true);
|
|
}
|
|
else
|
|
{
|
|
SpawnGameObjectWithRange(activeLastPosition + 1, renderLastPosition, true);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SpawnGameObjectWithRange(renderStartPosition, renderLastPosition, false);
|
|
}
|
|
}
|
|
|
|
private void AlignWithTargetRotation(Vector3 offsetDir)
|
|
{
|
|
transform.right = offsetDir;
|
|
}
|
|
|
|
private void InitRandomer()
|
|
{
|
|
int seed = System.DateTime.Now.GetHashCode();
|
|
if (m_randomSeed.Length != 0)
|
|
{
|
|
seed = m_randomSeed.GetHashCode();
|
|
}
|
|
|
|
m_randomer = new System.Random(seed);
|
|
}
|
|
|
|
private void AutoFillLength()
|
|
{
|
|
int length = m_backGroundPool.Length;
|
|
for (int i = length - 1; i >= 0; i--)
|
|
{
|
|
if (Mathf.Approximately(m_backGroundPool[i].Length, 0.0f))
|
|
{
|
|
m_backGroundPool[i].AutoLength();
|
|
}
|
|
|
|
if (Mathf.Approximately(m_backGroundPool[i].Length, 0.0f))
|
|
{
|
|
m_backGroundPool[i].Length = 1.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
AutoFillLength();
|
|
|
|
m_generatedObjectID_Distances = new List<KeyValuePair<int, float>>(PRE_GENRERATE_COUNT);
|
|
m_activeBackGrounds = new List<ActiveBackGround>();
|
|
m_possibleRenderEndingPosition = 0;
|
|
|
|
InitRandomer();
|
|
//PreGenerateIDs();
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
Vector3 offsetDir = m_rollerTarget.position - transform.position;
|
|
float offsetLength = offsetDir.magnitude;
|
|
|
|
GenerateEnoughIDs(offsetLength);
|
|
DetermineActiveObjects(offsetLength);
|
|
AlignWithTargetRotation(offsetDir);
|
|
}
|
|
}
|