How to reference custom assets from Inspector or Script
Hello, everyone. I'm recently starting to work with Unity and I'm following this tutorial (it's in Spanish but it doesn't hurt to add it). The tutorial shows how to build a 2D Platform and there are assets for 4 players (I'm currently using just 2 of them). In the specific video I've linked, it shows how to change skins from one player to another.
The question is basically about how to do it in a better way. Bellow I will share how it is done in the video and how I did it my own, trying to make it more flexible an dynamic. However, I want to know whether my approach was OK or if there is any other better way to do so.
How it is done in the video
It attaches a PlayerSelect script to the player prefab in which it creates a private enum and three public properties:
private enum PlayerSkins { MaskDude, NinjaFrog };
public PlayerSkins playerSkinSelected;
public RuntimeAnimatorController[] runtimeAnimatorControllers;
public Sprite[] sprites
The public ones are referenced directly from the inspector. The last of them, by dragging and dropping the AnimationTree and the Idle animation from each player, respectively.
The Idle sprites correspond to each player, respectively
And, then, in the void Start() built-in method, it does (actually, it does a switch but I changed it to use Linq):
animator.runtimeAnimatorController = skinRuntimeAnimatorControllers.ToList().First(animator => animator.PlayerSkin == playerSkinSelected).RuntimeAnimatorController;
spriteRenderer.sprite = skinSprites.ToList().First(sprite => sprite.PlayerSkin == playerSkinSelected).Sprite;
It does work as expected but I don't like the idea of having two arrays depending on each other. The elements must be ordered in the same way and you must know in which order they were added.
How I did it
So, in order to remove this disadvantage, I created two new models and a dedicated-enum file: Enum file: PlayerSkins
public enum PlayerSkins
{
MaskDude,
NinjaFrog
}
Model1: SkinSprite
using UnityEngine;
public class SkinSprite
{
public PlayerSkins PlayerSkin { get; set; }
public Sprite Sprite { get; set; }
}
Model2: SkinRuntimeAnimatorController
using UnityEngine;
public class SkinRuntimeAnimatorController
{
public PlayerSkins PlayerSkin { get; set; }
public RuntimeAnimatorController RuntimeAnimatorController { get; set; }
}
And, then, in the PlayerSelect script, I've created two public properties:
public SkinRuntimeAnimatorController[] skinRuntimeAnimatorControllers;
public SkinSprite[] skinSprites;
With this approach, as each model has a PlayerSkins property, I don't have to know the order nor to order both arrays in the same way. However, I'm not finding a way to adding instances to those properties neither from the inspector nor by scripting. In the inspector, as they are custom models (I guess), it doesn't allow me to drag and drop. Also, I don't know how to reference the assets from the script.
The only way of doing so (but it doesn't fully convince me) was to add 4 new properties to my PlayerManager script attached to my PlayerManager GameObject:
using UnityEngine;
public class PlayerManager : MonoBehaviour
{
public RuntimeAnimatorController MaskDudeRuntimeAnimatorController;
public RuntimeAnimatorController NinjaFrogRuntimeAnimatorController;
public Sprite MaskDudeSprite;
public Sprite NinjaFrogSprite;
}
And, from PlayerSelect, add a reference to that manager and initialize the arrays:
private void InitializeComponents()
{
skinRuntimeAnimatorControllers = new List<SkinRuntimeAnimatorController>
{
new SkinRuntimeAnimatorController
{
PlayerSkin = PlayerSkins.MaskDude,
RuntimeAnimatorController = playerManager.MaskDudeRuntimeAnimatorController
},
new SkinRuntimeAnimatorController
{
PlayerSkin = PlayerSkins.NinjaFrog,
RuntimeAnimatorController = playerManager.NinjaFrogRuntimeAnimatorController
}
};
skinSprites = new List<SkinSprite>
{
new SkinSprite
{
PlayerSkin = PlayerSkins.MaskDude,
Sprite = playerManager.MaskDudeSprite
},
new SkinSprite
{
PlayerSkin = PlayerSkins.NinjaFrog,
Sprite = playerManager.NinjaFrogSprite
}
};
}
(actually, I did it with lists but I wasn't able to write the lists in this forum because of minor and major symbols as it considers them as tags)
And, finally, in my PlayerSelect I created a method:
public void ChangeSelectedSkin(PlayerSkins playerSkin)
{
playerSkinSelected = playerSkin;
animator.runtimeAnimatorController = skinRuntimeAnimatorControllers.First(animator => animator.PlayerSkin == playerSkinSelected).RuntimeAnimatorController;
spriteRenderer.sprite = skinSprites.First(sprite => sprite.PlayerSkin == playerSkinSelected).Sprite;
}
which is more dynamic and flexible.
Summarizing
Despite what I'm trying to do does work, I'm sure there's a better way to achieve so. In a short way, I'd like to know if there's some way to reference those assets directly from inspector or from scripting without having to do that handrails between the PlayerManager and the PlayerSelect. I'm aware that I could have created the properties directly in the PlayerSelect. Maybe that's a design decision but the problem will still there.
I do want to remove these extra public properties I had to create:
public RuntimeAnimatorController MaskDudeRuntimeAnimatorController;
public RuntimeAnimatorController NinjaFrogRuntimeAnimatorController;
public Sprite MaskDudeSprite;
public Sprite NinjaFrogSprite;
I know this is a very small project and it's a tutorial but I consider it a very important feature to know because, in more complex scenarios, creating too many properties won't be a good approach.
Thanks for reading it and I hope you can understand what's my concern.
Your answer
Follow this Question
Related Questions
How to add a editing option to variables in a script in Inspector? 0 Answers
I am trying to reference a bool from another script but the only value that it returns is false 0 Answers
How To change a Text Object's Color Randomly using Color 32? 2 Answers