스프라이트 랜더러(Sprite Renderer)의 속성 중의 Sorting Layer의 경우


Sprite의 렌더링 순서를 정의해준다.


물론 Z의 크기값에 따라 조정할 수 있지만, 이것을 사용하면 수치가 아니라 좀 더 간편하게 할 수 있게 된다.


Sprite가 여러 개 있을 때, 


가장 뒤에 있어야 할 Sprite...예를 들면 배경등은 Sorting Layer 가장 상단에 작성하고,


가장 앞에 보여야 할 Sprite...예를 들면 Player등은 Sorting Layer 가장 하단에 작성한다.


이렇게되면 같은 Sprite라고 해도 위에 나오게 된다.


물론 Default가 가장 뒷쪽으로 가게 된다.



예를 들어 1 2 3이 있다고 하자.


1에는 Sorting Layer가 적용되지 않은 Default


2에는 Sorting Layer 첫 번째 Num_01


3에는 Sorting Layer 두 번째 Num_01


즉, 태그는 다음과 같이 생성되어있다.



이렇게 한 뒤, 실행해보자.


2 --> 1로 드래그해보면 1 위에 2가 올라가는 것을 볼 수 있다.



3은 1과 2 모두보다 앞으로 나온다. 실제로 드래그해보면 3밑으로 1과 2가 밑으로 나오는 것을 볼 수 있다.



결론. 1이 가장 밑 < 2가 중간 < 3이 가장 상위에 있는 것을 볼 수 있다.


이처럼 스프라이트(Sprite) 이미지의 레이어 층을 쉽게 만들어주는 것이 바로 Sorting Layer이다.




Posted by sungho88
,

게임 오브젝트를 움직이는 작업을 하다보면, 


화면을 벗어나 우주 공간처럼 끝없이 가게 되는 것을 볼 수 있다.


이때, 화면안에 있도록 제한을 해줘야 하는데 가장 간단하게 구현할 수 있는 것이 바로



Camera.main.WorldToViewportPoint 를 사용하는 것이다.




Transforms position from world space into viewport space.


Parameters:


    position:

Vector3 Camera.WorldToViewportPoint(Vector3 position)



바로 카메라(Camera).WorldToViewportPoint(pos)로 써도 되지만, Camera.main을 쓰는 이유는


MainCamera라는 태그(Tag)가 붙은 첫번째 활성화된 카메라를 불러온다는 뜻이다.


즉, 기본적으로 유니티 프로젝트 생성시 만들어지는 main카메라를 사용하겠다는 의미이다.


WorldToViewportPoint(현재 위치)의 경우 position을 월드 공간에서 뷰포트 공간으로 변경시킨다.


카메라의 좌측 하단은 (0,0 , 0.0)이며, 우측 상단은 (1.0 , 1.0)이다. 


또한, z position은 카메라로부터의 거리를 월드 단위로 환산한 값이다.


따라서,


       Vector3 pos = Camera.main.WorldToViewportPoint(transform.position);


            if (pos.x < 0f) pos.x = 0f;

            if (pos.x > 1f) pos.x = 1f;

            if (pos.y < 0f) pos.y = 0f;

            if (pos.y > 1f) pos.y = 1f;


        transform.position = Camera.main.ViewportToWorldPoint(pos);



렇게 하면, 현재 위치(transform.position)를 pos 변수에 대입하고,


pos.x < 0f 라면 왼쪽 화면 밖으로 나갔다는 의미이므로 아무리 왼쪽으로 이동해도 0.0f

 

pos.x > 1f 라면 오른쪽 화면 밖으로 나갔다는 의미이므로 아무리 오른쪽으로 이동해도 1.0f 


pos.y < 0f 라면 아랫쪽 화면 밖으로 나갔다는 의미이므로 아무리 아래쪽으로 이동해도 0.0f 


pos.y > 0f 라면 윗쪽 화면 밖으로 나갔다는 의미이므로 아무리 윗쪽으로 이동해도 0.0f 



로 조건을 줘서 화면 안에서 못 벗어나게 한다.


그 다음에 다시 뷰포트 공간에서 월드 공간으로 변경시킨 뒤, 현재 위치에 넣으면 된다.


이렇게 한 뒤, 게임을 실행해보면 아무리 애써도 화면을 벗어나지 않고 가장자리까지만 가는 것을 볼 수 있다.




Posted by sungho88
,

짧아서 간단히 작성할 것이라 생각했는데 약 2시간동안 고생했다.


드래그 코드는 이미 내장된 함수가 존재한다.


OnMouseDrag()


