Best practice to find object in List of custom classes? Do if in list, if not do something else

In my game players have the ability to inflict "debuffs" on each other. When one is supposed to inflict a debuff on the other player I loop through a List to see if that debuff already exists there, if it does I want to either extend the length, or maybe add to it's effect. What would be the best practice way of doing this? Right now I am doing the following:

var debuffs = List();
bool didExist = false;

And further down:

foreach (Debuff debuff in Debuffs)
{
if (debuff.GetName() == "debuffName")
{
debuff.AddDuration(10);
didExist = true;
}
if (didExist == true)
{
debuffs.Add(new Debuff("debuffName", 10, 10); // name, duration, effect
}
}

I feel like this can be done easier somehow, but not quite sure how. Surely I should be able to leave out the boolean?

Make each buff register with a "buff manager" type construct when it is loaded/created.

When it registers it says "I'm a HealthBuff17!" and here is me.

From then on anyone who goes "YOU GET A HealthBuf17!!!" calls the manager and the manager has one loop that either says "I got that, here you go," or else "Nope, error to the console log."

1 Like

Stuff that’s kind of basic: use numbers or an enumerated type instead of a string. Intellisense can pop those up, which means you don’t risk mispelling “Pioson” and having a skill do nothing:

public enum buffType_t {poison, hunger, sneeze};
buffTyper_t newType=buffType_t.hunger; // sample use. hunger is really just the number 1

if(B[i].buffType==incomingBuffType) // comparing is pretty normal

if(bt==buffType_t.sneeze) { // do sneeze stuff

Another trick which is 60 years old but is still sort of a new cool thing in C# is using a built-in search with a compare function:

Buff oldBuff =  Debuffs.Find(m => m.type==newType);
if(oldBuff!=null) oldBuff.duration+=10;
else { // new buff, add it

It’s nothing special. It’s doing the same loop you are, using a short => mini-function. It’s not worth learning it to get one thing done, but it’s a standard trick is every language so worth messing around with if you want to be programmer.

1 Like

BUT!!! Be very careful with enumerated types since Unity’s YAML serializer does not save the mnemonic of the enum but rather just an integer. If you change your enum in code, you could potentially silently bork all your prefabs, assets and scenes that contain these non-identifier serialized numbers. I try to stay away entirely from enums for anything that I am going to let Unity serialize. Otherwise they’re great.

using UnityEngine;

[CreateAssetMenu]
public class Attack : ScriptableObject
{
    //NEVER REMOVE OR INSERT ANY ITEMS! Only add to END OF LIST!
    public enum DamageType {
        NORMAL,
        MAGIC,
        ELECTRICAL,
    }

    public DamageType damageType;
}

The object I made:

6323361--701142--Screen Shot 2020-09-17 at 4.48.19 PM.png
And the YAML:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 0}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: 803d7771239ff4fd8be580a5e0888338, type: 3}
  m_Name: New Attack
  m_EditorClassIdentifier:
  damageType: 2

See the last line where damageType is serialized?

Veeeeeeeery dangerous, especially in a team work environment!

To rephrase, enum's make nice dropdowns in the Inspector -- you can select Poison, Hungry, or Sleepy instead of typing it in as a string. BUT, if you add a new condition, like Sleeping, if might might break them since all Unity remembers is "you set it to the second one in the list".

I suppose a reasonably safe fix is to include the values:

enum buffType_t {poison=0, hungry=1,  sneeze=2};

//  then we really want to add contaminated just after poison:
enum buffType_t {poison=0, contaminated=3, hungry=1, sneeze=2};

Not foolproof, but it makes you work hard to break Unity by changing the numbers.

You can't do tricks anymore where physical ones are <=3 and mental >3, but those were always funny anyway.

@Owen-Reynolds We actually hacked up an enum serializer editor script a few years back, to get the ease and semantics of an enum dropdown but it serialized / deserialized to a hidden field that contained the actual string, then worked it back with enum Parse or whatever it is on reload.

It was slick but fiddly to maintain, but it was pretty bulletproof.

Well, at least modulo renaming identifiers. :) "Whoops."