working save / load functions

problème : au moment de load une save, les tiles qui spawnaient des GameObjects au start les spawnaient malgré qu'ils l'avait déjà spawné dans la dernière session de jeu + problèmes de sérialisation divers

solution : spawner le GameObject seulement si le lifetime de la tile est de zéro. correction des différents problèmes de sérialisation.

note : les tiles ne semblent vraiment pas être faites pour avoir une update loop. mais bon, maintenant ça marche.
This commit is contained in:
Felix Boucher 2023-05-28 01:52:44 -04:00
parent 4fbce56853
commit d4f32e439f
13 changed files with 140 additions and 142 deletions

View File

@ -1,31 +0,0 @@
%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: edb1aa3d6230b1e4c9a50056da756015, type: 3}
m_Name: New Database
m_EditorClassIdentifier:
_prefabs:
- {fileID: 6962989255644195630, guid: 6cd87b398e7a0e94580f4fcbe2fd310a, type: 3}
- {fileID: 6962989255644195630, guid: 377c7275c0001cc47a6b8926ac57d573, type: 3}
- {fileID: 6962989255644195630, guid: 869a03bba705e8d4485aa73daad773dc, type: 3}
- {fileID: 6962989255644195630, guid: 9b40c232eddfd1b469bea688e3c970c0, type: 3}
- {fileID: 4052934186652138539, guid: 8560e1f66d452b543a705c8a0f3e22fa, type: 3}
- {fileID: 3814095509541806390, guid: 9527f3a1482b90a48bb6c62acc70f986, type: 3}
_scriptableObjects:
- {fileID: 11400000, guid: e715669e1ed4b294c82d07ac011e89bb, type: 2}
- {fileID: 11400000, guid: a6e34739c9325da4cac4fbaea30d052c, type: 2}
- {fileID: 11400000, guid: d37561e153d6a6448a03839488fdec5e, type: 2}
- {fileID: 11400000, guid: 4002377ed7e87b34699f126f2b10c703, type: 2}
- {fileID: 11400000, guid: 4aaf448680c7f8a438a9a5861c622a55, type: 2}
_folders:
- {fileID: 102900000, guid: 0ca30b5ca281be24bb62d7e48cc2bec8, type: 3}
- {fileID: 102900000, guid: f3dee7994db941e47b9445cb464c69a9, type: 3}
- {fileID: 102900000, guid: 4f8284570682f8f4c954e446b35ea0ae, type: 3}

View File

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 8fac5b907c0463e4590e43f7fedee816
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,13 +6,13 @@ using static Extensions;
public class Entity : LevelObject public class Entity : LevelObject
{ {
//Attribut //Attribut
[SerializeField, LevelSerialize] [SerializeField]
private int _hp; private int _hp;
[SerializeField, LevelSerialize] [SerializeField]
private float _speed; private float _speed;
[SerializeField, LevelSerialize] [SerializeField]
private int _attack_damage; private int _attack_damage;
[SerializeField, LevelSerialize] [SerializeField]
private float _attack_speed; private float _attack_speed;
private float _attack_speed_wait = 0f; private float _attack_speed_wait = 0f;
@ -83,8 +83,19 @@ public class Entity : LevelObject
dict[nameof(_speed)] = _speed; dict[nameof(_speed)] = _speed;
dict[nameof(_attack_speed)] = _attack_speed; dict[nameof(_attack_speed)] = _attack_speed;
dict[nameof(_attack_damage)] = _attack_damage; dict[nameof(_attack_damage)] = _attack_damage;
dict[nameof(_attack_speed_wait)] = _attack_speed_wait;
return dict; return dict;
} }
public override void LoadDictionary(Dictionary<string, object> dict)
{
base.LoadDictionary(dict);
_hp = dict[nameof(_hp)].ToInt();
_speed = dict[nameof(_speed)].ToFloat();
_attack_speed = dict[nameof(_attack_speed)].ToFloat();
_attack_damage = dict[nameof(_attack_damage)].ToInt();
_attack_speed_wait = dict[nameof(_attack_speed_wait)].ToFloat();
}
#endregion #endregion
} }

View File

