-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathObjectSpawner.cs
146 lines (126 loc) · 3.4 KB
/
ObjectSpawner.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ObjectSpawner.cs">
// Copyright (c) 2020 Johannes Deml. All rights reserved.
// </copyright>
// <author>
// Johannes Deml
// public@deml.io
// </author>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Supyrb
{
/// <summary>
/// Spawns an object in regular intervals
/// </summary>
public class ObjectSpawner : MonoBehaviour
{
[SerializeField]
private GameObject prefab = null;
[SerializeField]
private float spawnCoolDownSeconds = 0.5f;
[SerializeField]
private float spawnOffsetSeconds = 0f;
[SerializeField]
private int maxInstances = 200;
[SerializeField]
[Tooltip("If set, the object will be spawned in the scene with the given name")]
private string spawnSceneName = string.Empty;
public float SpawnCoolDownSeconds
{
get => spawnCoolDownSeconds;
set
{
spawnTimeBase += (spawnCoolDownSeconds - value) * totalSpawnCount;
spawnCoolDownSeconds = value;
}
}
public float SpawnOffsetSeconds
{
get => spawnOffsetSeconds;
set
{
spawnTimeBase += value - spawnOffsetSeconds;
spawnOffsetSeconds = value;
}
}
public int MaxInstances
{
get => maxInstances;
set => maxInstances = value;
}
private Queue<GameObject> spawnedObjects = null;
/// <summary>
/// Time from which the spawn times are calculated
/// will be set on Awake and updated when the spawner is paused, or spawning values are changed
/// </summary>
private float spawnTimeBase;
private int totalSpawnCount = 0;
private float pauseTime = 0f;
private void Awake()
{
spawnedObjects = new Queue<GameObject>(maxInstances + 5);
spawnTimeBase = Time.time + spawnOffsetSeconds;
}
private void Update()
{
float relativeSpawnTime = Time.time - spawnTimeBase;
if (Mathf.FloorToInt(relativeSpawnTime / spawnCoolDownSeconds) > totalSpawnCount)
{
SpawnObject();
}
}
public void PauseSpawning()
{
enabled = false;
pauseTime = Time.time;
}
public void ResumeSpawning()
{
enabled = true;
spawnTimeBase += Time.time - pauseTime;
}
private void SpawnObject()
{
if (spawnedObjects.Count >= maxInstances)
{
var recycleGo = spawnedObjects.Dequeue();
recycleGo.transform.localPosition = transform.position;
recycleGo.transform.localRotation = transform.localRotation;
spawnedObjects.Enqueue(recycleGo);
return;
}
var newGo = InstantiatePrefab();
spawnedObjects.Enqueue(newGo);
totalSpawnCount++;
}
private GameObject InstantiatePrefab()
{
var lastActiveScene = SceneManager.GetActiveScene();
if(!string.IsNullOrEmpty(spawnSceneName))
{
var spawnScene = SceneManager.GetSceneByName(spawnSceneName);
if(!spawnScene.IsValid())
{
spawnScene = SceneManager.CreateScene(spawnSceneName);
}
SceneManager.SetActiveScene(spawnScene);
}
var newGo = Instantiate(prefab, transform.position, transform.rotation);
if(!string.IsNullOrEmpty(spawnSceneName))
{
SceneManager.SetActiveScene(lastActiveScene);
}
return newGo;
}
#if UNITY_EDITOR
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, 0.5f);
}
#endif
}
}