티스토리 뷰
혼란하다 혼란해
유니티 에셋스토어의 공짜 모델인 좀비를 가지고 간단한 게임을 만들어봤습니다.
좀비 에셋은 여기서 받으실 수 있어요!
https://www.assetstore.unity3d.com/kr/?stay#!/content/30232
어떻게 진행되냐면
게임을 실행하면 좀비프리팹을 생성해서 랜덤으로 맵에 뿌려주고
캐릭터는 이동과 점프만 해주면 좀비가 가까이있으면 알아서 달려가서 자동으로 전투를 행합니다.
좀비는 세대 때리면 죽고,
죽을 때 땅에 몸이 묻히는 버그가 있지만 애니메이션의 문제니까 그냥 냅뒀습니다 ㅎㅎ
그리고 캐릭터의 주변을 펫 개념으로 뭔가가 공전하고 있고
아무런 영향은 끼치지 못합니다.
해당 부분은 로테이트어라운드로 했습니다.
몬스터 찾는 건
몬스터 전체에 접근해서 가장 가까운 녀석을 골라서 걔가 최대 범위보다 가까우면 타겟으로 설정해서 전투 모드가 됩니다.
퀄리티가 높게 만든 것도 아니고 연습용으로 빠르게 만든건데
사실 괜히 좀비물이 재밌게 느껴지네요.
죄의식도 안 느껴지고...
소스는 별로 예쁘게 안만들었지만 그래도 올려봅니다!
주인공 스크립트입니다
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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | using System.Collections.Generic; using System.Collections; using UnityEngine; public class Hero : MonoBehaviour { public static Hero Intstance; public enum eHeroState { Idle, Move, MoveToAttack, Attack, Jump, } [SerializeField] Transform camTrans; CharacterController cc; public Animation anim; public float rotateSpeed = 90; public float moveSpeed = 3; public float attackRange = 0.5f; Vector3 moveDir; Vector3 deltaPos; public Transform cubeTrans; public eHeroState state; Coroutine nowCoroutine; private void Awake() { cc = GetComponent<CharacterController>(); } void Start() { nowCoroutine = StartCoroutine(Detect()); state = eHeroState.Idle; deltaPos = transform.position; } void Attack(Transform monTrans) { } public IEnumerator Detect() { while (true) { if (cc.isGrounded) { var mons = GameObject.FindObjectsOfType<Monster>(); if (mons.Length > 0) { float distance = 0; int disnum = -1; for (int i = 0; i < mons.Length; i++) { float nowDis = (transform.position - mons[i].transform.position).sqrMagnitude; if (mons[i].hp > 0 && (disnum == -1 || distance > nowDis)) { disnum = i; distance = nowDis; } } if (distance < 2 && disnum != -1) { targetMonster = mons[disnum]; state = eHeroState.MoveToAttack; nowCoroutine = StartCoroutine(MoveToAttack()); break; } } } yield return new WaitForSeconds(0.1f); } } public IEnumerator MoveToAttack() { while (true) { moveDir = (targetMonster.transform.position - transform.position+new Vector3(0.2f,0,0.2f)).normalized*moveSpeed; anim.Play("run@loop"); transform.rotation = Quaternion.Euler(0, 90 - Mathf.Atan2(moveDir.z, moveDir.x) * Mathf.Rad2Deg, 0); if((targetMonster.transform.position - transform.position).magnitude < attackRange) { moveDir = Vector3.zero; state = eHeroState.Attack; nowCoroutine = StartCoroutine(AttackMonster()); break; } yield return null; } } public IEnumerator AttackMonster() { while (true) { transform.LookAt(new Vector3(targetMonster.transform.position.x,transform.position.y, targetMonster.transform.position.z )); anim.Play("attack_sword_01"); yield return new WaitForSeconds(0.3f); bool re = targetMonster.Damage(this, 10); yield return new WaitForSeconds(0.6f); if (!re) { state = eHeroState.Idle; nowCoroutine = StartCoroutine(Detect()); break; } } } Monster targetMonster; public void Hit() { targetMonster.Damage(this, 10); } void Update() { //moveDir = Vector3.zero; if (state == eHeroState.Idle || state == eHeroState.Move) { if (cc.isGrounded) { if (Input.GetButtonDown("Jump")) { anim.Play("jump"); moveDir.y += 5; } else { float h = Input.GetAxisRaw("Horizontal"); float v = Input.GetAxisRaw("Vertical"); //moveDir = transform.TransformDirection(moveDir); moveDir = new Vector3(h, 0, v).normalized * moveSpeed; if (Mathf.Abs(h) > 0.3f || Mathf.Abs(v) > 0.3f) { state = eHeroState.Move; anim.Play("run@loop"); transform.rotation = Quaternion.Euler(0, 90 - Mathf.Atan2(moveDir.z, moveDir.x) * Mathf.Rad2Deg, 0); } else { state = eHeroState.Idle; anim.Play("idle@loop"); } } } } moveDir.y += Physics.gravity.y * Time.deltaTime; cc.Move(moveDir * Time.deltaTime); var cv = transform.position - deltaPos; cv.y = 0; cubeTrans.position += cv; camTrans.position += cv; deltaPos = transform.position; } } | 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 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Monster : MonoBehaviour { [SerializeField] Animator anim; public int hp = 100; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } public bool Damage(Hero hero, int attackPower) { anim.Play("attack"); transform.LookAt(hero.transform); hp -= attackPower; if(hp <= 0) { Dead(); return false; } return true; } void Dead() { //GetComponent<CapsuleCollider>().enabled = false; transform.position += new Vector3(0, 0.1f, 0); anim.Play("fallingback"); } } | cs |
주변 도는 녀석입니다. 원래 큐브였어서 클래스이름이 큐브입니다 ㅋ
1 2 3 4 5 6 7 8 9 10 11 12 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Cube : MonoBehaviour { public Transform target; void Update () { transform.RotateAround(target.position, Vector3.up, 90 * Time.deltaTime); transform.position = new Vector3(transform.position.x, 1, transform.position.z); } } | cs |
몬스터 소환하는 부분입니다.
이 부분은 특히 최적화 안했지만 연습 문제라 그냥 냅둡니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class MonsterManager : MonoBehaviour { void Start () { GameObject o = (GameObject)Resources.Load("Monster"); for (int i = 0; i < 30; i++) { Instantiate(o, new Vector3(Random.Range(-10f, 10f), 0.03f, Random.Range(-10f, 10f)), Quaternion.Euler(0, Random.Range(-180f, 180f), 0), transform); } } } | cs |
참고로 훨씬 쉽고 깔끔하게 코딩할 수 있으니
이해만 하시고 따라 치지 마시길 바랍니다.
코드 자체는 별로에요~~
'개발일기 > 유니티3D' 카테고리의 다른 글
7가지의 이동방식을 직접 비교해서 보여드림. (2) | 2018.10.05 |
---|---|
태양, 지구, 달의 공전 RotateAround로 어떻게 되는지 확인해보자. (0) | 2018.10.04 |
Translate로 이동할 때, Space.World와 Space.Self의 차이점 (0) | 2018.10.04 |
유니티에서 각도 구할 때 Mathf.Atan()대신에 Mathf.Atan2를 쓰는 이유 (0) | 2018.10.02 |
캐릭터컨트롤러로 10초만에 키보드로 이동 구현 (0) | 2018.10.01 |