Files
FORT-BO/Assets/CONTENT/FEATURES/PipeJunk/ItemPipe.cs
T
Henjke d71b90c8bd Edited
Добавлен таймер, конфиг и публичный метод
SpawnItems()
CooldownRemaining - оставшееся время до спавна float
CooldownSecondsRemaining - оставшееся время до спавна int
2026-08-11 18:42:09 +05:00

165 lines
4.6 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class ItemPipe : MonoBehaviour
{
[Header("Pipe")]
[SerializeField] private Transform spawnPoint;
[Header("Configuration")]
[SerializeField] private ItemPipeConfig config;
[Header("Temporary testing")]
[SerializeField] private bool spawnOnE = true;
private bool isSpawning;
public float CooldownDuration => config != null ? config.SpawnCooldown : 0f;
public float CooldownRemaining { get; private set; }
public int CooldownSecondsRemaining => Mathf.CeilToInt(CooldownRemaining);
public bool CanSpawnItems => config != null && !isSpawning && CooldownRemaining <= 0f;
private void Update()
{
if (CooldownRemaining > 0f)
CooldownRemaining = Mathf.Max(0f, CooldownRemaining - Time.deltaTime);
if (!spawnOnE || Keyboard.current == null)
return;
if (Keyboard.current.eKey.wasPressedThisFrame)
SpawnItems();
}
public void SpawnItems()
{
if (!CanSpawnItems)
return;
StartCoroutine(SpawnSequence(config));
}
private IEnumerator SpawnSequence(ItemPipeConfig activeConfig)
{
isSpawning = true;
List<GameObject> spawnQueue = BuildSpawnQueue(activeConfig);
for (int i = 0; i < spawnQueue.Count; i++)
{
Spawn(spawnQueue[i], activeConfig);
if (i < spawnQueue.Count - 1)
yield return new WaitForSeconds(activeConfig.SpawnInterval);
}
isSpawning = false;
CooldownRemaining = activeConfig.SpawnCooldown;
}
private List<GameObject> BuildSpawnQueue(ItemPipeConfig activeConfig)
{
List<GameObject> queue = new();
// Добавляем предметы в точном количестве.
foreach (ItemPipeConfig.GuaranteedItem item in activeConfig.GuaranteedItems)
{
if (item.prefab == null)
continue;
for (int i = 0; i < item.amount; i++)
queue.Add(item.prefab);
}
// Выбираем указанное количество случайных предметов.
for (int i = 0; i < activeConfig.RandomItemCount; i++)
{
GameObject selectedPrefab = ChooseWeightedRandom(activeConfig);
if (selectedPrefab != null)
queue.Add(selectedPrefab);
}
// Перемешиваем гарантированные и случайные предметы вместе.
Shuffle(queue);
return queue;
}
private GameObject ChooseWeightedRandom(ItemPipeConfig activeConfig)
{
float totalWeight = 0f;
foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems)
{
if (item.prefab != null && item.weight > 0f)
totalWeight += item.weight;
}
if (totalWeight <= 0f)
return null;
float roll = Random.value * totalWeight;
float currentWeight = 0f;
foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems)
{
if (item.prefab == null || item.weight <= 0f)
continue;
currentWeight += item.weight;
if (roll < currentWeight)
return item.prefab;
}
return null;
}
private void Shuffle(List<GameObject> queue)
{
for (int i = queue.Count - 1; i > 0; i--)
{
int randomIndex = Random.Range(0, i + 1);
(queue[i], queue[randomIndex]) =
(queue[randomIndex], queue[i]);
}
}
private void Spawn(GameObject prefab, ItemPipeConfig activeConfig)
{
if (prefab == null || spawnPoint == null)
return;
float offsetX = RandomRange(-activeConfig.RandomSpawnX, activeConfig.RandomSpawnX);
float offsetZ = RandomRange(-activeConfig.RandomSpawnZ, activeConfig.RandomSpawnZ);
Vector3 spawnPosition =
spawnPoint.position +
spawnPoint.right * offsetX +
spawnPoint.forward * offsetZ;
GameObject item = Instantiate(
prefab,
spawnPosition,
Random.rotationUniform
);
if (item.TryGetComponent(out Rigidbody body))
{
Vector3 worldVelocityChange =
spawnPoint.TransformDirection(activeConfig.LocalVelocityChange);
body.AddForce(worldVelocityChange, ForceMode.VelocityChange);
}
}
private float RandomRange(float min, float max)
{
return Random.Range(min, max);
}
}