Reputation: 79
Let me first explain the scenario of what I'm trying to do. I'm trying to create a VN like game where the characters change their image depending on the Time of the day. So for example, at daytime between 8:00AM to 11:00AM, The npc character named Benjamin would be standing by the pond in the scene and after 11:00AM he would sit by the campfire in the scene. This means that every npc character has many different sprites/images but only one of them should be activated depending on time of day.
I want to follow best practices when it comes to coding and structuring how my scripts work. So I don't want something that works but is done in a messy way and I feel like it could be improved. So this is how I did it:
public class Benjamin : MonoBehaviour
{
public GameObject BenjaminStanding;
public GameObject BenjaminSitting;
void Update()
{
//If Time logic Between 8:00AM - 11:00AM
ActivateBenjaminStanding();
//if Time logic is After 11:00AM
ActivateBenjamindSitting();
}
//Activate Benjamin standing image
public void ActivateBenjaminStanding()
{
BenjaminSitting.SetActive(false);
BenjaminStanding.SetActive(true);
}
//Activate Benjamin sitting image
public void ActivateBenjamindSitting()
{
BenjaminStanding.SetActive(false);
BenjaminSitting.SetActive(true);
}
}
In my hierarchy I have the empty gameobject Benjamin and then all the images under that parent object like this:
Benjamin
I attach the script to my Benjamin object and do all the necessary image referencing.
Now the above code works but I feel like this is very messy way of doing things, because if I have more characters I have to make individual scripts for each character, some may have few images, some might have lots. And I have to create a method for each image when activating them. So is there a better way of doing this?
I'm looking for something quicker, cleaner and efficient. I would greatly appreciate any help or advice. Thanks!
Upvotes: 0
Views: 471
Reputation: 26
You can decrease your labor by organizing your GameObjects into a data structure and using a single function for switching between images.
By doing so you can generalize your Benjamin
class into a more general purpose class for any given character, giving your component re-usability.
This example uses a Dictionary
to organize each GameObject by their name and assumes each image shares the same name as the GameObject,
so that the intended GameObject can be referenced by name. This way, instead of writing variables for each image and writing a method for each of them,
we can call a single function ( ex: Activate("BenjaminStanding")
).
public class ClassNameHere : MonoBehaviour
{
public GameObject[] images;
private Dictionary<string, GameObject> imageDict;
private GameObject currentImage;
void Awake()
{
imageDict = new Dictionary<string, GameObject>();
foreach (GameObject image in images)
{
imageDict.Add(image.name, image);
}
}
void Activate(string name)
{
if (currentImage) currentImage.SetActive(false);
var image = imageDict[name];
image.SetActive(true);
currentImage = image;
}
void Update()
{
//If Time logic Between 8:00AM - 11:00AM
Activate("BenjaminStanding");
//if Time logic is After 11:00AM
Activate("BenjaminSitting");
}
}
Upvotes: 1
Reputation: 12621
If you have many images for each one, a common thing to do is just have an inspector variable that is an array,
public ImageOrSomething[] avatars;
Note that then in the Inspector you can just put in as many images as you like, without any change in the code.
Note that where I say "ImageOrSomething" that could be anything ... a Texture
, an Image
, an entire animated character, some sprite sheet ... whatever it is in your situation.
Further...
You can actually just organize the images in your Resources folder and load them by name.
In that way when your design department makes or changes images, or adds different times, you make no changes in the code.
Here's a kind of random example of loading a texture on to a card (think of playing cards say),
private int _Cardnumber = 1;
public int Cardnumber
{
get { return _Cardnumber; }
set
{
.. obviously check for valid numbers, etc
string f = "bonuscards/bonus_" + Cardnumber.ToString();
Texture t = Resources.Load(f, typeof(Texture)) as Texture;
ri.texture = t;
}
}
In the example the images would be named by your art department "bonus_3.png" "bonus_4.png" and so on.
You could additionally automatically determine what items are sitting in that folder and choose one randomly (or whatever the case may be).
The smartass way to do it is just have the actual times in the image name.
So something like
cat_03.png
cat_09.png
cat_13.png
would mean you change to those images at 0300, 0900 and 1300 respectively.
Say you want to add a new one for sleeping cat, and you want it to happen at 10pm. All you do is add the new image,
cat_22.png
just drop it in your resource folder and it is automatic from there.
Upvotes: 1
Reputation: 627
You can create a base class for your characters. Make it abstract class, and add variable and methods that all characters should have.
Like
public abstract class Character : MonoBehaviour
{
public GameObject characterStanding;
public GameObject characterSitting;
internal virtual void Update()
{
//If Time logic Between 8:00AM - 11:00AM
ActivateCharacterStanding();
//if Time logic is After 11:00AM
ActivateCharacterSitting();
}
//Activate Benjamin standing image
public void ActivateCharacterStanding()
{
characterSitting.SetActive(false);
characterStanding.SetActive(true);
}
//Activate Benjamin sitting image
public void ActivateSitting()
{
characterStanding.SetActive(false);
characterSitting.SetActive(true);
}
}
Then you can create sub class and inherit from Character class.
public class Benjamin : Character
{
}
public class Marting: Character
{
}
public class John: Character
{
// You can change main class function and override it
override Update(){
// If you remove this doesn't apply base class function.
base.ActivateCharacter();
} }
But if every character have similar properties and you create many of them, this approach is not useful at all. You can use Scriptable Object you can create asset for every character and assign Scriptable Object to scene object or prefab, choose which way is good for your setup.
Upvotes: 2