Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Looking for design ideas/feedback related to modifying the properties of prefabs

Discussion in 'Scripting' started by Zodd, Jun 2, 2022.

  1. Zodd

    Zodd

    Joined:
    Mar 28, 2013
    Posts:
    31
    Hello!

    To give you a simple explanation of what I've done and where I am going:

    I've created spells in a game. Each spell is a prefab with the same Spell script attached to it. By adjusting variables on that script, I create unique behavior for the spell. These prefabs are assigned to skill1, skill2, etc GameObject variables on the PlayerController script.

    The player presses buttons to cast the spells, which basically just instantiates the spell GameObject. Once instantiated the Spell automatically handles the behavior of the spell.

    Now let's say I want to allow the player to increase the damage of the spell, projectile speed, or change other properties, over the course of a single run. Modifying the spell prefabs assigned on the PlayerController script seems to modify the actual prefab, which isn't ideal unless I want to save the state of it and reset the state of it every time the player ends and starts a new run etc.

    I am curious what best practices there are for designing such a system. If anyone has any good resources, I'd love to read through them.

    One idea I read about was to spawn all the spell GameObjects off screen and modify those, and then just clone them. To do that though, I would need to inhibit certain behaviors in the off screen versions and then remove the inhibitions on the clones, which is possible but seemed kind of sloppy.

    Another idea I had was to decouple the spell data from the actual spell projectile as much as possible. I could make each spell request all modifiable values from a separate GameObject, where I track them all for each run, the moment it spawns. This would require a bit of code refactoring but seems like a decent approach.


    I am just curious to what other approaches people have used or can think of. Especially interested in tried and true coding patterns for these types of systems.

    Thanks!
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    It sounds to me like you need to learn about ScriptableObjects!

     
    Zodd likes this.
  3. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    185
    If you decide to pursue this approach, you could instantiate the spell GOs, then in the same frame de-activate them and modify them as needed. Then those clones would be your instantiation source objects for future spells.

    But if I understand your description correctly, it sounds to me like you might be better off storing the "spell modifier" values separately from the spell prefabs. Then, each time the player casts a spell, you would instantiate it and apply the current modifiers to that instance's values.

    e.g. something like
    Code (CSharp):
    1. public SpellScript CreateSpell(Vector3 position, Quaternion dir)
    2. {
    3.     var go = Instantiate(m_spellPrefab, position, dir);
    4.     var spell = go.GetComponent(SpellScript);
    5.     spell.damage *= Player.spellDamageMult;
    6.     spell.speed *= Player.spellSpeedMult;
    7.     etc...
    8.    return spell;
    9. }
    -Scott
     
    Zodd likes this.
  4. PanicEnsues

    PanicEnsues

    Joined:
    Jul 17, 2014
    Posts:
    185
    Forgot to add: I've used both of those approaches, and they both work. I find the latter method much cleaner and preferable if all you need to modify are script values.

    But if you need to make more significant changes to the prefab (transforms, collisions, particles, etc.), then the former approach will do the job.
     
    Zodd likes this.
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,849
    I would also go with what Kurt says and use scriptable objects. Definitely no reason to instantiate game objects just to gleam data from them, when scriptable objects exist for that exact purpose.

    For situations where you want to modify spell data - because changing the data on the SO will be reflected upon anything else that references it - you can encapsulate the spell data in a plain class, make copies of that and edit that data. Or make a wrapper class for the SO which acts as an intermediary between outside sources and the SO's data.
     
    Zodd likes this.
  6. Hikiko66

    Hikiko66

    Joined:
    May 5, 2013
    Posts:
    1,302
    You can Create an Instance of an SO and modify that without changing the SO

    If you want to be able to save and load then plain classes are really easy though
     
    Zodd likes this.