I'm creating chess in unity, and I want to create the chess board using a 2D array of cells. I was able to create an array of pieces and could reference them with their respective prefabs in Unity. But I have no option to reference the 2D array.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class gameManager : MonoBehaviour
{
public GameObject[,] cell = new GameObject[7,7];
public GameObject[] Wpawn = new GameObject[7];
public GameObject[] Bpawn = new GameObject[7];
public GameObject[] Wrook = new GameObject[1];
public GameObject[] Brook = new GameObject[1];
public GameObject[] Wknight = new GameObject[1];
public GameObject[] Bknight = new GameObject[1];
public GameObject[] Wbishop = new GameObject[1];
public GameObject[] Bbishop = new GameObject[1];
public GameObject Wking;
public GameObject Bking;
public GameObject Wqueen;
public GameObject Bqueen;
bool[] Bpawn2 = new bool[7];
bool[] Wpawn2 = new bool[7];
short turn = 0;
// Start is called before the first frame update
void Start()
{
#region Board
for (float y = 0F; y <= 7; y+= 1)
{
for (float x = 0F; x <= 7F; x+= 1)
{
if (y % 2 == 0)
{
if (x % 2 == 0)
{
cell[(int)x,(int)y].GetComponent<SpriteRenderer>().color = Color.gray;
} else if (x % 2 == 1)
{
cell[(int)x,(int)y].GetComponent<SpriteRenderer>().color = Color.white;
}
} else if (y % 2 == 1)
{
if (x % 2 == 0)
{
cell[(int)x,(int)y].GetComponent<SpriteRenderer>().color = Color.white;
} else if (x % 2 == 1)
{
cell[(int)x,(int)y].GetComponent<SpriteRenderer>().color = Color.gray;
}
}
Instantiate(cell[(int)x,(int)y], new Vector3(x - 3.5F, y -3.5F), transform.rotation);
}
}
#endregion
}
}
As you can see I've properly initialized my 2D array. I only showed you the setboard Region because there were no problems in the rest.
Here is the gamemanager script component and what it is showing me.
There is no option to reference the Cell Prefab
TL;DR
The default Inspector can only show variables that are Serializable by Unity's Serializer, i.e. files which can be written-to and read-from a file by Unity for saving/loading purposes. 2D arrays are not Serializable, thus they're not visible in the Inspector.
Please familiarize yourself with the Serialization rules in Unity. Here's an answer about what Serialization is.
Alternative
Even List<List> or T[][] type 2D arrays are not Serializable. This has to do with limitations regarding generic serialization in Unity. A simple alternative to define a concrete class as follows:
[Serializable]
public class GameObjectList //not a monobehavior
{
public List<GameObject> gameObjects;
}
using it later on as field
public GameObjectList[] pieces;
This should show up a list of lists in the Inspector, letting you reference your GameObjects. Of course, this method is a bit cumbersome, having to define a new class every time, but it works.
Notes:
A lot of the limitations surrounding generic serialization have been lifted in Unity 2020.2 update, but you still can't serialize 2D arrays/lists directly.
Related
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsReplace : MonoBehaviour
{
public class TransformInfo
{
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
}
public void GetDoors()
{
var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");
TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length];
for (int i = 0; i < trnfrm.Length; i++)
{
trnfrm[i] = new TransformInfo();
trnfrm[i].pos = DoorsLeft[i].transform.position;
trnfrm[i].rot = DoorsLeft[i].transform.rotation;
trnfrm[i].scale = DoorsLeft[i].transform.localScale;
}
}
}
This is working fine for the DoorsLeft but I want that trnfrm will include also the info of the objects from DoorsRight so the array or list trnfrm structure will be something like that :
DoorLeft 0...info inside
DoorLeft 1...info inside
.
.
.
DoorRight 0...info inside
DoorRight 1...info inside
This is how the array looks like now :
I want it to include also the DoorRight and to add some id like a string to know what door info is belong to for example :
DoorLeft 0...info inside
DoorLeft 1...info inside
.
.
.
DoorRight 0...info inside
DoorRight 1...info inside
And how to read the info back into GameObjects ?
The main goal is to Instantiate a prefab at the doors positions and same doors rotations and scaling.
So this is what I did :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsReplace : MonoBehaviour
{
public struct TransformInfo
{
public string ID;
public Transform Transform;
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
public TransformInfo(Transform transform, string id)
{
Transform = transform;
ID = id;
// For this kind of stuff I always prefer working on the local values
pos = transform.localPosition;
rot = transform.localRotation;
scale = transform.localScale;
}
public void Apply()
{
Transform.localPosition = pos;
Transform.localRotation = rot;
Transform.localScale = scale;
}
public void Apply(Transform transform)
{
transform.localPosition = pos;
transform.localRotation = rot;
transform.localScale = scale;
}
}
public GameObject prefabToInit;
// Note your method should probably return something
public TransformInfo[] GetDoors()
{
var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");
TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length * 2];
int trnfrmIndex = 0;
for (int i = 0; i < DoorsLeft.Length; i++)
{
trnfrm[trnfrmIndex] = new TransformInfo(DoorsLeft[i].transform, $"{i}_L");
trnfrm[trnfrmIndex + 1] = new TransformInfo(DoorsRight[i].transform, $"{i}_R");
trnfrmIndex += 2;
}
return trnfrm;
}
public void ApplyDoors()
{
foreach (var info in GetDoors())
{
info.Apply(Instantiate(prefabToInit.transform));
}
}
}
And calling this ApplyDoors from a editor script :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(ObjectsReplace))]
public class ObjectsReplaceEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
ObjectsReplace myScript = (ObjectsReplace)target;
if (GUILayout.Button("Add"))
{
myScript.ApplyDoors();
}
}
}
The problem is that it's Instantiating the prefab many times at the main hierarchy node and not as the doors as childs so it put all the prefabs at the same area instead where the doors are :
But now I see that it's changing the original source prefab asset to a cube :
But the original prefab source asset scaling was :
Not sure why it's changed the prefab it self scaling to 1,1,1
And this is a screenshot of my scene game and example on the right of how the doors should be placed and on the left far other places with doors that this prefab should be Instantiated at. I don't want to destroy the doors but to Instantiate the prefab on the doors at the doors positions with the right rotations like the doors are :
The doors in green at the right are doors left and right that I manually add the DoorShieldFXLocked Variant prefab. And this is how all the doots should look like after Instantiating the DoorShieldFXLocked prefab.
Each door is built with Door_Left and Door_Right and on each door it should be Instantiating the DoorShieldFXLocked but instead it's changing the DoorShieldFXLocked scale to 1,1,1 and put all the Instantiated DoorShieldFXLocked's at other area almost at the same place.
And this is a screenshot in the Hierarchy of example of how a door is built the structure of a door :
Each door is a child of a prefab. It's just the prefab I could not fit it in the screenshot but above all this there is a prefab. So I wonder if there is a way also the apply the prefab of each door ? But this is a door structure example :
Okey before wasn't clear what you wanted so here the updated answer:
The problem was that
This would apply the exact same local rotation, position and scale to the DoorShieldFX objects .. this is not what you want since these positions and rotations would be relative to it's parents. So yeah in this case you rather wanted the global transforms.
You spawn all of them into the scene root, not as children of according doors.
What you rather want to do in this case is
public struct TransformInfo
{
public Transform Transform;
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
public TransformInfo(Transform transform)
{
Transform = transform;
pos = transform.position;
rot = transform.rotation;
scale = transform.scale;
}
public void Apply(Transform transform)
{
// First of all it is important that
// this new FX is a child of the according door so
transform.SetParent(Transform, false);
// Then you can put it in position if it is still needed
// since actually SetParent with worldPositionStays = false
// should actually already do that anyway.
transform.position = pos;
transform.rotation = rot;
// Not sure about the scale since it would be relative to the door
// depends on your case
}
}
Then in order to get the infos from both lists you could simply do e.g. (assuming the amount is equal for left and right)
// Note your method should probably return something
public TransformInfo[] GetDoors()
{
var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");
TransformInfo[] trnfrm = new TransformInfo[DoorsLeft.Length * 2];
trnfrmIndex = 0;
for (int i = 0; i < DoorsLeft.Length; i++)
{
trnfrm[trnfrmIndex] = new TransformInfo(DoorsLeft[i]);
trnfrm[trnfrmIndex+1] = new TransformInfo(DoorsRight[i]);
trnfrmIndex += 2;
}
return trnfrm;
}
Then for reapply these to all doors you can do
foreach(var info in transformInfos)
{
info.Apply(Instantiate (prefabToInit).transform);
}
The ID is then actually not needed anymore.
However
Well actually the entire script is not needed for your goal since you could also simply iterate over the two arrays like
public void ApplyDoors()
{
var DoorsLeft = GameObject.FindGameObjectsWithTag("Door_Left");
var DoorsRight = GameObject.FindGameObjectsWithTag("Door_Right");
foreach(var door in DoorsLeft)
{
Instantiate(prefabToInit, door.transform.position, door.transform.rotation, door.transform);
}
foreach(var door in DoorsRight)
{
Instantiate(prefabToInit, door.transform.position, door.transform.rotation, door.transform);
}
}
without the need of any in-between class!
I'm currently developing a game in Unity and I ran into a small problem. I'm trying to access a variable that is located in another class because I need it in order to be able to spawn a gameobject ("clock") at random during a specified amount of time while an update method is running. However for some reason even if I change the variable to a static variable or create a new instance of the class in which the variable I'm trying to access is located. I keep on getting an error message stating:
NullReferenceException: Object reference not set to an instance of an
object InteractControl.Update () (at Assets/Scripts/Scene 2
Scripts/InteractControl.cs:87)
This is part of the class that I'm trying to access showing how the variable in question ("public Transform[] spawnPoints") is declared:
public class BallSpawnerControl : MonoBehaviour
{
public Transform[] spawnPoints = new Transform[] { };
int randomSpawnPoint, Interact;
int index = 1;
public static bool spawnAllowed;
public static int TimerOn = 1;
ObjectPooler objectPooler;
public static int LevelTrans = 1;
public static bool HeartSpawn = false;
private int Hearts = 1;
// Use this for initialization
public void Start()
{
objectPooler = ObjectPooler.Instance;
spawnAllowed = true;
InvokeRepeating("SpawnAInteract", 0f, 1f);
}
This is part of the class that is trying to access the variable showing how the variable in question ("public Transform[] spawnPoints") is being accessed:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InteractControl : MonoBehaviour, IPooledObject
{
private Rigidbody2D rb;
GameObject target;
Vector3 directionToTarget;
public static int LevelStart = 0;
Renderer m_Renderer;
public static float moveSpeed = 5f;
public static bool isSlowMotion = true;
public static float timeLeft = 5f;
ObjectPooler objectPooler = ObjectPooler.Instance;
int randomSpawnPosition;
float randomSpawnTime;
int Spawn = 1;
BallSpawnerControl Bc = new BallSpawnerControl();
void Update()
{
if (target != null)
{
if (ScoreScript.scoreValue > 10)
{
timeLeft -= Time.deltaTime;
if (timeLeft > 0)
{
directionToTarget = (target.transform.position - transform.position).normalized;
rb.velocity = new Vector2(directionToTarget.x * moveSpeed,
directionToTarget.y * moveSpeed);
if (Spawn == 1)
{
randomSpawnTime = Random.Range(1, 5);
randomSpawnPosition = Random.Range(0, Bc.spawnPoints.Length);
Spawn++;
}
if (timeLeft > randomSpawnTime && Spawn <= 2)
{
objectPooler.SpawnFromPool("Clock", Bc.spawnPoints[randomSpawnPosition].position, Quaternion.identity);
}
}
if (timeLeft < 0)
{
GameObject[] gos = GameObject.FindGameObjectsWithTag("ColouredBall Highress");
foreach (GameObject go in gos)
{
go.SetActive(false);
}
BallSpawnerControl.HeartSpawn = true;
}
}
}
}
}
What normally should happen is that the clock will spawn randomly at position "Bc.spawnPoints[randomSpawnPosition].position" during the 5 first seconds that ScoreScript.scoreValue > 10 .
The problem is in this line of code.
BallSpawnerControl Bc = new BallSpawnerControl();
You create a new ballspawnercontrol in your class. However, since BallSpawnerControll is a MonoBehaviour, it will not instantiate correctly.
you should either attach the ballspawner control to a gameobject within Unity and then drag it into a field on your InteractControl.
Or you can create it via script by using the AddComponent method.
However, if you create it via script then you would also have to manually declare the spawnPoints from script. I suspect that you want to assign the values from within the inspector.
I suggest making your Bc variable either serializable or public.
public BallSpawnerControl Bc;
OR
[SerializeField]
private BallSpawnerControl Bc;
Now you can assign the correct control from the scene into your script.
I have two scripts each one attached to another empty GameObject:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooler : MonoBehaviour
{
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
public int size;
}
#region Singleton
public static ObjectPooler Instance;
private void Awake()
{
Instance = this;
}
#endregion
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
// Start is called before the first frame update
void Start()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach(Pool pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for(int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
{
if(!poolDictionary.ContainsKey(tag))
{
Debug.LogWarning("Pool with tag " + tag + " doesn't exist.");
return null;
}
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation;
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if(pooledObj != null)
{
pooledObj.OnObjectSpawn();
}
poolDictionary[tag].Enqueue(objectToSpawn);
return objectToSpawn;
}
}
And the second one and here I added inside the FixedUpdate the random part:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeSpawner : MonoBehaviour
{
ObjectPooler objectPooler;
// Start is called before the first frame update
void Start()
{
objectPooler = ObjectPooler.Instance;
}
private void FixedUpdate()
{
var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
objectPooler.SpawnFromPool("Cube", randp, Quaternion.identity);
}
}
It does what I want so far, But did I add the random part in the right script and place?
And how can I make that instead of generating nonstop random objects it will generate them only when I will change a Range slider of the size variable?
For example [Range(1,150])
And when I change the value it will add/remove the objects in the FixedUpdate? (It should be Update it's FixedUpdate since before that I used a Rigidbody but not now).
The idea is to either to change the size or if I set the size for example to 1000 and then to use a Range slider to change the number of using objects for example 445 or 500 or 1000.
And each time I change the size it will random the objects in other random positions. But once and not all the time like now in the FixedUpdate.
Each time changing the size change the objects positions randomly.
So if the size I changed it to 10 change the position of 10 objects randomly and use only these 10 objects. If I change the size to 700 then reposition randomly 700 objects and use the 700. (Not sure if it's right to say use or destroy).
UPDATE:
This is what I tried in the the first script I added the oldSize variable and the Range:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPooler : MonoBehaviour
{
[System.Serializable]
public class Pool
{
public string tag;
public GameObject prefab;
[Range(1, 150)]
public int size;
public int sizeOld;
}
#region Singleton
public static ObjectPooler Instance;
private void Awake()
{
Instance = this;
}
#endregion
public List<Pool> pools;
public Dictionary<string, Queue<GameObject>> poolDictionary;
// Start is called before the first frame update
void Start()
{
poolDictionary = new Dictionary<string, Queue<GameObject>>();
foreach(Pool pool in pools)
{
Queue<GameObject> objectPool = new Queue<GameObject>();
for(int i = 0; i < pool.size; i++)
{
GameObject obj = Instantiate(pool.prefab);
obj.SetActive(false);
objectPool.Enqueue(obj);
}
poolDictionary.Add(pool.tag, objectPool);
}
}
private void Update()
{
}
public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
{
if(!poolDictionary.ContainsKey(tag))
{
Debug.LogWarning("Pool with tag " + tag + " doesn't exist.");
return null;
}
GameObject objectToSpawn = poolDictionary[tag].Dequeue();
objectToSpawn.SetActive(true);
objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation;
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if(pooledObj != null)
{
pooledObj.OnObjectSpawn();
}
poolDictionary[tag].Enqueue(objectToSpawn);
return objectToSpawn;
}
}
And in the second script in the Start I'm using once the whole objects for example I start the game when the Range value is at 27 and then when changing the value I'm updating the oldSize:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CubeSpawner : MonoBehaviour
{
ObjectPooler objectPooler;
// Start is called before the first frame update
void Start()
{
objectPooler = ObjectPooler.Instance;
foreach (ObjectPooler.Pool pool in objectPooler.pools)
{
var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
objectPooler.SpawnFromPool("Cube", /*transform.position*/ randp, Quaternion.identity);
}
}
private void Update()
{
foreach (ObjectPooler.Pool pool in objectPooler.pools)
{
if (pool.size != pool.sizeOld)
{
int diff = pool.size - pool.sizeOld;
pool.sizeOld = pool.size;
// Spawn new diff number of objects if diff is positive
var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
objectPooler.SpawnFromPool("Cube", /*transform.position*/ randp, Quaternion.identity);
}
}
//var randp = new Vector3(Random.Range(0, 300), Random.Range(0, 300), Random.Range(0, 300));
//objectPooler.SpawnFromPool("Cube", transform.position /*randp*/, Quaternion.identity);
}
}
But in fact the spawners in the Hierarhcy never changed there is all the time 27. If the Range is lower then 27 it will use less objects but if it's higher then 27 still in the hierarchy there will be only 27 spawners.
The size of spawners never change. And then when moving the Range left right it will fill the spawners use them until the end and that's it it will never change it will use them all but only 27.
Even if Range value is 150 for example still there are 27 spawners in the hierarhcy and in the game it self and not 150.
It does what I want so far, But did I add the random part in the right script and place ?
I don't know, if you ask me is 1 + 1 = 2, I can give you an answer.
And how can I make that instead generating nonstop random objects it will generate them only when I will change a Range slider of the size variable ?
You need another size field:
public class Pool
{
public string tag;
public GameObject prefab;
[Range(1, 150)]
public int size;
private int sizeOld;
}
Then in the Update of FixedUpdate do a simple compare:
void Update()
{
foreach(Pool pool in pools)
{
if(pool.size != pool.sizeOld)
{
int diff = pool.size - pool.sizeOld;
pool.sizeOld = pool.size;
// Spawn new diff number of objects if diff is positive
}
}
}
And when I change the value it will add/remove the objects in the FixedUpdate ?
Depends on where you call spawning method.
I'm trying to get a GameObject to be created by inputting the TileID.
For my Terrain Generation I'd eventually like to be able to do something like
Generate()
{
Tile(<TileID>);
}
Right now It will only generate a Stone tile for me since its the second of two items in the list. What can I do to allow myself to input the TileID to display the right tile.
TileObject Class:
public class TileObject : MonoBehaviour {
//Instance Variables
TileManager tileManager;
GameObject gameManager;
//Variables
public int TileID;
Sprite TileSprite;
string TileName;
SpriteRenderer spriteRenderer;
// Use this for initialization
void Start ()
{
gameManager = GameObject.Find("Manager");
tileManager = gameManager.GetComponent<TileManager>();
spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
foreach (Tile tile in tileManager.Tiles)
{
TileID = tile.tileID;
TileSprite = tile.tileSprite;
TileName = tile.tileName;
}
}
public TileObject(int TileID)
{
gameObject.name = TileName;
spriteRenderer.sprite = TileSprite;
}
// Update is called once per frame
void Update ()
{
}
Tile Class:
public Tile(int newTileID, string newTileName, Sprite newTileSprite, float newBreakSpeed)
{
tileID = newTileID;
tileName = newTileName;
tileSprite = newTileSprite;
breakSpeed = newBreakSpeed;
}
Your tileManager should instantiate new tiles. For example:
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TileManager : MonoBehaviour {
public GameObject tilePrefab;
[Serializable]
public class Tile {
public int tileID;
public string tileName;
public Sprite tileSprite;
public float breakSpeed;
}
// List should be populated in inspector
public List<Tile> Tiles;
public GameObject Generate(int id) {
GameObject newObj = null;
try {
var data = Tiles.FirstOrDefault(tileData => id == tileData.tileID);
newObj = Instantiate(tilePrefab);
newObj.GetComponent<SpriteRenderer>().sprite = data.tileSprite;
newObj.name = data.tileName; // same name to multiple tiles?
} catch {
Debug.LogWarning("TileManager not initialised properly!");
}
return newObj;
}
}
The tilePrefab is a game object that is used as "prototype" for instantiation. In this example it is just a 2d sprite.
the tileManager tile data is populated in the inspector:
then you can generate tiles with:
var manager = GetComponent<TileManager>();
// generate 10 tiles with id [0..maxid]
int tilecount = 10;
int maxid = 1;
for (int id = 0; id <= maxid; ++id) {
for (int i = 0; i < tilecount; ++i) {
var obj = manager.Generate(id);
obj.transform.position = UnityEngine.Random.insideUnitCircle;
}
}
Based on what I see here it appears as though you are trying to use a single TileObject when you should be using one for each tile you want to render.
Where are you calling the constructor for TileObject? If it is from within the TileManager class, including that would make answering this question a lot easier.
All I can say without a clear view of the TileManager class is that when the Start() method is called, while proceeding through your foreach you write over each previously set value for
TileID = tile.tileID;
TileSprite = tile.tileSprite;
TileName = tile.tileName;
So as it reads though the list of tiles in TileManager, the previously read tile information is overwritten. For Example...
Iteration 1
TileID = 0;
TileSprite = sprite1;
TileName = firstTile;
Iteration 2
TileID = 1;
TileSprite = sprite2;
TileName = secondTile;
Iteration 3
TileID = 2;
TileSprite = sprite3;
TileName = thirdTile;
After it reaches the end of the list (of size n) you will end up with
Iteration N
TileID = **N-1**;
TileSprite = sprite**N**;
TileName = **Nth**Tile;
Essentially the TileObject class will contain the values from the last tile in tileManager.Tiles. Then when you call TileObject() it is creating a tile using the values from the last tile in the list.
I can help lead you more in the correct direction once I have a copy of the TileManager class. Hopefully this helps, if you have any questions don't hesitate to ask.
The script below is added to an empty game object WeaponGroup, which can be populated using the editor. I have made a new game object WeaponGroups which should have a script SetupWeaponGroupsScript. How can I transfer the properties below so that each WeaponGroup (SetupWeaponGroupsScript will have an array of WeaponGroup objects) is setup in a way similar to what is done below, so that I make the SetupWeaponsScript properties hidden to the inspector and populate them through SetupWeaponGroupsScript?
public class SetupWeaponsScript {
// Here's our tuple combining a weapon prefab and a direction.
[System.Serializable]
public struct DirectedWeapon {
public WeaponScript weapon;
public WeaponScript.Direction direction;
}
// The prefabs array is now this tuple type.
public DirectedWeapon[] weaponPrefabs;
public WeaponScript[] weapons;
void Start ()
{
weapons = new WeaponScript[weaponPrefabs.Length];
for (int i = 0; i < weaponPrefabs.Length; i++)
{
// Using typed Instantiate to save a GetComponent call.
weapons[i] = Instantiate<WeaponScript>(weaponPrefabs[i].weapon);
weapons[i].weaponDir = weaponPrefabs[i].direction;
}
}
}
Graphically, I would like to have the following hierarchy in the editor for a new script SetupWeaponGroupsScript:
This should be close :
public class SetupWeaponsScript
{
[System.Serializable]
public struct DirectedWeaponGroup
{
public DirectedWeaponScript[] weaponPrefabs;
}
// Here's our tuple combining a weapon prefab and a direction.
[System.Serializable]
public struct DirectedWeapon
{
public WeaponScript weapon;
public WeaponScript.Direction direction;
}
// The prefabs array is now this tuple type.
public DirectedWeaponGroup[] weaponGroups;
public DirectedWeapon[] weaponPrefabs;
public WeaponScript[] weapons;
void Start()
{
weaponGroups = new DirectedWeaponScript[weaponGroups.Length];
for (int h = 0; h < weaponGroups.Length; h++)
{
weaponPrefabs = weaponGroups[h].weaponPrefabs;
weaponPrefabs[h] = Instantiate<DirectedWeaponScript>(weaponGroups[h].weaponPrefabs);
weapons = new WeaponScript[weaponPrefabs.Length];
for (int i = 0; i < weaponPrefabs.Length; i++)
{
// Using typed Instantiate to save a GetComponent call.
weapons[i] = Instantiate<WeaponScript>(weaponPrefabs[i].weapon);
weapons[i].weaponDir = weaponPrefabs[i].direction;
}
}
}