오늘은 네트워크 게임 만드는 방법을 공부했다.
네트워크라니...뭔가 복잡해보이는데
그렇기에 photon서버를 사용하여 따로 서버를 구축할 필요 없이
나름 쉽게 작업을 할 수 있다.
photon서버 구축하는 방법은 생략한다.
photon은 통신을 하는 것이다.
우선 기본적으로 컨트롤 가능한 탱크와 환경을 만든다.
탱크 컨트롤 하는 스크립트는 키입력을 받아서 사용. 간단하여 생략.
오늘 배운 코드 중 제일 어려운 코드는
!!Screen Point to Ray!!를 이용하여서 2차원 좌표를 받아서 3차원좌표를 감지하는 기능을 사용하는 것이었다.
이 코드를 이용하여 마우스의 방향으로 탱크의 헤드가 회전하도록 만들어보았다.
우선 ray를 camera에서 나오도록 생성합니다. Camera.main.ScreenPointToRay
카메라에서 출발하여 마우스 포지션을 향해서 ray를 쏜다.
hit.point는 world좌표이기 때문에 local좌표를 가지고 있는 현재 사물과의 관계에 대한 각도를 구할려고 하면 오차가 일어난다. 그렇기 때문에 InverseTransformPoint 를 사용하여서 현재 게임오브젝트tr을 기준으로 local position을 구해준다.
사이각을 구하는 공식은 aTan(탄젠트의 역함수)를 이용하여서 구한다.
기본 공식은 Mathf.Atan2(localPos.x, localPos.z) * Mathf.Rad2Deg;이다.
현재 위 공식은 localPos.x와 localpos.z 사이의 각을 구하는 것이다.
x와 z의 사이각을 구하고 그 각도 만큼 y축을 돌리면 된다.
!!삼각함수에 대한 부분은 추가적으로 더 공부를 요한다.!! (나중에 책 오면 삼각함수 부분 정리하기)
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class ScreenPointToRay : MonoBehaviour { private Transform tr; public float rotSpeed = 60.0f; private RaycastHit hit; void Start() { tr = GetComponent<Transform>(); } void Update() { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Debug.DrawRay(ray.origin, ray.direction * 50.0f, Color.green); if(Physics.Raycast(ray, out hit, Mathf.Infinity, 1<<9)) { //사이각 구하기 Vector3 localPos = tr.InverseTransformPoint(hit.point); float angle = Mathf.Atan2(localPos.x, localPos.z) * Mathf.Rad2Deg; tr.Rotate(0, angle, 0); } } } | cs |
photon은 resources폴더에 있는 파일을 호출한다.(탱크는 resources파일에 있어 호출 가능.)
계속 동기화가 필요한 부분에 photon의 기본형을 사용한다.
<photon의 기본형>
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 | using Photon.Pun; using Photon.Realtime; using TMPro; public class MoveCtrl : MonoBehaviourPunCallbacks { public TextMeshProUGUI nickName; void Start () { //룸에 들어가서 자기자신이면 camera follow 스크립트가 활성화 되도 if(photonView.IsMine) { Camera.main.GetComponent<SmoothFollow>().target = tr.Find("camPivot").transform; } nickName.text = photonView.Owner.NickName; } void Update () { //remote시키는 객체 if(!photonView.IsMine) { return; } } } | cs |
그리고 계속 동기화시킬 부분에는 photon view와 photon transform view 컴포넌트를 추가한다.
RPC는 send message의 기능을 한다.
(현재 본인 뿐만 아니라 원격으로 존재하는 본인에게도 똑같은 행위를 하도록 명령하는 것.)
동일한 룸 내의 같은 게임오브젝트의 다른 클라이언트를 호출한다.
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; using Photon.Pun; using Photon.Realtime; public class FireCannon : MonoBehaviourPunCallbacks { public Transform firePos; public GameObject cannon; public AudioClip fireSfx; private AudioSource _audio; private void Start() { _audio = this.gameObject.AddComponent<AudioSource>(); } void Update () { if (!photonView.IsMine) return; if(Input.GetMouseButtonDown(0)) { //원격지에 있는 자기 자신에게 총을 쏘도록 photonView.RPC("Fire", RpcTarget.Others, null); //현재 자신이 총을 쏘는 함수 호출 Fire(); } } [PunRPC] void Fire() { _audio.PlayOneShot(fireSfx, 0.8f); Instantiate(cannon, firePos.position, firePos.rotation); } } | cs |
TextMash Pro를 사용하여 상대방의 닉네임 확인하기.
+textmash pro는 한국어나 특수한 외국어를 사용하고 싶을 때 사용한다. 글자 깨짐 현상도 해결해준다.
패키지는 window - textmashpro 에서 import tmp essential과 import tmp examples 두 개를 import 하면된다.
그 후에 font asset creator에서 원하는 폰트를 고른다.
게임 오브젝트에 canvas를 생성하고 panel(배경) 생성 후에 textmeshpro text를 차일드한다.
RectTransform은 0,0으로 바꿔주고 extra padding을 선택해준다.
textmeshpro text를 유저의 닉네임을 보는데 사용하기 위해서는 아래와 같은 코드가 필요하다.
| using TMPro; public class MoveCtrl : MonoBehaviourPunCallbacks { public TextMeshProUGUI nickName; void Start () { nickName.text = photonView.Owner.NickName; } } | cs |
스크립트 작성 후에 textMeshPro Text를 Nick Name으로 끌어다 놓는다.
카메라를 향해서 캔버스 바라보게 만들기(lookat)
| void LateUpdate () { transform.LookAt(Camera.main.transform.position); } | cs |
잘 작동한다! :)
<Reference>
[나중에 게임 서버상에서 다른 사람과 대화할 때 사용가능 함.]
http://loadofprogrammer.tistory.com/168?category=661940