- Home /
Having trouble accessing a variable in another class
So I'm trying to set up a mechanic where enemies spawn in a certain range based on how many keys you have. However, I had put the keys obtained counter in the PlayerController script that's attached to the Player object because of the OnTriggerEnter code. In the SpawnManager, I want to reference the number of keysObtained, however I'm not sure what to do. I read that static makes the variable the same no matter the class, but it made the keysObtained counter disappear in the Unity UI and no enemies spawn (one would spawn before since I have a crappy work around I gave up on to look into the static route). Here's my SpawnManager script (I know its a mess, I'm new to game development, just please be gentle)
EDIT: idk why the code looks like this. The code looks properly formatted for me in the edit question screen so I'm not sure what's happening to it
public GameObject keyPrefab;
public GameObject enemyPrefab;
public int keyCount;
public int enemyCount;
float keysObtained = PlayerController.keysObtained;
private float leftSpawnRangeX = 22.0f;
private float rightSpawnRangeX = -19.0f;
private float lowerSpawnRangeY = 10.5f;
private float upperSpawnRangeY = 29.0f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
keyCount = FindObjectsOfType<Key>().Length;
enemyCount = FindObjectsOfType<EnemyMovement>().Length;
if (keyCount == 0)
{
SpawnKey();
}
if (enemyCount == 0 && keysObtained == 1)
{
SpawnEnemy();
} else if (enemyCount == 1 && keysObtained == 3)
{
SpawnEnemy();
} else if (enemyCount == 2 && keysObtained == 5)
{
SpawnEnemy();
} else if (enemyCount == 3 && keysObtained == 8)
{
SpawnEnemy();
} else if (enemyCount == 4 && keysObtained == 10)
{
SpawnEnemy();
}
}
private void SpawnKey()
{
Instantiate(keyPrefab, GenerateRandomSpawn(), keyPrefab.transform.rotation);
}
private void SpawnEnemy()
{
Instantiate(enemyPrefab, GenerateRandomSpawn(), enemyPrefab.transform.rotation);
}
private Vector3 GenerateRandomSpawn()
{
float SpawnPosX = Random.Range(leftSpawnRangeX, rightSpawnRangeX);
float SpawnPosY = Random.Range(lowerSpawnRangeY, upperSpawnRangeY);
Vector3 randomPos = new Vector3(SpawnPosX, SpawnPosY, 0);
return randomPos;
}
}
hey there,
i fixed your code formatting. There is a little icon with "10010101" over the text field. Press that and enter your code to get proper code formatting.
Answer by Captain_Pineapple · Jan 31 at 08:58 AM
In general i suggest you take 2 steps back and get comfy with static variables first.
i guess the major misunderstanding you have is that
float keysObtained = PlayerController.keysObtained;
will only set the value of keysObtained
once. (when you create this object)
This line does not mean that keysObtained
will always have the exact same value as PlayerController.keysObtained
.
What you instead want to do here is to remove the keysObtained
variable in your SpawnManager completly and just write PlayerController.keysObtained
in your if statements.
Sidenote:
While this is nothing you asked about i still want to adress it: do not use FindObjectOfType or any similar function in Updates. This is horrible on performance and should only be done in Start functions. In general you can ofc still use it as it is but if your project grows larger/more demanding it might come back to bite you in your arse. If you have issues with the tracking of the current keycount otherwise let me know. There are nice ways to deal with that.
So this fix does work, and thanks for the tip about not using FindObjectsOfType in Update. I'm basing it off what Unity said in the Junior Programmer Pathway. I works right with PlayerController.keysObtained. However, if I put FindObjectsOfType in void Start(), it breaks the game by endlessly spawning enemies and keys. I'll leave it in void Update() because it works with it there, but thank you for the help
glad i could help.
when you put the statement
keyCount = FindObjectsOfType<Key>().Length;
in Start like it is this will ofc break your current setup as keyCount would never change when you spawn a key.
However if we assume that the only place where you spawn and keep track of keys is your SpawnManager
then you can simply bypass this and get rid of FindObjectOfType
completly if increment the keyCount when you Instantiate a new key.
Apart from that you can give your enemys a variable
public SpawnManager spawnManagerReference;
that you set like this:
private void SpawnEnemy()
{
var newEnemy = Instantiate(enemyPrefab, GenerateRandomSpawn(), enemyPrefab.transform.rotation);
newEnemy.GetComponen<EnemyScript>().spawnManagerReference = this;
}
Then give your spawnManager class a function enemyHasDied
which you call in your EnemyScript
when an enemy is killed. This way you can tell the spawnManager when something happens.
This design choice can help you simplify stuff in a lot of situations as you don't have to implement Update
routines left and right that always ask "has something happed?" "has something happed?" "has something happed?" "has something happed?" but instead just get notified when stuff happens. Like when an enemy dies. That way you can for example track the amount of enemies alive as you increment an enemiesAlive
counter when you spawn an enemy and decrement it when it notifies the SpawnManager
when it has died.
This way you can get rid of your FindObjectOfType<Enemy>
in the update as well.