본문 바로가기
게임 개발/유니티 게임 개발 일지

#8 캐릭터 구현하기 - 일반공격(매직미사일 발사) 구현

by FlowTree 2020. 2. 19.
반응형

구현 목적

1.캐릭터 컨셉(마법사)에 어울리는 일반 공격(매직미사일 발사) 구현하기

 

2.반드시 적중하는 일반 공격(매직 미사일 유도 추적 기능) 구현하기

2.1.왜? 추적 기능이 필요한지? 

  • 조준 보완 장치
    이 게임은 가상패드로 캐릭터를 조종하기 때문에 섬세한 적 조준이 어렵다. 추적 기능을 추가하여 
    가상패드의 조준 기능을 보완한다.
  • 원활한 적 처치와 마나 파밍
    일반 공격이 반드시 적중하여 원활하게 적을 처치하고 드랍하는 마나를 원활하게 파밍한다.
  • 축적된 마나를 통해 스킬 사용 유발(마나 파밍과 스킬 관련 기획의도라서 삭제)
    축적된 마나는 스킬 사용을 유발하고 스킬 사용을 통해 단조로운 플레이(일반공격+회피)에 
    력한 광역 스킬(강력한 한방)을 조합하는 재미를 제공한다.

*유도

1.사람이나 물건을 목적한 장소나 방향으로 이끎 = 안내


*추적

1. 도망하는 사람의 뒤를 밟아서 쫓음

2. 사물의 자취를 더듬어 감

 

매직미사일이 대상을 쫓아가기 때문에 추적이 더 어울림

 

구현할 기능

스크립트 기능 설명

FieldOfView

- 타겟팅 대상 선별

 

Staff

- BasicAttack() 메서드: 일반 공격 입력 시 일반 공격 애니메이션 실행, 타겟팅 대상 바라보기, 이동 제어

- 매직 미사일 발사 위치(GameObject) 설정

- 매직 미사일을 생성할 프리팹(GameObject) 설정

- FieldOfView 스크립트에 접근하여 타겟팅 대상(GameObejct) 정보 가져오기

- 일반 공격 시 캐릭터가 타겟팅 대상 방향으로 바라보기

- 일반 공격 시 캐릭터 이동 비활성화(bCanMove = false) 설정

- Fire(): 일반 공격 애니메이션의 특정 프레임에서 Fire() 실행, 매직 미사일을 생성

- OnCanMove(): 일반 공격 애니메이션이 끝날 때 OnCanMove() 실행하여 이동 활성화(bCanMove = true) 설정

 

MagicMissileMove

- 매직 미사일 변수(속도, 데미지, 사용하는 파티클(GameObejct))

- FieldOfView의 타겟팅 대상 가져오기

- 매직 미사일 이동 기능(rigidbody, transform.forward 이용)

- 매직 미사일 타겟팅 대상 추적 기능

- 매직 미사일 충돌과 소멸 기능(OnCollisionEnter를 이용, VFX 관련 기능이라 잘 모름)

 

매직 미사일(매직 미사일 에셋의 스크립트를 이용함)

  • 마법사 캐릭터가 일반 공격 시 사용하는 공격 마법
  • 외형: 하얀 빛으로 구성된 마법 화살
  • 매직 미사일의 데이터: 발사 위치, 이동 속도, 이동 방향, 소멸 시간, 데미지

 

일반 공격 시 캐릭터가 타겟팅 대상 바라보기 + 이동 비활성화

  • 일반 공격 시 캐릭터가 타겟팅 대상 방향으로 바라보기 
  • 캐릭터의 공격 방향과 날아가는 매직미사일 방향이 다르면 부자연스러워 보이기 때문에
    캐릭터가 타겟팅 대상 방향으로 바라본다.
  • 캐릭터가 일반 공격 중에 이동이 가능해서 부자연스럽다. 일반 공격 중에 이동 비활성화하기

 

매직 미사일 발사

  • 일반 공격 시 일반 공격 애니메이션의 특정 프레임에서 매직 미사일을 발사하기
  • 발사 위치: 캐릭터가 착용한 지팡이의 수정 부분

 

