자작 게임도 잘 부탁드려요~

adsense



유니티 2D 슈팅게임 개발일지 - 3일차 (2D 콜라이더-총알 명중)

적 캐릭터에게 명중하는 총알



시작부터 보스?

딱히 보스부터 만들 필요는 없는데, 재미있으니까(?) 기본 적으로 보스를 올려봅니다.

보스캐릭터는 여러개 파트로 나눠져 있으므로 포토샵에서 배치해서 psb파일로 저장하고 프로젝트로 끌어옵니다.

생명체 같으면 본을 심어서 스키닝 애니메이션을 만들텐데, 이 경우는 아무래도 포지션, 스케일, 로테이션만으로 연출하게 될 듯.

적 캐릭터는 빈 오브젝트를 만들어서 여기에 모두 올리고,

빈 오브젝트(==== Enemy)에는 Sorting Group 컴포넌트를 줘서 랜더링 우선순위를 정합니다.
슈팅게임은 앞뒤로 가리는 개념이 희박하니까 배경-적캐릭터&적탄-플레이어&플레이어탄-이펙트-UI 순서로 고정해도 될 듯 합니다. (적 캐릭터가 위에서 강하하거나 아래로 추락하거나 하는 연출이 필요하다면 그때는 별도의 소팅 그룹을 마련해야 할 듯)


2D 스프라이트 충돌 처리

콜라이더
스프라이트에 콜라이더(중에서도 2D란 이름이 붙은 것) 컴포넌트를 붙여줍니다.

여러개 조각으로 이루어진 보스 캐릭터는 각 조각 단위로 Box Collider 2D를 붙여준 후
(조각을 모두 선택한 상태에서 add component 하면 모든 조각에 한꺼번에 붙어줍니다)
가느다란 녹색 선을 조절해 불필요한 콜라이더는 삭제하고, 적당히 모양을 잡아줍니다.

모든 콜라이더는 물리 반동을 쓸게 아니니까 is Trigger에 체크

서로 충돌할 것 끼리는 최소한 한 쪽에 강체(RigidBody2D)를 붙여줘야 한다고 하네요.

또, transform.position을 써서 직접 움직이는 것 보다 리지드바디를 MovePosition 하는게 가볍다고..?
그러면 가급적 리지드바디를 써 주는게 좋겠네요.

보스의 경우는 리지드바디를 움직임 제어용으로만 쓸 것이니 최상위의 루트 오브젝트(boss1)에만 붙입니다.
플레이어 총알에 리지드바디가 있으니 각 조각에는 콜라이더만 있으면 충분.

총알에도 콜라이더와 리지드바디를 붙이고,
리지드바디를 움직이는 건 FixedUpdate에서 해 주는게 좋다고 하니
기존에 Update에 만들어놨던 총알 이동 로직을, FixedUpdate로 이동하고 리지드바디 컴포넌트의 MovePosition으로 변경.

  1. private void FixedUpdate()
  2. {
  3. if (isTrig)
  4. return;
  5.  
  6. GetComponent<Rigidbody2D>().MovePosition(
  7. transform.position + new Vector3(0, 1, 0) * Time.deltaTime * info.speed);
  8. info.speed += info.accel;
  9. if (transform.position.y > Screen.height * 0.5f + 100)
  10. {
  11. player.GetComponent<PlayerController>().ReleaseFire(this.gameObject);
  12. }
  13. }
적과의 충돌 체크를 위해 OnTriggerEnter2D함수를 추가합니다.

물리 반응이 아니라 단순 겹침 여부만 판단하므로 OnCollisionEnter2D가 아니라 OnTriggerEnter2D를 씁니다.

  1. private void OnTriggerEnter2D(Collider2D collision)
  2. {
  3. if(collision.gameObject.tag=="Enemy")
  4. {
  5. StartCoroutine(effector());
  6. }
  7. }
effector 함수는 하술.

총알이 충돌했을 때 이펙트입니다.

한 장 짜리 스프라이트를 크기와 투명도를 애니메이션 해 주는 식입니다.


총알과 적이 충돌하면 이펙트를 생성하고 총알을 플레이어가 갖고 있는 큐에 반환합니다.
이 일련의 과정이 다음 코드입니다.

  1. IEnumerator effector()
  2. {
  3. isTrig = true;
  4. GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 0);
  5. if (_effect == null)
  6. _effect = Instantiate(effect, transform);
  7.  
  8. _effect.SetActive(true);
  9. while (!_effect.GetComponent<Animator>().isActiveAndEnabled)
  10. {
  11. yield return null;
  12. }
  13. _effect.GetComponent<Animator>().Play(0);
  14. while(_effect.GetComponent<Animator>().GetCurrentAnimatorStateInfo(0).normalizedTime < 1f)
  15. {
  16. yield return null;
  17. }
  18. _effect.SetActive(false);
  19. player.GetComponent<PlayerController>().ReleaseFire(this.gameObject);
  20. }

9~12 : 애니메이션 사용이 가능해질때까지 대기 (안그러면 game object with animator is inactive 경고가 뜹니다)
13 : 루트 애니메이션 재생
14~17 : 애니메이션의 1루프 재생이 끝날 때까지 대기
19 : 총알을 플레이어 큐에 반납


자잘?한게 조금 생략됐지만, 이렇게 해서 맨 처음의 gif처럼 움직이게 됩니다.




덧글

댓글 입력 영역


Books

Geek라이프

기초부터 시작하는 모형 전자공작
박성윤 저

사이토 나오키의 일러스트 첨삭 레슨 Before & After
사이토 나오키 저/박수현 역

MSX&재믹스 퍼펙트 카탈로그
마에다 히로유키 저/조기현 역

핵심강좌! Cocos2d-x
이재환 저
예스24 | 애드온2
일본서적 전문사이트 NEPIC