'Unity/Unity Tutorial'에 해당되는 글 2건

  1. 2019.05.03 Tower Defense Template
  2. 2019.05.02 Shooting Tutorial 자습서 분해하고 재구성하기

Tower Defense Template

Unity/Unity Tutorial 2019. 5. 3. 17:58

유니티 자습서에 있는 Tower Defense Template를 분해하여 나만의 코드로 다시 재구현 해보았다.

구현한 부분은 길 만들기(Navmesh), 적군 오브젝트 생성(Object Pool이용), 노드 단위로 이동(Collider이용), 도착시 일정시간 후 비활성화 및 재활용이다.

느낀점 : Tutorial 맞나싶다.


//분석

카메라 컨트롤

  - 바운더리의 마우스 위치에 따라 카메라 이동

  - 마우스 중간휠로 줌인/줌아웃

타워선택

- 스냅

- 건설 불가 지역에는 빨간색 표시

- 타워에 원 생성 (Radius Visualiser?)

- 건설 가능 위치에서 타워 로테이션

- 우클릭시 선택된 타워 설치 취소

타워설치

- 애니메이션 실행

- 원이 사라짐

- 타워 설치 된 곳 (바닥)에 색이 칠해짐(mesh)

적기생성

- 오브젝트 풀링(PoolManager)

- 풀링 후 오브젝트를 꺼내지 않는다.

지형

- Navmesh 사용

- Areas : (Flyable)

- Level04_Pt{n}_Road 여러개에 Navmesh적용

Hoverbuggy

- Navmesh Agent

- Capsule Collider

- Rigid Body (Is Kinematic Active)

- Targetter.cs, TargetterEditor.cs (target collider를 editor에서 표시)

- 이동 : Agent.cs, MoveToNode() method 실행, 한번에 목표지점으로 이동이 아닌 노드 단위로 나누어 이동

Node(Node.cs)

- MonoBehaviour

- NodeEditor.cs => Inspector Customizing

- Level1Configuration/Nodes/{n}


//계획

1. new project

2. 바닥에 mesh(navmesh 적용)

3. 시작위치, 끝 위치 설정

4. 버튼 생성

5. 버튼 누를 시 적군 생성하여 시작위치부터 끝 위치까지 navmesh통하여 이동하는지 확인

6. 노드 제작

7. 노드 단위로 이동하게끔 변경


//코드읽고 생각을 정리한 것

Node

AreaMeshCreator Type 이용하여 area에 Mesh를 지정하는 탭을 생성

NodeSelector를 이용하여 다음 Node를 리턴한다.

GetRandomPointInNodeArea : Node의 MeshCreator를 이용하여 영역 내 랜덤 위치값을 찾아 리턴함

OnTriggerEnter를 이용하여 다른 gameObject의 Agent가 node의 area에 enter할 때, 현재 노드를 기준으로 다음 노드를 가져옴.

OnValidate Method에서 Collider가 있으면 isTrigger를 활성화하고, AreaMeshCreator가 null일 경우 자식에게서 찾는다.

OnDrawGizmos를 통해 노드 상단에 이미지를 가지고 기즈모로 출력함.

Vector3.up = Vector3(0,1,0)

NodeSelector

linkedNodes라는 List에 Node들을 저장하고 NodeSelector를 통해 노드를 선택한다.

