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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Complex object with NetworkBehaviour (object with children having their own logic)

Discussion in 'Multiplayer' started by jathrek, Jan 4, 2016.

  1. jathrek

    jathrek

    Joined:
    Jul 16, 2015
    Posts:
    36
    Hello,

    I was wondering how to correctly (if a correct way already exists ;-p) implement a NetworkIdentity game object that would have children game object having their "own" logic.

    By example, a ship that would have cannons; the ship is the one with the NetworkBehaviour, but the cannons themselves can follow a given target (and not the same one for all the cannons) and fire independently from each other.

    So I'll have to handle the logic of all these elements at the level of the ship itself;
    - The ship can move
    - A cannon can have a target set (selection of the target propagated by the server)
    - A cannon can fire as soon as it's ready (and afterwards, it has to wait for a cooldown to elapse before firing again) (fire handled by the server)
    - A cannon should visually follow its target (ont the client side)

    The ship control part is quite easy, as the NetworkBehaviour is at the level of that object, the implementation is pretty straightforward.

    For the cannons part, my latest idea was to use a SyncListStruct (at the level of the ship) where each struct would be a "reference" to a specific cannon, indicating;
    • What's the prefab of the cannon (useful if I want to allow for upgrade of a cannon),
    • What's the position of the cannon on the ship (some code, by example left-side-second-line),
    • A reference to the actual game object representing this cannon,
    • What's the current target for the cannon (if any),
    • What's the current cooldown for the cannon (used server-side only, as it's the server that will handling the cooldown and the actual firing).
    So the client, when an element of the list gets dirtied, can create - if necessary - the cannon at its level (so the graphics of the cannon appear) and/or make it follow its current target.

    An element would be dirtied only when the prefab of the cannon changes (creation or upgrade of the cannon) or when the target of a cannon is changed (the server decides what the target is, either on its own or through a command that will be called by the client when a click on a specific enemy occurs). So such updates should be quite rare (and shouldn't happen 50 times per second ;-p).

    Would anyone happen to have some best practices to share on this topic?

    I know there're some "hacks" that would allow me to create each of these cannons with its own NetworkBehaviour and change it's parent to the ship afterwards, but I think it's preferable to avoid this. Please correct me if I'm wrong.
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
  3. jathrek

    jathrek

    Joined:
    Jul 16, 2015
    Posts:
    36
    Hello,

    It does seem quite related.

    But the example in that post is quite simple (one player, one gun) and I was wondering if anyone had pattern-like tips for more complex situations (one player, multiple independent guns that can be replaced in-game). I suppose it's not only about guns, but any other kind of children that would require some communication to go through the NetworkBehaviour root.

    I implemented my idea based on SyncListStruct and it seems to be working, but it is quite a lot longer than your example and thus probably more prone to error and not as easy to understand...

    To be more precise;
    • I create two struct, a "light" one that is used for sync containing only the type of weapon (identifier-based), the location of that weapon on the root object (identifier-based as well, with some lookup script to find out the related game object at the client level) and the target of that weapon, and another "heavy" one with contains all the references for the current scene (so that actual GameObject representing the gun, which could not be present in the sync-struct as it does not have a NetworkIdentity) and other "quick-access" elements.
    • When the root object is instanciated, the server set up the sync struct list with the default loadout for that object and populates the "heavy" struct list with its local view of all the guns
    • When the root object is started on the client, the sync struct list is parsed and the client proceed with the instanciation of anything relavant for a client (such as the skin used to visually represent the gun, necessary for the client but not so much for the server) and populates the "heavy" struct list with its own local view.
    • I'll later add a callback to monitor for changes on the struct list, such as the type of a gun being changed (in case of creation/upgrade) or if the target of one of the gun is changed.
    Well, at least it's working for now. ;-)