2D Game Tutorial. Part 2. 2D character with several states and dynamic sprite changing

In this video tutorial I will talk about 2D character, combined with random sprites sets and which has several states, like walk, idle etc. This character can consist of a lot of different sprite sets and change them dynamically, which allows as to create a lot of different characters using same animation and movement logic.

Author: Sergey Taraban

:ad:

Part 1. Character creating and tinting

I have a girl and a boy characters. Both of them have several heads with different haircuts. These characters has five states: idle, walk top, walk bottom, walk left and walk right. I need to change these states when move character in some direction.

For this I write a very useful script for dynamic state changing and simplifying working with different sprites for same character.

Tutorial plan:

  1. Problem overview. Girl and boy sprites
  2. Setuping and using script for simple state changing
  3. Adding sprite set changing feature (different haircuts)
  4. Generation of random characters

MultiSpriteCharacter script

// Copyright (C) 2014 Sergey Taraban 
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using UnityEngine;
using System.Collections;
using System.Linq;

[System.Serializable] public class SpritePartInfo { public Transform Part; public string SpriteName; public Vector3 scale = Vector3.one; }

[System.Serializable] public class SpriteSetForPart { public Transform Part; public int CurrSpriteID = -1; }

[System.Serializable] public class AnimPartInfo { public string StateInfo; //read only public SpritePartInfo[] SpriteParts = new SpritePartInfo[1]; };

public class MultiSpriteCharacter : MonoBehaviour {

public enum eState
{
	DEFAULT = 0,
	MOVE_TOP,
	MOVE_BOTTOM,
	MOVE_LEFT,
	MOVE_RIGHT,
};
public eState State = eState.DEFAULT;

static char[] Separator = {'#'};

public string MainSpriteName = ""; 

public SpriteSetForPart[] SpriteSet = null;
public AnimPartInfo[] AnimPartDesc = new AnimPartInfo[1];

void OnValidate()
{
	UpdateParts();
}

void Start () {
	UpdateParts();
}

public void SetState(eState state)
{
	State = state;
	UpdateParts();
}

void UpdateParts()
{
	bool error = false;
	UnityEngine.Object[] sprites = Resources.LoadAll(MainSpriteName) as UnityEngine.Object[];
	if(sprites == null || sprites.GetLength(0) == 0) {
		error = true;
	}
	int i = 0;
	foreach(var part in AnimPartDesc)
	{
		if(part != null)
		{
			part.StateInfo = ((eState)i).ToString();
			if(error)
			{
				part.StateInfo = "ERROR";
				continue;
			}
		}
		i++;
	}
	if((int)State < AnimPartDesc.GetLength(0)) 		{ 			AnimPartInfo part = AnimPartDesc[(int)State]; 			if(part.SpriteParts != null) 			{ 				foreach(var spritePart in part.SpriteParts) 				{ 					if(spritePart.Part == null) 					{ 						continue; 					} 					UnityEngine.Sprite spr = null; 					//process '#' symbol 					SpriteSetForPart spriteSetForPart = System.Array.Find(SpriteSet, s => s.Part.name == spritePart.Part.name) as SpriteSetForPart;
				if(spriteSetForPart != null)
				{
					int spriteSetID = spriteSetForPart.CurrSpriteID;
					string spriteName = spritePart.SpriteName;
					string[] splitSpriteNames = spriteName.Split(Separator);
					bool is_two_part_sprite = splitSpriteNames.GetLength(0) > 1;
					if(is_two_part_sprite) {
						spriteName = splitSpriteNames[0] + spriteSetID + splitSpriteNames[1];
					}
					else {
						spriteName = splitSpriteNames[0] + spriteSetID;
					}
					spr = System.Array.Find(sprites, s => s.name == spriteName) as UnityEngine.Sprite;
					if(spr == null)
					{
						if(is_two_part_sprite) {
							spriteName = splitSpriteNames[0] + splitSpriteNames[1];
						}
						else {
							spriteName = splitSpriteNames[0];
						}
						spr = System.Array.Find(sprites, s => s.name == spriteName) as UnityEngine.Sprite;
					}
				}
				else
				{
					spr = System.Array.Find(sprites, s => s.name == spritePart.SpriteName) as UnityEngine.Sprite;
				}

				if(spr != null)
				{
					spritePart.Part.GetComponent().sprite = spr;
				}
				spritePart.Part.localScale = spritePart.scale;
			}
		}
	}
}

}

Random customizator script

I use this script for change character appearance in random way.
using UnityEngine;
using System.Collections;

public class RandomCustomizator : MonoBehaviour {

Color32[] SkinColorSet = 
{
	new Color32(226, 200, 173, 255),
	new Color32(114, 86,  65,  255),
	new Color32(204, 179, 138, 255),
	new Color32(237, 220, 204, 255),
	new Color32(220, 171, 141, 255),
	new Color32(253, 180, 155, 255)
};

void OnTriggerEnter2D(Collider2D obj)
{
	MultiSpriteCharacter msc = obj.GetComponent();
	msc.SpriteSet[0].CurrSpriteID = Random.Range(0, 5); //change hairdress

	Character chr = obj.GetComponent();
	chr.HairColor = GetRandomColor();
	chr.SkinColor = SkinColorSet[(int)Random.Range(0, SkinColorSet.GetLength(0))];
	chr.HandColor = chr.SkinColor;
	chr.SkirtColor = GetRandomColor();
	chr.PaintPlayer();
}

Color GetRandomColor()
{
	Vector3 color = new Vector3(Random.Range(0, 1.0f), Random.Range(0, 1.0f), Random.Range(0, 1.0f));
	color.Normalize();
	return new Color(color.x, color.y, color.z, 1.0f);
}

}

 

Author: Sergey Taraban

Related posts