Unity 강의/Unity Course(2) - 절대강좌! 유니티
[Unity Course 2] 15. 포톤 클라우드를 활용한 네트워크 게임 5
첨부엉.
2024. 7. 4. 21:52
반응형
위키북스 출판사 이재현 저자님 의 '절대강좌! 유니티' 책을 참고하여 필기한 내용입니다.
배틀 필드 세부기능 구현
접속 정보 및 룸 나가기 기능 구현
해당 룸의 룸 이름과 접속자 수를 표시하고 룸 나가기 버튼을 구현해보기
BattleField 씬으로 전환해서 UI를 다음과 같이 구성하기

GameManager.cs 스크립트 수정하기
더보기
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviourPunCallbacks
{
public TMP_Text roomName;
public TMP_Text connectInfo;
public Button exitBtn;
private void Awake()
{
CreatePlayer();
// 접속 정보 추출 및 표시
SetRoomInfo();
// Exit 버튼 이벤트 연결
exitBtn.onClick.AddListener(() => OnExitClick());
}
void CreatePlayer()
{
// 출현 위치 정보를 배열에 저장
Transform[] points = GameObject.Find("SpawnPointGroup").GetComponentsInChildren<Transform>();
int idx = Random.Range(1, points.Length);
// 네트워크상에 캐릭터 생성
PhotonNetwork.Instantiate("Player",
points[idx].position,
points[idx].rotation,
0);
}
/// <summary>
/// 룸 접속 정보를 출력
/// </summary>
void SetRoomInfo()
{
Room room = PhotonNetwork.CurrentRoom;
roomName.text = room.Name;
connectInfo.text = $"({room.PlayerCount} / {room.MaxPlayers})";
}
/// <summary>
/// Exit 버튼의 OnClick에 연결할 함수
/// </summary>
private void OnExitClick()
{
PhotonNetwork.LeaveRoom();
}
/// <summary>
/// 포톤 룸에서 퇴장했을 때 호출되는 콜백 함수
/// </summary>
public override void OnLeftRoom()
{
SceneManager.LoadScene("Lobby");
}
/// <summary>
/// 룸에서 새로운 네트워크 유저가 접속했을 때 호출되는 콜백 함수
/// </summary>
/// <param name="newPlayer"></param>
public override void OnPlayerEnteredRoom(Player newPlayer)
{
SetRoomInfo();
}
public override void OnPlayerLeftRoom(Player otherPlayer)
{
SetRoomInfo();
}
}
PhotonNetwork.CurrentRoom은 현제 접속한 룸 정보를 나타냄
반환 값은 Room 클래스 타입으로 룸이름, 현재 접속자수, 최대 접속자수 등을 확인 가능
/// <summary>
/// 룸 접속 정보를 출력
/// </summary>
void SetRoomInfo()
{
Room room = PhotonNetwork.CurrentRoom;
roomName.text = room.Name;
connectInfo.text = $"({room.PlayerCount} / {room.MaxPlayers})";
}
버튼과 Text를 각각 연결하기

접속 로그 모니터링

다음과 같이 Pannel 하나를 더 추가하고 디자인하기