매직 미사일 이동(매직 미사일 에셋의 스크립트를 이용함)

  • 이동 속도

- 매직 미사일의 이동 속도

- 매직 미사일의 공격이 유효할 수 있는 빠른 속도 + 플레이어가 적당히 빠르다는 속도감을 
  느낄 수 있을 정도의 속도

- 테스트를 통해 상세한 값 정할 예정

- 현재는 에셋 기본값 적용 중

- 구체적인 값을 안정해도 되나? 어떤 느낌을 주고 싶은지 적으면 되나? 

 

  • 이동 방향

- 타겟팅 대상이 있을 때 타겟팅 대상 방향으로 날아간다.
- 타겟팅 대상이 없을 때 캐릭터의 전방으로 날아간다.

 

  • 소멸 시간

- 소멸 시간은 매직 미사일이 대상과 충돌을 못했을 때 남아 있는 매직 미사일을 없애기 위해 필요한 시간이다.

- 매직 미사일은 소멸 시간 후 소멸한다.(마법에는 유지 시간이 있음을 보여주는 연출 + 컴퓨터의 연산 낭비 방지?) 

- 소멸 시간은 매직 미사일이 발사되서 스마트폰 화면 밖에서 소멸할 정도의 시간

- 관련 변수를 확인 못했고, 매직 미사일 프리팹, 파티클 시스템과 연관 있는 것 같다.

 

  • 데미지

- 매직 미사일의 데미지(고정 데미지)

- 이전에는 성장 시스템을 구현해서 캐릭터 스텟 + 무기 데미지 + 일반 공격 공식을 적용해서 데미지를 
  구현하려고 했으나 시간 부족, 구현 실력 부족으로 인해 성장 시스템을 제외하고 고정 데미지로 변경함

 

매직 미사일 추적

  • 추적 조건

- 일반 공격 시 선정된 타겟팅 대상이 있을 경우 추적한다.

- 일반 공격 시 선정된 타겟팅 대상이 없을 경우 매직 미사일은 캐릭터의 전방으로 날아간다.

 

  • 추적 규칙

- 타겟팅 대상이 움직여도 추적한다.

- 타겟팅 대상 고정: 매직 미사일 날아가는 도중에 타겟팅 대상이 바뀌지 않는다.

- 추적 도중 타겟팅 대상이 사망하면 해당 방향으로 날아가고 소멸 시간이 지난 후 소멸한다.

 

매직 미사일 소멸(매직 미사일 에셋의 스크립트를 이용함)

- 매직 미사일은 소멸 시간이 지난 후 소멸한다.

- 매직 미사일이 게임 오브젝트(Collider)와 충돌 시 소멸한다.

- 매직 미사일 에셋의 스크립트에 구현되어있음(OnCollisionEnter이용)

 

구현 과정

매직 미사일

  • 마법으로 생성된 화살 느낌이 나도록 마법의 빛으로 이루어진 화살을 생각했는데 유니티 에셋 스토어에 있어서 구매했다.
  • 하얀빛이 나는 화살 프리팹이 비슷하여 이용했다.
  • 에셋에 매직 미사일 구현에 대한 스크립트도 있어서 그대로 이용했다.
  • ParticleSystem과 VFX는 잘 몰라서 에셋을 구매했지만 원하는 스킬을 구현할 때는 공부할 예정,원하는 매직 미사일은 이미 있기 때문에 구매하여 시간 절약!

 

일반 공격 시 캐릭터가 타겟팅 대상 바라보기 + 이동 비활성화

  • 일반 공격 시 캐릭터가 타겟팅 대상 방향을 안 보고 매직 미사일이 날아가서 부자연스러움을 느꼈다.
  • 그래서 캐릭터가 일반 공격 시 타겟팅 대상쪽으로 방향을 돌렸다
  • 구현 도중에 테스트를 하다보니 공격 하면서 이동이 가능한 부분이 신경쓰였다. 상세하게 전투 스타일을 정한 건 아니지만 이동하면서 공격하는 것은 애니메이션이 없어서 부자연스럽기도 했고 게임 난이도가 너무 쉬워지고 캐주얼한 슈팅게임이 되는 것 같았다. 플레이어가 주어진 상황을 판단하고 이동 또는 공격의 선택에서 오는 긴장감을 주고 싶었다. 그래서 이동과 공격의 선택을 위해서 일반 공격 도중 이동 불가 기능을 추가했다.

 

