상세 컨텐츠

본문 제목

Unity 쿠키런 용과쿠키.

C#/수업내용

by McRobbin 2020. 5. 29. 18:31

본문

 

하... 처음에는 괜찮았는데 하다보니 구조가 이상해져서 대대적인 작업이 필요할듯 합니다.

 

이게 그 애니메이터라는 녀석인데 얽혀있기가 정글짐 입니다.

제 생각에는 Transition 상태 이전이 저런식으로 정성스럽고 복잡하게 하는거 말고 저 하늘색 애니 스테이트!!!

저걸좀 조져봐야 겠다는 생각이 듭니다. 그리고 Transition할때 HasExitTime, Duration 이런 옵션들이 있는데

이거를 좀 자세히 알아봐야 애니메이터 설계가 되겠다는 생각을 합니다.

 

전에 애니메이터 하나 올렸었는데 다시 올려야겠습니다. 

결론은 애니메이터는 ㅈ..조.은 녀석이다.

 

 

코드는 모두 올리기가 아주 복잡해서 핵심이라고 생각되는것만 올립니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
 
public class PassingObject : MonoBehaviour
{
    public IEnumerator coroutine;
 
    protected float passingSpeed;
    protected float startXpos;
    protected float endXpos;
 
    public virtual void Init(float passingSpeed, float startXPos, float endXPos)
    {
        this.passingSpeed = passingSpeed;
        this.startXpos = startXPos;
        this.endXpos = endXPos;
    }
 
    public virtual IEnumerator Passing()
    {
        while(this.transform.position.x > this.endXpos)
        {
            this.transform.position -= Vector3.right * Time.deltaTime * this.passingSpeed;
            yield return null;
        }
 
        this.Passed();
    }
 
    public virtual void Passed()
    {
 
    }
 
    public void SpeedUp(float speed)
    {
        this.passingSpeed += speed;
    }
 
    public void StopPassing()
    {
        StopCoroutine(this.coroutine);
    }
 
}
 
 
cs

저는 PassingObject.cs라는 클래스를 하나 만들었습니다. 쿠키런 게임을 보면 사실 주인공은 위아래로만 움직이고

배경과 아이템들이 뒤로 지나가면서 앞으로 가는 느낌을 줍니다.

 

그래서 뒤로 지나가는 모든 오브젝트들을 일반화한 PassingObject를 만들었고 기능은 Init으로 초기화,

코루틴 Passing함수 => 이건 매프레임 뒤로 이동하게 하는 함수 입니다.

 

void Passed 함수 => 뒤로 이동하는 오브젝트들이 일정거리 이동해 화면에 잡히지 않을 만큼 가면 실행할 함수 입니다.

예를들어 맵의 경우 뒤로 지나가면 저는 위치를 다시 오른쪽으로 옮겨 뒤에것과 이어붙이고 무한히 맵이 긴것처럼 보이게 했습니다.

대부분의 것들은 뒤로 지나가면 자동 삭제되게 했습니다.

 

그리고 특별한 아이템을 먹으면 뒤의 배경이 빨라지는 경우, 캐릭터가 죽으면 이동을 멈추는데 모든 배경과 아이템이 멈춥니다. 그걸위한 함수가 있습니다.

 

이 클래스는 유용하고 중요한데 아이템, 맵, 공중에 있는 타일?, 장애물 또한 이걸 상속받게 할겁니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
 
public class Item : PassingObject
{
    public override void Init(float passingSpeed, float startXPos, float endXPos)
    {
        base.Init(passingSpeed, startXPos, endXPos);
        this.coroutine = this.Passing();
 
        //랜덤 포지션 1 ~ 4까지.
        float yPos = (float)new System.Random().Next(15);
        this.transform.position += new Vector3(this.startXpos, yPos);
 
 
        StartCoroutine(this.coroutine);
    }
 
    public override void Passed()
    {
        Destroy(this.gameObject);
    }
 