Text 를 하나 추가하고 설정은 다음과 같이 한다.
그리고 Pannel-Msg에 Mask 컴포넌트를 추가한다.
GameManager.cs를 다음과 같이 수정한다.
더보기
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviourPunCallbacks
{
public TMP_Text roomName;
public TMP_Text connectInfo;
public TMP_Text msgList;
public Button exitBtn;
private void Awake()
{
CreatePlayer();
// 접속 정보 추출 및 표시
SetRoomInfo();
// Exit 버튼 이벤트 연결
exitBtn.onClick.AddListener(() => OnExitClick());
}
void CreatePlayer()
{
// 출현 위치 정보를 배열에 저장
Transform[] points = GameObject.Find("SpawnPointGroup").GetComponentsInChildren<Transform>();
int idx = Random.Range(1, points.Length);
// 네트워크상에 캐릭터 생성
PhotonNetwork.Instantiate("Player",
points[idx].position,
points[idx].rotation,
0);
}
/// <summary>
/// 룸 접속 정보를 출력
/// </summary>
void SetRoomInfo()
{
Room room = PhotonNetwork.CurrentRoom;
roomName.text = room.Name;
connectInfo.text = $"({room.PlayerCount} / {room.MaxPlayers})";
}
/// <summary>
/// Exit 버튼의 OnClick에 연결할 함수
/// </summary>
private void OnExitClick()
{
PhotonNetwork.LeaveRoom();
}
/// <summary>
/// 포톤 룸에서 퇴장했을 때 호출되는 콜백 함수
/// </summary>
public override void OnLeftRoom()
{
SceneManager.LoadScene("Lobby");
}
/// <summary>
/// 룸에서 새로운 네트워크 유저가 접속했을 때 호출되는 콜백 함수
/// </summary>
/// <param name="newPlayer"></param>
public override void OnPlayerEnteredRoom(Player newPlayer)
{
SetRoomInfo();
string msg = $"\n<color=#00ff00>{newPlayer.NickName}</color> is joined room";
msgList.text += msg;
}
public override void OnPlayerLeftRoom(Player otherPlayer)
{
SetRoomInfo();
string msg = $"\n<color=#ff0000>{otherPlayer.NickName}</color> is left room";
msgList.text += msg;
}
}
ActorNumber 활용
여러 명의 유저가 접속해 서로 전투를 벌이다가 사망했을 때 누구에 의해 사망했는지 알아야됨
RPC로 호출된 FireBullet 함수에서 생성한 Bullet 에 룸에 접속한 네트워크 유저의 고유 번호인 ActorNumber 를 저장하여 확인 가능
Bullet.cs를 다음과 같이 수정
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public GameObject effect;
// 총알을 발사한 플레이어의 고유 번호
public int actorNumber;
private void Start()
{
GetComponent<Rigidbody>().AddRelativeForce(Vector3.forward * 1000.0f);
// 일정 시간이 지난 후 총알을 삭제
Destroy(this.gameObject, 3.0f);
}
private void OnCollisionEnter(Collision coll)
{
// 충돌 지점 추출
var contact = coll.GetContact(0);
// 충돌 지점에 스카프 이펙트 생성
var obj = Instantiate(effect,
contact.point,
Quaternion.LookRotation(-contact.normal));
Destroy(obj, 2.0f);
Destroy(this.gameObject);
}
}
총알을 발사하는 스크립트에서 총알을 발사하는 네트워크 고유 번호인 ActorNumber를 설정
Fire.cs 스크립트를 다음과 같이 수정
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
public class Fire : MonoBehaviour
{
public Transform firePos;
public GameObject bulletPrefab;
private ParticleSystem muzzleFlash;
private PhotonView pv;
// 왼쪽 마우스 버튼 클릭 이벤트 저장
private bool isMouseClick => Input.GetMouseButtonDown(0);
private void Start()
{
// 포톤뷰 컴포넌트 연결
pv = GetComponent<PhotonView>();
// FirePos 하위에 있는 총구 화염 효과 연결
muzzleFlash = firePos.Find("MuzzleFlash").GetComponent<ParticleSystem>();
}
private void Update()
{
// 로컬 유저 여부와 마우스 왼쪽 버튼을 클릭했을 때 총알을 발사
if(pv.IsMine && isMouseClick)
{
FireBullet(pv.Owner.ActorNumber);
// RPC로 원격지에 있는 함수를 호출
pv.RPC("FireBullet", RpcTarget.Others, pv.Owner.ActorNumber);
}
}
[PunRPC]
void FireBullet(int actorNo)
{
// 총구 화염 효과가 실행 중이 아닌 경우에 총구 화염 효과 실행
if (!muzzleFlash.isPlaying) muzzleFlash.Play(true);
GameObject bullet = Instantiate(bulletPrefab,
firePos.position,
firePos.rotation);
bullet.GetComponent<Bullet>().actorNumber = actorNo;
}
}
피격 당했을 때 충돌한 총알의 ActorNumber 를 활용하여 어떤 네트워크 유저가 발사한 총알인지 확인하기 위해
Damage.cs를 다음과 같이 수정
더보기
using System.Collections;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using Player = Photon.Realtime.Player;
public class Damage : MonoBehaviourPunCallbacks
{
// 사망 후 투명 처리를 위한 MeshRenderer 컴포넌트의 배열
private Renderer[] renderers;
// 캐릭터의 초기 생명치
private int initHp = 100;
// 캐릭터의 현재 생명치
public int currHp = 100;
private Animator anim;
private CharacterController controller;
// 애니메이터 뷰에 생성한 파라미터의 해시값 추출
private readonly int hashDie = Animator.StringToHash("Die");
private readonly int hashRespawn = Animator.StringToHash("Respawn");
private GameManager gameManager;
private void Awake()
{
// 캐릭터 모델의 모든 Renderer 컴포넌트를 추출한 후 배열에 할당
renderers = GetComponentsInChildren<Renderer>();
anim = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
// 현재 생명치를 초기 생명치로 초깃값 설정
currHp = initHp;
gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
}
private void OnCollisionEnter(Collision coll)
{
// 생명 수치가 0보다 크고 충돌체의 태그가 CULLET인 경우에 생명 수치를 차감
if(currHp > 0 && coll.collider.CompareTag("BULLET"))
{
currHp -= 20;
if(currHp<=0)
{
// 자신의 PhotonView 일 때만 메세지를 출력
if(photonView.IsMine)
{
// 총알의 ActorNumber를 추출
var actorNo = coll.collider.GetComponent<Bullet>().actorNumber;
// ActorNumber로 현재 룸에 입장한 플레이어를 추출
Player lastShootPlayer = PhotonNetwork.CurrentRoom.GetPlayer(actorNo);
// 메세지 출력을 위한 문자열 포맷
string msg = string.Format("\n<color=#00ff00>{0}</color> is killed by <color=#ff0000>{1}</color>",
photonView.Owner.NickName,
lastShootPlayer.NickName);
photonView.RPC("KillMessage", RpcTarget.AllBufferedViaServer, msg);
}
StartCoroutine(PlayerDie());
}
}
}
[PunRPC]
void KillMessage(string msg)
{
// 메세지 출력
gameManager.msgList.text += msg;
}
IEnumerator PlayerDie()
{
// CharacterController 컴포넌트 비활성화
controller.enabled = false;
// 리스폰 비활성화
anim.SetBool(hashRespawn, false);
// 캐릭터 사망 애니메이션 실행
anim.SetTrigger(hashDie);
yield return new WaitForSeconds(3.0f);
// 리스폰 활성화
anim.SetBool(hashRespawn, true);
// 캐릭터 투명 처리
SetPlayerVisible(false);
yield return new WaitForSeconds(1.5f);
// 생성 위치를 재조정
Transform[] points = GameObject.Find("SpawnPointGroup").GetComponentsInChildren<Transform>();
int idx = Random.Range(1, points.Length);
transform.position = points[idx].position;
// 리스폰 시 생명 초깃값 설정
currHp = 100;
// 캐릭터를 다시보이게 처리
SetPlayerVisible(true);
// CharacterController 컴포넌트 활성화
controller.enabled = true;
}
// Renderer 컴포넌트를 활성 / 비활성화 하는 함수
void SetPlayerVisible(bool isVisible)
{
for(int i =0; i<renderers.Length; i++)
{
renderers[i].enabled = isVisible;
}
}
}
빌드한 후 실행하게 되면 KillMessage 함수가 실행되면서 다음과 같이 메세지가 표시됨
반응형