简体   繁体   中英

Better way to count all existing citizens?

I've started making a simple city builder game, in the spirit of Zeus/Poseidon, but much simpler. I have the grid system ready and ability to add houses and roads. Yesterday I began to add citizens, in a simple way, that is, whenever a house is created, 5 people are created and move directly from one edge of the map to that particular house. Once they reach that particular house, I consider they became citizens, and add them to the list of residents of the house, and also to the list of citizens of the city.

For that, each house instance has a List of Human, and my Game class which contains all the information of the game also has one List of human.

To simplify it looks like this:

Game.cs

public class Game {
    private static Game instance; // this is a singleton
    private int currentAmount; //this is the value I'm using to display the number of citizens on screen
    private List<Human> humen;
    public List<Human> Humen
    {
        get { return humen; }
        set
        {
            humen = value;
            currentAmount = humen != null ? humen.Count : 0;
        }
    }
    public void AddHuman(Human human)
    {
        humen.Add(human);
        currentAmount = humen.Count;
    }
    /// <summary>
    /// Private constructor to ensure it's only called when we want it
    /// </summary>
    private Game()
    {
        humen = new List<Human>();
    }


    public static void setGame(Game game)
    {
        instance = game;
    }

    /// <summary>
    /// Returns the instance, creates it first if it does not exist
    /// </summary>
    /// <returns></returns>
    public static Game getInstance() {
        if (instance == null)
            instance = new Game();
        return instance;
    }
}

House.cs

public class House : Building {
    public static int CAPACITY = 5;
    private List<Human> habitants;

    public List<Human> Habitants
    {
        get { return habitants; }
        set { habitants = value; }
    }
    public House() {
        habitants = new List<Human>();
    }
}

HumanEntity.cs

public class HumanEntity : MonoBehaviour {
    private Human human;
    private float speed;

    public Human Human
    {
        get { return human; }
        set { human = value; }
    }


    // Use this for initialization
    void Start () {
        speed = Random.Range(5.0f, 10.0f);

    }

    // Update is called once per frame
    void Update () {
        if (human != null)
        {
            Vector3 targetPosition = human.Target.GameObject.transform.position;
            if (transform.position.Equals(targetPosition)) {
                if (!human.HasAHouse)
                {
                    human.HasAHouse = true;
                    Game.getInstance().AddHuman(human); // here I'm adding the human to the list of citizens
                    ((House)human.Target).Habitants.Add(human); // here I'm adding it to the house list of habitants
                }
            }
            else {
                float step = speed * Time.deltaTime;
                transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
            }
        }
    }
}

And this is working as expected, but I'm wondering if having one list of human by house in addition with a global list in the game class is not a little overkill, and if there was maybe a more elegant way to achieve that count on the Game class, maybe something more "Unity friendly" if I may say so, as I don't really know a lot about the capacities of Unity. Do you have any advice on what to do, is that okay to keep it this way or is there a more elegant way?

Fast and appropriate way to know how many human would be to have a static counter on HumanEntity class:

public class HumanEntity : MonoBehaviour 
{
     public static int HousedHuman { get; private set; }
     public static int HumanCount { get; private set; }

     void Awake() {  HumanCount++;  }
     void OnDestroy()
     { 
         HumanCount--; 
         if(human.HasAHouse == true){ HousedHuman--; }
     }
     public static void ResetCounter() {  HouseHuman = HumanCount = 0; }

     void Update () {
        if (human != null)
        {
            Vector3 targetPosition = human.Target.GameObject.transform.position;
            if (transform.position.Equals(targetPosition)) {
                if (!human.HasAHouse)
                {
                    HouseHuman++;    // Added
                    human.HasAHouse = true;
                    // Rest of code
                }
            }
            // Rest of code
        }
    }
}

When a new instance is added, the counter is increased, when the instance is destroyed, the counter is decreased.

You can access via HumanEntity.HumanCount. You won't be able to set it elsewhere than in the HumanEntity class.

Make sure to reset the counter when you start/leave the scene.

EDIT: based on comment, I added a second static counter for HousedHuman. This is increased when the entity reaches the house. It gets decreased when the entity is destroyed if the entity was housed. It also gets reset when needed along with the overall counter.

Building on Everts's idea...

Game:

public class Game {
    private static Game instance; // this is a singleton
    public static int currentAmount { get; set; }

    //rest of class
}

House:

public class House : Building {
    public static int CAPACITY = 5;
    private List<Human> habitants;

    public List<Human> Habitants
    {
        get { return habitants; }
        set { habitants = value; }
    }
    public House() {
        habitants = new List<Human>();
    }
    public void AddHuman(Human human)
    {
        human.HasAHouse = true;
        habitants.Add(human);
        Game.currentAmount++;
    }
}

UpdateLoop:

// Update is called once per frame
void Update () {
    if (human != null)
    {
        Vector3 targetPosition = human.Target.GameObject.transform.position;
        if (transform.position.Equals(targetPosition)) {
            if (!human.HasAHouse)
                ((House)human.Target).AddHuman(human);
        }
        else {
            float step = speed * Time.deltaTime;
            transform.position = Vector3.MoveTowards(transform.position, targetPosition, step);
        }
    }
}

If checking house capacity is required, you can change the AddHuman method to a bool return type, do a capacity check inside and return whether or not it was successfully added.

You can also add a RemoveHuman method that would count humans down via Game.currentAmount--;

As for the list in Game, it really depends on the context. The List in your Game class could be useful to differentiate between wandering humans, and humans who are housed, if this behavior is required. (Wandering humans in the Game list, housed in the housed list)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM