Search Unity

Question Instantiate Object - Best Practice / Advice request

Discussion in 'Visual Scripting' started by Carcophan, Dec 29, 2021.

  1. Carcophan

    Carcophan

    Joined:
    May 10, 2021
    Posts:
    79
    Greetings all.

    My entire set up so far has focused on using a blank game object 'Player', that controlled 'Player01' movement / etc (Mesh, box collider, script machines, rigid body, ...)
    upload_2021-12-29_16-11-5.png

    I had never instantiated anything before, and going through the steps to turn the 'Player01' (or 'Player') object into a Prefab, is causing questions on how to properly do things.

    Changing the Object from itself, to the blue prefab, and then removing the unpacked object from the Hierarchy, like this
    upload_2021-12-29_16-8-19.png


    When I delete the instantiated object through the script (delete 'an' instantiated object), the Player game object then goes to 'blank' like this. Which also causes the On Click stuff associated to that object (a button click here, that used the object as a reference), to also be deleted.
    upload_2021-12-29_16-10-35.png upload_2021-12-29_16-12-41.png



    This obviously causes all types of issues.


    How can I 'convert' my incorrectly designed "one player game", into a proper 2-player game (using PUN).

    Everything uses instantiated prefabs of objects. I am trying to convert my stuff here to instead use instantiated prefabs for players.


    Is there any good guidance on this, that you can point me towards?
     
  2. Carcophan

    Carcophan

    Joined:
    May 10, 2021
    Posts:
    79
    (There is a 5 image limit per post, so made a second post to show this)

    Per the video, at about the 11:30 mark:


    upload_2021-12-29_16-18-44.png

    Player01 can't be in the hierarchy, since it is going to be an instantiated object.

    Deleting Player01 prefab causes all those other 'dependencies' that pointed to it, to then break, because they are missing stuff.
     
    Last edited: Dec 29, 2021
  3. PanthenEye

    PanthenEye

    Joined:
    Oct 14, 2013
    Posts:
    2,063
    Correct me if I'm wrong, but it seems a bunch of logic depends on the non-prefabbed version of Player GameObject to exist in Hierarchy, and if it's removed (or prefabbed and removed), those direct references are lost since it doesn't exist in the hierarchy anymore.

    So the solution is to Set these references and dependencies in code when Player object gets instantiated because then it does exist.

    There are no built in refactoring tools for Unity VS so you have to do the "conversion" manually. And there are many ways to approach this.

    Player could Set itself as a Scene or Application GameObject variable in On Enable or Start which other graphs can then reference.

    Alternatively, the logic that instantiates the player object can also set that player as a variable using Instantiate nodes output, which is the GameObject you've just instantiated.

    Then you replace all missing Player references with this new variable.

    The On Click one is tricky, though. It shouldn't reference Player object directly if that Player object doesn't exist in On Click Object's Hierarchy at all times. You could replace it with a graph which has the graph version of the On Click event. That can also reference the Player scene variable.
     
    Last edited: Dec 30, 2021
  4. Carcophan

    Carcophan

    Joined:
    May 10, 2021
    Posts:
    79
    That is great feedback, thank you. I'm trying to digest and understand your comments and implement, but it makes me want to ask:

    Is 'instantiation' even the right approach for me? Are every object of a player in a game like 'Bomberman' instantiated upon the loading of a scene? Are the players character objects, because they are individual to each person / persons game, not prefabs within my game?

    In the tank demo, and others, they describe how instantiation works for their scenario - but is it required for games like these? Necessary? Better? All bullets being shot are typically the same, but your character and my character are different. Those tanks were clones of each other, with real time networked 'instantiated' control of the object. What if each tank was unique (skin, design, qualities, abilities) - how can they then be 'clones' or a prefab.

    Can you / should you instantiate SOME things (individual bullets being shot, dozens of the same destructible object, etc) - but not instantiate all objects (like the primary character models for Players 1-4)


    Take the simple 2 or 4 player game, like Bomberman. I am currently trying to use something like PUN to play over the internet (not local). Each character essentially starts in a corner of a square chess-board shaped map, and they take turns moving around and doing stuff.


    I'm having a hard time understanding the best way to manage turn control, and player movement and UI controls, based off of whose turn it is.

    I am picturing 'taking my turn' and de-activating all of my user input and UI controls until the end of player 2's turn, via an On Update or trigger or something. Each person takes their set of actions, and the 'control' of the on screen character and camera objects transitions back and forth between Character 1 and character 2, based on 'whose turn it is'. On player 1's turn, player 1 can control player 1's character on screen - then swap to player 2 who can control the player 2 character.

    But how does Player 2's character, their information, design, etc, get sent to my games screen? How do I know if your character should load into my scene as being purple or blue, tall or short, wizard or warrior? I'm currently trying to learn how to instantiate and play through something like PUN, but I'm having to do so locally, with game conditions that I already know ahead of time (which prefab to load into a scene) - not taking into account 'your player creation', how to get that, control that. Idk. I'm talking in circles and confusing myself now.

    Does any of that make sense?
     
  5. PanthenEye

    PanthenEye

    Joined:
    Oct 14, 2013
    Posts:
    2,063
    Generally, instantiation is the way to go for things like this. You set up the system once and then reuse it to do a thing N times. No idea how Bomberman does it, but typically you'd expect instantiation or a similar solution for a game like that when it's unknown how many players will be active.

    I'm not sure what you mean here. Prefabs are still GameObjects. And when you instantiate a prefab, it's not a prefab anymore, just a regular GameObject in Hierarchy that you can freely change via code. Prefabs also have per instance overrides once they're dropped in Hierarchy, so they can be differently configured in the scene by hand (and then saved as prefab variant assets if you need to).

    Since Bomberman characters typically do the same or very similar things, it would be a single character Prefab that gets its visuals swapped out and player assigned upon instantiation. ie prefab is a base template for shared functionality in this scenario so you don't have to set things four or more times for each player by hand, which is error prone.

    It's not "required" but it is objectively "better" to instantiate things in these scenarios. The alternative is to hard-code and set up each player's character by hand. But then, if project requirements change - you need less or more characters, or the character functionality changes - you now have to revisit each character manually, then do the same changes for each character. This is both time-consuming and error prone.

    A system that instantiates a player has to be set up once, then it can be reused any amount of times. And if the system has to change or needs additions, you only have to make changes in a single place. Same with debugging, if something doesn't work, you know where to look immedietly.

    Even if each character is "unique", how unique are they really? Don't they still perform the same actions as other characters?

    You can do anything that makes sense to you and works for you. Especially as a solo dev. But this wouldn't be considered a good practice due to manual work involved in setting up these characters by hand. It's error prone, hard to debug, hard to change or add to it and probably involves a lot of spaghetti code that links these characters directly to UI and other game systems. There's also the extra memory load they incur even if disabled and not directly taxing the CPU.

    Visual Scripting has a special State Machine graph which would fit the use case. The state machine has On Enter State and On Exit State events that you could use for enabling or disabling UI, etc.

    That's more a question of game architecture. And Visual Scripting alone isn't really good for that. In C# you could define the character's attributes (everything that's unique about a character) in a Scriptable Object which is an asset that can be created via right click context menu and manually filled in.

    Code (CSharp):
    1. [CreateAssetMenu(fileName = "New Character")]
    2. public class MyCharacter: ScriptableObject
    3. {
    4.     public string ID;
    5.     public string Name;
    6.     public int Strength;
    7.     public int Agility;
    8.     public GameObject Visuals;
    9. }
    A character could be a single prefab, that has a character loader script on it that takes the Scriptable Object data and loads it in. There's no direct alternative to Scriptable Objects in Visual Scripting. Albeit Visual Scripting can work with C# Scriptable Objects very well. And it's pretty easy to write and create them even if you don't know C# well.

    Player 2 would get assgined a scriptable object, the system then instantiates a generic prefab template and loads the unique data on it from the scriptable object. Scriptable Objects are defined at design time and are known objects ahead of time which fits your use case.

    That's one possible solution to the problem. It can be solved in many ways.

    You could also have unique prefabs for each unique character or prefab variants that share some functionality. Then create an AoTDictionary variable with string IDs as keys and Character prefabs as Values. Then assign each player a string ID and use Get Dictionary Item node to retrieve the Prefab via it's Dictionary key.
     
    Last edited: Jan 7, 2022
    Carcophan likes this.
  6. Carcophan

    Carcophan

    Joined:
    May 10, 2021
    Posts:
    79
    This is incredibly helpful and amazing. Thank you so very much for the energy and focus that you put into this feedback, it is genuinely appreciated.
     
  7. Trindenberg

    Trindenberg

    Joined:
    Dec 3, 2017
    Posts:
    396
    SurreyMuso likes this.