Search Unity

Discussion How do you handle (structure scripts) animation, audio, etc.

Discussion in 'Scripting' started by stroibot, Nov 9, 2022.

  1. stroibot

    stroibot

    Joined:
    Feb 15, 2017
    Posts:
    91
    Hi,

    I have a question regarding how do you structure your code to handle animations, audio, etc.?

    E.g., let's say I create a game where we have a Cube that we can Tap and Pop. When we are tapping it and popping we want to hear audio and see animation, obviously. How you will handle this?
    Do you just have on massive Cube class that contains everything related to animation, audio, tapping and popping?
    Do you create different monobehaviour classes that go like Cube, CubeAudioComponent, CubeAnimationComponent, CubeTapComponent and CubePopCompoent receiving weird thing where Tap relies on Cube, Pop relies on Cube and Tap, Audio relies on Tap, etc.?
    Or maybe some other way around? It's really hard to find like good structured approach for this kind of issue.

    How DO you handle this?

    P.S. Please don't give me "you'll figure it out as you go what best fits you, go experiment", come on, design patterns don't exist just because, there's always a way
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    I really don't know what to tell you. I've done it pretty much differently every time.

    And I will continue to do it differently depending on the details of what I need each time.

    The details of your game are always important to how the pain points manifest.

    Remember, this is SOFT-ware, which means it is SOFT, which means you can change course as you go.

    https://en.wikipedia.org/wiki/Code_refactoring
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    Well I don't know about others... but for my team this would be done with our event driven T&I system.

    This system uses something we call SPEvent which is very similar to UnityEvent, but we designed it before UnityEvent came out and it has a few extra bells and whistles to work in our workflow.

    So, right now, I just went into a new project with our framework imported and created exactly what you said:
    upload_2022-11-9_18-49-13.png

    I just created a default Cube by clicking GameObject->3D Object->Cube

    I then attached an Animator and created a simple animation of it doing a scale effect. Then in the Animator I set the default state to no animation, and had another state named 'TestAnim' with this animation in it (this is a stupid simple example so I didn't get very complicated with the Animator):
    upload_2022-11-9_18-51-21.png

    The TestAnim returns back to the empty Default state on complete... this is inconsequential though as you'll see later.

    Also I attach a premade script that we have called "T_OnCursorClick", so in our T&I system we have a lot of scripts prefixed with either a T or an I. They all do standard common things in the game like play sound effects or listen for interactions. In the case of this script it listens for a cursor to click (this also works with touch). In our system T's are "triggers", they signal events like being clicked, or colliders colliding, or on game start. There's lots of them:
    upload_2022-11-9_19-7-13.png

    In this specific example T_OnCursorClick ties into our IInputManagerService OR the Unity EventSystem as can be seen here:
    https://github.com/lordofduct/space...Runtime/src/SPInput/Events/t_OnCursorClick.cs

    This means I'd have to make sure this is setup on start of the game. If I wanted to just to just tie into the OnMouseDown/OnMouseUp messages from more legacy versions of Unity I'd use PT_OnMouseClick. The PT means this really should only be used for prototyping as most of our fully fledged games will have a more robust input manager.
    https://github.com/lordofduct/space...Runtime/src/SPInput/Events/pt_OnMouseClick.cs

    OK...

    So now that I've listened for the click, you'll notice that its trigger target is the child gameobject e.OnTap. This e.XXX naming convention is our common naming convention. It's the name of GameObjects that exist solely to perform the actions of an event.

    And on it I've attached a few components:
    upload_2022-11-9_19-0-54.png

    I have an AudioSource to play the audio.

    I have a component called i_PlaySoundEffect which plays some audio on that AudioSource.
    https://github.com/lordofduct/space...ggers/Runtime/src/Events/i_PlaySoundEffect.cs

    And I have a i_PlayAnimation_Mecanim:
    https://github.com/lordofduct/space...src/Mecanim/Events/i_PlayAnimation_Mecanim.cs

    (Note - it's got mecanim on the end because before mecanim released we already had one called i_PlayAnimation that uses the legacy animation system)

    And well, I configure them accordingly.

    Lastly in the i_PlayAnimation_Mecanim there's a followup event called "OnStateExit", this will fire when the animation state it went to exits (it won't fire if it loops forever). And I tell it to Destroy our Cube on end thus finishing our entire interaction.

    This all results in:
    CubeClick.gif

    I'll say this... it took me wayyyy more time to write this post than it did for me to setup this example.

    But this is also because we've spent a lot of time designing our toolset over the past several years. Just sort of adding things as we saw fit.

    A point of caution... I'd advise not using our toolset. I do have it on github, but it's got a steep learning curve, and is seldom in a completely stable condition. I only have it on github to offer up conversation/examples for posts like these.
     
    Last edited: Nov 10, 2022
    Strafe_m and Ryiah like this.
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,532
    With that post now complete.

    Some might wonder why in the heck I even do it this way? Why not just write a simple adhoc script that does all of this in the moment? This seems more over-engineered than a simple script.

    And... it is. It very much definitely is an over-engineered way of doing it!

    ...

    But the reason is that I'm on a 2-man team. Me and my partner who is an artist and couldn't write code to save his life.

    But this, this he can do.

    Hell, he's sat down with this toolset and made little game jam games without even having to call me up. One year he even made a "Crossy-Road" clone he called "Charisy-Road" as a gift to his girlfriend for their anniversary. It basically was Crossy-Road but themed all about his girlfriend in Japan (they lived in Japan at the time). He didn't have to ask me to write a single line of code and instead glued the entire thing together using these building blocks like they were lego.

    I built this for fun YEARS ago. Honestly it was early in my programming career where I worked in the Enterprise world and I'd just write code for Unity on the weekends. My partner and I didn't get to work in tandem all that much and instead needed a way to develop generalized tools for my partner to then go off and tinker with while I was at work.

    Now that it's all built out years later. Now I can just focus on the core mechanics of a game while he throws together the polish/art stuff.

    For example we just wrapped up our last game and I'm now working on a prototype for our next arcade style shooting game. On my side I have to hammer out the movement mechanics, multiplayer networking, and procedural generation, which are very complicated. But he needs something to do while I do that. Well... he can create MOBs that can be shot down without interrupting me while I'm heads down getting the core mechanics working. He pulls latest and all of his assets just work in the game with out me having to do anything.
     
    Last edited: Nov 10, 2022
    Ryiah and Kurt-Dekker like this.
  5. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,637