Loop through a List to check whether a bool is tru

2019-08-16 00:10发布

I have a character Scriptable Object 'Character' and it has a bool IsMale. I also have a 'Team' Scriptable Object and it has a list of Characters from the Character Scriptable Object Class. Now, I want to create a custom method in the Team Class for looping through this list and check how many characters are male and how many are not.

Character.cs

 using UnityEngine;

 // Personal Attributes
 public string firstName;
 public string middleName;
 public string lastName;
 public string fullName;

 public bool isMale;

Team.cs

 using UnityEngine;

 public List<Character> characters;

 // For adding ten players.
 public void AddPlayer(Character p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
 {
 characters.Add(p1);
 characters.Add(p2);
 characters.Add(p3);
 characters.Add(p4);
 characters.Add(p5);
 characters.Add(p6);
 characters.Add(p7);
 characters.Add(p8);
 characters.Add(p9);
 characters.Add(p10);
 }
 // I want to loop through these ten characters in the list and tell how many are males and how many are not

Again, I want to create a custom method in the Team Class for looping through this list and check how many characters are male and how many are not.

For the questions in the comments @derHugo Character.cs

using UnityEngine;
using System;

[CreateAssetMenu()]
public class Character : ScriptableObject
{
    // Personal Attributes
    public string firstName;
    public string middleName;
    public string lastName;
    public string fullName;

    public bool isMale;

    private int age;
    public int personalMoney;

    public Sprite image;

    // Game Attributes
    public int totalRuns;
    public int salary;

    public enum characterTypes { PlayerCharacter, Manager, Player, Staff };
    public characterTypes characterType;
    public enum battingHands { LeftHanded, RightHanded };
    public battingHands battingHand;
    public enum bowlingHands { LeftHanded, RightHanded };
    public bowlingHands bowlingHand;
    public enum battingMentalities { Aggressive, Balanced, Defensive };
    public battingMentalities battingMentality;
    public enum bowlingMentalities { Aggressive, Balanced, Defensive };
    public bowlingMentalities bowlingMentality;

    // Skills
    // Technical Skills
    public int technical; // Overall Technical
    public int judgement; // Batting
    public int agility; // Running, Low means if player accidentaly falls down, the time he will take to get back up
    public int cardioFitness; // Injury
    public int muscleFitness; // Injury and Hitting Power
    public int runSpeed; // Running
    public int strength; // Hitting Power

    // Methods
    // Personal Attributes Methods
    public void CalculateAge(DateTime dateOfBirth)
    {
        age = 0;
        age = DateTime.Now.Year - dateOfBirth.Year;
        if (DateTime.Now.DayOfYear < dateOfBirth.DayOfYear)
            age = age - 1;
    }

    // Starting Game Methods Required
    public void SetCharacterType(characterTypes cT)
    {
        Debug.Log("Setting Character Type for " + fullName);

        cT = characterType;

        if (cT == characterTypes.PlayerCharacter)
        {
            Debug.Log(fullName + " is a Player Character");
        }
        else if (cT == characterTypes.Manager)
        {
            Debug.Log(fullName + " is a Manager");
        }
        else if (cT == characterTypes.Player)
        {
            Debug.Log(fullName + " is a Player");
        }
        else if (cT == characterTypes.Staff)
        {
            Debug.Log(fullName + " is a Staff");
        }
        else
        {
            Debug.Log("No Character Type");
        }
    }
    public void TechnicalAverage()
    {
        technical = (judgement + agility + cardioFitness + muscleFitness + runSpeed + strength / 600) * 100;
    }
}

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-08-16 00:48

You can e.g. use Linq Count for that (I'ld rather use properties here but you could do the same using methods ofcourse.):

using System.Linq;

public int Males
{
    get
    {
        return characters != null ? characters.Count(c => c.isMale) : 0;
    }
}

public int Females
{
    get
    {
        return characters != null ? characters.Count(c => !c.isMale) : 0;
    }
}

You would simply use that value like e.g.

Debug.LogFormat(this, "Males: {0}, Females: {1}", Males, Females);

Hint: even though the Unity Inspector automatically initializes List and array fields you shoudl always do it together with the definition like

public List<Character> characters = new List<Character>(10);

just to be sure it is never null when calling Add and make sure to set a default capacity to what you expect the List to have as Count later.

Or alternatively you could use

Character[] characters = new Character[10];

since you don't want the size to be dynamic anyway. (Note however that the Inspector in Unity always overrides those definitions)

The reason why this is better: List in the background stores it's values in an array anyway. By adding elements using Add it everytime checks if the array is still big enough and if not expands it to the double size (see here)

public void AddPlayer(Character p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
{
    characters.Add(p1); // characters has now capacity 4
    characters.Add(p2);
    characters.Add(p3);
    characters.Add(p4);
    characters.Add(p5); // characters reallocated and has now capacity 8 
    characters.Add(p6);
    characters.Add(p7);
    characters.Add(p8);
    characters.Add(p9); // characters reallocated and has now capacity 16
    characters.Add(p10);
}

so you see using Add 10 or 11 times always allocates more memory than actually needed.

I would do

// hide because if you do it via the method you probably don't
// want to add items via Inspector which would get overwritten later anyway
[HideInInspector] public Character[] characters = new Character[10];

public void AddPlayer(Character p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
{
    characters[0] = p1;
    characters[1] = p2;
    characters[2] = p3;
    characters[3] = p4;
    characters[4] = p5;
    characters[5] = p6;
    characters[6] = p7;
    characters[7] = p8;
    characters[8] = p9;
    characters[9] = p10;
}

other than that there is no big difference between how you access or change values in array or List.


For setting all the values you need for every character you could/should use a proper constructor (I would change the naming though):

[Serializable]
public class Character
{
    // Personal Attributes
    public string firstName;
    public string middleName;
    public string lastName;
    public string fullName;

    public bool isMale;

    public Character(string _firstName, string _middleName, string _lastName, bool _isMale)
    {
        firstName = _firstName;
        middleName = _middleName;
        lastName = _lastName;

        fullName = string.Format("{0} {1} {2}", firstName, middleName, lastName);

        isMale = _isMale;
    }
}
查看更多
登录 后发表回答