    private void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Player")
        {
            StopCoroutine(this.coroutine);
            Destroy(this.gameObject);
        }
            
    }
}
 
 
cs

아이템 클래스 입니다. PassingObject를 상속 받았고 Init할 시에 자동으로 뒤로 가도록 했습니다.

y축은 랜덤 좌표를 주었고 아이템이 영웅과 닿았을 때, 아이템이 많이 지나갔을 때 삭제하도록 했습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
 
public class SpecialItem : Item
{
    private Animator anim;
 
    public override void Init(float passingSpeed, float startXPos, float endXPos)
    {
        base.Init(passingSpeed, startXPos, endXPos);
        this.anim = this.gameObject.GetComponent<Animator>();
    }
 
    public void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Player")
        {
            var hero = GameObject.FindWithTag("Player");
            var heroCompo = hero.GetComponent<Hero>();
            if (heroCompo.coroutine != null)
                StopCoroutine(heroCompo.coroutine);
            heroCompo.coroutine = heroCompo.Rush();
            StartCoroutine(heroCompo.coroutine);
 
            var map = GameObject.Find("map");
            var mapCompo = map.GetComponent<Map>();
            if (mapCompo.coroutine != null)
                StopCoroutine(mapCompo.coroutine);
            mapCompo.coroutine = mapCompo.SpeedUp();
            StartCoroutine(mapCompo.coroutine);
 
 
            StopCoroutine(this.coroutine);
            Destroy(this.gameObject);
        }
 
 
    }
}
 
 
cs

그 영웅이 먹으면 이동이 빨라지는 아이템 입니다. 급하게 하다보니 코드가 부끄럽게 됐습니다.

영웅과 닿았으면 영웅을 Rush()하고 맵의 속도를 올렸습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
 
public class ItemSpawner : MonoBehaviour
{
    public float createdSpeed;
 
    public void Init()
    {
        this.createdSpeed = 0f;
    }
 
    public void CreateItem(string resource)
    {
        var itemPrefab = Resources.Load<GameObject>("Prefabs/Item/" + resource);
        var itemGo = Instantiate<GameObject>(itemPrefab);
 
 
        itemGo.transform.SetParent(this.transform, false);
        var itemCompo = itemGo.GetComponent<Item>();
        itemCompo.Init(Map.GROUND_SPEED + createdSpeed, 10f, -10f);
    }
 
}
 
 
cs

아이템이 지나가면서 먹었을때 효과같은걸 확인하기가 어려워 아이템 만드는 녀석을 만들었습니다.

리소스 이름 넣으면 자기 자식으로 아이템 불러옵니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
 
public class UIPressingBtn : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    public UnityAction onPointerDown;
    public UnityAction onPointerUp;
 
    public void OnPointerDown(PointerEventData eventData)
    {
        this.onPointerDown();
    }
 
    public void OnPointerUp(PointerEventData eventData)
    {
        this.onPointerUp();
    }
}
 
 
cs

UIPressingBtn.cs입니다. 슬라이드 버튼을 보면 눌렀다 떼는게 아니라 누르는 동안 슬라이드, 떼면 슬라이드를 멈춥니다.