타겟팅 대상 바라보기 + 이동 불가 순서

 

1.캐릭터가 타겟팅 대상쪽으로 방향 돌리기

2.bCanMove(bool)로 이동 제어하기

3.이동 가능 bCanMove = true(기본값)

4.일반 공격 시 bCanMove(bool) = false로 이동 불가 상태로 변경

5.유니티 애니메이션 이벤트로 일반 공격이 끝날 때 bCanMove = true로 바꿔주는 메서드를
  실행하여 이동 가능상태로 변경

6.유니티 애니메이션 이벤트는 아래의 미사일 발사에서 자세히 설명함

7.유니티 애니메이션 이벤트로 일반 공격 애니메이션이 끝날 때 이벤트를 생성(파란색 책갈피)

8.파란색 책갈피 지점에서 Staff 스크립트의 OnCanMove() 메서드를 실행

 

 

매직 미사일 발사

1.발사 위치 생성 및 할당하기

 

Staff 스크립트에서 GameObject 타입으로 firePoint(발사 위치), magicMissilePrefab을 선언한다.

Staff 스크립트를 캐릭터에 할당한다.

 

캐릭터의 지팡이의 수정부분에서 매직 미사일이 발사될 수 있도록 지팡이 오브젝트에서 빈 게임 오브젝트를 생성한다.

이름을 Fire Point로 변경하고, 해당 오브젝트의 위치를 지팡이의 수정부분으로 이동시킨다. 

 

Fire Point 게임 오브젝트를 캐릭터  > 인스펙터 > Staff스크립트의 Fire Point에 할당한다.

Magic Missile Prefab에는 프로젝트 > 매직 미사일 프리팹을 할당한다.

 

 

 

2.일반 공격 메서드 BacsicAttack() 구현 

 

일반 공격과 매직 미사일  플로우

일반 공격과 매직 미사일 구현을 할 때 뭐가 있는지 알기 위해서 간단하게 플로우를 작성하니 이해하기 좋았다.

 

 

BasicAttack()

 

일반 공격 입력 시 BasicAttack() 메서드 실행

일반 공격 애니메이션 실행 playerAnimator.SetTrigger("isBasicAttack");

 

PlayerMovement 스크립트에 접근해서 이동 활성화 변수 bCanMove = false; 해서 이동 비활성화하기

PlayerMovement playerMovement = GameObject.Find("Player").GetComponent(); 
playerMovement.bCanMove = false; //캐릭터 이동 비활성화

 

캐릭터가 타겟팅 대상 방향을 바라보기

this.transform.LookAt(missileTarget.transform);

 

일반 공격 애니메이션의 특정 프레임일 때(지팡이를 앞으로 휘둘렀을 때) Fire() 메서드 실행하기 매직 미사일 생성하기 유니티 애니메이션 이벤트를 이용 Fire() 실행

 

Fire() 메서드에서 Instantiate()를 이용해서  매직 미사일 생성하기

할당된 매직 미사일 프리팹을 인스턴스화하여 생성한다.

magicMissile = Instantiate(magicMissilePrefab, firePoint.transform.position, firePoint.transform.rotation);

 

일반 공격 애니메이션이 끝날 때 OnCanMove() 메서드를 실행해서 bCanMove(bool)을 true하여 이동 활성화하기
(위의 타겟팅 대상 바라보기 + 이동 불가 플로우 참조) 

 

 

 

유니티 애니메이션 이벤트 - 애니메이션 실행 중 특정 프레임에서 메서드 실행하기

1.일반 공격 애니메이션 선택: 일반 공격 애니메이션이 실행 중에 특정 메서드를 실행하기 위해서

 

 

2.인스펙터창 > Animation 선택

 

 

3.Animation을 선택하고 인스펙터창을 아래로 스크롤하면 Events 항목을 볼 수 있음

 

 

4.Events을 터치하면 Events 칸이 열린다. 타임라인에서 원하는 시점을 클릭하면 파란색 책갈피가 생긴다.

