[이벤트(Event) 시스템(System)]


유저가 웹브라우저에서 DOM 요소들과 상호 작용하는 것을 이벤트(Event)라 부른다.


- 버튼을 클릭했을 때, onclick

- 버튼을 두번 클릭했을 때,

- 버튼에 마우스 커서를 올렸을 때, 

- input 창에 값이 바뀔 때,


등등 수많은 이벤트가 존재한다.


HTML 이벤트와 비교해서 리액트에서 이벤트 사용시 주의 사항


1. camelCase를 사용한다.


HTML에서는 onclick, onkeyup과 같이 소문자로 작성했다. 

하지만, React에서는 camelCase를 쓴다. 

camelCase란 여러 단어가 붙여지는 변수 선언시 첫 단어를 대문자 처리하는 것이다.

onClick, onKeyUp으로 사용한다. 


2. 이벤트에 실행할 자바스크립트 코드를 전달하지 않고, 함수 형태의 값을 전달한다.


HTML에서는 

<button onclick= "alert('Clicked')">클릭</button>와 같이 


onclick 안에 자바스크립트 코드가 들어가지만, React에서는 


 <button onClick= { () => {

            this.setState({

              number: this.state.number+22

            })

          }

        }

        >Plus 22

        </button>


와 같이 함수 형태로 전달한다. 물론, 외부에 미리 함수를 만들어서 전달해도 된다.



3. DOM 요소에서만 이벤트를 설정할 수 있다. 


- 직접 만든 컴포넌트는 이벤트를 자체적으로 설정할 수 없다

- 우리가 만든 컴포넌트에 이벤트를 달게 되면, 이름으로 설정되어 props값을 전달하게 된다.

- 전달받은 props를 컴포넌트 내부의 DOM 이벤트로 설정할 수는 있다.


이벤트 처리 방법


1.함수를 직접 기입하기

<button onClick={() => {
alert('버튼 클릭됨');
}
}>확인</button>


2. 함수를 외부에 선언 후, 함수 호출하기

handleClick = () => {
    alert('handleClicked!!');
}

<button onClick={this.handleClick}>확인</button>



이 코드는 매우 짧아서 못 느끼겠지만,


길어지게 되면 아래 코드가 더욱 간결 & 깔끔하며 가독성이 높아진다는 것을 알 수 있다.



[input 여러 개 핸들링]


인풋이 여러개면, 메소드를 인풋 개수만큼 만들어야할까?


그럼 매우 비효율적일 것이다. 바로 event 객체를 활용하는 것이다.


input의 이름(name)속성을 이용하여 이벤트 핸들러에서 e.target.name을 사용할 수 있다.



 













Posted by sungho88
,

유니티에서 사용하는 모든 UI 요소들은 기본적으로 Canvas안에 위치해야 한다.

캔버스(Canvas)는 Canvas 컴포넌트가 존재하는 게임 오브젝트의 일종이다.


캔버스를 먼저 생성하지 않아도, GameObject - UI 메뉴에서 자신이 원하는 UI (버튼, 이미지, 스크롤뷰 등등...)를


선택하면, 자동으로 Canvas가 생성이 되며, 그 안에 선택한 UI가 자식으로 생성이 된다.


또한, 캔버스(Canvas) 기능을 돕기 위해 EventSystem 오브젝트가 사용되기 때문에 동시에 생성된다.


캔버스(Canvas) 영역은 씬(Scene) 뷰에서 사각형으로 나타나므로 UI요소를 배치하기 용이하다.


캔버스(Canvas)에 있는 UI 요소는 계층 구조에 나타나는 것과 동일한 순서이다.


즉, 첫 번째 자식이 처음... 두 번째 자식이 그 다음으로 그려진다.


다시말하면, 첫 번째 자식이 두 번째 자식에 가려져 안 보이게 된다.


변경을 하고 싶다면 드래그하여 계층 구조에서 순서를 변경하면 된다.


또는 메소드를 사용하여 스크립트로 제어할 수도 있다.


1. Transform.SetAsLastSibling

가장 마지막으로 순서 변경

Move the transform to the end of the local transfrom list.



2. Transform.SetAsFirstSibling

가장 처음으로 순서 변경

Move the transform to the start of the local transfrom list.



3. Transform.SetSiblingIndex

순서 설정(index 값)

Sets the sibling index.



4. Transform.GetSiblingIndex

현재 순서 반환(index 값)

Gets the sibling index.

 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

렌더 모드(Render Mode)

캔버스에는 스크린 공간 또는 월드 공간에 렌더링하도록 하기 위해 사용되는 렌더 모드(Render Mode) 설정이 존재함.


1) 스크린 공간(Screen Space - Overlay)


이 렌더 모드에서는 UI 요소가 화면에서 씬 위에 렌더링된다.

스크린의 크기가 조절되거나 해상도가 변경되면 캔버스는 여기에 맞춰 자동으로 크기를 변경한다.



2) 스크린 공간(Screen Space - Camera)


이 모드는 Screen Space - Overlay 와 유사하지만 
이 렌더 모드에서는 캔버스가 특정 Camera 에서 주어진 거리만큼 앞쪽에 위치한다.
UI 요소는 이 카메라에 의해 렌더링된다. 즉 카메라 설정이 UI의 모습에 영향을 준다. 
카메라가 Perspective 으로 설정되어 있으면 UI 요소는 원근감이 있게 렌더링되며,
원근 왜곡의 정도는 카메라 Field of View 에 의해 조절될 수 있다. 
스크린의 크기가 조절되거나 해상도가 변경되거나 카메라 절두체가 변경되면 캔버스 역시 여기에 맞춰 
자동으로 크기를 변경한다.

3)월드 공간(World Space)


이 렌더 모드에서는 캔버스는 씬에 있는 다른 게임오브젝트처럼 동작한다.

캔버스의 크기는 사각 트랜스폼(Rect Transform)을 사용하여 수동으로 설정할 수 있다. (위 두 개는 수동 설정 불가)

또한 UI 요소는 3D 배치에 기반하여 씬의 다른 오브젝트의 앞 또는 뒤에 렌더링된다.

이 방식은 월드의 일부를 이루도록 의도된 UI에 유용하며 이 방식을 서사적 인터페이스라 부르기도 한다.

Posted by sungho88
,

스프라이트 랜더러(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
,