2
\$\begingroup\$

The project that I'm working on demands the ability for game designers to be very flexible when balancing, customizing items, etc. The most difficult requirement to meet at the moment is that they want to drag-drop, say, a weapon prefab onto a weapon field in some game entity component and from there be able to tweak the prefab's parameters. If I provide some tools that create derived prefabs at such moments, then we'll end up with possibly hundreds of pretty much same prefab variations and also loose the ability to edit the initial prefab and transfer the changes to derivatives.

What I'm starting to consider is introducing a "Data Map" structure in every entity that requires high level of parameter customization. Every parameter would be set through methods like Set/GetFloat("key", "value"), Set/GetFloatArray, Set/GetInt, etc. So basically a dictionary that maps a string to a predefined set of data types. When a prefab of such entity would be drag-dropped into a field of another component, an editor tool would separate the "Data Map" from the prefab, allow the game designer to tweak the values of the keys and eventually serialize it to json. During runtime uppon instantiation of a prefab with a "Data Map" a manager would check the deserialized overrides and override the "Data Map" with the tweaked values if needed.

Though to me this sounds overly complicated and maybe some of you had a similar situation and came up with a simple solution? Maybe it's worth trying the ECS approach? Thanks.

An example: Let's say there are prefabs: Axe, Sword, Bow with a bunch of parameters configured, say Damage, Durability, etc. There are many other components that can accept a weapon prefab and once it's dropped, the designers want to have "on the spot editing" say, okay, for this situation here the Axe prefab needs to be a little different and have Damage+3. Creating a new prefab means that the link to the initial Axe prefab is lost and there are now two Axe prefabs that need to be managed - this is the problem we're trying to address.

\$\endgroup\$
  • \$\begingroup\$ You can go with object pooling \$\endgroup\$ – AVI Dec 8 '15 at 13:02
  • \$\begingroup\$ The problem is not instance creation/management, but how to provide a way for game designers to do small/minor tweaks of prefabs during edit mode and where/how to store such changes and then apply to instances of prefabs during runtime (instead of creating new prefabs for every tweak). \$\endgroup\$ – mt_ Dec 8 '15 at 13:08
  • \$\begingroup\$ Then you can add that prefab in a seperated pool \$\endgroup\$ – AVI Dec 8 '15 at 13:13
  • \$\begingroup\$ possible solution forum.unity3d.com/threads/replace-game-object-with-prefab.24311 \$\endgroup\$ – AVI Dec 8 '15 at 13:20
  • 2
    \$\begingroup\$ Can you say a bit more about what traits you hope to preserve via the link to the "initial axe prefab"? Is it data values (damage, etc.), or is it the rest of the prefab junk, meshes, components, etc.? In your ideal case, if e.g. someone makes AwesomeAxe with +3 damage and later changes the base axe to have 2 more damage, should AwesomeAxe be +5? I'm trying to understand the constraints here. \$\endgroup\$ – Chris Mills-Price Dec 8 '15 at 18:13
2
\$\begingroup\$

Though I'm still not 100% clear on what your designers need, here's one approach that should get you easy customization while maintaining prefab connections. The limitation is that you still need unique prefabs for each distinct thing you're going to store outside of a scene.

Core concept is either the "Decorator" pattern, or maybe the "Mutator" pattern. Either way I'll call them Mutators.

First, you need a base class that will be modified. This class has the various values you want to allow designers to set.

public class WeaponBase : MonoBehaviour {
    // values designers set directly *tied to the prefab*
    public float BaseDamage = 1.0f;
    public float BaseDurability = 10.0f;
    public int handsRequired = 1;

    // cached values built up from mutators below this object
    private float modDamage = 0.0f;
    private float modDurability = 0.0f;

    void Start () {
        WeaponMutator[] mutators = GetComponentsInChildren<WeaponMutator>();
        for(int i=0; i<mutators.Length; i++)
        {
          modDamage += mutators[i].getModDamage();
          modDurability += mutators[i].getModDurability();
          handsRequired = Mathf.Max(handsRequired, mutators[i].getHandsRequired());
        }
    }
    // update cache values in Update() if you want them to be changeable real-time.
}

Then, you need a 'mutator' script, which gets placed on a "CustomizeWeapon" prefab somewhere. In that script, you store values:

public class WeaponMutator : MonoBehaviour {
    // values designers set directly *in the scene hierarchy*
    public float ModDamage = 0.0f;
    public float ModDurability = 0.0f;
    public int ModHandsRequired = 1;

    public float getModDamage(){
        return ModDamage;
    }
    // ditto for getModDurability, getHandsRequired, etc.
}

(These could be merged, but I think to make the purpose clear for your designers, keeping them separate is helpful.)

Then for each core weapon type you do want individual prefabs for, you can use just the WeaponBase script if that's sufficient. If not, you can do WeaponMutators to define it as you need.