@ -27,15 +27,15 @@ public class DatabaseEditor : Editor
foreach (var file in GetAllPaths(path)) foreach (var file in GetAllPaths(path))
{ {
var scriptableObject = AssetDatabase.LoadAssetAtPath<ScriptableObject>(file); var scriptableObject = AssetDatabase.LoadAssetAtPath<ScriptableObject>(file);
if (scriptableObject && !Database.Instance.ScriptableObjects.Contains(scriptableObject)) if (scriptableObject && !targ.ScriptableObjects.Contains(scriptableObject))
{ {
Database.Instance.ScriptableObjects.Add(scriptableObject); targ.ScriptableObjects.Add(scriptableObject);
} }
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(file); var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(file);
if (prefab && !Database.Instance.Prefabs.Contains(prefab)) if (prefab && !targ.Prefabs.Contains(prefab))
{ {
Database.Instance.Prefabs.Add(prefab); targ.Prefabs.Add(prefab);
} }
} }
} }
@ -53,15 +53,8 @@ public class DatabaseEditor : Editor
} }
} }
#endif #endif
public class Database : SingletonBehaviour<Database>
[CreateAssetMenu(menuName = "Gather And Defend/Database")]
public class Database : ScriptableObject
{ {
public static Database Instance
{
get;
private set;
}
public const string TYPE = nameof(TYPE); public const string TYPE = nameof(TYPE);
[Serializable] [Serializable]
@ -99,7 +92,6 @@ public class Database : ScriptableObject
public Database() public Database()
{ {
if (!Instance) Instance = this;
_prefabs = new List<GameObject>(); _prefabs = new List<GameObject>();
_scriptableObjects = new List<ScriptableObject>(); _scriptableObjects = new List<ScriptableObject>();
} }

View File

@ -4,7 +4,7 @@ MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: -1
icon: {instanceID: 0} icon: {instanceID: 0}
userData: userData:
assetBundleName: assetBundleName:

View File

@ -2,9 +2,46 @@
using System.Collections.Generic; using System.Collections.Generic;
using BindingFlags = System.Reflection.BindingFlags; using BindingFlags = System.Reflection.BindingFlags;
using UnityEngine; using UnityEngine;
using System.Collections;
public static class Extensions public static class Extensions
{ {
public static int ToInt(this object jobj)
{
return int.Parse(jobj.ToString());
}
public static float ToFloat(this object jobj)
{
return float.Parse(jobj.ToString());
}
public static Vector3 ToVector3(this object jobj)
{
var p_enum = (jobj as IEnumerable).GetEnumerator();
float[] p_array = new float[3];
p_enum.MoveNext();
p_array[0] = float.Parse(p_enum.Current.ToString());
p_enum.MoveNext();
p_array[1] = float.Parse(p_enum.Current.ToString());
p_enum.MoveNext();
p_array[2] = float.Parse(p_enum.Current.ToString());
return new Vector3(p_array[0], p_array[1], p_array[2]);
}
public static bool ToBool(this object jobj) => bool.Parse(jobj.ToString());
public static GameObject Create(this GameObject prefab, Vector3 position, Quaternion rotation = default, Transform parent = null)
{
if (!prefab)
{
Debug.Log("");
}
if (rotation == default) rotation = Quaternion.identity;
var instance = GameObject.Instantiate(prefab, position, rotation);
instance.transform.SetParent(parent);
instance.name = prefab.name;
return instance;
}
public static T GetComponentInChildren<T>(this Component obj, string name) where T : Component public static T GetComponentInChildren<T>(this Component obj, string name) where T : Component
{ {
foreach (var comp in obj.GetComponentsInChildren<T>()) foreach (var comp in obj.GetComponentsInChildren<T>())
@ -18,36 +55,4 @@ public static class Extensions
{ {
return Mathf.Approximately(Vector3.Distance(vect, other), 0); return Mathf.Approximately(Vector3.Distance(vect, other), 0);
} }
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class LevelSerializeAttribute : Attribute { }
/// <summary>
/// turns an object into a serializable dictionary
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static Dictionary<string, object> ToDictionary<T>(this T obj) where T : ILevelObject
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
var toReturn = new Dictionary<string, object>();
var type = obj.GetType();
foreach (var field in type.GetFields(flags))
{
if (!Attribute.IsDefined(field, typeof(LevelSerializeAttribute))) continue;
toReturn[field.Name] = field.GetValue(obj);
}
foreach (var property in type.GetProperties(flags))
{
if (!Attribute.IsDefined(property, typeof(LevelSerializeAttribute))) continue;
toReturn[property.Name] = property.GetValue(obj);
}
if (obj is LevelObject) toReturn[nameof(LevelObjectType)] = LevelObjectType.GameObject;
else toReturn[nameof(LevelObjectType)] = LevelObjectType.Tile;
return toReturn;
}
} }

View File

@ -4,6 +4,7 @@ using Unity.Plastic.Newtonsoft.Json;
using UnityEngine; using UnityEngine;
using UnityEngine.Tilemaps; using UnityEngine.Tilemaps;
using GatherAndDefend.LevelEditor; using GatherAndDefend.LevelEditor;
using Unity.VisualScripting.YamlDotNet.Core.Tokens;
#region [custom inspector] #region [custom inspector]
#if UNITY_EDITOR #if UNITY_EDITOR
@ -17,11 +18,11 @@ public class LevelManagerEditor : Editor
DrawDefaultInspector(); DrawDefaultInspector();
if (GUILayout.Button("Save")) if (GUILayout.Button("Save"))
{ {
LevelManager.Instance.SaveLevel(); LevelManager.Instance.SaveFile();
} }
if (GUILayout.Button("Load")) if (GUILayout.Button("Load"))
{ {
LevelManager.Instance.LoadSave(); LevelManager.Instance.LoadFile();
} }
} }
} }
@ -130,7 +131,7 @@ public class LevelManager : Singleton<LevelManager>
} }
Clear(); Clear();
} }
public void SaveLevel() public void SaveFile()
{ {
var list = _levelObjects.Select(obj => obj.ToDictionary()).ToList(); var list = _levelObjects.Select(obj => obj.ToDictionary()).ToList();
list.Add(new Dictionary<string, object>() list.Add(new Dictionary<string, object>()
@ -143,16 +144,14 @@ public class LevelManager : Singleton<LevelManager>
Debug.Log("game saved successfully"); Debug.Log("game saved successfully");
} }
public void LoadLevel(string levelName, bool clear = false) public void LoadLevel(Level level, bool clear = false)
{ {
if (clear) if (clear)
{ {
ClearLevel(); ClearLevel();
} }
//fetch level from database _currentLevel = level;
_currentLevel = Database.Instance.ScriptableObjects[levelName] as Level;
Grid grid = Object.FindObjectOfType<Grid>(); Grid grid = Object.FindObjectOfType<Grid>();
//create new grid if there is none //create new grid if there is none
if (!grid) if (!grid)
@ -178,35 +177,49 @@ public class LevelManager : Singleton<LevelManager>
} }
Debug.Log("level loaded successfully"); Debug.Log("level loaded successfully");
} }
public void LoadSave() public void LoadLevel(string levelName, bool clear = false)
{
if (clear)
{
ClearLevel();
}
//fetch level from database
_currentLevel = Database.Instance.ScriptableObjects[levelName] as Level;
LoadLevel(_currentLevel, clear);
}
public void LoadFile()
{ {
ClearLevel(); ClearLevel();
var dicts = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(saved); var dicts = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(saved);
//instantiate all prefabs var prefabDicts = dicts.FindAll(x => x[Database.TYPE].ToString() == nameof(Database.Prefabs));
foreach (var dict in JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(saved)) foreach (var prefabDict in prefabDicts) CreatePrefab(prefabDict);
{
switch (dict[Database.TYPE].ToString()) var tileDicts = dicts.FindAll(x => x[Database.TYPE].ToString() == nameof(Database.ScriptableObjects));
{ foreach (var tileDict in tileDicts) CreateTile(tileDict);
case nameof(Database.Prefabs):
CreatePrefab(dict);
break;
case nameof(Level):
LoadLevel(dict["Name"].ToString());
break;
}
}
Debug.Log("game loaded successfully"); Debug.Log("game loaded successfully");
} }
private void CreatePrefab(Dictionary<string, object> dict) private void CreatePrefab(Dictionary<string, object> dict)
{ {
var name = dict["Name"].ToString(); var name = dict["Name"].ToString();
var prefab = Database.Instance.Prefabs[name]; var prefab = Database.Instance.Prefabs[name];
var instance = Object.Instantiate(prefab, LevelTransform); var instance = prefab.Create(Vector3.zero, parent: LevelTransform);
var comp = instance.GetComponent<LevelObject>(); var comp = instance.GetComponent<LevelObject>();
comp.LoadDictionary(dict); comp.LoadDictionary(dict);
} }
private void CreateTile(Dictionary<string, object> dict)
{
var name = dict["Name"].ToString();
var tile = Object.Instantiate(Database.Instance.ScriptableObjects[name]) as LevelTile;
tile.Instantiated = true;
tile.LoadDictionary(dict);
tile.AddToLevel();
}
#endregion #endregion
} }
#endregion #endregion
@ -216,6 +229,7 @@ public class LevelManagerScript : MonoBehaviour
{ {
public Level firstLevel; public Level firstLevel;
private static LevelManagerScript _instance; private static LevelManagerScript _instance;
void Awake() void Awake()
{ {
if (!_instance) _instance = this; if (!_instance) _instance = this;

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using static Extensions; using static Extensions;
@ -7,9 +8,7 @@ using static Extensions;
/// </summary> /// </summary>
public abstract class LevelObject : MonoBehaviour, ILevelObject public abstract class LevelObject : MonoBehaviour, ILevelObject
{ {
[LevelSerialize]
public Vector3 Position { get => transform.position; protected set => transform.position = value; } public Vector3 Position { get => transform.position; protected set => transform.position = value; }
[LevelSerialize]
public string Name { get => name; protected set => name = value; } public string Name { get => name; protected set => name = value; }
void Awake() void Awake()
@ -41,14 +40,13 @@ public abstract class LevelObject : MonoBehaviour, ILevelObject
{ {
{nameof(Name), Name }, {nameof(Name), Name },
{nameof(Position), new float[]{Position.x, Position.y, Position.z } }, {nameof(Position), new float[]{Position.x, Position.y, Position.z } },
{Database.TYPE, nameof(Database.Instance.Prefabs) } {Database.TYPE, nameof(Database.Prefabs) }
}; };
} }
public virtual void LoadDictionary(Dictionary<string, object> dict) public virtual void LoadDictionary(Dictionary<string, object> dict)
{ {
Name = dict[nameof(Name)].ToString(); Name = dict[nameof(Name)].ToString();
var p_array = (float[])dict[nameof(Position)]; Position = dict[nameof(Position)].ToVector3();
Position = new Vector3(p_array[0], p_array[1], p_array[2]);
} }
public void RemoveFromLevel() public void RemoveFromLevel()

View File

@ -11,16 +11,16 @@ public abstract class LevelTile : TileBase, ILevelObject
{ {
[SerializeField] [SerializeField]
private Sprite _sprite; private Sprite _sprite;
[LevelSerialize]
public bool Instantiated { get; set; }
public Vector3 Position { get; protected set; } public Vector3 Position { get; protected set; }
private Tilemap _tilemap; private Tilemap _tilemap;
[LevelSerialize]
public string Tilemap public string Tilemap
{ {
get => _tilemap.name; get => _tilemap.name;
} }
[LevelSerialize]
public string Name { get => name; protected set => name = value; } public string Name { get => name; protected set => name = value; }
public virtual void LevelStart() { } public virtual void LevelStart() { }
@ -41,6 +41,12 @@ public abstract class LevelTile : TileBase, ILevelObject
return base.StartUp(position, tilemap, go); return base.StartUp(position, tilemap, go);
} }
//if it was created from the level manager, then it is already instantiated, and we shouldn't do it again
if (Instantiated)
{
return base.StartUp(position, tilemap, go);
}
var comp = tilemap.GetComponent<Tilemap>(); var comp = tilemap.GetComponent<Tilemap>();
//need to create an instance of the tile, otherwise the position will change for all tiles instead of only this one. //need to create an instance of the tile, otherwise the position will change for all tiles instead of only this one.
@ -72,19 +78,24 @@ public abstract class LevelTile : TileBase, ILevelObject
{nameof(Name), Name }, {nameof(Name), Name },
{nameof(Position), new float[]{Position.x, Position.y, Position.z } }, {nameof(Position), new float[]{Position.x, Position.y, Position.z } },
{nameof(Tilemap), Tilemap }, {nameof(Tilemap), Tilemap },
{Database.TYPE, nameof(Database.Instance.Prefabs) } {Database.TYPE, nameof(Database.ScriptableObjects) }
}; };
} }
public virtual void LoadDictionary(Dictionary<string, object> dict) public virtual void LoadDictionary(Dictionary<string, object> dict)
{ {
Name = dict[nameof(Name)].ToString(); Name = dict[nameof(Name)].ToString();
float[] pArray = (float[])dict[nameof(Position)]; Position = dict[nameof(Position)].ToVector3();
Position = new Vector3(pArray[0], pArray[1], pArray[2]);
var tilemap = FindObjectOfType<Grid>().GetComponentInChildren<Tilemap>(Tilemap); var tilemapName = dict[nameof(Tilemap)].ToString();
_tilemap = FindObjectOfType<Grid>().GetComponentInChildren<Tilemap>(tilemapName);
} }
public void AddToLevel()
{
_tilemap.SetTile(Vector3Int.RoundToInt(Position), this);
}
public void RemoveFromLevel() public void RemoveFromLevel()
{ {
_tilemap.SetTile(Vector3Int.RoundToInt(Position), null); _tilemap.SetTile(Vector3Int.RoundToInt(Position), null);

View File

@ -9,13 +9,11 @@ public class ResourceTile : LevelTile
[Tooltip("the prefab of the currency that will be spawned when mining this resource")] [Tooltip("the prefab of the currency that will be spawned when mining this resource")]
private GameObject _yieldPrefab; private GameObject _yieldPrefab;
[LevelSerialize]
private string YieldPrefabName => _yieldPrefab.name; private string YieldPrefabName => _yieldPrefab.name;
[SerializeField, LevelSerialize] [SerializeField]
private float _yieldSpeed = 1; //resource per second private float _yieldSpeed = 1; //resource per second
private float _yieldCounter = 0; private float _yieldCounter = 0;
[LevelSerialize]
public bool Occupied { get; set; } public bool Occupied { get; set; }
public override void LevelUpdate() public override void LevelUpdate()
@ -52,7 +50,8 @@ public class ResourceTile : LevelTile
base.LoadDictionary(dict); base.LoadDictionary(dict);
var prefabName = dict[nameof(YieldPrefabName)].ToString(); var prefabName = dict[nameof(YieldPrefabName)].ToString();
_yieldPrefab = Database.Instance.Prefabs[prefabName]; _yieldPrefab = Database.Instance.Prefabs[prefabName];
_yieldSpeed = (float)dict[nameof(_yieldSpeed)]; _yieldSpeed = dict[nameof(_yieldSpeed)].ToFloat();
Occupied = (bool)dict[nameof(Occupied)]; _yieldCounter = dict[nameof(_yieldCounter)].ToFloat();
Occupied = dict[nameof(Occupied)].ToBool();
} }
} }

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using Unity.Plastic.Newtonsoft.Json.Linq;
using UnityEngine; using UnityEngine;
[CreateAssetMenu(menuName = "Gather And Defend/Spawner Tile")] [CreateAssetMenu(menuName = "Gather And Defend/Spawner Tile")]
@ -8,33 +7,36 @@ public class SpawnerTile : LevelTile
[SerializeField] [SerializeField]
private GameObject _prefab; private GameObject _prefab;
[SerializeField] [SerializeField]
private bool _spawnOnStart = true; private bool _spawnOnStart;
private float _lifetime;
[SerializeField] [SerializeField]
private float _spawnSpeed = 0; private float _spawnSpeed = 0;
[SerializeField, Range(0, 1.001f)]
private float _spawnCounter = 0; private float _spawnCounter = 0;
public override void LevelStart() public override void LevelStart()
{ {
if (!_spawnOnStart) return; if (_spawnOnStart && _lifetime <= 0)
var instance = Instantiate(_prefab, Position, Quaternion.identity); {
instance.transform.SetParent(LevelManager.Instance.LevelTransform); _prefab.Create(Position, parent: LevelManager.Instance.LevelTransform);
}
} }
public override void LevelUpdate() public override void LevelUpdate()
{ {
_lifetime += Time.deltaTime;
_spawnCounter += Time.deltaTime * _spawnSpeed; _spawnCounter += Time.deltaTime * _spawnSpeed;
if (_spawnCounter < 1) return; if (_spawnCounter < 1) return;
_spawnCounter = 0; _spawnCounter = 0;
var instance = Instantiate(_prefab, Position, Quaternion.identity); _prefab.Create(Position, parent: LevelManager.Instance.LevelTransform);
instance.transform.SetParent(LevelManager.Instance.LevelTransform);
} }
public override bool Equals(ILevelObject other) public override bool Equals(ILevelObject other)
{ {
return other is SpawnerTile spawner return other is SpawnerTile spawner
&& base.Equals(spawner) && base.Equals(spawner)
&& spawner._prefab == _prefab && spawner._prefab == _prefab
&& spawner._spawnOnStart == _spawnOnStart
&& spawner._spawnSpeed == _spawnSpeed; && spawner._spawnSpeed == _spawnSpeed;
} }
public override Dictionary<string, object> ToDictionary() public override Dictionary<string, object> ToDictionary()
@ -42,9 +44,10 @@ public class SpawnerTile : LevelTile
var dict = base.ToDictionary(); var dict = base.ToDictionary();
dict[nameof(_prefab)] = _prefab.name; dict[nameof(_prefab)] = _prefab.name;
dict[nameof(_spawnOnStart)] = _spawnOnStart;
dict[nameof(_spawnSpeed)] = _spawnSpeed; dict[nameof(_spawnSpeed)] = _spawnSpeed;
dict[nameof(_spawnCounter)] = _spawnCounter;
dict[nameof(_lifetime)] = _lifetime;
dict[nameof(_spawnOnStart)] = _spawnOnStart;
return dict; return dict;
} }
public override void LoadDictionary(Dictionary<string, object> dict) public override void LoadDictionary(Dictionary<string, object> dict)
@ -53,7 +56,9 @@ public class SpawnerTile : LevelTile
var prefabName = dict[nameof(_prefab)].ToString(); var prefabName = dict[nameof(_prefab)].ToString();
_prefab = Database.Instance.Prefabs[prefabName]; _prefab = Database.Instance.Prefabs[prefabName];
_spawnOnStart = (bool)dict[nameof(_spawnOnStart)]; _spawnSpeed = dict[nameof(_spawnSpeed)].ToFloat();
_spawnSpeed = (float)dict[nameof(_spawnSpeed)]; _spawnCounter = dict[nameof(_spawnCounter)].ToFloat();
_lifetime = dict[nameof(_lifetime)].ToFloat();
_spawnOnStart = dict[nameof(_spawnOnStart)].ToBool();
} }
} }

View File

@ -16,3 +16,4 @@ MonoBehaviour:
_prefab: {fileID: 6962989255644195630, guid: 377c7275c0001cc47a6b8926ac57d573, type: 3} _prefab: {fileID: 6962989255644195630, guid: 377c7275c0001cc47a6b8926ac57d573, type: 3}
_spawnOnStart: 1 _spawnOnStart: 1
_spawnSpeed: 0 _spawnSpeed: 0
_spawnCounter: 0

View File

@ -16,3 +16,4 @@ MonoBehaviour:
_prefab: {fileID: 6962989255644195630, guid: 6cd87b398e7a0e94580f4fcbe2fd310a, type: 3} _prefab: {fileID: 6962989255644195630, guid: 6cd87b398e7a0e94580f4fcbe2fd310a, type: 3}
_spawnOnStart: 1 _spawnOnStart: 1
_spawnSpeed: 0 _spawnSpeed: 0
_spawnCounter: 0