[RequireComponent(type())]


보통 GetComponent는 대부분 자기 자신의 컴포넌트 중 하나를 가져와 사용한다.


자신에 부착돼있는 컴포넌트를 가져와 사용하려면 기본적으로, 다음과 같이 호출한다.


Rigidbody rigid = GetComponent<Rigidbody>();


보통 이런 목적으로 사용할 때는 Awake나 Start에서 미리 선언한 뒤 사용한다. 


하지만 Rigidbody 컴포넌트의 존재를 보장하지 않는다. 


무슨말이냐면, 실수로 Rigidbody를 게임오브젝트에서 지웠다면 null이 되어 실행 시, 문제가 발생된다.


그래서 엄격히 컴포넌트의 존재를 보장하고 싶을 때 RequireComponent를 사용한다.


사용방법은 다음과 같다. 클래스보다 위에 쓴다는 점. 명심하자.



[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(Collider))]

public class Bullet : MonoBehaviour
{



제법 깔끔하기도 하고 자주 사용하는 방법이다.


이렇게 되면, 이 게임오브젝트는 반드시 Rigidbody와 Collider를 갖고 있어야 한다는 의미이다.


따라서, 위 두 컴포넌트는 삭제할 수 없다. Delete해봐라. 그럼 아래와 같은 창을 볼 수 있다.



Bullet 스크립트가 Box Collide를 요구하고 있기때문에, 이것은 삭제할 수 없게 되므로 에러 발생 확률이 적어진다.






이렇게 인스펙터와 관련된 기능이 많다.



Posted by sungho88
,

01)  유니티 네트워크(Unet) 사용 전 알아야할 개념

02) 유니티 네트워크(Unet) 사용 : NetworkManager

플레이어들 사이에 위치를 네트워크 동기화를 시켜주기 위한 방법에 대해 알아보자.


NetworkTransform가 붙은 오브젝트는 


자기 자신의 위치를 자신의 네트워크 너머에 있는 리모트 플레이어에게 위치를 전달할 수 있다.


즉, 위치를 자동으로 위치를 동기화시켜주는 역할을 한다.


하지만, 다른 클라이언트에게 직접적으로 동기화를 하는 것이 아니라 호스트(방장)을 거쳐가게 된다.


NetworkTransform 컴포넌트에서는 이러한 속성들이 있다.





Transform Sync Mode에는 어떤 것을 동기화할 것인지 설정하는 것으로 다음과 같은 속성이 있다.


테스트하는 것이므로 기본값으로 해보자.


다시 창 2개를 띄우고 접속한 뒤 움직여보자.


로컬 플레이어만 움직이며, 움직이는 모습이 두 창에서 동기화된다.


그런데 여기 문제점이 하나 있다.


Player root 객체는 움직이는데 만약, 계층 구조로 되어 있다면, 이 자식 젝체들은 회전하지 않는다.


그래서, 자동차 같은 경우 바퀴와 차량 본체로 이뤄져 있다면 이동방향과 상관없이 회전하지 않는다.


따라서 이를 위해서 NetworkTransformChild을 사용해야 한다.


주의할 점은 이것을 자식 게임오브젝트에 추가하는 것이 아니라 Player(부모 게임오브젝트)에 컴포넌트로 넣는다.


PlayerCar

ㄴ wheel

ㄴ body


라면 PlayerCar에 NetworkTransformChild를 두 개 추가해준 뒤, 


Target에 wheel과 body를 드래그 & 드롭하면 된다. 이렇게 하면 두 화면 모두 동기화되어 잘 움직인다.






Posted by sungho88
,

네트워크에서 식별을 하기 위해서는 NetworkIdentity가 필요하다.


NetworkManager 개념 설명


유니티 네트워크를 사용하기 위해서는 NetworkManager라는 컴포넌트를 사용하는데,

이 때 NetworkIdentity가 없는 게임 오브젝트는 네트워크 상에서 동기화를 할 수 없다.

왜 동기화를 거절할까?


NetworkIdentity를 붙였다는 것은 서버와 클라이언트 간 이미 약속된 게임오브젝트라는 의미이다.

따라서, NetworkIdentity가 붙지 않았다는 것은 나쁜 짓(버그,핵)을 할 가능성이 있으므로 동기화를 거절한다.


Local Player Authority


컴퓨터 앞에 앉아 있는 캐릭터인 로컬 플레이어의 권한을 갖고 있다.


이렇게 한 뒤, 실행을 해보면 


NetworkManagerHUD에 의해 좌측 상단에 접속할 수 있 버튼이 만들어져있다.


가장 위에 LAN Host(H)를 누르면 Player가 생성된다.


PC로 빌드를 해서 1개를 더 띄운다음에 2번째 것은 LAN Client로 접속한다.


서버 호스트는 이미 만들었으므로. 그러면 플레이어가 두 개가 생성되는 것을 볼 수 있다.


캐릭터를 상하좌우로 움직여보면 


두 캐릭터가 동시에 같은 입력을 받아 움직이는 것을 확인할 수 있다.


