Добавлен таймер, конфиг и публичный метод
SpawnItems()
CooldownRemaining - оставшееся время до спавна float
CooldownSecondsRemaining - оставшееся время до спавна int
This commit is contained in:
2026-08-11 18:42:09 +05:00
parent 5b888fba95
commit d71b90c8bd
8 changed files with 159 additions and 74 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bb903df62880440f80782f53ec0f6692
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 142c75ae48de4c7ba6fd0daad6905872, type: 3}
m_Name: ItemPipeConfig
m_EditorClassIdentifier:
spawnInterval: 0.05
spawnCooldown: 10
localVelocityChange: {x: 0, y: -5, z: 0}
guaranteedItems:
- prefab: {fileID: 4504260422113134419, guid: 8790cd6f776403940ac664c5db12dab4, type: 3}
amount: 1
randomItemCount: 7
randomItems:
- prefab: {fileID: 2474374521670934351, guid: c91d2337125ccaf45a0c57af9a6703c8, type: 3}
weight: 1
- prefab: {fileID: 4728426142119307488, guid: 795e138cd804c7c42aa508895e6a61df, type: 3}
weight: 1
- prefab: {fileID: 4504260422113134419, guid: 8790cd6f776403940ac664c5db12dab4, type: 3}
weight: 3
randomSpawnX: 1
randomSpawnZ: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3883e23238f84f748e616770b66fa885
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(
fileName = "ItemPipeConfig",
menuName = "Fort Bo/Pipe Junk/Item Pipe Config")]
public sealed class ItemPipeConfig : ScriptableObject
{
[Serializable]
public sealed class GuaranteedItem
{
public GameObject prefab;
[Min(1)]
public int amount = 1;
}
[Serializable]
public sealed class RandomItem
{
public GameObject prefab;
[Min(0f)]
public float weight = 1f;
}
[Header("Timing")]
[SerializeField, Min(0.05f)] private float spawnInterval = 0.5f;
[SerializeField, Min(0f)] private float spawnCooldown = 10f;
[Header("Instant velocity change")]
[SerializeField] private Vector3 localVelocityChange = Vector3.forward * 4.5f;
[Header("Guaranteed items")]
[SerializeField] private List<GuaranteedItem> guaranteedItems = new();
[Header("Random items")]
[SerializeField, Min(0)] private int randomItemCount = 5;
[SerializeField] private List<RandomItem> randomItems = new();
[Header("Spawn position randomization")]
[SerializeField, Min(0f)] private float randomSpawnX = 0.2f;
[SerializeField, Min(0f)] private float randomSpawnZ = 0.2f;
public float SpawnInterval => spawnInterval;
public float SpawnCooldown => spawnCooldown;
public Vector3 LocalVelocityChange => localVelocityChange;
public IReadOnlyList<GuaranteedItem> GuaranteedItems => guaranteedItems;
public int RandomItemCount => randomItemCount;
public IReadOnlyList<RandomItem> RandomItems => randomItems;
public float RandomSpawnX => randomSpawnX;
public float RandomSpawnZ => randomSpawnZ;
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 142c75ae48de4c7ba6fd0daad6905872
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+43 -55
View File
@@ -1,4 +1,3 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@@ -6,77 +5,66 @@ using UnityEngine.InputSystem;
public class ItemPipe : MonoBehaviour public class ItemPipe : MonoBehaviour
{ {
[Serializable]
private class GuaranteedItem
{
public GameObject prefab;
[Min(1)]
public int amount = 1;
}
[Serializable]
private class RandomItem
{
public GameObject prefab;
[Min(0)]
public float weight = 1f;
}
[Header("Pipe")] [Header("Pipe")]
[SerializeField] private Transform spawnPoint; [SerializeField] private Transform spawnPoint;
[SerializeField, Min(0.05f)] private float spawnInterval = 0.5f;
[Header("Instant velocity change")] [Header("Configuration")]
[SerializeField] private Vector3 localVelocityChange = Vector3.forward * 4.5f; [SerializeField] private ItemPipeConfig config;
[Header("Guaranteed items")]
[SerializeField] private List<GuaranteedItem> guaranteedItems = new();
[Header("Random items")]
[SerializeField, Min(0)] private int randomItemCount = 5;
[SerializeField] private List<RandomItem> randomItems = new();
[Header("Spawn position randomization")]
[SerializeField, Min(0f)] private float randomSpawnX = 0.2f;
[SerializeField, Min(0f)] private float randomSpawnZ = 0.2f;
[Header("Temporary testing")] [Header("Temporary testing")]
[SerializeField] private bool spawnOnE = true; [SerializeField] private bool spawnOnE = true;
private bool isSpawning; 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() private void Update()
{ {
if (!spawnOnE || isSpawning || Keyboard.current == null) if (CooldownRemaining > 0f)
CooldownRemaining = Mathf.Max(0f, CooldownRemaining - Time.deltaTime);
if (!spawnOnE || Keyboard.current == null)
return; return;
if (Keyboard.current.eKey.wasPressedThisFrame) if (Keyboard.current.eKey.wasPressedThisFrame)
StartCoroutine(SpawnSequence()); SpawnItems();
} }
private IEnumerator SpawnSequence() public void SpawnItems()
{
if (!CanSpawnItems)
return;
StartCoroutine(SpawnSequence(config));
}
private IEnumerator SpawnSequence(ItemPipeConfig activeConfig)
{ {
isSpawning = true; isSpawning = true;
List<GameObject> spawnQueue = BuildSpawnQueue(); List<GameObject> spawnQueue = BuildSpawnQueue(activeConfig);
foreach (GameObject prefab in spawnQueue) for (int i = 0; i < spawnQueue.Count; i++)
{ {
Spawn(prefab); Spawn(spawnQueue[i], activeConfig);
yield return new WaitForSeconds(spawnInterval);
if (i < spawnQueue.Count - 1)
yield return new WaitForSeconds(activeConfig.SpawnInterval);
} }
isSpawning = false; isSpawning = false;
CooldownRemaining = activeConfig.SpawnCooldown;
} }
private List<GameObject> BuildSpawnQueue() private List<GameObject> BuildSpawnQueue(ItemPipeConfig activeConfig)
{ {
List<GameObject> queue = new(); List<GameObject> queue = new();
// Добавляем предметы в точном количестве. // Добавляем предметы в точном количестве.
foreach (GuaranteedItem item in guaranteedItems) foreach (ItemPipeConfig.GuaranteedItem item in activeConfig.GuaranteedItems)
{ {
if (item.prefab == null) if (item.prefab == null)
continue; continue;
@@ -86,9 +74,9 @@ public class ItemPipe : MonoBehaviour
} }
// Выбираем указанное количество случайных предметов. // Выбираем указанное количество случайных предметов.
for (int i = 0; i < randomItemCount; i++) for (int i = 0; i < activeConfig.RandomItemCount; i++)
{ {
GameObject selectedPrefab = ChooseWeightedRandom(); GameObject selectedPrefab = ChooseWeightedRandom(activeConfig);
if (selectedPrefab != null) if (selectedPrefab != null)
queue.Add(selectedPrefab); queue.Add(selectedPrefab);
@@ -100,11 +88,11 @@ public class ItemPipe : MonoBehaviour
return queue; return queue;
} }
private GameObject ChooseWeightedRandom() private GameObject ChooseWeightedRandom(ItemPipeConfig activeConfig)
{ {
float totalWeight = 0f; float totalWeight = 0f;
foreach (RandomItem item in randomItems) foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems)
{ {
if (item.prefab != null && item.weight > 0f) if (item.prefab != null && item.weight > 0f)
totalWeight += item.weight; totalWeight += item.weight;
@@ -113,10 +101,10 @@ public class ItemPipe : MonoBehaviour
if (totalWeight <= 0f) if (totalWeight <= 0f)
return null; return null;
float roll = UnityEngine.Random.value * totalWeight; float roll = Random.value * totalWeight;
float currentWeight = 0f; float currentWeight = 0f;
foreach (RandomItem item in randomItems) foreach (ItemPipeConfig.RandomItem item in activeConfig.RandomItems)
{ {
if (item.prefab == null || item.weight <= 0f) if (item.prefab == null || item.weight <= 0f)
continue; continue;
@@ -134,20 +122,20 @@ public class ItemPipe : MonoBehaviour
{ {
for (int i = queue.Count - 1; i > 0; i--) for (int i = queue.Count - 1; i > 0; i--)
{ {
int randomIndex = UnityEngine.Random.Range(0, i + 1); int randomIndex = Random.Range(0, i + 1);
(queue[i], queue[randomIndex]) = (queue[i], queue[randomIndex]) =
(queue[randomIndex], queue[i]); (queue[randomIndex], queue[i]);
} }
} }
private void Spawn(GameObject prefab) private void Spawn(GameObject prefab, ItemPipeConfig activeConfig)
{ {
if (prefab == null || spawnPoint == null) if (prefab == null || spawnPoint == null)
return; return;
float offsetX = RandomRange(-randomSpawnX, randomSpawnX); float offsetX = RandomRange(-activeConfig.RandomSpawnX, activeConfig.RandomSpawnX);
float offsetZ = RandomRange(-randomSpawnZ, randomSpawnZ); float offsetZ = RandomRange(-activeConfig.RandomSpawnZ, activeConfig.RandomSpawnZ);
Vector3 spawnPosition = Vector3 spawnPosition =
spawnPoint.position + spawnPoint.position +
@@ -157,13 +145,13 @@ public class ItemPipe : MonoBehaviour
GameObject item = Instantiate( GameObject item = Instantiate(
prefab, prefab,
spawnPosition, spawnPosition,
UnityEngine.Random.rotationUniform Random.rotationUniform
); );
if (item.TryGetComponent(out Rigidbody body)) if (item.TryGetComponent(out Rigidbody body))
{ {
Vector3 worldVelocityChange = Vector3 worldVelocityChange =
spawnPoint.TransformDirection(localVelocityChange); spawnPoint.TransformDirection(activeConfig.LocalVelocityChange);
body.AddForce(worldVelocityChange, ForceMode.VelocityChange); body.AddForce(worldVelocityChange, ForceMode.VelocityChange);
} }
@@ -171,6 +159,6 @@ public class ItemPipe : MonoBehaviour
private float RandomRange(float min, float max) private float RandomRange(float min, float max)
{ {
return UnityEngine.Random.Range(min, max); return Random.Range(min, max);
} }
} }
@@ -45,19 +45,5 @@ MonoBehaviour:
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
spawnPoint: {fileID: 286431562970531899} spawnPoint: {fileID: 286431562970531899}
spawnInterval: 0.05 config: {fileID: 11400000, guid: 3883e23238f84f748e616770b66fa885, type: 2}
localVelocityChange: {x: 0, y: -5, z: 0}
guaranteedItems:
- prefab: {fileID: 4504260422113134419, guid: 8790cd6f776403940ac664c5db12dab4, type: 3}
amount: 1
randomItemCount: 7
randomItems:
- prefab: {fileID: 2474374521670934351, guid: c91d2337125ccaf45a0c57af9a6703c8, type: 3}
weight: 1
- prefab: {fileID: 4728426142119307488, guid: 795e138cd804c7c42aa508895e6a61df, type: 3}
weight: 1
- prefab: {fileID: 4504260422113134419, guid: 8790cd6f776403940ac664c5db12dab4, type: 3}
weight: 3
randomSpawnX: 1
randomSpawnZ: 1
spawnOnE: 1 spawnOnE: 1
@@ -104,7 +104,7 @@
{ {
"type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "type": "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
"key": "ShapeBuilder.ActiveShapeIndex", "key": "ShapeBuilder.ActiveShapeIndex",
"value": "{\"m_Value\":7}" "value": "{\"m_Value\":6}"
}, },
{ {
"type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
@@ -119,7 +119,7 @@
{ {
"type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",
"key": "ShapeBuilder.LastSize.Cylinder", "key": "ShapeBuilder.LastSize.Cylinder",
"value": "{\"m_Value\":{\"x\":4.177962303161621,\"y\":0.2011122703552246,\"z\":-4.202449798583984}}" "value": "{\"m_Value\":{\"x\":-0.4658929109573364,\"y\":0.78654944896698,\"z\":-0.47608280181884768}}"
}, },
{ {
"type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "type": "UnityEngine.Vector3, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null",