애니메이션이 실행할 때 파란색 책갈피가 있는 시점에서 특정 스크립트의 메서드를 실행할 수 있다.

아래는 일반 공격 애니메이션이 실행 도중 파란색 책갈피 시점이 되면 Staff 스크립트에서 Fire() 메서드를 실행한다.

 


매직 미사일 이동과 추적

기본 이동 기능은 에셋의 스크립트에 구현되어 있어서 참고해서 MagicMissileMove 스크립트를 쉽게 작성했다. 
매직 미사일이 이동 중에 타겟팅 대상을 추적해야하므로 해당 기능을 스크립트에 추가했다.

 

FieldOfView에서 선별한 타겟팅 대상을 받아와서 매직 미사일이 실시간으로 그 대상을 추적한다.

Start()에서 매직 미사일이 생성되면 FieldOfView 스크립트에 접근해서 타겟팅 대상을 가져온다.

void Start() //매직 미사일이 처음 생성됐을 때 한번 실행하기 때문에 타겟팅 대상은 고정된다.

FieldOfView fieldOfView = GameObject.Find("Player").GetComponent(); 
//다른 스크립트에 있는 변수 접근, 해당 스크립트가 있는 오브젝트 찾아서 접근 
missileTarget = fieldOfView.targeting; 
//MagicMissileMove는 Staff의 Fire()메서드가 실행되서 매직미사일 오브젝트가 생성되고 공격 당시의 타겟팅 대상 정보를 가져옴

 

이후 FiexdUpdate()에서 매직 미사일이 날아가고, 이동 중에 실시간으로 타겟팅 대상의 위치를 계산하여 해당 방향으로 매직 미사일을 움직인다. 타겟팅 대상이 없을 경우 캐릭터의 전방으로 매직 미사일을 날린다.

void FixedUpdate()

{ 
  if (speed != 0) 
  { 
    if ( missileTarget != null) 
    { 
      rb.velocity = transform.forward * speed; 
      Vector3 targetPos = missileTarget.transform.position - transform.position; 
       //실시간으로 공격 당시의 타겟팅 대상과 매직 미사일의 현재 위치로 방향 벡터를 계산
      transform.rotation = Quaternion.LookRotation(targetPos); 
      //실시간으로 타겟팅 대상 방향으로 매직미사일의 방향을 돌린다.

    } 

    else  //타겟팅 대상이 없을 때 매직 미사일은 전방으로 날아간다.(추적X)
   { 
     rb.velocity = transform.forward * speed; 
    }

 

매직 미사일 소멸

OnCollisionEnter를 이용

에셋 스크립트를 살펴봐도 잘 모르겠다. 일단 패스 스킬 구현할 때 자세히 공부하자.

 void OnCollisionEnter(Collision collision)  //매직미사일이 충돌했을 경우
 { 
        //Lock all axes movement and rotation 
        rb.constraints = RigidbodyConstraints.FreezeAll; 
        speed = 0; 
        //이곳에 데미지 적용 

        //충돌될 경우 연출인 듯?
        ContactPoint contact = collision.contacts[0]; 
        Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal); 
        Vector3 pos = contact.point + contact.normal * hitOffset; 

        if (hit != null) 
        { 
            var hitInstance = Instantiate(hit, pos, rot); 
            if (UseFirePointRotation) { hitInstance.transform.rotation = gameObject.transform.rotation * Quaternion.Euler(0, 180f, 0); } 
            else if (rotationOffset != Vector3.zero) { hitInstance.transform.rotation = Quaternion.Euler(rotationOffset); } 
            else { hitInstance.transform.LookAt(contact.point + contact.normal); } 

            var hitPs = hitInstance.GetComponent(); 
            if (hitPs != null) 
            { 
                Destroy(hitInstance, hitPs.main.duration); 
            } 
            else 
            { 
                var hitPsParts = hitInstance.transform.GetChild(0).GetComponent(); 
                Destroy(hitInstance, hitPsParts.main.duration); 
            } 
        } 
        foreach (var detachedPrefab in Detached) 
        { 
            if (detachedPrefab != null) 
            { 
                detachedPrefab.transform.parent = null; 
            } 
        } 
        Destroy(gameObject); 
    } 
}