그 이유는 이것은 생성된 플레이어가 게임 상에서 로컬 플레이어인지 리모트 플레이어인지 구분을 하지 않는다.


따라서, 스크립트의 모든 내용을 공유하기 때문에 뒤늦게 생성된 게임오브젝트는 리모트 플레이어지만 


로컬 플레이어만 동작해야 할 코드를 같이 적용하게 되는 것이다.


따라서,  로컬 플레이어인지 체크한 뒤에 조작과 관련된 코드의 적용을 통제해야한다.


하지만, 먼저 MonoBehaviour가 아니라 NetworkBehaviour 를 상속해주어야 네트워크 관련 코드를 작성할 수 있다.




Update() 코드에서 조작을 하는 코드 위에 다음과 같이 작성해준다.


        if (!isLocalPlayer)

        {

            return;

        }

 

이렇게되면, 로컬 플레이어가 아니라면 조건문이 true가 되므로 return으로 빠져나가 나 자신만 움직일 수 있게 된다.

Posted by sungho88
,

유니티 네트워크를 사용하기 위해서 가장 중요한 세팅이 바로 NetworkManager를 추가하는 것이다.


NetworkManager는 로컬 플레이어와 리모트 플레이어의 전반적인 동기화를 담당하며 네트워크 통신을 관리해준다.


NetworkManager는 게임 상태 관리, 배치 관리, 씬 관리, 게임 매치 등등 전반적인 프로젝트 상태를 관리하게  된다. 


NetworkManagerHUD는 네트워크 개발 시 프로토타입으로 사용할 때 사용하는 객체로 기본 버튼이 생성된다.


NetworkManager에 플레이어를 등록을 하게 되면, 그 로컬 플레이어로써 게임 상에 탄생을 시킨다.


등록하는 위치는 아래 이미지에서와 같이, Spawn Info - Player Prefab이다.




NetworkManager 생성 방법


1. Create Empty로 빈 GameObject를 생성한다.

2. 된 GameObject의 이름을 NetworkManager로 재정의한다.

3. 해당 GameObject를 선택한 뒤, NetworkManager, NetworkManagerHUD 컴포넌트를 추가한다.

 

추가 방법

Add Component -> Network선택하면 확인할 수 있다.


다시 한번 정리


NetworkManager : 

- 게임의 전체적인 네트워크 상태를 관리 및 제어한다.


NetworkManagerHUD :

-실행시, 네트워크 상태를 조작할 수 있는 간단한 유저 인터페이스를 제공한다.

- 물론, 개발 단계에서 프로토타입 용도로 사용되는 것이며, 게임 출시전에는 제거한 뒤 커스텀해야한다.


Posted by sungho88
,

일단, 출처는 여기다.


4인 멀티 플레이어 게임은 총 몇 명이 존재할까?

당연히, 4명이라고 말하겠지만, 실제로는 16명의 플레이어가 존재한다.

이유는, 4인의 컴퓨터에 각각 4개의 캐릭터가 보이기 때문이다. 즉, 네 개의 게임 세상이 존재한다고 할 수 있다.


A에도 A, B, C, D 캐릭터가

B에도 A, B, C, D 캐릭터가

C에도 A, B, C, D 캐릭터가

D에도 A, B, C, D 캐릭터가 보인다.


따라서, 4*4 총 16개의 플레이어가 보이게 된다.

(물론 인간은 4명이겠지만...여기서 플레이어는 게임 상에서 나타나는 캐릭터를 뜻한다.)



(빨간색 - 로컬 플레이어 / 파란색 - 리모트 플레이어)



1) 로컬 플레이어란?


A라는 플레이어가 하고 있는 게임 상에서는 A캐릭터가 플레이어를 대표한다. 즉, A 세상에서는 A가 주인공이다.

이 대표하는 플레이어를 로컬 플레이어라 부른다. 또는 로컬 클라이언트라고돌 한다.

정리하면,


A 게임 상에서는 A가,  

B 게임 상에서는 B가,  

C 게임 상에서는 C가, 

D 게임 상에서는 D가

로컬 플레이어라고 할 수 있다.


2) 리모트 플레이어란?


반면에,

A 게임 상에서는 B, C ,D는 다른 로컬 플레이어가 아니라 다른 게임 세상에서 (원격으로) 건너온 플레이어이므로

원격 플레이어 또는 리모트 플레이어(Remote Player)라고 부른다. 또는 리모트 클라이언트라고돌 한다.

다른 

정리하면,


A 게임 상에서는 B,C,D 가,  

B 게임 상에서는 A,C,D 가,  

C 게임 상에서는 A,B,D 가, 

D 게임 상에서는 A,B,C 가

리모트 플레이어라고 할 수 있다.


그럼 어떻게 네 개의 게임 세상이 마치 하나의 게임처럼 동기화가 될까?

A의 입장에서는 A 게임 세상에서 A만 실존하는 존재이며, B,C,D 캐릭터는 그냥 보여지는 복제품일 뿐이다.

따라서, A만 컨트롤하고 이동하거나, 총을 쏘거나 하는 움직임이 발생하면 B,C,D에 있는 A에게 동기화를 적용한다.

