게임개발자/Unity3D

스프라이트 애니메이션 플레이 시키는 방법 - 유니티로 만드는 인디게임. 두더지 잡기 게임 MollyMolly 함께 만들기(2)

스타(star) 2014. 7. 25. 18:31

유한상태머신

애니메이션을 재생시키고 서로 상태를 변환시키기 위해서는 FSM(Finite State Machine)을 알아야 한다.


오늘 만들어볼 두더지의 상태 흐름은 아래와 같이 구성하기로 하였다.

각 상태의 변화에는 특정한 조건이 필요하다.



함수는 총 5개의 상태 * 2를 만들 것이다. 하나는 도입부, 그리고 하나는 상태에 따른 액션을 행동하는 함수.

아래 보면, 이 부분이 5개의 상태를 말한다.

이제 각각 상태를 변환 시킬 수 있는 조건들을 설정하면 된다.


public enum MoleState

{

None, Open, Idle, Close, Catch

}


우선 이 부분은 스크립트의 실행을 담당하는 부분인데 MS라는 변수값이 MoleState.Open이면 계속해서 Open_Ing()실행 시키도록 하고 있다. 

과연 저기 MoleState.Open을 조절하는 부분이 어디일까 살펴 보자.


// Update is called once per frame

void Update () {

{

if (MS == MoleState.Open) {

Open_Ing ();

}


}


이 부분은 Open 이라는 상태를 구현한 부분이다.

일단 Open_On()에서는 애니메이션 재생을 담당한다. MoleState.Open이라는 상태로 선언하도록 만들었다. 그러고 나서 Ani_count를 0으로 세팅한다.

위의 Update함수에 의해서 Open_Ing()를 무조건 수행하게 되어 있다.
자세히 들여다 보면, 배열로 선언한 변수의 매트리얼 텍스쳐를 하나씩 오픈하도록 만들었다. 물론, 실행할 때마다 하나씩 카운터 값을 올린다.
아무래도 이 부분에서 다음 이미지로 넘어가도록 설정 한 것 같다.
그러면 리소스들을 배열에 넣을 때 값을 1, 2, 3, 4, 5와 같이 넣어줘야 한다는 것이다.


//Open

public void Open_On()

{

MS = MoleState.Open;

Ani_count = 0;

}


public void Open_Ing()

{

renderer.material.mainTexture = Open_Images [Ani_count];

Ani_count+=1;


if (Ani_count >= Open_Images.Length)

{

Idle_On();

}


}


사실 여기까지가 핵심적인 부분인 것 같다. 그 외의 부분들은 주기적으로 None 상태일 때 다른 함수로 보내는 설정이나, 애니메이션의 스피드 조절하는 부분이 전부이다.

가장 기본적으로 2D 애니메이션 출력을 할 수 있는 방법이다.

그 외에 각종 조건에 의해서 STATE를 변환 시키는 것은 또 다른 문제이다.


그럼 왜 On과 Ing 함수를 하나로 합치지 않았을까 생각해 봤는데, 의외로 단순했다. 

Ani_count를 계속해서 0으로 세팅하면 문제가 생기니까 그런 것이다. 


using UnityEngine;

using System.Collections;


public enum MoleState

{

None, Open, Idle, Close, Catch

}




public class Hole : MonoBehaviour {


public IEnumerator Wait(){

MS = MoleState.None;

Ani_count=0;

float wait_Time = Random.Range(1.5f, 1.5f);

yield return new WaitForSeconds(wait_Time);

Open_On();

}


public MoleState MS;


public Texture[]Open_Images;

public Texture[]Idle_Images;

public Texture[]Close_Images;

public Texture[]Catch_Images;


public float Ani_Speed;

public float _now_ani_time;



int Ani_count;


//Open

public void Open_On()

{

MS = MoleState.Open;

Ani_count = 0;

}


public void Open_Ing()

{

renderer.material.mainTexture = Open_Images [Ani_count];

Ani_count+=1;


if (Ani_count >= Open_Images.Length)

{

Idle_On();

}


}


//Idle

public void Idle_On()

{

MS = MoleState.Idle;

Ani_count = 0;

}

public void Idle_Ing()

{

renderer.material.mainTexture = Idle_Images [Ani_count];

Ani_count+=1;

if (Ani_count >= Idle_Images.Length)

{

Close_On();

}

}



//Close

public void Close_On()

{

MS = MoleState.Close;

Ani_count = 0;

}

public void Close_Ing()

{

renderer.material.mainTexture = Close_Images [Ani_count];

Ani_count+=1;

if (Ani_count >= Close_Images.Length)

{

StartCoroutine("Wait");


}

}


//Catch

public void Catch_On()

{

MS = MoleState.Catch;

Ani_count = 0;

}

public void Catch_Ing()

{

renderer.material.mainTexture = Catch_Images [Ani_count];

Ani_count+=1;

if (Ani_count >= Catch_Images.Length)

{

StartCoroutine("Wait");

}

}

// Use this for initialization

void Start () {

}

// Update is called once per frame

void Update () {

if(_now_ani_time>=Ani_Speed)

{

if (MS == MoleState.Open) {

Open_Ing ();

}


if (MS == MoleState.Idle) {

Idle_Ing ();

}


if (MS == MoleState.Close) {

Close_Ing ();

}


if (MS == MoleState.Catch) {

Catch_Ing ();

}


_now_ani_time = 0;

}

else

{

_now_ani_time += Time.deltaTime;

}

}

}