WXMC/.svn/pristine/44/447d81a718156b8abbb2c1e0b5f1d9aaa5109868.svn-base
2024-12-04 16:18:46 +08:00

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);
}
}