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

How to optimize a Switch statement into something better for a Collectibles script?

Discussion in 'Scripting' started by ciprianbiris, Feb 26, 2020.

  1. ciprianbiris

    ciprianbiris

    Joined:
    Oct 11, 2013
    Posts:
    32
    Hi,

    I have a coder's block:)
    I have the following script attached to all of my collectables:
    I would like to find a way in which instead of the switch statement, I could use functions - the problem is that I don't have a way to say, if you are a Bomb, use the bomb function only.
    I have looked into delegates and they might do the job but it seems overkill for this.
    Is there any way I could either store functions for each case in a function array and call by index?
    How does Unity call functions assigned through the editor? (like OnClick?) Could I use something similar?

    ps. The switch should not be evaluated OnTriggerEnter because we already know which case we're going for..

    Regards,

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. public enum ePowerUp { None, Bomb, Bullet, BulletArmored, Life, Seamine, Key, Shield1, Shield2, Shield3, Shield4, Speed1, Speed2, Speed3, Speed4, SuperSpeed1, SuperSpeed2, SuperSpeed3, SuperSpeed4, Steel }
    5. public class Collectibles : MonoBehaviour
    6. {
    7.     public int Amount;
    8.     public ePowerUp RewardType;
    9.  
    10.     private void OnTriggerEnter(Collider collider)
    11.     {
    12.         if (collider.gameObject.CompareTag("Player"))
    13.         {
    14.             switch (RewardType)
    15.             {
    16.                 case ePowerUp.Bomb:
    17.                     GDS.Bomb += Amount;
    18.                     AdvancedUI.AUI.ManageProjUI(13, GDS.Bomb, 0);
    19.                     break;
    20.                 case ePowerUp.Bullet:
    21.                     GDS.Bullet += Amount;
    22.                     AdvancedUI.AUI.ManageProjUI(15, GDS.Bullet, 1);
    23.                     break;
    24.                 case ePowerUp.BulletArmored:
    25.                     GDS.BulletArmored += Amount;
    26.                     AdvancedUI.AUI.ManageProjUI(16, GDS.BulletArmored, 1);
    27.                     break;
    28.                 case ePowerUp.Life:
    29.                     GDS.Lives += Amount;
    30.                     AdvancedUI.AUI.iPortraitMain.iPortraitCanvas.iTopBar.UpdateLivesTxt(GDS.Lives);
    31.                     break;
    32.                 case ePowerUp.Seamine:
    33.                     GDS.Seamine += Amount;
    34.                     AdvancedUI.AUI.ManageProjUI(14, GDS.Seamine, 0);
    35.                     break;
    36.                 case ePowerUp.Key:
    37.                     GDS.Keys += Amount;
    38.                     AdvancedUI.AUI.iPortraitMain.iPortraitCanvas.iTopBar.UpdateKeysTxt(GDS.Keys);
    39.                     break;
    40.                 case ePowerUp.Steel:
    41.                     GDS.Steel += Amount;
    42.                     AdvancedUI.AUI.iPortraitMain.iPortraitCanvas.iTopBar.UpdateSteelTxt(GDS.Steel);
    43.                     break;
    44.                 case ePowerUp.Speed1:
    45.                     GDS.Speed1 += Amount;
    46.                     AdvancedUI.AUI.ManageItemUI(5, GDS.Speed1);
    47.                     break;
    48.                 case ePowerUp.Speed2:
    49.                     GDS.Speed2 += Amount;
    50.                     AdvancedUI.AUI.ManageItemUI(6, GDS.Speed2);
    51.                     break;
    52.                 case ePowerUp.Speed3:
    53.                     GDS.Speed3 += Amount;
    54.                     AdvancedUI.AUI.ManageItemUI(7, GDS.Speed3);
    55.                     break;
    56.                 case ePowerUp.Speed4:
    57.                     GDS.Speed4 += Amount;
    58.                     AdvancedUI.AUI.ManageItemUI(8, GDS.Speed4);
    59.                     break;
    60.                 case ePowerUp.SuperSpeed1:
    61.                     GDS.SuperSpeed1 += Amount;
    62.                     AdvancedUI.AUI.ManageItemUI(9, GDS.SuperSpeed1);
    63.                     break;
    64.                 case ePowerUp.SuperSpeed2:
    65.                     GDS.SuperSpeed2 += Amount;
    66.                     AdvancedUI.AUI.ManageItemUI(10, GDS.SuperSpeed2);
    67.                     break;
    68.                 case ePowerUp.SuperSpeed3:
    69.                     GDS.SuperSpeed3 += Amount;
    70.                     AdvancedUI.AUI.ManageItemUI(11, GDS.SuperSpeed3);
    71.                     break;
    72.                 case ePowerUp.SuperSpeed4:
    73.                     GDS.SuperSpeed4 += Amount;
    74.                     AdvancedUI.AUI.ManageItemUI(12, GDS.SuperSpeed4);
    75.                     break;
    76.                 case ePowerUp.Shield1:
    77.                     GDS.Shield1 += Amount;
    78.                     AdvancedUI.AUI.ManageItemUI(1, GDS.Shield1);
    79.                     break;
    80.                 case ePowerUp.Shield2:
    81.                     GDS.Shield2 += Amount;
    82.                     AdvancedUI.AUI.ManageItemUI(2, GDS.Shield2);
    83.                     break;
    84.                 case ePowerUp.Shield3:
    85.                     GDS.Shield3 += Amount;
    86.                     AdvancedUI.AUI.ManageItemUI(3, GDS.Shield3);
    87.                     break;
    88.                 case ePowerUp.Shield4:
    89.                     GDS.Shield4 += Amount;
    90.                     AdvancedUI.AUI.ManageItemUI(4, GDS.Shield4);
    91.                     break;
    92.                 default:
    93.                     break;
    94.             }
    95.  
    96.             PlayAudioS(AudioReferences.AR.RewardAudio);
    97.             Destroy(gameObject);
    98.         }
    99.     }
    100.  
    101.     private void PlayAudioS(AudioClip AudioC)
    102.     {
    103.         if (GDS.Sfx)
    104.         {
    105.             float dist = Mathf.Pow(CameraController.CC.PlayerPos.x - transform.position.x, 2.0f) + Mathf.Pow(CameraController.CC.PlayerPos.z - transform.position.z, 2.0f);
    106.             float volume = 1.0f - Mathf.Pow(dist, 0.5f) / 15.0f;
    107.  
    108.             if (volume < 0.0f)
    109.                 volume = 0.0f;
    110.  
    111.             volume = Mathf.Pow(10.0f, (volume * GDS.VolumeLin) * 4.0f - 4.0f);
    112.  
    113.             AudioSource.PlayClipAtPoint(AudioC, CameraController.CC.transform.position + Vector3.down, volume);
    114.         }
    115.     }
    116. }
     
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
  3. ciprianbiris

    ciprianbiris

    Joined:
    Oct 11, 2013
    Posts:
    32
    Thank you very much, this is perfect! While I used dictionaries before, never used the System.Action, which seems it will do wonders for me. Thanks again!

    Regards,
     
    orionsyndrome likes this.
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    those are just blank (generic) system-defined delegates. there is also Func (for when you need an action that can also return a value).

    you could make a custom system of your own, by declaring a delegate, but this is arguably a simpler solution.
     
    Last edited: Feb 26, 2020
    ciprianbiris likes this.
  5. ServantOMallard

    ServantOMallard

    Joined:
    Aug 17, 2018
    Posts:
    14
    An alternative approach to the above I use often is to make use of scriptable objects. I'd have a base class such as:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public abstract class CollectibleTypeBase : ScriptableObject
    4. {
    5.     public abstract void Collect(int amount);
    6. }
    You'd then implement your logic in separate concrete CollectibleType classes e.g for a bomb:

    Code (CSharp):
    1. [CreateAssetMenu(menuName = "Collectible Types/Bomb")]
    2. public class BombCollectibleType : CollectibleTypeBase
    3. {
    4.     public override void Collect(int amount)
    5.     {
    6.         GDS.Bomb += amount;
    7.         AdvancedUI.AUI.ManageProjUI(13, GDS.Bomb, 0);
    8.     }
    9. }
    This lets you right click in the project view to create a new BombCollectibleType asset. You'd then just need to alter your Collectibles monobehaviour to hold a reference to a CollectibleTypeBase then call Collect(Amount) in your OnTriggerEnter method.

    This method may be a bit overkill for your needs but I find it makes things easier to extend in future.

    Cheers,

    Nathan
     
    ciprianbiris likes this.