티스토리 뷰

 

 

 

 

 

Player 와 Monster 를 만들어서 기본적인 움직임과 Player 에 Animation 을 넣는 기초적인 작업을 해봤다.

+ 추가적으로 Player 를 기준으로 했을 때 가장 가까운 Monster 를 찾는 기능이랑, 3인칭 카메라 구현도...

따로 글 쓰기 귀찮으니 한 번에 다 때려 넣어야지. 

 

 

 

 

 

 

 

 

[ GIF ]

 

 

 

 

 


[ 코드 ]

 

 

 

 

 

 

1. Player 생성

 

GetComponent 를 사용하지 않기 위해 Player 스크립트를 생성해두고, 해당 스크립트를 이용하여 씬에 Player 를 생성해줬다.

( GetComponent 는 진짜 왠만해선 사용하지 않기. )

Player 관리자 클래스를 만들어서 로드 후 인스턴스를 생성하는 작업.

 

    Player player;

    public void CreatePlayer(string rcname)
    {
    
        GameObject tmp = Resources.Load<GameObject>(rcname);
        GameObject obj = Instantiate<GameObject>(tmp);
        obj.name = "Player";
        player = obj.AddComponent<Player>();
        
    }

 

 

 

 

 

 

 

 

2. Monster 생성

 

Player 생성할 때와 마찬가지로 Monster 스크립트 생성 후 동일하다.

이름은 그냥 랜덤 숫자를 붙여 만든거다.

 

Player 처럼 만들면 ( 0, 0, 0 ) 에 똑같이 위치하게 되니, 좌표를 랜덤으로 찍어줬다.

List<Monster> 로 몬스터들을 넣어 관리할 리스트를 만들어주어서 해당 리스트에 추가해줬다.

 

    List<Monster> mobList = new List<Monster>();
    public Transform mobParent;

    public void CreateMonster(string rcname)
    {
      
      	GameObject tmp = Resources.Load<GameObject>(rcname);
        GameObject obj = Instantiate(tmp);
        obj.transform.SetParent(mobParent);
        obj.name = "Mob_" + Random.Range(0, 100);

        Monster mob = obj.AddComponent<Monster>();

        float x = Random.Range(-7, 7);
        float z = Random.Range(-7, 7);
        obj.transform.position = new Vector3(x, 0, z);

        mobList.Add(mob);

    }

 

 

 

 

 

 

 

 

3. Mouse Picking 에 캐릭터 이동

 

마우스 왼쪽 버튼을 누를 경우 Player 캐릭터가 이동하는 코드이다.

광선(Ray)을 만들어서 움직일 수 있다. 레이어 마스크를 이용하여 캐릭터를 눌러도 캐릭터 뒤쪽으로 통과하여 광선을 쏠 수 있도록 했다.

콜라이더 이름 또는 태그가 Terrain 일 경우로 코드를 짤 수 있는데, 나는 Player를 눌렀을 때로 해서 flag를 두었다. 

이게 더 코드가 길어지니까 그냥 전자 방법으로 하는게 나을 수도 있다.

 

Vector3.MoveTowards 함수를 이용해서 해당 광선이 쏘아진 곳으로 캐릭터가 움직이도록 두었다.

근데 그렇게만 두면 캐릭터가 앞을 보는 상태에서 뒤로 움직이거나, 옆으로 움직일 수가 있어서 캐릭터의 시선을 돌려주도록 해야한다.

 

Vector3.RotateTowards 함수를 이용해서 그 부분을 잡아주었다.

근데 그러려면 목적지를 향한 방향벡터로 일단, 광선의 좌표에서 현재 캐릭터의 좌표를 뺀 벡터를 정규화 시켜주어 사용한다.

 

또 여기까지 하면 캐릭터의 위치에 따라서 바닥까지의 거리와 각도의 차이로 기울임 현상이 발생할 수 있기 때문에, 기울여서 움직이지 않도록 광선의 y좌표와 캐릭터의 y좌표를 똑같이 해주어 움직이도록 한다.

 

 

    Vector3 vEnd = Vector3.zero;
    float moveSpeed = 3f;
    float rotateSpeed = 3f;
    bool bFlag = true;

    void MousePicking()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            int layerMask = 1 << 9;
            layerMask = ~layerMask;

            RaycastHit hitInfo;
            if( Physics.Raycast(ray, out hitInfo, Mathf.Infinity, layerMask))
            {
                if (hitInfo.collider.name == "Player")
                    bFlag = false;
                else
                    bFlag = true;
                vEnd = hitInfo.point;
            }
        }
        if( bFlag)
        {
            player.transform.position = Vector3.MoveTowards(player.transform.position, vEnd,
                                    Time.deltaTime * moveSpeed);
        }

        // 기울임 맞추기
        Vector3 tmp = vEnd;
        tmp.y = player.transform.position.y;

        // 목적지 방향벡터
        Vector3 dir = tmp - player.transform.position;
        Vector3 newDir = Vector3.RotateTowards(player.transform.forward, dir.normalized,
                Time.deltaTime * rotateSpeed, Time.deltaTime * rotateSpeed);
        player.transform.rotation = Quaternion.LookRotation(newDir);
        
    }

 

 

 

 

 

 

 

 

 

 

4. Awake() 함수

 

1, 2번에서 만든 CreatePlayer() 와 CreateMonster() 은 Awake 함수에서 사용했다.

