실행 이미지
using Photon.Pun;
using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
public class PlayerController : MonoBehaviourPun, IPunObservable
{
[SerializeField] private float speed = 1f;
[SerializeField] private GameObject bombPrefab;
public float moveDistance = 10;
private Animator anim;
private PlayerType playerType;
private Vector3 networkPosition;
private Quaternion networkRotation;
private Vector3 networkScale;
private int networkAnimDir;
private GameObject collidedBomb; // 충돌된 BOMB 오브젝트를 저장할 변수
private float distance;
private float angle;
public enum PlayerType
{
BombGuy,
BigGuy
}
public void Init(PlayerType player)
{
playerType = player;
}
private void Start()
{
anim = this.GetComponentInChildren<Animator>();
networkPosition = transform.position;
networkRotation = transform.rotation;
networkScale = transform.localScale;
networkAnimDir = 0;
if (playerType == PlayerType.BombGuy)
StartCoroutine("CreateBomb");
else
StartCoroutine("AttackBomb");
}
void Update()
{
if (photonView.IsMine)
{
HandleMovement();
}
else
{
// 네트워크 위치, 회전, 스케일로 보간
transform.position = Vector3.Lerp(transform.position, networkPosition, Time.deltaTime * 20);
//transform.rotation = Quaternion.Slerp(transform.rotation, networkRotation, Time.deltaTime * 15);
transform.localScale = networkScale;
anim.SetInteger("dir", networkAnimDir);
}
}
void HandleMovement()
{
float dirX = Input.GetAxisRaw("Horizontal");
var dir = new Vector2(dirX, 0);
transform.localScale = new Vector3(dirX == 0 ? transform.localScale.x : dirX, 1, 1);
anim.SetInteger("dir", (int)dirX);
transform.Translate(new Vector3(dir.x, dir.y, 0) * speed * Time.deltaTime);
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
// 우리가 움직이는 캐릭터라면 현재 위치, 회전, 스케일, 애니메이션 상태를 네트워크로 전송
stream.SendNext(transform.position);
stream.SendNext(transform.rotation);
stream.SendNext(transform.localScale);
stream.SendNext(anim.GetInteger("dir"));
}
else
{
// 네트워크로부터 다른 플레이어의 위치, 회전, 스케일, 애니메이션 상태를 수신
networkPosition = (Vector3)stream.ReceiveNext();
networkRotation = (Quaternion)stream.ReceiveNext();
networkScale = (Vector3)stream.ReceiveNext();
networkAnimDir = (int)stream.ReceiveNext();
}
}
// 트리거 시작 시 호출되는 함수
void OnTriggerEnter2D(Collider2D other)
{
// 충돌된 오브젝트의 태그가 BOMB인지 확인
if (other.gameObject.CompareTag("BOMB") && photonView.IsMine && playerType == PlayerType.BigGuy)
{
Debug.Log("폭탄 충돌 시작");
collidedBomb = other.gameObject;
}
}
// 트리거 종료 시 호출되는 함수
void OnTriggerExit2D(Collider2D other)
{
// 충돌이 종료된 오브젝트의 태그가 BOMB인지 확인
if (other.gameObject.CompareTag("BOMB") && photonView.IsMine && playerType == PlayerType.BigGuy)
{
Debug.Log("폭탄 충돌 해제");
collidedBomb = null;
}
}
IEnumerator CreateBomb()
{
while (true)
{
if (photonView.IsMine && Input.GetKeyDown(KeyCode.Space) && playerType == PlayerType.BombGuy)
{
PhotonNetwork.Instantiate(bombPrefab.name, new Vector3(transform.position.x, -3.46f), Quaternion.identity);
Debug.Log("폭탄 생성");
}
yield return null;
}
}
IEnumerator AttackBomb()
{
while (true)
{
if (Input.GetKeyDown(KeyCode.Space) && playerType == PlayerType.BigGuy)
{
anim.SetTrigger("attackBomb");
Debug.Log("폭탄 날리기");
if (collidedBomb != null)
{
photonView.RPC("MoveBomb", RpcTarget.All, collidedBomb.GetComponent<PhotonView>().ViewID, transform.localScale.x);
}
}
yield return null;
}
}
[PunRPC]
void MoveBomb(int bombViewID, float direction)
{
GameObject bomb = PhotonView.Find(bombViewID).gameObject;
Bomb bombScript = bomb.GetComponent<Bomb>();
bombScript.dir = direction;
bombScript.isMoved = true;
}
}
PlayerController.cs
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
private void Awake()
{
Instance = this;
}
[SerializeField] private GameObject bombGuyPrefab;
[SerializeField] private GameObject bigGuyPrefab;
private void Start()
{
if (PhotonNetwork.IsMasterClient)
{
// bombGuy 만들기
GameObject go = PhotonNetwork.Instantiate(bombGuyPrefab.name, new Vector3(0, -4.37f, 0), Quaternion.identity);
go.GetComponent<PlayerController>().Init(PlayerController.PlayerType.BombGuy);
}
else
{
// bigGuy 만들기
GameObject go = PhotonNetwork.Instantiate(bigGuyPrefab.name, new Vector3(0, -4.37f, 0), Quaternion.identity);
go.GetComponent<PlayerController>().Init(PlayerController.PlayerType.BigGuy);
}
}
}
GameManager.cs
using Photon.Pun;
using System.Collections;
using Unity.VisualScripting;
using UnityEngine;
public class Bomb : MonoBehaviourPun, IPunObservable
{
[SerializeField] float speed = 1f;
private float attenuation = 0.98f;
public bool isMoved = false;
public float dir = 1;
private Vector3 networkPosition;
void Start()
{
}
void Update()
{
if (photonView.IsMine)
{
float speedX = speed;
if (isMoved)
{
// 0.1 유닛씩 이동한다.
this.gameObject.transform.Translate(new Vector3(speedX * dir, 0, 0) * Time.deltaTime);
}
}
else
{
// 네트워크 위치로 보간
transform.position = Vector3.Lerp(transform.position, networkPosition, Time.deltaTime * 10);
}
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
if (stream.IsWriting)
{
// 우리가 움직이는 객체라면 현재 위치를 네트워크로 전송
stream.SendNext(transform.position);
stream.SendNext(isMoved);
stream.SendNext(dir);
}
else
{
// 네트워크로부터 다른 플레이어의 위치와 이동 상태를 수신
networkPosition = (Vector3)stream.ReceiveNext();
isMoved = (bool)stream.ReceiveNext();
dir = (float)stream.ReceiveNext();
}
}
}
Bomb.cs
using Photon.Pun;
using Photon.Realtime;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class LobbyMain : MonoBehaviourPunCallbacks
{
[SerializeField] private string gameVersion;
[SerializeField] private Text statusText;
[SerializeField] private Button joinButton;
// Start is called before the first frame update
void Start()
{
// 마스터 서버 접속
PhotonNetwork.GameVersion = gameVersion;
PhotonNetwork.ConnectUsingSettings();
PhotonNetwork.ConnectUsingSettings(); //마스터 서버 접속 시도
joinButton.interactable = false;
UpdateStatusText("마스터 서버에 접속중");
joinButton.onClick.AddListener(() =>
{
Connect();
});
}
public void Connect()
{
//Join 버튼을 누르면 호출되는 점수
joinButton.interactable = false;
// 마스터 서버 접속죽인가?
if (PhotonNetwork.IsConnected)
{
//랜덤룸 조인
UpdateStatusText("방에 접속중...");
PhotonNetwork.JoinRandomRoom();
}
else
{
//마스터서버에 재접속 시도
ReconnectToMasterServer();
}
}
public override void OnDisconnected(DisconnectCause cause)
{
// 마스터 서버에 접속 실패, 마스터 서버에 접속 되어있는 상태에서 솝속이 끊길떄, 호출되는 콜백
joinButton.interactable = false;
UpdateStatusText("오프라인 : 마스터 서버와 연결이 되지 않음\n접속 재시도중...");
PhotonNetwork.ConnectUsingSettings();
}
public override void OnConnectedToMaster()
{
// 마스터 서버에 접속하면 호출되는 콜백
joinButton.interactable = true;
UpdateStatusText("온라인 : 마스터 서버와 연결됨");
}
private void UpdateStatusText(string v)
{
statusText.text = v;
}
public void ReconnectToMasterServer()
{
UpdateStatusText("오프라인 : 마스터 서버와 연결이 되지 않음\n접속 재시도 중...");
PhotonNetwork.ConnectUsingSettings();
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
// (빈방이 없어서) 랜덤 룸 참가에 실패한 경우. 호출되는 콜백
UpdateStatusText("빈방이 없습니다.\n새로운 방을 생성 중입니다...");
PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = 4 });
}
public override void OnCreatedRoom()
{
//방 생성에 성공 했을때 호출 되는 콜백
UpdateStatusText($"방이 생성되었습니다.");
}
public override void OnJoinedRoom()
{
UpdateStatusText("방에 입장했습니다.");
PhotonNetwork.LoadLevel("Main");
}
}
LobbyMain.cs
'KDT > 네트워크 콘텐츠 제작' 카테고리의 다른 글
[PUN - Photon Unity Networking] Photon Engine 사용해보기 (0) | 2024.06.11 |
---|