이 함수를 호출하여 원하는 코드를 적으면 된다.


일단, 움직이고자 하는 게임오브젝트들에 Drag.cs 파일을 갖다 붙인뒤 Drag.cs파일에 코드를 입력한다.


[Drag.cs]


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

public class Drag : MonoBehaviour
{

float distance = 10;

void OnMouseDrag()
{
print("Drag!!");
Vector3 mousePosition = new Vector3(Input.mousePosition.x,
Input.mousePosition.y, distance);
Vector3 objPosition = Camera.main.ScreenToWorldPoint(mousePosition);
transform.position = objPosition;
}
}


불필요한 Start() 함수와 Update() 함수를 삭제하고 OnMouseDrag()함수만 작성해 간략하게 만들었다.


그런데!! 아무리 해도 함수가 실행되지 않았다.


그래서 혹시나해서 OnMouse로 시작하는 모든 함수를 작성해보았다.


OnMouseEnter

OnMouseExit

OnMouseUp

OnMouseDown

..


모든 마우스 관련 함수가 호출되지 않았다.


고민끝에 혹시나해서 이미지(Sprite)에 Collider를 추가해봤더니 이런 !! 된다.


마우스 관련 함수를 사용하기 위해서는 반드시 


콜라이더를 써야만 한다는 것을 알게 되었다.


위와 같이 쓴 다음에 실행해보면 게임오브젝트가 마우스로 이동하는 것을 볼 수 있다.

 

Posted by sungho88
,

FPS = Frames Per Second(초당 프레임 횟수)


즉, 1초에 출력, 만들어낼 수 있는 프레임 횟수를 뜻한다.


PC의 성능에 따라 FPS는 다를 수밖에 없다.


성능이 뛰어난 컴퓨터는 1초에 100FPS가 날 수도 있고,


후진 고물 컴퓨터는 1초에 5FPS일 수도 있다.


이럴경우, 총싸움을 하면 어떻게 될까?


예를들어, 1초에 100발이 나가는 사람과 1초에 5발이 나가는 사람이 싸운다면?


말이 안된다. 게다가 게임 성능에도 매우 좋지 않다. 큰 리소스를 잡아먹는다.


따라서, 성능에 무관하게 Time.deltatime으로 두 사용자가 동일한 FPS 결과값을 보장하게 한다.



Time.deltaTime의 의미는 다음과 같다.


이전 프레임에서 현재 프레임까지 걸린 시간이다.


만약,


int speed=1; 