완성 영상

https://youtu.be/8HfSXyc-MOQ

스크립트

뭔가 새로운 기능들이 추가될 때마다 기능은 구현할 수 있으나, 코드의 품질은 난잡해지는 것 같다. 확실이 프로그래밍은 기본기가 중요한 것 같다. 코드 최적화...

 

Staff 스크립트

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
 
//Staff를 구현
public class Staff : MonoBehaviour
{
    public PlayerInput playerInput; //PlayerInput 스크립트를 이용하기 위한 컴포넌트 참조변수
    public Animator playerAnimator; // 애니메이터 컴포넌트 참조변수
 
    //스태프
    public GameObject firePoint; //매직미사일이 발사될 위치
    public GameObject magicMissilePrefab; //사용할 매직미사일 할당
 
    /*매직미사일 변수와 데이터는 매직미사일에서 조절? 스태프에서 조절?
    public float damage = 25; //공격력, 사용 안했음
    public float range = 15f; //매직미사일 사거리, 사용 안했음 매직 미사일 프리팹에서 적용 중
    public float projectileSpeed = 15f; //매직미사일 속도, 사용 안했음 매직 미사일 프리팹에서 적용 중
    //개인적으로 이런 수치들은 공식이나 계산을 하고, 그 값을 여러 곳에서 사용할 수 있기 때문에 XML or MySQL 등 DB필요 데이터를 저장하고 불러올 수 있는 데이터베이스가 필요할 것 같다.
    일단은 매직 미사일 고정데미지 적용, 게임 완성 후 업데이트를 한다면 그때 성장 시스템 생각하기
    */
    
    public GameObject missileTarget; //타겟팅 대상의 방향을 계산하기 위해 사용하는 변수
    public GameObject magicMissile; //Instantiate()메서드로 생성하는 매직미사일을 담는 게임오브젝트
 
    public void Start()
    {
        //사용할 컴포넌트 참조 가져오기
        playerInput = GetComponent<PlayerInput>();
        playerAnimator = GetComponent<Animator>();
 
    }
 
    public void FixedUpdate()
    {
        BasicAttack();
        FieldOfView fieldOfView = GameObject.Find("Player").GetComponent<FieldOfView>(); //다른 스크립트에 있는 변수 접근, 해당 스크립트가 있는 오브젝트 찾아서 접근
        missileTarget = fieldOfView.targeting;
    }
 
 
    public void BasicAttack()
    {
        // 입력을 감지하고 BasicAttack 실행
        if (playerInput.basicAttack)
        {
 
            playerAnimator.SetTrigger("isBasicAttack");
            PlayerMovement playerMovement = GameObject.Find("Player").GetComponent<PlayerMovement>();
            playerMovement.bCanMove = false; //캐릭터 이동 비활성화
            if (missileTarget != null)
            {
                this.transform.LookAt(missileTarget.transform);
            }
 
        }
    }
 
    //캐릭터 이동 여부 bool = true, 공격 애니메이션이 끝날 때(애니메이션 이벤트 이용) 함수가 실행된다.
//캐릭터 이동 활성화
    public void OnCanMove()
    {
        PlayerMovement playerMovement = GameObject.Find("Player").GetComponent<PlayerMovement>();
        playerMovement.bCanMove = true;
    }
 
    //일반 공격 애니메이션의 특정 프레임 일 때 Fire()를 실행한다.
    //특정 프레임을 정하는 건 유니티 애니메이션 이벤트로 정할 수 있다.
 
 
    private void Fire()
    {
         magicMissile = Instantiate(magicMissilePrefab, firePoint.transform.position, firePoint.transform.rotation); //Instatiate()로 매직 미사일 프리팹을 복제 생성한다.
    }
    
}
cs

 

 

