Home > Blockchain >  Problem with creating tower defense money farm script
Problem with creating tower defense money farm script

Time:10-23

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;
}
  1. 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();
    }
  1. 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;
    }
...
}
  1. 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());
    }
}
  • Related