void Update(){ 

      shotBullet += speed; 



정리하면, 


슈퍼 컴퓨터는 1초에 1000프레임이라고 가정하자.


그러면 Time.deltaTime는 1/1000(1000분의 1)이다.


이것을 곱하면  1000 * speed * 1/1000 이므로  = speed만 남는다.

 


게임용 일반 컴퓨터는 1초에 80프레임이라고 가정하자.


그러면 Time.deltaTime는 1/80(80분의 1)이다.


이것을 곱하면  80 * speed * 1/80 이므로  = speed만 남는다.



10년이 지난 구린 컴퓨터는 1초에 20프레임이라고 가정하자.


그러면 Time.deltaTime는 1/20(20분의 1)이다.


이것을 곱하면  20 * speed * 1/20 이므로  = speed만 남는다.



결론 : Time.deltaTime을 이용하면, PC의 성능과는 무관하게 동등한 조건이 되게 되므로 반드시 필요하다. 

Posted by sungho88
,

1. GameObject.Find(string name)


GameObject shop = GameObject.Find("Shop");


이렇게하면, Shop이라는 이름을 갖은 게임오브젝트를 찾은 뒤 그 값을 리턴한다.


가장 처음에 나오는 게임오브젝트를 찾아서 반환한다.


이후에는 shop 변수를 통해 게임오브젝트를 조작할 수 있다.


예를 들어 시작했을때, 이 게임오브젝트를 안 보이게... 비활성화시키고 싶다면,


shop.SetActive(false);


를 Start함수에 입력해주면 된다.


또한,


shop.activeSelf을 통해 현재 Object가 어떤 상태인지 확인해볼 수 있다.



bool temp = (shop.activeSelf == true) ? false : true;


이렇게하면, shop.activeSelf를 if 조건문에 넣어


true라면 false로, false라면 true로 토글(Toggle)할 수 있게 된다.



2. GameObject FindGameObjectsWithTag(string tagname)


var t = GameObject.FindGameObjectsWithTag("Player");


이렇게 작성하게 되면, 유니티에서 Player이라고 Tag를 설정한 게임오브젝트들의 리스트를 반환한다.


만약, 발견되지 않으면 null값을 반환한다.


리스트이므로, for문이나 foreach문을 사용하여 처리한다.

s

3. GameObject.FindGameObjectWithTag()


var t = GameObject.FindGameObjectWithTag("Player");


이렇게 하면, Player라는 태그를 갖는 게임오브젝트를 불러온다.


위에 GameObject.FindGameObjectsWithTag("태그명")과 헷갈린다. 뭐가 다른지 한참을 처다봤다.


s 차이다. 복수로 리스트 형태로 가져오느냐, 달랑 하나만 가져오느냐 차이이다.


태그를 여러개 사용시에는 2번을 사용해 리스트로 사용하고, 태그가 하나라면 3번을 사용한다.



4. transform.Find(string name)


Text titleTxt = transform.Find("Title").GetComponent<Text>();


이렇게 하면, Find와 마찮가지로 찾지만, 자식이나 부모 관계에서만 찾는다.


즉, 해당 게임오브젝트의 자식 관계에 있는 Title이라는 게임오브젝트를 찾고 


그 Title에 붙어있는 컴포넌트들 중 Text를 가져온뒤 titleTxt에 저장하는 코드이다.


반면, GameObject.Find("오브젝트명"); 으로 작성할 경우에는 Hierarchy안에서 위에서부터 다 찾는다.





Posted by sungho88
,




인스펙터에서 값을 조정하기 위해서는 기본적으로 public으로 공개를 하고, 변수를 선언했다.


public int Size = 12;


이렇게 작성하면, 유니티 상의 Inspector에서는 


이렇게 나오는 것이 정상(기본)적이었다.

하지만, 그 외에 형태를 바꿔서 Inspector에서 볼 수도 있다.

만약, 슬라이더 형태로 값을 변경하기 위해서는 


[Range(0, 12)]

public int Size = 12;


으로 작성하면 된다.


이렇게 하면,


이렇게 슬라이더로 값을 변경할 수 있게된다.

이렇게 하면, 최소값과 최대값을 제한해놓을 수 있기때문에 유용하다.

만약, 소숫점까지 하고 싶다면,


[Range(0.0f, 12.0f)]

public float Size = 12.0f;


로 변경하면, 소수점 두 자리까지 컨트롤할 수 있게 된다.

Posted by sungho88
,

enum을 선언해도, Inspector에 나타나지 않아 잠시 당황했지만,


간단한 이유때문이었다.


enum의 경우 아래와 같이 class 외부에 작성하므로,


public enum MoveDirection{

Right, Left, Up, Down

}


public class InputManager : MonoBehaviour {



클래스 안에 선언되 있지 않기떄문에 유니티 인스펙터(Inspector) 창에 보이지 않는다.

예제에서는 보였는데 왜 보이지 않을까?

당연하게도 public으로 enum 변수를 선언해주어야 한다.

public class InputManager : MonoBehaviour {
public MoveDirection md;
}


와 같이 작성해주어야 보이게 된다.



Posted by sungho88
,

Random.Range(0, 10);


이라는 명령어를 통해 0부터 9까지의 값들 중 하나를 랜덤으로 생성하게 된다.


중요한 것은 0부터 10이 아니라는 것이다.


매개변수 두 개 중 


시작값인 0은 포함(inclusive)되고, 끝값은 제외(exclusive)된다.


물론 시작값이 0이 아니어도 마찮가지이다.


만약, 1부터 99까지의 값들중에 랜덤으로 값을 만들기 위해서는 다음과 같이 작성하면 된다.


Random.Range(1, 100);


100까지 하고 싶다면, 마지막 값에 +1을 해주는 방식으로 작성해야한다.


/////


float와 int형 두 개의 값을 구할 수 있다. 다른점은



 


float 범위를 구할때는 최대값이 포함되고,

int 범위를 구할때는 최대값이 제외된다.


즉,


Random.Range(0.0, 4.0);  --> 0.0부터 4.0까지의 범위 중 소숫점 임의의 값을 구할 수 있다. 4.0도 포함이다.


Random.Range(0, 4);  --> 0부터 4까지의 범위 중 정수값 중 임의의 값을 구할 수 있다. 4는 제외된다.



 

Posted by sungho88
,

이동을 하기 위해 키보드의 값 또는 마우스의 클릭을 받아야할 때가 있다.

이때 사용하는 문법이 바로 Input클래스이다.

 

        if (Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W))

        {

            anim.Play(walk_up); 

        }

        else if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S))

        {

            anim.Play(walk_down); 

        }