GetNextNode()를 이용하여 리스트에서 다음 노드를 찾아 리턴하고, 다음 노드가 null일 경우 endPoint를 리턴한다.




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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class Level01 : MonoBehaviour
{
    public Button btn;
    public GameObject objPool;
    public GameObject startPosition, endPosition;
 
    private Level01_ObjectPool pool;
    private int idx;
    
    void Start()
    {
        this.pool = this.objPool.GetComponent<Level01_ObjectPool>();
        this.btn.onClick.AddListener(() =>
        {
            this.CreateEnemy();
        });    
    }
 
    private void CreateEnemy()
    {
        var list = this.pool.listEnemy;
        if(this.idx == list.Length - 1)
        {
            this.idx = 0;
        }
        for(; this.idx < list.Length; idx++)
        {
            if (list[this.idx].gameObject.activeSelf == false)
            {
                list[this.idx].transform.position = startPosition.transform.position;
                list[this.idx].SetActive(true);
                list[this.idx].GetComponent<Level01_Enemy>().Move(this.startPosition.GetComponent<TestNode>().GetNextNode().transform.position);
                break;
            }
        }
    }
}
 
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestNode : MonoBehaviour
{
    public TestNode GetNextNode()
    {
        var selector = this.gameObject.GetComponent<TestNodeSelector>();
        if(selector != null)
        {
            return selector.GetNextNode();
        }
        return null;
    }
 
    public void OnTriggerEnter(Collider other)
    {
        var agent = other.gameObject.GetComponent<Level01_Enemy>();
        if(agent != null)
        {
            if(this.gameObject.name == "End")
            {
                StartCoroutine(this.WaitForSeconds(() =>
                {
                    agent.gameObject.SetActive(false);
                    StopAllCoroutines();
                }));
            }
            else
            {
                var coordinate = this.GetNextNode().transform.position;
                agent.Move(coordinate);
                Debug.Log("다음 node coordinate 전달완료");
            }
        }
    }
 
    private IEnumerator WaitForSeconds(System.Action OnCompleteWait)
    {
        yield return new WaitForSeconds(1.0f);
        OnCompleteWait();
    }
}
 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
 
public class Level01_Enemy : MonoBehaviour
{
    public void Move(Vector3 target)
    {
        NavMeshAgent agent = this.GetComponent<NavMeshAgent>();
        agent.enabled = false;
        if(this.gameObject.activeSelf == true)
        {
            agent.enabled = true;
            agent.destination = target;
        }        
    }
}
 
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class Level01 : MonoBehaviour
{
    public Button btn;
    public GameObject objPool;
    public GameObject startPosition, endPosition;
 
    private Level01_ObjectPool pool;
    private int idx;
    
    void Start()
    {
        this.pool = this.objPool.GetComponent<Level01_ObjectPool>();
        this.btn.onClick.AddListener(() =>
        {
            this.CreateEnemy();
        });    
    }
 
    private void CreateEnemy()
    {
        var list = this.pool.listEnemy;
        if(this.idx == list.Length - 1)
        {
            this.idx = 0;
        }
        for(; this.idx < list.Length; idx++)
        {
            if (list[this.idx].gameObject.activeSelf == false)
            {
                list[this.idx].transform.position = startPosition.transform.position;
                list[this.idx].SetActive(true);
                list[this.idx].GetComponent<Level01_Enemy>().Move(this.startPosition.GetComponent<TestNode>().GetNextNode().transform.position);
                break;
            }
        }
    }
}
 
cs


'Unity > Unity Tutorial' 카테고리의 다른 글

Shooting Tutorial 자습서 분해하고 재구성하기  (0) 2019.05.02
:

Shooting Tutorial 자습서 분해하고 재구성하기

Unity/Unity Tutorial 2019. 5. 2. 18:49


