Reputation: 350
For the game I'm trying to do, I have quite a few objects:
Where all start with a specific sprite, like the Hero:
Except that the Hero is the only one which has an Animator
component and follows animation states.
The other game objects would get their sprite and position based on the Hero, using the following script:
using UnityEngine;
public class SpritePosition : MonoBehaviour {
[SerializeField] private string objectName;
[SerializeField] private int objectIndex;
[SerializeField] private int objectR;
[SerializeField] private int objectG;
[SerializeField] private int objectB;
private Rigidbody2D body;
private SpriteRenderer objectRenderer;
private GameObject hero;
private Rigidbody2D heroRigidBody;
private SpriteRenderer heroRenderer;
private Sprite currentHeroSprite;
private HeroResources heroResourcesScript;
private HeroMovement heroMovementScript;
private Sprite[] spriteGroup;
private void Start() {
body = GetComponent<Rigidbody2D>();
objectRenderer = GetComponent<SpriteRenderer>();
hero = GameObject.Find("Hero");
heroRigidBody = hero.GetComponent<Rigidbody2D>();
heroRenderer = hero.GetComponent<SpriteRenderer>();
currentHeroSprite = heroRenderer.sprite;
heroResourcesScript = hero.GetComponent<HeroResources>();
Debug.Log(objectName + "(" + objectR + ", " + objectG + ", " + objectB + ")");
spriteGroup = heroResourcesScript.spriteGroup[objectName];
}
private void Update() {
heroMovementScript = hero.GetComponent<HeroMovement>();
if (currentHeroSprite != heroRenderer.sprite) {
currentHeroSprite = heroRenderer.sprite;
}
SetSprite();
SetPosition();
}
private bool shouldMirrorSprite(int index) {
return index >= 0 && index <= 34 ||
index >= 69 && index <= 71 ||
index >= 81 && index <= 83 ||
index >= 97 && index <= 99 ||
index >= 117 && index <= 118 ||
index >= 133 && index <= 175;
}
private void SetSprite() {
int currentSpriteIndex = int.Parse(currentHeroSprite.name.Replace("hero-body_", ""));
objectRenderer.sprite = spriteGroup[currentSpriteIndex];
objectRenderer.color = new Color32((byte)objectR, (byte)objectG, (byte)objectB, 255);
if (heroMovementScript.isFacingLeft && shouldMirrorSprite(currentSpriteIndex)) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
// for this to work, the game object must have a
// RigidBody2D component with Freeze Position active
// for X and Y axis
private void SetPosition() {
Vector2 currentHeroPosition = heroRigidBody.position;
transform.position = currentHeroPosition;
}
}
Which, when added as a component, expects a name, index, and R, G, and B values:
Here, the Name
is necessary to load specific sprites for each game object, in this script:
using System.Collections.Generic;
using UnityEngine;
public class HeroResources : MonoBehaviour
{
public Dictionary<string, Sprite[]> spriteGroup = new Dictionary<string, Sprite[]>();
void Awake () {
spriteGroup.Add("pants", Resources.LoadAll<Sprite>("Spritesheets/pants"));
spriteGroup.Add("boots", Resources.LoadAll<Sprite>("Spritesheets/boots"));
spriteGroup.Add("shirt", Resources.LoadAll<Sprite>("Spritesheets/shirt"));
spriteGroup.Add("tunic", Resources.LoadAll<Sprite>("Spritesheets/tunic"));
spriteGroup.Add("belt", Resources.LoadAll<Sprite>("Spritesheets/belt"));
Debug.Log(spriteGroup.Count);
}
}
and the sprites are loaded from several folders in the Resources
folder:
These spritesheets are all of the same size, so they can be cleanly sliced:
Thus, having the sprites like this, I can simply call the SetSprite
function and the SetPosition
function based on the Hero:
private void SetSprite() {
int currentSpriteIndex = int.Parse(currentHeroSprite.name.Replace("hero-body_", ""));
objectRenderer.sprite = spriteGroup[currentSpriteIndex];
objectRenderer.color = new Color32((byte)objectR, (byte)objectG, (byte)objectB, 255);
if (heroMovementScript.isFacingLeft && shouldMirrorSprite(currentSpriteIndex)) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
// for this to work, the game object must have a
// RigidBody2D component with Freeze Position active
// for X and Y axis
private void SetPosition() {
Vector2 currentHeroPosition = heroRigidBody.position;
transform.position = currentHeroPosition;
}
This works, and the other sprites update based on the index of the Hero game object and follow it, so it looks like the user has a lot of equipment. However, sometimes the sprites either fail to keep up or the position falls behind a bit:
There also seems to be some black lines toward the top of the sprites. I assume this happens because the sprites do not load fast enough, and if so, is there a way to ensure these sprites load faster? Or does this have to do with a computer's performance?
Also, to have the sprites follow, I need to freeze X and Y position on the other game objects' RigidBody2D. The Hero has Transform, Sprite Renderer, Box Collider 2D, RigidBody2D, two scripts (HeroMovement and HeroResources), and Animator components, while the other game objects only have Transform, Sprite Renderer, RigidBody2D, and a script (SpritePosition)
Upvotes: 0
Views: 294
Reputation: 2197
Instead of positioning the clothes yourself you could let Transform component do the heavy lifting by just placing the cloth GameObjects under the hero GameObject with correct offsets.
This way you could also have HeroAnimator component that gets all the clothing components under the hero with GetComponentsInChildren at startup and changes the sprites and flip them to match movement direction. Clothing components could focus
because the sprites do not load fast enough
You're loading all the sprite resources with HeroResources.Awake so they should all be loaded to memory during startup. Same goes for all sprites you're referencing in your scene.
String operations like this in update method can generate surprising amount of garbage for the garbage collector which can affect performance down the line.
int currentSpriteIndex = int.Parse(currentHeroSprite.name.Replace("hero-body_", ""));
Its good to note that implementing something like this can get really tricky. Many 2D games that let you change outfit use skeletal animation or have very limited set of minimal animations.
Upvotes: 0