0
\$\begingroup\$

I'm creating a spaceshooter clone and I like to achieve the following.

In the menu the player can choose between 3+ ships(characters). When the player hits the "Start Game" Button the game starts in a different scene and is flying the selected ship.

Therefore I have done the following:

I have 2 scenes. "MainMenu" and "Game". In "MainMenu" I have a few buttons and a GameControl Object. The GameControl object will not be destroyed on load. I followed this tutorial to have this.

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

public class GameControl : MonoBehaviour
{

    public static GameControl instance;
    public static int WIDTH = 800;
    public static int HEIGHT = 600;
    public static bool FULLSCREEN = true;
    public static int REFRESHRATE = 60;


    public GameObject playerShip;

    public float health;
    public float experience;
    public float score;


    void Awake()
    {
        if (instance == null)
        {
            Screen.SetResolution(WIDTH, HEIGHT, FULLSCREEN, REFRESHRATE);
            DontDestroyOnLoad(gameObject);
            instance = this;
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }
    }

    void OnGUI()
    {
        GUI.Label(new Rect(10, 10, 100, 30), "Health: " + health);
        GUI.Label(new Rect(10, 40, 100, 30), "XP: " + experience);
        GUI.Label(new Rect(10, 70, 100, 30), "Score: " + score);
    }

    // Use this for initialization
    void Start()
    {

    }
    // Update is called once per frame
    void Update()
    {

    }

    public void loadScene(string sceneName)
    {
        SceneManager.LoadScene(sceneName);
    }

    public void quitGame()
    {
        Application.Quit();
    }

    public void setShip(GameObject ship)
    {
        Destroy(playerShip);
        playerShip = Instantiate<GameObject>(ship);
        playerShip.SetActive(false);
    }
}

I also followed this tutorial about character selection. But in the video it is done a little bit different than I need it. All my ships are prefabs like it is done in the tutorial. So in "MainMenu" I have a ShipSelection that looks like that:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;

public class ShipSelection : MonoBehaviour {

    private int selectionIndex = 0;

    public List<GameObject> availableShips;


    // Use this for initialization
    void Start () {
        availableShips = new List<GameObject>();
        foreach(Transform t in transform)
        {
            availableShips.Add(t.gameObject);
        }

        foreach(GameObject ship in availableShips)
        {
            ship.SetActive(false);
        }
        nextShip();
    }

    // Update is called once per frame
    void Update () {

    }

    void OnGUI()
    {
    }


public void nextShip()
{
    availableShips[selectionIndex].SetActive(false);
    selectionIndex++;

    if(selectionIndex >= availableShips.Count)
    {
        selectionIndex = 0;
    }
    availableShips[selectionIndex].SetActive(true);

    GameControl.instance.setShip(availableShips[selectionIndex]);
}

public void previousShip()
{
    availableShips[selectionIndex].SetActive(false);
    selectionIndex--;
    if(selectionIndex < 0)
    {
        selectionIndex = availableShips.Count - 1;
    }

    availableShips[selectionIndex].SetActive(true);

    GameControl.instance.setShip(availableShips[selectionIndex]);
}

}

I thought that when I call GameControl.instance.setShip(availableShips[selectionIndex]); I could pass an instance of the selected ship to the next scene. But when I change the scene the value is null. I think this is because the objects from the "MainMenu" are all destroyed and so is the reference to the selected ship...

But how can I achieve to pass a "selected Ship" to the next or another scene, so that this scene knows which ship should be spawned/instantiated?

If you need to look into the project you can find it at
github.com/Naxos84/SpaceShooterGame
If something is unclear please do not hesitate to request more information.

Apparently I don't have enough reputation to post more than 2 links. So sorry for the plain repo link.

EDIT: I found another tutorial on character selection.
youtube.com/watch?v=ERuxfU8ArqA
But this video is using all "player object" in the game scene too. Is this really the only way of doing a character selection? Or is there an even better way?

\$\endgroup\$
  • \$\begingroup\$ Wouldn't it make much more sense to have a prefab for every ship and instantiate only the selected ship when you load your main scene? So you would not store a reference to the whole gameobject, but just the name (or some id) of the ship. If you are not familiar with the concept of prefabs, i would really advise you to look into it. Its one of the most powerful features of Unity3D! \$\endgroup\$ – Commodore Yournero Sep 7 '17 at 19:01
  • \$\begingroup\$ All my (currently) 3 ships are prefabs. And are added to ship selection like it was done in the video tutorial. \$\endgroup\$ – Naxos84 Sep 7 '17 at 19:24
  • \$\begingroup\$ Possible duplicate of Unity 5 - What is the proper way to handle data between scenes? \$\endgroup\$ – Philipp Mar 14 '18 at 14:08
1
\$\begingroup\$

To create prefabs, take the gameObject (the ship) and drag it to the project window and go.

in the game scene, inside the script that controls the load creates 3 variables publishes GameObject and you assign to each one, one of the prefabs ships.

public GameObject ship01;
public GameObject ship02;
public GameObject ship03;

In the Menu Scene, you save a reference of the chosen ship by the player, for example the name, you do something like:

PlayerPrefs.SetString ("ShipSelected", availableShips [selectionIndex] .name);

it will persist even if the game is closed.

Then in loading the game scene, you do something like:

string shipSelected = PlayerPrefs.GetString ("ShipSelected");

Swich (shipSelected)
{
case "Ship01":
playerShip = Instantiate (ship01);
break;
case "Ship02":
playerShip = Instantiate (ship02);
break;
case "Ship03":
playerShip = Instantiate (ship03);
break;
}
\$\endgroup\$
  • \$\begingroup\$ Thank you for pointing this out. This is a very similar approach as it was done in the video that I found. (see edit of my question). So I guess this is the only way? \$\endgroup\$ – Naxos84 Sep 7 '17 at 20:29
  • \$\begingroup\$ There are always more ways, depending on the case, what will best apply to what we need. I use this because I think passing a string as a reference, instead of everything an object is easier and less likely to fail. \$\endgroup\$ – NorbyAriel Sep 8 '17 at 12:53
  • \$\begingroup\$ It is just that: having an assigned Reference of all possible characters in every scene where i need the character. Seems strange. \$\endgroup\$ – Naxos84 Sep 8 '17 at 13:19
  • 1
    \$\begingroup\$ PlayerPrefs might not the ideal solution for this. PlayerPrefs are supposed to persistently store information between restarts of the game, not just to pass information from scene to scene. It might be useful to remember the ship preference of the player so they get the same one pre-selected in their next session, but if you don't want to do that, then PlayerPrefs is overkill. \$\endgroup\$ – Philipp Mar 14 '18 at 14:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.