자습서 중 하나인 Space Shooter Tutorial의 코드를 공부하고 처음부터 나만의 코드로 다시 재구성 해보았다.



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
86
87
88
89
90
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestShootingGame : MonoBehaviour
{
    public Transform[] arrGround;
    public GameObject[] meteors;
    public GameObject spaceShip;
    public GameObject objPool;
    public Vector3 spawnPosition;
    public float xMin, xMax, zMin, zMax;
    public float tilt;
    public float waveDelay, spawnDelay, meteorCount;
    private Rigidbody shipBody;
    private float speed = 5.0f;
    private int index = 0;
 
    // Start is called before the first frame update
    void Start()
    {
        this.shipBody = this.spaceShip.GetComponent<Rigidbody>();
    }
 
    // Update is called once per frame
    void Update()
    {
        for (int i = 0; i < this.arrGround.Length; i++)
        {
            this.arrGround[i].Translate(new Vector3(0-0.1f, 0* this.speed);
            if (this.arrGround[i].transform.localPosition.z <= -30)
            {
                this.arrGround[i].transform.localPosition = new Vector3(00, 60f);
            }
        }
        if(Input.GetMouseButtonDown(0))
        {
            var list = this.objPool.GetComponent<TestObjectPool>().listObj;
            print(list.Count);
            foreach(var bullet in list)
            {
                if(bullet.activeSelf == false)
                {
                    bullet.SetActive(true);
                    bullet.gameObject.GetComponent<TestBullets>().Init();
                    bullet.transform.position = GameObject.Find("bulletStartPoint").transform.position;
                    break;
                }
            }
        }
        this.Move();
        StartCoroutine(this.CreateWave());
    }
 
    private IEnumerator CreateWave()
    {
        yield return new WaitForSeconds(2.0f);
        while (true)
        {
            for (int i = 0; i < this.meteorCount; i++)
            {
                GameObject meteor = this.meteors[Random.Range(0, meteors.Length)];
                if(meteor.activeSelf == false)
                {
                    meteor.SetActive(true);
                    meteor.transform.GetComponent<TestMeteor>().Init();
                    meteor.transform.position = new Vector3(Random.Range(-this.spawnPosition.x, this.spawnPosition.x), this.spawnPosition.y, this.spawnPosition.z);
                    meteor.transform.rotation = Quaternion.identity;
                }
                yield return new WaitForSeconds(this.spawnDelay);
            }
        }
    }
 
    private void Move()
    {
        //Horizaontal = 수평, Virtical = 수직 (-1 ~ 1 return)
        float horizontal = Input.GetAxis("Horizontal");
        float virtical = Input.GetAxis("Vertical");
 
        var movement = new Vector3(horizontal, 0, virtical);
        this.shipBody.velocity = movement * this.speed;
 
        this.shipBody.position = new Vector3(Mathf.Clamp(this.shipBody.position.x, this.xMin, this.xMax),
                                             0, Mathf.Clamp(this.shipBody.position.z, this.zMin, this.zMax));
        this.shipBody.rotation = Quaternion.Euler(00this.shipBody.velocity.x * -this.tilt);
 
    }
}
 
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestBGScroller : MonoBehaviour
{
    public Transform[] ground;
    public float speed = 2.0f;
 
    private void Update()
    {
        for (int i = 0; i<this.ground.Length; i++)
        {
            this.ground[i].Translate(new Vector3(0-0.1f, 0* this.speed);
            if(this.ground[i].transform.localPosition.z <= -30)
            {
                this.ground[i].transform.localPosition = new Vector3(00, 60f);
            }
        }
    }
}
 
cs


1
2
3
4
5
6
7
8
9
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestObjectPool : MonoBehaviour
{
    public List<GameObject> listObj;
}
 
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestMeteor : MonoBehaviour
{
    public float tumble;
    public float speed;
    public GameObject particle;
    private ParticleSystem fx;
 
    void Start()
    {
        this.fx = this.particle.GetComponentInChildren<ParticleSystem>();
        GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere * this.tumble;
        GetComponent<Rigidbody>().velocity = transform.forward * this.speed;
    }
 
    public void Init()
    {
        StartCoroutine(this.CountDownToPassive());
    }
 
    private IEnumerator CountDownToPassive()
    {
        while(true)
        {
            if(this.transform.position.z < -14)
            {
                this.gameObject.SetActive(false);
                break;
            }
            yield return null;
        }
        
        //Debug.Log("countdonwtopassive");
        //yield return new WaitForSeconds(2.0f);
        //this.gameObject.SetActive(false);
        //yield return null;
    }
 
    private void OnTriggerEnter(Collider other)
    {
        if(!other.CompareTag("Enemy"))
        {
            this.gameObject.SetActive(false);
            this.fx.gameObject.SetActive(true);
            this.fx.transform.position = this.gameObject.transform.position;
            this.fx.Play();
        }
    }
}
 
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class TestBullets : MonoBehaviour
{
    public float speed;
 
    void Start()
    {
        GetComponent<Rigidbody>().velocity = transform.forward * speed;
    }
 
    public void Init()
    {
        StartCoroutine(this.TimeToOff());
    }
 
    private void OnTriggerEnter(Collider other)
    {
        this.gameObject.SetActive(false);
    }
 
    private IEnumerator TimeToOff()
    {
        yield return new WaitForSeconds(1.0f);
        this.gameObject.SetActive(false);
    }
}
 
cs


'Unity > Unity Tutorial' 카테고리의 다른 글

Tower Defense Template  (0) 2019.05.03
: