- Home /
Populating custom class items (containing a list) from another script
Hi. I have been learning how to use custom classes and using them to store information about monsters in a card game I'm working on. First I should say that I can make this work by directly inputing all the information into the inspector, but I want to determine where I'm going wrong with my scripts where I try to populate information. The problem I believe is with the list object. Heres the custom class code. [System.Serializable] is present for the public class.
public class Monster
{
public string name;
public int id;
public string description;
public List<int> attackpattern;
public Monster()
{
// This is my "empty constructor"
}
// For the main constructor I wasn't sure how to define the list item
public Monster(string name, int id, string description)
{
this.name = name;
this.id = id;
this.description = description;
}
}
I then tried to populate these items through a second script (attached to empty game object), as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Monsters : MonoBehaviour
{
// I tried doing this two ways, first by defining two specific monsters..
public Monster Monster1;
public Monster Monster2;
// .. and then by creating an array of monsters
public Monster[] monsters;
void Start()
{
// I added the following line during testing, but initially set the value in the inspector
monsters = new Monster[10];
Monster1 = new Monster("Alpha", 1, "Wolf");
Monster2 = new Monster("Beta", 2, "Slime");
// The following lines worked IF I defined Monster1 in the inspector, but return object reference not set to instance error if I populated through code
Monster1.attackpattern.Add(2);
Monster1.attackpattern.Add(4);
monsters[0] = new Monster("Alpha", 1, "Alpha monster");
// The following commands work IF I remove the array size command and define monsters[0] in the inspector but not through the line above.
monsters[0].attackpattern.Add(2);
monsters[0].attackpattern.Add(4);
int randomX = Random.Range(1, 5);
monsters[0].attackpattern.Add(randomX);
Debug.Log(monsters[0].attackpattern.Count);
for (var i = 0; i < monsters[0].attackpattern.Count; i++)
{
Debug.Log(monsters[0].attackpattern[i]);
}
}
}
I'm not entirely sure where I'm going wrong. I am using the list item because each monster will have a different attack list which may be different lengths. I've read many articles about custom classes and as I said I wonder if I need to ammend the public class to somehow include the list item in the constructor, but if so I cannot figure out what the code will be there and then what I'd need to add in the second script. To state again, I can make this work nicely by editing everything into the inspector, but I'd like to know how to do it through a script if thats possible. I hope this made sense and I appreciate any help you can give.
Answer by KoenigX3 · Mar 11, 2021 at 06:01 PM
The root of your problem is that you forgot to initialize the list itself.
public Monster()
{
attackpattern = new List<int>();
}
public Monster(string name, int id, string description)
{
this.name = name;
this.id = id;
this.description = description;
attackpattern = new List<int>();
}
public Monster(string name, int id, string description, List<int> attackpattern)
{
this.name = name;
this.id = id;
this.description = description;
this.attackpattern = attackpattern;
}
I have corrected your constructor methods. You can even construct a Monster object with a pre-existing list.
Monster monster = new Monster("name", 1, "desc", new List<int>() {2, 3, 5});
That is exactly what I was after Koenig. I'd used the exact statement in the constructor that you used, but I then couldn't construct the items correctly so I took it back out. It's that second bit that slots it together for the actual construction in the script. When I sleep now I dream of all the different brackets, arranged in so many permutations. Thank you so much.
Answer by $$anonymous$$ · Mar 11, 2021 at 05:30 PM
Try this its much more cleaner and more extendable.
[CreateAssetMenu]
public class Monster : ScriptableObject {
public new string name;
public int id;
public string description;
public List<int> attackPattern;
}
public class Monsters : MonoBehaviour {
public Monster[] monsters;
private void Start() {
for (int i = 0; i < monsters.Length; i++) {
for (int index = 0; index < monsters [i].attackPattern.Count; index++) {
Debug.Log (monsters [i].attackPattern [index]);
}
}
}
}
If you haven't used ScriptableObjects check this Tutorial out
That does help considerably Vividius. I've actually been playing with Scriptable objects today and watching the Unity tutorial which (no disrespect to the Unity teachers) was pretty dry. That tutorial you linked is excellent and since I'm making a card type game looks perfect to take me in new and funky directions. I'll see if I can accept this as an answer as well since I think it might be where I end up (but I also got an answer below which did specifically answer the question I'd asked, so if I can only accept one, it'll have to be that). But I very much appreciate your help and wanted you to know that.
Yeah, I can only accept one answer. But karma++ for you...
Your answer
Follow this Question
Related Questions
How to destroy and instantiate something without breaking this code 1 Answer
My Animation Loops 3/4 of the way through 3 Answers
How to detect which how many of a type a variable a script has 1 Answer
How do I reset my object rotation when it collides and spins around 1 Answer
a problem with a public static bool in very very simple 2d game 2 Answers