구현하려면 이런식으로 인터페이스 상속받아 구현해야 합니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Hero : MonoBehaviour
{
    public IEnumerator coroutine;
    public GameObject model;
 
 
    private Animator anim;
    private Rigidbody rigid;
 
    private float upSpeed;
    private float downSpeed;
 
    private void Awake()
    {
        this.anim = this.model.GetComponent<Animator>();
        this.rigid = this.GetComponent<Rigidbody>();
 
        this.upSpeed = 15f;
        this.downSpeed = 45f;
 
    }
 
    public void Init()
    {
    }
 
    private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.name == "groundCollider")
            this.anim.SetInteger("Jump"0);
    }
 
    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.name == "groundCollider")
            this.anim.SetInteger("Jump"1);
    }
 
    public void Slide()
    {
        this.anim.SetBool("IsSlide"true);
    }
 
    public void SlideUp()
    {
        this.anim.SetBool("IsSlide"false);
    }
 
    public void Jump()
    {
        if (this.anim.GetInteger("Jump"!= 2)
        {
 
            this.rigid.velocity = Vector3.zero;
            this.rigid.velocity += Vector3.up * this.upSpeed;
 
            this.anim.SetInteger("Jump"this.anim.GetInteger("Jump"+ 1);
        }
    }
 
    public IEnumerator Rush()
    {
        this.anim.SetBool("Rush"true);
        float time = 0f;
 
        while(time < 5.0f)
        {
            time += Time.deltaTime;
            yield return null;
        }
 
        this.anim.SetBool("Rush"false);
    }
 
    private void Update()
    {
        if (this.rigid.velocity.y != 0)
            this.rigid.velocity -= Vector3.up * Time.deltaTime * this.downSpeed;
    }
}
 
 
cs

Hero.cs 입니다.

애니메이터를 썼을 때 긍정적인 부분은 코루틴 사용이 많이 줄어듭니다. 애니메이션 동작중에 할 일을 코루틴으로

돌리는데 애니메이터는 한번 설정만 해두면 자동으로 상태를 바꾸게 할 수 있습니다.

 

그래도 애니메이터는 구립니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
 
public class Map : MonoBehaviour
{
    public IEnumerator coroutine;
 
    public static float BG_SPEED1 = 2.0f;
    public static float BG_SPEED2 = 4.0f;
    public static float BG_SPEED3 = 6.0f;
    public static float GROUND_SPEED = 8.0f;
    public static float FASTER_SPEED = 7.0f;
 
    public List<InGameBg> bgList;
    public ItemSpawner itemSpawner;
 
    public void Init()
    {
        //배경 초기화.
        for (int i = 0; i < bgList.Count; i++)
        {
            bgList[i].Init(i % 4 * 2.0f + 2.0f, 32.8f, -30);
        }
 
        this.itemSpawner.Init();
    }
 
    public IEnumerator SpeedUp()
    {
        float time = 0f;
        this.itemSpawner.createdSpeed += Map.FASTER_SPEED;
        GameObject.FindObjectsOfType<PassingObject>().ToList().ForEach(x => x.SpeedUp(Map.FASTER_SPEED));
 
        while(time < 5.0f)
        {
            time += Time.deltaTime;
            yield return null;
        }
 
        GameObject.FindObjectsOfType<PassingObject>().ToList().ForEach(x => x.SpeedUp(-Map.FASTER_SPEED));
        this.itemSpawner.createdSpeed -= Map.FASTER_SPEED;
    }
 
    public void StopAllPassing()
    {
        GameObject.FindObjectsOfType<PassingObject>().ToList().ForEach(x => x.StopPassing());
    }
}
 
 
cs

map.cs 입니다.

배경이 레이어로 몇겹이 있는데 그 속도가 각각 달라 상수로 놨습니다.

bgList에 배경 전부 넣어두고 알아서 Passing() 돌아가게 했습니다.

 

모든 뒤로 넘어가는 오브젝트를 PassingObject로 일반화 했을때의 장점? 같은게 여기서 나오는데,

속도가 빨라질 경우 뒤로 가는 모든 오브젝트들(아이템, 맵, 장애물 등등) 전부 다른 클래스로 되어있지만

PassingObject라는 클래스로 찾으면 이 모든게 다 걸려옵니다.

걸려온 모든 애들을 스피드업 해주면 되겠습니다.

 

 

코드가 너무 길어져서 전부 못적어 가지고 유니티 안에서 씬 돌아가는거 올리겠습니다.

이해 안가는게 있으면 이거보고 도움이 됐으면 합니다.

관련글 더보기