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

How to start a particle system or prefab from a keyboard button?

Discussion in 'Scripting' started by AnatIv, Jun 23, 2020.

  1. AnatIv

    AnatIv

    Joined:
    Jun 3, 2020
    Posts:
    3
    Hello. I have a scene with a character. The character has several animations that are switched by the keyboard buttons, and there are several particle systems for each animation. How can I make a certain particle system start with the desired animation after pressing a button on the keyboard.

    Thank.
     
  2. Nstdspace

    Nstdspace

    Joined:
    Feb 6, 2020
    Posts:
    26
    For such problems, you should consider studying the unity scripting documentation, which you can find here.
    Scrolling through the documentation of the class ParticleSystem, we find the table of available "public methods", which typically represent actions in object-oriented programming which are intended to be triggered from external sources.
    Looking at this table one should find the following entry:

    upload_2020-6-23_14-4-44.png

    Seems like this is exactly the Method we were searching for!

    Now, the interesting part is how we can or how we should trigger this action from our code. This totally depends on the structure on your project, and you exactly want to achieve which does not get clear from your description, but I take a guess. Assuming you are using the new Unity Input System, I assume you have set up your Controls correctly, and there exists at least one action map with some keyboard binding which should look like this:

    upload_2020-6-23_14-13-13.png

    If this assumption is correct, you have also assigned actions to your Action in a script to trigger animation changes.
    A part of your code should then look similar to the following:

    Code (CSharp):
    1. private TestControls controls;
    2.  
    3. void Start()
    4. {
    5.     TestControls controls = new TestControls();
    6.     controls.TestActionMap.Enable();
    7.     controls.TestActionMap.TestAction.performed += callbackContext => PlayAnimation();
    8. }
    Where PlayAnimation() is capable of somehow retrieving the correct animation and run it.
    We will follow this path and add another Action to our TestAction in the Start method of our Script:

    Code (CSharp):
    1. controls.TestActionMap.TestAction.performed += callbackContext => PlayParticleSystem();
    The question now is how we get the references to our particle systems, how many of those actually are required and in which relation they are with the animations. I can only guess here again.
    Assuming you have an Enum EAnimationType representing the type of the animation, and you want to play several particle systems which each animation, I would consider holding a Dictionary which maps a given animation type to a list of Particle Systems:

    Code (CSharp):
    1. private Dictionary<EAnimationType, List<ParticleSystem>>    animationTypeToParticleSystems;
    Now, this is clean in terms of OOP but not so nice in combination with unitys very limited serialization api. Because of that, we cannot simply edit such a dictionary in the inspector. We have multiple choices here.
    Either we implement a custom serialization system, or we have to induce simpler "helper-structures" for inspector-support which induces a lot kind of ugly workarounds. If you have a very limited number of animation types, we could consider creating a separate list for each one - we could then edit this lists from the inspector. For example:

    Code (CSharp):
    1. [SerializeField] private List<ParticleSystem> particleSystemsAnimationX;
    2. [SerializeField] private List<ParticleSystem> particleSystemsAnimationY;
    3. [SerializeField] private List<ParticleSystem> particleSystemsAnimationZ;
    4.  
    As I seed, this is very ugly, and we also have to fill the dictionary manually afterward:

    Code (CSharp):
    1. animationTypeToParticleSystems.Add(EAnimationType.AnimationX, particleSystemsAnimationX);
    2. animationTypeToParticleSystems.Add(EAnimationType.AnimationY, particleSystemsAnimationY);
    3. animationTypeToParticleSystems.Add(EAnimationType.AnimationZ, particleSystemsAnimationZ);
    4.  
    A cleaner way to do this would be to create a custom scriptable object which holds the given values. We could then enforce the dictionary-like structure from in the Validate method, which blows up the scope of this answer.
    Let us now assume that we have the dictionary pointing an animation type to the list of particle systems.
    We could now implement the method assigned to the TestAction as follows:

    Code (CSharp):
    1. private void PlayParticleSystem()
    2. {
    3.     EAnimationType type = GetCurrentAnimationType();
    4.     List<ParticleSystem> particleSystems = animationTypeToParticleSystems[type];
    5.     foreach (ParticleSystem system in particleSystems)
    6.     {
    7.         system.Play();
    8.     }
    9. }
    Maybe this helps you with your problem. Also, I could try to give you more helpful advice if you provide more concrete information about your setup, level of knowledge, actual problem, what you have tried and what exactly did not work, and what exactly you want to achieve.
     
    AnatIv likes this.
  3. AnatIv

    AnatIv

    Joined:
    Jun 3, 2020
    Posts:
    3
    Thank you so much for the extensive response. I will try to solve the problem given your advice. If I have more questions, I will definitely ask for advice.
    Thanks again.