SummerGame/Assets/_Project/Scripts/RunnerPart/Van/VanController.cs

155 lines
4.4 KiB
C#

using System.Collections;
using UnityEngine;
using Boxes;
public class VanController : MonoBehaviour
{
[Header("Движение")]
public float forwardSpeed = 5.0f;
public float moveSpeed = 10.0f;
[Header("Спавн коробок")]
public BoxData[] availableBoxes;
public float spawnInterval = 0.5f;
public float boxEjectionForce = 2f;
public float boxTorqueForce = 5f;
[Header("AI Уклонения")]
public float detectionDistance = 40f;
public LayerMask trafficLayer;
private int _currentLaneIndex = 3;
private float _targetX;
private bool _isChangingLane;
private float _totalSpawnWeight;
private bool _isAlive = true;
private int[] _safeLanesBuffer;
private void OnEnable()
{
GameEvents.OnPlayerDied += StopActivities;
}
private void OnDisable()
{
GameEvents.OnPlayerDied -= StopActivities;
}
void Start()
{
_targetX = transform.position.x;
_totalSpawnWeight = 0;
foreach (var box in availableBoxes)
{
_totalSpawnWeight += box.spawnWeight;
}
_safeLanesBuffer = new int[RoadManager.Instance.GetLanesCount()];
StartCoroutine(SpawnBoxesInfinitely());
StartCoroutine(AvoidanceRoutine());
}
void Update()
{
if (!_isAlive) return;
transform.Translate(Vector3.forward * forwardSpeed * Time.deltaTime);
Vector3 newPos = transform.position;
newPos.x = Mathf.Lerp(newPos.x, _targetX, Time.deltaTime * moveSpeed);
transform.position = newPos;
}
private void StopActivities() => _isAlive = false;
IEnumerator SpawnBoxesInfinitely()
{
while (_isAlive)
{
yield return new WaitForSeconds(spawnInterval);
SpawnPhysicalBox();
}
}
void SpawnPhysicalBox()
{
BoxData boxToSpawn = GetRandomBoxType();
if (boxToSpawn == null || boxToSpawn.boxPrefab == null) return;
GameObject box = SimpleObjectPool.Instance.Get(boxToSpawn.boxPrefab, transform.position, Random.rotation);
Box boxComponent = box.GetComponent<Box>();
if (boxComponent != null) boxComponent.Init(boxToSpawn);
Rigidbody rb = box.GetComponent<Rigidbody>();
if (rb != null)
{
rb.linearVelocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
rb.AddForce(Vector3.back * boxEjectionForce, ForceMode.Impulse);
rb.AddTorque(Random.insideUnitSphere * boxTorqueForce, ForceMode.Impulse);
}
}
BoxData GetRandomBoxType()
{
if (availableBoxes.Length == 0) return null;
float randomValue = Random.Range(0, _totalSpawnWeight);
float currentWeight = 0;
foreach (var boxData in availableBoxes)
{
currentWeight += boxData.spawnWeight;
if (randomValue <= currentWeight) return boxData;
}
return null;
}
IEnumerator AvoidanceRoutine()
{
while (_isAlive)
{
yield return new WaitForSeconds(0.2f);
if (_isChangingLane) continue;
if (IsObstacleAhead()) TryToEvade();
}
}
bool IsObstacleAhead() => Physics.Raycast(transform.position, Vector3.forward, detectionDistance, trafficLayer);
void TryToEvade()
{
int safeLanesCount = 0;
int totalLanes = RoadManager.Instance.GetLanesCount();
for (int i = 0; i < totalLanes; i++)
{
if (i == _currentLaneIndex) continue;
float laneX = RoadManager.Instance.GetLaneX(i);
Vector3 checkPosition = new Vector3(laneX, transform.position.y, transform.position.z);
if (!Physics.Raycast(checkPosition, Vector3.forward, detectionDistance, trafficLayer))
{
_safeLanesBuffer[safeLanesCount] = i;
safeLanesCount++;
}
}
if (safeLanesCount > 0)
{
int chosenLane = _safeLanesBuffer[Random.Range(0, safeLanesCount)];
StartCoroutine(ChangeLane(chosenLane));
}
}
IEnumerator ChangeLane(int newLaneIndex)
{
_isChangingLane = true;
_currentLaneIndex = newLaneIndex;
_targetX = RoadManager.Instance.GetLaneX(newLaneIndex);
yield return new WaitForSeconds(0.6f);
_isChangingLane = false;
}
}