MagicMissileMove 스크립트

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class MagicMissileMove : MonoBehaviour
{
    public float speed = 15f;
    public float hitOffset = 0f;
    public bool UseFirePointRotation;
    public Vector3 rotationOffset = new Vector3(000);
    public GameObject hit;
    public GameObject flash;
    private Rigidbody rb;
    public GameObject[] Detached;
    public GameObject missileTarget;
    
    //매직 미사일 고정 데미지
    public int magicMissileDamage = 50;
    
 
 
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        FieldOfView fieldOfView = GameObject.Find("Player").GetComponent<FieldOfView>(); //다른 스크립트에 있는 변수 접근, 해당 스크립트가 있는 오브젝트 찾아서 접근
        missileTarget = fieldOfView.targeting; //MagicMissileMove는 Staff의 Fire()메서드가 실행되서 매직미사일 오브젝트가 생성되고 공격 당시의 타겟팅 대상 정보를 가져옴
 
        if (flash != null)
        {
            var flashInstance = Instantiate(flash, transform.position, Quaternion.identity); //Quaternion.identity 회전 없음
            flashInstance.transform.forward = gameObject.transform.forward;
            var flashPs = flashInstance.GetComponent<ParticleSystem>();
            if (flashPs != null)
            {
                Destroy(flashInstance, flashPs.main.duration);   //ParticleSystem의 main.duration, 기본 시간인듯, duration은 따로 값을 정할 수 있음
            }
            else
            {
                var flashPsParts = flashInstance.transform.GetChild(0).GetComponent<ParticleSystem>();
                Destroy(flashInstance, flashPsParts.main.duration);
            }
        }
 
        Destroy(gameObject, 5);
    }
 
    //매직 미사일 이동 기능
    void FixedUpdate()
    {
        if (speed != 0)
        {
            if ( missileTarget != null)
            {
                rb.velocity = transform.forward * speed;
                Vector3 targetPos = missileTarget.transform.position - transform.position; //공격 당시의 타겟팅 대상을 기준으로 방향 벡터를 계산(실시간으로)
                transform.rotation = Quaternion.LookRotation(targetPos); //실시간으로 타겟 방향으로 매직미사일 방향 변경
            }
 
            else
            {
               rb.velocity = transform.forward * speed; //타겟팅 대상이 없을 때 매직 미사일은 전방으로 날아간다
            }
 
        }
    }
 
    //https ://docs.unity3d.com/ScriptReference/Rigidbody.OnCollisionEnter.html
    void OnCollisionEnter(Collision collision)  //매직미사일이 충돌헀을 경우, 잘 모르겠음 좀 더 봐야함
    {
        //Lock all axes movement and rotation
        rb.constraints = RigidbodyConstraints.FreezeAll;
        speed = 0;
        //이곳에 데미지 적용
 
        //충돌될 경우 VFX 연출 구현인듯
        ContactPoint contact = collision.contacts[0];
        Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal);
        Vector3 pos = contact.point + contact.normal * hitOffset;
 
        if (hit != null)
        {
            var hitInstance = Instantiate(hit, pos, rot);
            if (UseFirePointRotation) { hitInstance.transform.rotation = gameObject.transform.rotation * Quaternion.Euler(0, 180f, 0); }
            else if (rotationOffset != Vector3.zero) { hitInstance.transform.rotation = Quaternion.Euler(rotationOffset); }
            else { hitInstance.transform.LookAt(contact.point + contact.normal); }
 
            var hitPs = hitInstance.GetComponent<ParticleSystem>();
            if (hitPs != null)
            {
                Destroy(hitInstance, hitPs.main.duration);
            }
            else
            {
                var hitPsParts = hitInstance.transform.GetChild(0).GetComponent<ParticleSystem>();
                Destroy(hitInstance, hitPsParts.main.duration);
            }
        }
        foreach (var detachedPrefab in Detached)
        {
            if (detachedPrefab != null)
            {
                detachedPrefab.transform.parent = null;
            }
        }
        Destroy(gameObject);
    }
 
}
 
cs

 

다음 구현 목표

  • 적과 적AI 구현하기: 전투 테스트를 위한 적을 구현할 것이다. 반복 테스트로 전투 컨셉을 생각해볼 것이다.
  • 가상패드(이동 패드, 스킬 버튼) 구현하기: 가상패드를 구현해서 전투 테스트를 하고 이거 다음 구현 목표인 스킬 사용을 위해서 스킬 단축키도 구현할 것이다.
반응형

댓글