- Home /
Having trouble swapping GameObjects on button click
Hello. I have an issue with swapping GameObjects on button click. I am trying to switch out players that have scripts attached to them along with animations. For some reason, when switching out the player, the code is stopping before being exicuted. With using Debug.Log(), I notice that when switching players, the code is accessing another IEnumerator when it should not be as the code directly shows which IEnumerator to use. There are no errors, just misbehaves when switching GameObjects. During runtime, I have to have 1 GameObject shown and 23 GameObjects hidden using (SetActive true,false). Each of the 24 GameObjects have their own Player Script along with other scripts for functionality. I included some code from a Player Script and some code from my Game Controller Scripts that contains the IEnumerators. My first Player Code is:
public class Player1 : MonoBehaviour
{
// code not shown as too much
//
//
public void WinLevel()
{
GameController.instance.WinGame1();
}
}
My Second Player code is:
public class Player2 : MonoBehavior
{
// code not shown as too much
//
//
public void WinLevel()
{
GameController.instance.WinGame2();
}
}
My Game Controller Script is:
public class GameController : MonoBehaviour
{
// code not shown as too much
//
//
public void WinGame1()
{
StartCoroutine(WinGameCor1());
}
public void WinGame2()
{
StartCoroutine(WinGameCor2());
}
// more code as too much
// there are 24 (WinGame) -- each one for a different Player
//
IEnumerator WinGameCor1()
{
gameOverScreen.SetActive(false);
pauseButton.SetActive(false);
Portal1.SetActive(true);
yield return new WaitForSeconds(1.5f);
Destroy(Player1.instance.gameObject);
yield return new WaitForSeconds(0.5f);
WinScreen.SetActive(true);
counterText.gameObject.SetActive(false);
scoreCount.text = score + "";
coinsCount.text = coins + "";
if (Services.ServicesAreEnable)
Services.instance.ReportToLeaderboard(score);
}
IEnumerator WinGameCor2()
{
gameOverScreen.SetActive(false);
pauseButton.SetActive(false);
Portal2.SetActive(true);
yield return new WaitForSeconds(1.5f);
Destroy(Player2.instance.gameObject);
yield return new WaitForSeconds(0.5f);
WinScreen.SetActive(true);
counterText.gameObject.SetActive(false);
scoreCount.text = score + "";
coinsCount.text = coins + "";
if (Services.ServicesAreEnable)
Services.instance.ReportToLeaderboard(score);
}
}
When choosing player 2, the IEnumerator that is being accessed is IEnumerator WinGameCor1() when it should be IEnumerator WinGameCor2(). Please let me know what your thoughts are on this issue. Thanks
Answer by jackmw94 · Jan 12, 2021 at 04:39 PM
Wanted to post this as a comment but it kept failing so here it is as a semi-helpful answer!
I can't see any specific issue with your code that would cause this behaviour but would be doing you a disservice if I navigated away from this page without strongly advising you to cut down on how much duplicate code you have! Not just because it's nice to read or clean but because it will really help when debugging things like this :)
If I were you, instead of having multiple player scripts and accessing each by Player1.instance, I'd have the GameController hold an array of 'players' - with 'Player' being a single script that does everything that your Player1, Player2, etc scripts currently do. Player can hold a value which will be its player number so you can address it. Have a look at the following as an example - I would be surprised if the issue was not at least partly related to how confusing that much code is:
public class Player : MonoBehaviour
{
[SerializeField] private int _playerNumber;
public int PlayerNumber => _playerNumber;
public void WinLevel()
{
GameController.instance.WinGame(_playerNumber);
}
}
public class GameController : MonoBehaviour
{
// Since it seems each player has their own portal we can bundle them together like this
// Alternatively you could add portal as a reference in player and access it that way
[Serializable]
public struct PlayerData
{
public Player Player;
public GameObject Portal;
}
[SerializeField] private PlayerData[] allPlayerData;
public static GameController instance;
[Conditional("UNITY_EDITOR")]
private void OnValidate()
{
for (int i = 0; i < allPlayerData.Length; i++)
{
// Since we're no longer hard coding player numbers we do have to be careful we have unique player numbers!
Debug.Assert(allPlayerData[i].Player.PlayerNumber == i + 1, $"Player in element {i} position does not have player number {i + 1}!");
}
}
private void Awake()
{
instance = this;
}
public void WinGame(int playerNumber)
{
StartCoroutine(WinGameCor(playerNumber));
}
IEnumerator WinGameCor(int playerNumber)
{
PlayerData playerData = GetPlayerData(playerNumber);
gameOverScreen.SetActive(false);
pauseButton.SetActive(false);
playerData.Portal.SetActive(true);
yield return new WaitForSeconds(1.5f);
Destroy(playerData.Player.gameObject);
yield return new WaitForSeconds(0.5f);
WinScreen.SetActive(true);
counterText.gameObject.SetActive(false);
scoreCount.text = score + "";
coinsCount.text = coins + "";
if (Services.ServicesAreEnable)
Services.instance.ReportToLeaderboard(score);
}
private PlayerData GetPlayerData(int playerNumber)
{
int playerIndex = playerNumber - 1;
if (playerIndex < 0 || playerIndex >= allPlayerData.Length)
{
throw new Exception($"Cannot access player at element {playerIndex} as it is out of bounds of the array!");
}
return allPlayerData[playerIndex];
}
}
Let me know if you need clarification on any of this
I fixed the issue. I ended up using only 1 GameObject and adding in the GetComponent<> to switch out the sprite, box collider, and some script functions. Now, when switching from each player, the properties for each player are adapted and run correctly. Works faster as well. For my animator, I had to create two scripts to provide an override to the original animation, similar to setting up triggers on a 3D object but in a 2D state. Works great.
Your answer
Follow this Question
Related Questions
Disabling A Script on a GameObject From a Different Script 2 Answers
Issue with GameObject has been destroyed but it is not destroyed 1 Answer
Multiple Cars not working 1 Answer
How could I save my Gameobject inside a defined Prefab ? 1 Answer
How to determine the direction of an object to the player. 1 Answer