Your prefabs are then fairly simple. A standard 2-handed axe prefab might be:

  • Axe (contains all the generic axe data in a WeaponBase instance)
    • 2H (GameObject with a WeaponMutator, just defines handsRequired as '2')

Then in your scene if the designers want to make some guard's 2H axe really strong, they could just drag-drop your WeaponMutator prefab under 2H, rename it, give it values:

  • Axe
    • 2H Modifier
      • NatalyaBuff (another WeaponMutator with ModDamage = 5.0f)

(Bolded to show which part is still linked to a prefab.)

There are of course many variations on this style of composition, and what I describe here is standard "fits in a StackOverflow answer" clunky.

If I were implementing this myself, I would probably build this using lists of ScriptableObjects in place of Mutator prefabs, perhaps something like what's described here. But it depends a lot on what kind of UX your designers will be happy with.

Hope this gets you headed in the right direction.

\$\endgroup\$
  • \$\begingroup\$ Thanks for those two documentations though. :) "Decorator" pattern and "Mutator" pattern \$\endgroup\$ – AVI Dec 12 '15 at 7:25
  • \$\begingroup\$ Thanks for this idea. Why are you iterating over mutators in both WeaponBase and WeaponMutator? I assumed only WeaponBase needed to iterate, leaving WeaponMutator to just expose the various modifier-values. \$\endgroup\$ – Jon Lauridsen Aug 14 '16 at 22:19
  • 1
    \$\begingroup\$ Good catch! When I wrote this I apparently forgot that GetComponentsInChildren recurses for you. I've edited the example code to reflect this. I think in a more robust solution, I would instead have each layer get only its direct children, to allow for an ordered series of modifications. Since ModDamage here is only adding, never multiplying, order of operations doesn't matter. However, not allowing multiplicative tweaks for an RPG seems very strange. \$\endgroup\$ – Chris Mills-Price Aug 15 '16 at 17:24
2
\$\begingroup\$

(For example) Have a script named PrefabDatabase. Define an Enum called PrefabType that covers all your prefabs. Then define a Dictionary< PrefabType, GameObject >. Assign all your prefabs to this dictionary.

There is an issue here though. You can't initialize dictionaries in inspector; here comes the solution:

 [System.Serializable]
 public struct EnumPrefabPair 
 {
      public PrefabType type;     //For "TL;DR"ers, this is an enum that has a value for all prefabs...
      public GameObject prefab;   //...and this will be the prefab referance.
  }

  public EnumPrefabPair[] typesAndReferances;

Initialize this array in inspector and then in your Awake(), run a foreach loop on it to pass values to your dictionary.

Then you can simply referance your prefab by enum value.

\$\endgroup\$
0
\$\begingroup\$

What you can do is just replace the current prefab with a new prefab for that moment.for an example

var prefab1 : GameObject;
var prefab2 : GameObject;

// Prefab to use
private var prefab : GameObject;

function Start ()
{
   prefab = prefab1;
}

function Update ()
{
   // Use the first prefab when pressing 1 and the second prefab when pressing 2..
   if ( Input.GetKeyDown ("1") )
      prefab = prefab1;
   if ( Input.GetKeyDown ("2") )
      prefab = prefab2;


   if ( /* Something happens ?? */ )
      Instantiate (prefab, transform.position, Quaternion.identity);
}

Referred from : link

\$\endgroup\$
  • \$\begingroup\$ No we can't. We'll have at least a 100 of item prefabs. If we start to create additional prefabs for every "derivative prefab" this will become extremely tedious. We don't want prefabs like AwesomeBow, AwesomeBowWithABitMoreDamage, AwesomeBowWithABitLessDurability, we only want to have AwesomeBow prefab and a mechanism that would allow to introduce small parameter changes on the editor side and transfer those changes to realtime. Sorry but you are misreading the problem. \$\endgroup\$ – mt_ Dec 8 '15 at 13:27
  • \$\begingroup\$ say, 100 of axes, granades, guns, etc. And whenever a game designer drops one of these in a prefab field of a component, they want to be able to tweak it's parameters if needed. For example, they drop one of the 100 items, say SuperGranadeLauncher and they want that it's parameters, "reload speed" if dropped onto CharacterX be 2.0f, but if drooped onto CharacterY be 3.0f, oh and also if on CharacterY the damage should be +2. But they don't want to have additional prefabs like SuperGranadaLauncherWithFasterReloadForCharX, etc. \$\endgroup\$ – mt_ Dec 8 '15 at 13:38
  • \$\begingroup\$ can't imagine any other solution rather than changing animation(using animator controller) and this solution though. :/ \$\endgroup\$ – AVI Dec 8 '15 at 13:43
  • \$\begingroup\$ Isn't there any possibility use animator controller?This is very useless though.Because Animator controller is the easiest way,next is this. \$\endgroup\$ – AVI Dec 8 '15 at 13:45
  • \$\begingroup\$ Chris Mills provided the right answer \$\endgroup\$ – AVI Dec 12 '15 at 7:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.