How to instantiate a prefab that a specific script is attached to?

I am prototyping my first game that uses random encounters and functions like a JRPG. I made a monobehavior called BattlerData that holds the data for a battler game object (could be a player or enemy). I attached this script to two different game objects(A tree and a bush just to test with). I then made prefabs out of the tree and bush so that when they are instantiated they will have the correct sprite and animation displayed.:

4774118--454817--upload_2019-7-22_18-24-57.png
(Yes the art is just place holder for testing. I made it in 2 minutes)

public class BattlerData : MonoBehaviour {

    public int health;
    public int level;
    public int attack;
    public int defense;

}

Now for the random encounters I have an Encounter_Area script that has a public array of BattlerData and attached the script to an EncounterArea object (An invisible object that functions as a hitbox to start an encounter):

using UnityEngine;
using System.Collections;

public class Encounter_Area : MonoBehaviour {

    public BattlerData[] enemies;
    //public int targetSceneID;
    public int troop_min_size;
    public int troop_max_size;

//will change so encounters only happen sometimes later. This is just for testing
    private void OnTriggerEnter2D(Collider2D other) {
        if(other.gameObject.CompareTag("Player")) {
//choose members from enemies at random to make a troop
            int troop_size = Random.Range (troop_min_size, troop_max_size + 1);
            BattlerData[] troop = new BattlerData[troop_size];
            for (int i = 0; i < troop_size; i++) {
                troop [i] = enemies [Random.Range (0, enemies.Length)];
            }

            Game_Handler.getInstance ().startBattle(troop);
        }

    }
       
}

To handle Scene transition I have a game handler object and script that takes the enemy troop data and passes it to the next scene with startBattle(troop):

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class Game_Handler : MonoBehaviour {

    private static Game_Handler instance;

    private void Awake() {
        DontDestroyOnLoad (this);
        if (instance == null) {
            instance = this;
        } else {
            DestroyObject(gameObject);
        }
    }

    public static Game_Handler getInstance() {
        return instance;
    }

    public void loadScene(int id) {
        SceneManager.LoadScene (id);
    }

    public void startBattle(BattlerData[] enemy_troop) {
        loadScene (1);
        for (int i = 0; i < enemy_troop.Length; i++) {
//does not work
            Instantiate (enemy_troop[i], Vector3.zero, Quaternion.identity);
        }
    }
}

Now when I move my player to the EncounterArea game object to trigger the startBattle function the scene changes but no new objects are instantiated. Here is the EncounterArea monobehavior settings. As you can see I added my two enemies to the array and set the troop min and max size:

4774118--454820--upload_2019-7-22_18-34-48.png

and here is the Inspector view for the Tree (the bush is very similar so not posting it):

I assume this does not work because BattlerData is not a game object but a script. What I want to do is instantiate the prefab that the script is attached to and I don’t even know if that’s possible. Additionally, I want to capture a reference to the instantiated prefab so I can further modify the values on its BattlerData as the battle progresses (like decreasing health when damage is taken). It is very possible that I have completely taken the wrong approach to this entire process altogether. If I have, please explain a/the proper way to do this. I am very confused. Thanks.

It’s probably not working because you’re loading a scene directly preceding instantiating.

LoadScene doesn’t happen synchronously – the scene will finish loading on the next frame, meaning that your freshly instantiated objects are immediately getting destroyed by the fresh scene load.

2 Likes

Okay so now I attempted to instantiate the BattlerData objects after the scene loads by using a scene load event and it sometimes partially works but it only ever seems to spawn bushes, not the trees. Also sometimes it dosen’t spawn anything saying: 4778879--455726--upload_2019-7-24_0-15-53.png

Here is my updated code. I added the event subscription in the OnEnable and I attempt to store the BattlerData[ ] that I want to instantiate in a buffer variable but it does not always work:

using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;

public class Game_Handler : MonoBehaviour {

    private static Game_Handler instance;
    private static BattlerData[] enemyTroopBuffer;


    private void Awake() {
        DontDestroyOnLoad (this);
        if (instance == null) {
            instance = this;
        } else {
            DestroyObject(gameObject);
        }
    }

    private void OnEnable() {
        SceneManager.sceneLoaded += OnSceneLoaded;
    }

    public static Game_Handler getInstance() {
        return instance;
    }

    public void loadScene(int id) {
        SceneManager.LoadScene (id);
    }

    public void startBattle(BattlerData[] enemy_troop) {
        enemyTroopBuffer = enemy_troop;
        loadScene (1);
    }

    void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
        if (scene.buildIndex == 1) {
            for (int i = 0; i < enemyTroopBuffer.Length; i++) {
                Instantiate (enemyTroopBuffer[i], Vector3.zero, Quaternion.identity);
            }
        }
    }

}