이렇게 작성을 하면, 


위 화살표 키 또는 W키가 눌렸을때, walk_up 애니메이션을 실행하고,

아래 화살표 키 또는 S키가 눌렸을때, walk_down 애니메이션을 실행한다.


Input.GetKeyDown(KeyCode.XX)


이것으로 키보드의 입력을 받아들인다.

그렇다면, 마우스 클릭은 어떻게 받아들일까?


Input.GetMouseButtonDown(0)


이렇게 작성하면 마우스의 클릭 신호를 받는다. 

그런데 괄호안에 0은 무엇을 의미하는 것일까.

바로, 0은 왼쪽 마우스 버튼, 1은 오른쪽 마우스 버튼을 의미한다.


게임할때는 주로 왼쪽을 사용하므로 (0)을 기입하면된다.


Posted by sungho88
,
GameObject Object.Instantiate<GameObject>(GameObject original, Vector3 position, Quaternion rotation)


Instantiate()함수를 사용하면 게임을 실행하는 도중에 게임오브젝트를 생성할 수 있다.

물론 게임이 실행되기 전 미리 만들어놓을 수 있겠지만, 사실상 불가능하다!


만약, RPG 게임이라면 수많은 아이템, 캐릭터, 배경등 모든것들을 어떻게 미리 만들어놓을 수 있을까?

만약, 총을 쏘는 게임이라면 그... 수많은 총알을 어떻게 미리 만들어 놓을 것인가? 

미리 만들어 놓는다는 것은 말도 안된다. 이럴 때는 게임 중에 게임오브젝트를 생성해야 한다.

아니, 생성이 아니라 해당 게임오브젝트의 복제본을 생성한다고 해야 정확할 것이다.

이럴 때 사용하는 함수가 바로 Instantiate() 함수이다. 
ㅇㅣ 함수는 위와 같이 3개의 매개변수를 갖고 있다.


Instantiate(GameObject original ,Vector3 position ,Quaternion rotation)


1. GameObject original

- 생성하고자 하는 게임오브젝트명. 현재 씬에 있는 게임오브젝트나 Prefab으로 선언된 객체를 의미함.


2. Vector3 position

- Vector3으로 생성될 위치를 설정함.


3. Quaternion rotation

- 생성될 게임오브젝트의 회전값을 지정한다. 

- 회전을 굳이 줘야할 상황이 아니라면, 그냥 기본값으로 설정하는 것. --> Quaternion.identity

- 또는 게임오브젝트에서 설정된 회전값. 즉, original.transform.rotation으로 작성해도 됨.


아래와 같이 선언해서 obj라는 게임오브젝트 객체를 동적으로 생성한다.


Instantiate(obj, new Vector3(x,y,z), Quaternion.identity);      // 그냥 회전없음.

또는 

Instantiate(obj, new Vector3(x,y,z), obj.transform.rotation);   // obj의 회전값.


유니티로 돌아와서 실행을 해보면, 해당 게임오브젝트가 복제되고 있음을 볼 수 있다.

어떻게 보냐면, 오브젝트 옆에 괄호로 (clone)이 줄줄이 복제되어 늘어나는 것을 볼 수 있다.

그런데...안 없어진다.

총알을 100번을 날렸다고 가정해보자. 그럼 100개의 총알이 Instantiate에 의해 생성되어 있다는 것이다.


+ 2018/06/08일 내용 추가 & 수정


GameObject UnityEngine.Object.Instantiate<GameObject>(GameObject original, Transform parent)


즉, position과 rotation 설정하지 않고, 특정 하이어라키 위치에서 생성하기 위해 사용할 수 있다.

넣고 싶은 오브젝트를 두 번째 파라미터인 parent에 적어주면 복제 생성시 하위 자식으로 생성된다.



그렇다면, 반대로 Instantiate로 생성한 오브젝트를 제거.삭제하는 함수는 무엇일까?

바로 Destroy()함수이다. Destroy라는 뜻 자체가 파괴하다, 죽이다. 라는 의미이다.


사용방법은 매우 쉽다.

Destroy(GameObject obj);


괄호안에 게임오브젝트 객체를 넣으면 제거된다. 이렇게 호출하면, 그 객체는 곧바로 사라진다.

바로 사라지지 않고 짧은 시간을 지연시킨 후에 오브젝트를 파괴하는 것도 가능하다.


Destroy(GameObject obj, float time);


두 번째 매개변수로 float형 소수를 적어주면, 그 시간만큰 지연 후 사라지도록 할 수 있다.



Posted by sungho88
,