Awake 함수는 Unity 의 Start 보다 순서가 더 먼저 시작한다.

캐릭터는 한 명, 몬스터는 10개를 만들어주었다.

 

    private void Awake()
    {
    
        CreatePlayer("Ekard");

        for (int i = 0; i < 10; i++)
        {
            CreateMonster("StoneMonster");
        }
        
    }

 

 

 

 

 

 

 

 

 

 

 

5. Animator 캐릭터 애니메이션 연동

 

Project 에서 Assets / Character / Models / Animator 에 새로운 Animator 를 만들어준다.

내가 만든 것은 " New Animator " 이다. 더블클릭하면 아래와 같은 창이 뜬다.

이 Animatior 에서 원하는 대로 만들어준다. 내가 만든 것은 여러 애니메이션들 스킵하고 세개로 대충 만든거니까 참고하지는 말았으면..!

 

 

 

 

 

왼쪽 상단에 Parameters 에서 + 버튼을 이용하여 INT 로 Index 를 하나 만들어주었다.

키보드 버튼을 이용해서 애니메이션을 바꿔주려고 만든 인덱스 이다. 

 

 

 

 

 

 

다 만들어주었으면, 사용하던 캐릭터에 원래 쓰이던 Animator 가 아니라 새로 만든 Animator 를 추가해 주어야 한다.

그 후에 각 Animation 들이 Loop 가 되어있지 않으면 한 번 동작하고 더이상 동작을 하지 않으니 Loop 체크를 해준다.

그리고 각 Animation 들끼리 연결되어있는 저 관계 화살표에 만들어둔 인덱스를 이용하는 것을 추가해준다.

내가 한 것은 ' aniIndex - equals - 숫자 ' 로 두었다.

 

 

 

위에서 Parameters 에 만든 인덱스를 C# 스크립트에서 사용한다. 

대충 F1 키를 누르면 Index 를 0 으로.. 그런 기능이다.

이렇게 코드를 짜지 않고, 아래 처럼 enum 열거형 이용해서 해도 좋다.

 

    void Animation()
    {
    
        if (Input.GetKeyDown(KeyCode.F1))
            ani.SetInteger("aniIndex", 0);

        if (Input.GetKeyDown(KeyCode.F2))
            ani.SetInteger("aniIndex", 1);

        if (Input.GetKeyDown(KeyCode.F3))
            ani.SetInteger("aniIndex", 2);
            
    }
    enum eANIPLAYER { NONE = -1, IDLE, WALK, ATTACK };

 

 

 

 

 

 

 

 

 

 

 

6. Update() 함수

 

3, 5번에서 만든 함수들은 계속 렌더링해야하니 Update 함수에서 사용한다.

 

    void Update()
    {
        MousePicking();
        Animation();
    }

 

 

 

 

 

 

 

 

 

 

 

 

7. 3인칭 카메라 구현

 

캐릭터가 움직이면, 카메라가 가만히 있는 것이 아닌 캐릭터가 움직인 방향과 거리만큼 3인칭 (메인) 카메라도 함께 움직이는 코드이다.

 

이 스크립트는 Main Camera 에 넣어둔 스크립트이다.

Player의 이전 좌표를 먼저 구해놓고, deltaPos 라는 이동된 캐릭터의 좌표에서 이전 좌표를 뺀 방향벡터를 구해놓는다.

이후에 카메라의 좌표를 그만큼 이동시킨다.

 

카메라는 Update 함수가 아닌 LateUpdate 함수에서 움직여준다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraManager : MonoBehaviour
{

    public Player player;
    Vector3 prePos;		// 이전 좌표

    void Awake()
    {

    }

    void Start()
    {
        prePos = player.transform.position;
    }

    public void CameraMove()
    {
        Vector3 deltaPos = player.transform.position - prePos;
        transform.position += deltaPos;
        prePos = player.transform.position;
    }

    void Update()
    {
        
    }

    void LateUpdate()
    {
        CameraMove();
    }


}

 

 

 

 

 

 

 

 

 

 

 

 

 

8. 거리에 의한 Monster 식별

 

간단하게, 숫자 배열에서 가장 작은 숫자 찾아내는 방식과 같다.

Vector3.Distance 함수를 이용해서 Monster 와 Player 의 거리를 구하고, 그 거리들 중에서 가장 가까운 거리의 몬스터를 잡아내는 코드이다. 

 

그 다음 Start 함수에서 이 함수를 불러 사용해줬다. 

이거 때문에 위에서 몬스터에게 랜덤의 숫자의 이름을 부여해준 것이었다.

 

    public Monster FindMonsterWithDistance()
    {
    
        float minDistance = Vector3.Distance(mobList[0].transform.position, player.transform.position);
        
        Monster closeMob = mobList[0];

        for(int i=0; i<mobList.Count; i++)
        {
            float dis = Vector3.Distance(mobList[i].transform.position, player.transform.position);
            
            if( minDistance > dis)
            {
                minDistance = dis;
                closeMob = mobList[i];
            }
        }
        
        return closeMob;
        
    }
    void Start()
    {
    
        Monster m = FindMonsterWithDistance();
        Debug.Log(m.name);

    }

 

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

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

Unity : 변환 파이프 라인  (0) 2021.04.11
Unity : Scene 생성 기초  (0) 2021.04.11
Unity : 프로그램 다운로드 (설치)  (0) 2021.03.25
댓글