이렇게 되면 B,C,D에 있는 A는 움직이게 된다. 하지만, 움직이는 주체는 A세상에 있는 A 캐릭터이다.


그렇다고 A가 복제되어 움직이는 것이 아니라 A,B,C,D 세상에 있는 A는 전혀 별개의 게임오브젝트이다.

단지 동기화를 통해 동작을 공유한다. 만약, 동기화가 안 될 경우 A는 각각 다른 행동을 취하게 된다.


서버 - 클라이언트 


서버-클라이언트를 게임에 적용하는 방식은 총 2가지가 있다.


1) 호스트(Host)

  

서버 자체도 한 명의 클라이언트로 참여하는 것이다. 흔히 방장이라고 부른다.

만약 A B C 세명이 멀티플레이어 게임을 한다고 할때 C가 호스트라고 가정하자. 


그러면 A,B,C의 네트워크 동작을 C가 관리하게 된다.

그래서, 위에서처럼 A가 직접 동기화를 시키는 것이 아니라 방장(Host)에게 수정을 요청한다.

그러면 Host가 동기화를 진행 한 뒤, 다른 클라이언트들에게 전파를 해서 동기화를 맞추게 된다.

즉, 어떤 처리를 동작하는 것처럼 보이지만 실제 동작하지 않고 호스트에게 부탁하고 호스트가 처리하게 된다.

결론 : 모든 중요한 처리는 Host가 대신 처리한 뒤, 다른 클라이언트들에게 뿌리는 방식이다.


장점 : 클라이언트가 나쁜 짓(핵,버그)을 할 수가 없다.

클라이언트를 믿지 않고 서버에서 처리하므로 아무리 클라이언트에서 나쁜 짓을 해도 서버에서 무시해버린다. 


단점 : 서버가 모든 일을 다 처리하므로, 동기화 및 통신의 지연시간이 발생할 수 밖에 없다. 

따라서, 총을 쏴도 안 맞는 일 발생. 왜냐하면 서버로 요청하는 순간 상대편이 이동하게 되면- 결국은 빗맞는다.

쏜 사람은 분명 쐈고 명중했다고 생각하는데 데미지를 입지않아 열받는 일이 발생한다.


클라이언트에서 아무리 뭘 열심히 했다고해도 서버에서 일어나지 않는일은 그냥 전혀 없던 일이 된다.


1) Dedicated

호스트 방식과 다른점은,


100% 자원을 서버 역할을 하기 위해 사용한다. 호스트와 다른점은 플레이어로 게임에 참가하지 않는다.

게임에 참여하지 않고 모든 ㅈㅏ원을 게임 서버로 사용하기 때문에 네트워크 품질이 좋아진다.






Posted by sungho88
,

DestroyImmediate를 사용하려고 했는데, 설명에는 다음과 같이 나온다.



Destroys the object obj immediately. You are strongly recommended to use Destroy instead.


즉,


Destroy 함수를 사용할 것을 강력하게 추천한다?


왜?


바로 없애면 좋은 것 아닌가?


하지만, 당장 오브젝트를 제거하는 것이 좋은 것이 아니라 나쁜 것이다.


이 블로그를 참조하자



Posted by sungho88
,
[Header("This is Header Text")]
public float smoothTime = 0.1f;


이렇게 했다면, 



이렇게 굵은 글씨체로 인스펙터(Inspector) 창에 보이게 된다.

이것을 통해


관련이 있는 필드들을 그룹화할 수 있다.


스크립트에서 


[ ]


을 쓰는 경우가 많은 것 같다.


나중에 한 번, 정리해봐야겠다.

Posted by sungho88
,

유니티 창에서 


1. 상단 메뉴 - File - Build Settings하면 Build Settings창이 열린다.


2. Player Setttings... 를 클릭한다.


3. 상단에 Product Name을 변경해주면된다.




이것이 빌드 후, 모바일에 설치될 때 이름이기 때문이다.

Posted by sungho88
,

유니티에서 안드로이드 모바일 폰으로 빌드를 했을 때,


아이콘이 두 개 생성되는 것을 볼 수 있다.


그 이유를 검색해본 결과,


유니티 개발 시 플러그인을 사용하는 경우가 많은데,


안드로이드 매니페스트(AndroidManifast.xml) 파일이 두 개 존재할 경우, 두 개의 아이콘이 생성된다.


자세히 말하면, AndroidManifast.xml 자체가 두 개여서가 아니라,

 


             <intent-filter>

                 <action android:name="android.intent.action.MAIN" />

                 <category android:name="android.intent.category.LAUNCHER" />

             </intent-filter>


위 코드가 존재하면, 메인화면이므로 아이콘이 1개 생성된다. 


기본적으로 아이콘이 만들어지므로, AndroidManifast.xml를 찾아 들어가서, 위 코드를 없애야한다.


이 블로그에서 해답을 찾았다. 



Posted by sungho88
,

클래스


- 연산자 .으로 호출

- 중복 허용.


아이디


- #으로 호출

- 중복 불가(유일한 1개 매칭)



Posted by sungho88
,