0
\$\begingroup\$

I am currently gaining experience in Unity by trying to make a basic Citysim. Since its based on a really small town all my citizen are actual Agents rather than statistical calculations.

I am currently thinking about an Need System but I can't decide on a datatype.

Requirements for the Need System

  • All needs are regularly iterated over to decrease their Satisfaction level
  • Certain events trigger a function specific to each need: OnSeekNeed(), OnSatisfyNeed()
  • Different Actors have different needs: Drug addict has a need "Drugs"
  • It should be possible to add new generic needs or remove needs from each actor at runtime: Discovery of Internet AddGenericNeed(Citizen c, Need n, float satisfaction)
  • It should be able to add new needs to the game without changing other classes
  • The need needs to be comparable: A pizza shop satisfies NeedFood but not NeedSleep`

OLD QUESTION INCLUDING SOLUTION IDEAS - feel free to ignore

I am currently gaining experience in Unity by trying to make a basic Citysim. Since its based on a really small town all my citizen are actual Agents rather than statistical calculations.

I am currently thinking about an Need System but I can't decide on a datatype. Each Agent should have his own needs and an satisfaction value for each. Not all Agents have the same Needs, a child for example does not need romantic interactions. An addict will have special drug needs.

My first Idea was to make an own class for each need, allowing me to make more Needs for DLCs or

Parent Need

public abstract class Need
{ 
    public abstract void OnSeek();
    public abstract void OnFurfill();
    public abstract void OnNotFurfill();
    public abstract bool IsHidden();
    public abstract string GetName();
    //ect...
}

Each Character should then get needs assigned and on each update they will be looped through and the value (0-100) would be decreased by 0.25f.

But how should I arrange the Needs in the Character Class?

Option1 - Harcoded Array

Each Need has an assigned spot in an float Array.

  • con: Enabling or disabling Needs requires further overhead instead of just editing the set.
  • con: all Citizen need to have the same need-set
  • con: no Object orientation allowing to call special events 'OnSeek()'

Option2 - Dictinary<Need,satisfaction>:

I tough this would be the solution unfortunately it's impossible to iterate over it and change the value. If there was this with TypeOf Need as Key and an over writable value it would be perfect.

  • con: It's impossible to change the satisfaction without replacing the entire node
  • con: Apparently its not possible to use Types as Keys

    private Dictionary<Type, float> n2 = new Dictionary<Type, float>(); 
    private Dictionary<Need, float> n3 = new Dictionary<Need, float>();
    //both don't seem to work
    

Option3 - LinkedList<Need>:

  • con: slow to find values when events change a need for all citizen 'needs.findByType(NeedRest)'
  • con: needs can be added twice. Checking for duplicates is expensive
  • con: Each need is a new Object for every Citizen containing the statisfaction float

So far I believe the Linked List will be my best bet, most of the time I will be looping through it anyway. I'll need to check for duplicates on insert but maybe somebody can help me get the Dictionary to work or knows a better solution.

Please keep in mind, I am new to C# and maybe I am missing something completely obvious... While trying to write this question I somehow managed to answer a lot of my problems and came up with something that will sort of work. I'll be posting this anyway just in case somebody is stuck on the same problem or has a solution that is way better.

\$\endgroup\$
5
  • \$\begingroup\$ Somewhat related but not really helpful to the question: gamedev.stackexchange.com/questions/67984/… \$\endgroup\$
    – MisteriosM
    Dec 21, 2017 at 19:31
  • \$\begingroup\$ Generally its better to provide less information about your "expected" solutions and more information about the context of the problem. Looking at your Need class, it makes me think the basic design of the system is flawed and all your pros/cons are thus irrelevant. Could you provide less detail about your assumed solutions and more information about why you structured your Need class like that? What do you expect the virtual methods might be used for? Why isn't the "satisfaction level" of the need part of the Need? How are you expecting to iterate over/process the complete set of needs? \$\endgroup\$
    – user1430
    Dec 21, 2017 at 19:59
  • \$\begingroup\$ @JoshPetrie I changed my question accordingly \$\endgroup\$
    – MisteriosM
    Dec 21, 2017 at 20:14
  • \$\begingroup\$ What do you envision these "OnWhatever" callbacks to do on a Need? Are they going to trigger behavioral changes on the owning character, or that sort of thing? \$\endgroup\$
    – user1430
    Dec 21, 2017 at 20:21
  • \$\begingroup\$ @JoshPetrie Yes, they will affect stats (mood, health ect...) on the owner and the character will go and seek to satisfy the need if there is no other activity currently playing \$\endgroup\$
    – MisteriosM
    Dec 21, 2017 at 20:27

2 Answers 2

1
\$\begingroup\$

Is there anything wrong with simply having a "Need" class and having each person carry around an array of needs(need objects)? That way you could add or remove needs at runtime and each one could be tracked and manipulated per-actor.

I'm talking about having a "Need" class that would have variables for its current level, its type, etc., and then you would create a script for your actors (or add it to an existing one) where you have each actor carrying their own array of type "Need".

Then whenever you go to add a new one, if you're worried about duplicates I would have a function to step through your array on that actor and check to make sure that the one you're about to add doesn't have the same "Need.Type" as any of the ones in their array.

The array doesn't need to be in a specific order, either, you just need to know the maximum number you're ok with them having. So you could set it up to be an array of size 10 and that essentially becomes a bucket for you to store all of an actor's needs.

\$\endgroup\$
2
  • \$\begingroup\$ A Need parent, SpecificNeed childs? Numberd Array? Or associative? I am starting to believe i am completely overthinking this... How do I check for duplicates? \$\endgroup\$
    – MisteriosM
    Dec 21, 2017 at 20:35
  • \$\begingroup\$ How you check for dupes depends on: a) how often you check, b) how many you elements you must check, c) the cost of checking each element and most importantly d) whether or not your current dupe strategy is meeting your needs. When in doubt, start with something straight forward (list or array) & adjust as your need dictate - it's often easier to move from a simple container to a more complex one than vice versa. \$\endgroup\$
    – Pikalek
    Dec 22, 2017 at 14:31
0
\$\begingroup\$

If you want to use a Class as a key in a List<Need>, the class must implement the CompareTo() operator from IComparable<T>.

class Need : IComparable<Need>
{
    enum NeedType
    {
        Food, Water, Sleep, Shelter, Drugs, Doctor, Love, Fun, Quiet, Beauty
    }
    public NeedType need;
    public float urgency=0.0f;

    public Need(NeedType n, float urg)
    {
        need=n;
        urgency=urg;
    }

    public Need(NeedType n)
    {
        need=n;
    }

    public int CompareTo(Need other)
    {
        if(other==null) return 1;
        return urgency-other.urgency;
    }
}

It's a bit of overkill to make Need a class if it doesn't track other attributes other than how much it's needed. In that case, just use the NeedType enum as the key in a Dictionary<NeedType,float>. This will let you quickly update the urgency of each need, check which needs they have, as well as use lambda expressions to sort the Dictionary to find the most urgent need.

\$\endgroup\$
2
  • \$\begingroup\$ I didn't want to use enums because it should be able to create new Needs without editing base files... \$\endgroup\$
    – MisteriosM
    Dec 25, 2017 at 11:52
  • \$\begingroup\$ And that's fine, you just have to implement IComparable for lists, dictionaries may need IEquatable<T> with an override on Equals() and GetHashCode() \$\endgroup\$
    – Stephan
    Dec 25, 2017 at 15:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .