|
Post by britannis on May 23, 2016 22:03:23 GMT
I have a Faction enum with a bunch of different factions.
Each moving object in my game has a Faction component with a Faction enum set.
My initial thought is to have a FactionManager object that keeps track of the relationship between factions. Each moving object in my game would then need a reference to the FactionManager and to check faction allegiance quite often to update AI behavior...
Is there a better way to handle this?
|
|
|
Post by britannis on May 24, 2016 6:40:25 GMT
|
|
|
Post by Admin on May 24, 2016 15:18:25 GMT
If the asset you found works well for you then that is good. Otherwise to answer your question, a "Manager" is not a bad way to go. The real question is how do you implement it? Are you passing a reference to each of the objects, do you make it a singleton, etc? I don't like passing references around, and everyone complains about singletons and tight coupling, so you could try another option. You can make extension methods, either for the enum itself or for the object class that contains that property. You can put all of the code that is responsible for managing the relationships in that extension class and then you don't have to worry about passing references, having a singleton, worrying about tight coupling or anything, but you still have your code nice and organized. I put extensions on my enums in the Tactics RPG project if you need reference.
|
|
|
Post by britannis on May 24, 2016 16:18:48 GMT
Gotcha, so if I have a Faction.cs class where the enum is defined, I'd make an extension class with static methods for the Faction class.
However, each object in my game that belongs to a faction has a Faction component, so it may be better to make a static class called FactionsManager and make extensions for that method.
|
|
|
Post by Admin on May 24, 2016 19:02:40 GMT
If you mean that you have a "faction component" in the sense of a separate "MonoBehaviour" attached to a game object, then you can also add the logic you might have put in the "Manager" to the "component" script instead. This works great because you can still work in an abstract way using GameObjects and components. You don't need to know if they are a Hero or an Enemy etc. you just know they have the Faction component and the settings in the component determine the relationship you want such as friend or foe.
If you had architected it in a less-reusable way such as having separate "Hero" and "Enemy" classes (hopefully that share an interface or base class) each that had a field of the Faction enum type, then you might want a "Manager" or extension etc. to help section off the logic that would be acting on that bit of data.
I think the most important idea to take away is that every script, class etc. should ideally have a single purpose. This will help your code stay easy to read and maintain.
|
|
|
Post by britannis on May 25, 2016 0:48:36 GMT
What I was thinking is there would be individual behavior and faction relationship. By default, individual behavior is based on faction relationship, which is represented by an int. Suppose a faction relationship of 33 or lower is hostile, 66 or higher is friendly, and in-between is neutral. An object belonging to a faction with a score of 55 might be neutral to the player upon first encounter, but if the player shoots that object, it becomes hostile. Attacking an object would decrease the relationship between the player and the faction, but not always by enough points to make the faction hostile. For example, if I kill that object and my faction relationship drops to 35, the next object from that faction would still be neutral to me. But if I attack that object and my faction score drops to 25, then all objects belonging to that faction will be hostile to me on first encounter.
The question, then, is how to represent the internal number and the operations that act upon that number. There would still be a Faction Relationships Manager, but whether it is represented as a static class with extensions or an empty gameobject is the real design issue. It seems like you suggest the static class with extensions method for global access and avoiding the need to pass references around.
|
|
|
Post by Admin on May 25, 2016 15:07:24 GMT
Do you only have to track the relationships from the single player to all the different factions, or do you also need to track the relationships of NPC's or multiple players? Either way, it seems like it would be easy to add this to a "Faction" or "FactionRelationship" component on a GameObject. It could be something as simple as a Dictionary which maps from "Faction" to "Int" so that you could very quickly look up your relationship level for any faction as you need. Or, if you wanted to be able to see it in the inspector for debugging sake, and if your Faction enum wasn't a bit mask, you could have an array so that the integer equivalent of a Faction was the index of the relationship value in the array. For example:
// if you had a relationships array with the length of the Factions int[] relationships = new int[Factions.Count];
// You could determine a relationship with a Faction by converting the Faction type to an index if (relationships[(int)Factions.Falcons] <= 33) { // Warning! }
That is one benefit over using a component over a static class manager - the ability to visually debug using the inspector. If you actually need to store data, instead of just adding methods to act on already stored data, then I would want an easy way to look at it, especially during the prototype phase.
|
|
|
Post by britannis on May 25, 2016 22:27:33 GMT
That makes sense for the individual Faction component on an object.
I mean the global FactionRelationship Manager - it will need to be called every time faction relationships change. However, it may not be a bad thing for each Faction component to have a reference to the singleton Manager.
What do you think?
|
|
|
Post by Admin on May 26, 2016 2:09:49 GMT
Sorry, but I don't understand the purpose of the "global FactionRelationship Manager" if you already have a Faction component on each relevant object. For example, say the player object kills a member of a particular Faction and that drops his relationship with that Faction down to 33 or less. You don't actually have to talk to a global manager in order to let any of the other faction members "know" about this, because when the player enters a collider trigger on another member of the Faction, it will grab the "Faction" component from the GameObject, check its relationship status for its own faction, and if necessary, engage in combat based on the relationship level. It can all be determined as it is needed.
If you still think you need other faction members to know about it immediately, you could always post a notification which the Faction component would be observing.
|
|
|
Post by britannis on May 26, 2016 3:46:55 GMT
I'm confused here.
If 3 objects belong to faction A and I attack one of them, the relationship from the player faction to faction A should decrease. But how would the other two objects know the faction relationship has decreased?
Would there be a static method that is called that would reduce the relationship integer for all of that faction's relevant objects?
|
|
|
Post by Admin on May 26, 2016 14:46:56 GMT
You might be thinking of the problem backwards. You don't want every object of Faction A to have to keep track of the player's relationship to said faction - that would be a lot of duplicate data for no reason. Instead, you want the player to keep track of his own relationship to each faction. There are a variety of triggers you can use check the relationship at relevant times. For example, if your objects have colliders so that OnTriggerEnter and or OnTriggerStay are invoked. On those method handlers, they would look at the object that they collided with, grab the "FactionRelationship" component and check the relationship of the other object to the own faction type.
If you don't want to poll for the relationship every frame in OnTriggerStay, you can also post a notification whenever significant relationship changes occur. For example, when the player's relationship to Faction A drops below 33 then you post a notification so that any object in Faction A can respond accordingly.
|
|
|
Post by britannis on May 26, 2016 19:57:14 GMT
This makes sense, but it limits the relationship change to objects in the scene.
Assuming factions have relationships to other nonplayer factions and there is more than one object that is part of the player's faction, I would need a way to update the relationship int across all objects belonging to the faction, and not necessarily just faction objects in the same scene.
|
|
|
Post by Admin on May 26, 2016 21:01:38 GMT
Okay, I think I understand a little better. You want to be able to map from "Faction to Faction" rather than from "Player to Faction". So for example, if the player is part of "Faction A" and attacks a member of "Faction B" and reduces their faction relationship down to 33 or less, then any "Faction B" member encountering any "Faction A" member would engage in combat?
If that is the case, then I think it would be totally acceptable to have a FactionRelationshipManager (singleton if desired) which maintains the table.
|
|