im pretty new to coding so maybe the answer is simple.
Im creating a tower defense game and right now im trying to code a tower, which adds a serializable amount of money after each wave is defeated.
My idea is that the script which controls the WaveSpawning should call all MoneyPumps to perform the function "GiveMoney()", that sits on their script MoneyPump. But there is a problem with static stuff, which I cant find a solution to.
Please help, thanks.
The Segment for WaveSpawning:
void Update()
{
if(spawningWave){return;}
if(GameManager.gameOver){enabled = false; return;}
maxWavePlayTime -= Time.deltaTime;
if(enemiesAlive > 0 && maxWavePlayTime >= 0f)
{
return;
}
if(waveIndex == waves.Length && !spawningWave)
{
gameManager.LevelWon();
this.enabled = false;
return;
}
//THE IDEA IS TO CALL HERE THE MONEY PUMPS 1 TIME
if(Countdown <= 0f )
{
Stats.WavesSurvived ;
waveToDisplay = waveIndex 1;
WaveIndexDisplay.text = "Wave " waveToDisplay.ToString();
spawningWave = true;
StartCoroutine(SpawnWave());
Countdown = WaveCounter;
maxWavePlayTime = StartmaxWavePlayTime;
return;
}
The short script for MoneyPumps:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoneyPump : MonoBehaviour
{
public int moneyEveryRound = 25;
public static bool giveMoney = false;
public void GiveMoney()
{
Stats.Money = moneyEveryRound;
}
}
The stuff to spawn a turret: 1.
[System.Serializable]
public class TurretBluePrint
{
public GameObject prefab;
public int cost;
public GameObject upgradedPrefab;
public int upgradeCost;
public int SellDivider;
}
- If we click on a designated Button the SelectMoneyPump() function gets called
public class Shop : MonoBehaviour
{
public TurretBluePrint LaserBeamer;
public void SelectMoneyPump()
{
Debug.Log("Money Pump Purchased");
BuildManager.SelectTurretToBuild(MoneyPump);
}
}
public void SelectTurretToBuild (TurretBluePrint turret)
{
turretToBuild = turret;
DeselectNode();
}
- If we now click on a node (basically a just a tile on a grid):
public class Node : MonoBehaviour
{
...
void onm ouseDown()
...
BuildTurret(buildmanager.GetTurretToBuild());
...
}
public class BuildManager : MonoBehaviour
{
...
public TurretBluePrint GetTurretToBuild()
{
return turretToBuild;
}
...
}
- Turret building
void BuildTurret(TurretBluePrint blueprint)
{
...
turretBlueprint = blueprint;
GameObject _turret = (GameObject)Instantiate(blueprint.prefab,
GetBuildPosition(), Quaternion.identity);
...
}
CodePudding user response:
If you want to call GiveMoney
methods, you need to store your MoneyPump
instances somewhere. For example you can store it inside WaveSpawning
and then just call GiveMoney
inside foreach loop
class WaveSpawning
{
private List<MoneyPump> moneyPumps;
...
void Update()
{
...
foreach(var mp in MoneyPump)
mp.GiveMoney();
...
}
}
So when you create new MoneyPump
instance you add it to the moneyPumps
. However it's not the best practice to store MoneyPump
inside WaveSpawning
, because it's wrong abstraction.
I would recommend to handle end of wave inside another class.
class WavesSystem
{
// Singleton pattern
private static _wavesSystem _instance;
// If you use C# 8 or newer
private static WavesSystem Instance => _instance ??= new WavesSystem();
// If you use older version
private static WaveSystem Instance => _instance ?? (_instance = new WavesSystem())
private WavesSystem()
{
}
public void BeginWave()
{
...
}
public void FinishWave()
{
...
}
}
Note that previous example is ok, when your WavesSystem
doesn't need to be MonoBehavior
, otherwise try another singleton
logic
class WavesSystem : MonoBehavior
{
public static WavesSystem Instance { get; private set; }
private void Awake()
{
// If there is an instance, and it's not me, delete myself.
if (Instance != null && Instance != this)
Destroy(this);
else
Instance = this;
}
...
}
Important: Instance
of WavesSystem
will not be null after Awake
, so do not get access to WavesSystem.Instance
in another Awake
method, because it can be tricky (sometimes your classA will be loaded before WavesSytem and it will work, but when you build your app, loading order can change and it will cause an error)
CodePudding user response:
I guess the solution is harder to find than I thought. I simply changed the concept a bit. The MoneyPumps do not give money after every wave defeated but after a defined amount of time, which is way more easy to code.
public class MoneyPump : MonoBehaviour
{
public int moneyEveryRound = 25;
public int moneyEverySeconds = 20;
void Start()
{
StartCoroutine(GiveMoney());
}
IEnumerator GiveMoney()
{
yield return new WaitForSeconds(moneyEverySeconds);
Stats.Money = moneyEveryRound;
Debug.Log("MoneyGiven: " moneyEverySeconds);
StartCoroutine(GiveMoney());
}
}