[24.04.15]Unity - Multiplay Mini Game

손지·2024년 4월 16일
0

Unity

목록 보기
36/44

과제 목록
1. 타이틀 화면
2. 접속후 필요한 인원수가 채워질때대기
3. 인원이 다 채워지면 카운트다운 후 게임 시작
4. 아이템 등등 만들기
5. 장애물 제작
6. 죽으면 관전 모드
7. 게임이 끝나면 순위 보여주기

타이틀 화면

카운트다운

아이템 생성 및 적용

원래 기본이동속도가 3이지만 아이템을 먹고 4로

늘어난걸 볼수있다.

Bullet.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Photon.Pun;


public class Bullet : MonoBehaviourPun
{
   private bool isShoot = false;
   private Vector3 direction = Vector3.zero;
   
   private float duration = 5.0f;
   private GameObject owner = null;
   public float bulletSpeed = 10.0f;
   private void Update()
   {
       if (isShoot)
       {
           this.transform.Translate(direction * bulletSpeed * Time.deltaTime);
       }
   }

   public void Shoot(GameObject _owner, Vector3 _dir, float _bspeed)
   {
       owner = _owner;
       direction = _dir;
       bulletSpeed += _bspeed;
       isShoot = true;

       

       Invoke("SelfDestroy", duration);
   }

   private void SelfDestroy()
   {
       PhotonNetwork.Destroy(this.gameObject);
   }

   private void OnTriggerEnter(Collider other)
   {
       if (!photonView.IsMine) return;

       if( owner != other.gameObject &&
           other.CompareTag("Player"))
       {
           other.GetComponent<PlayerCtrl>().OnDamage(1);
           SelfDestroy();
       }
   }
}

BulletSpeedUpitem.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BulletSpeedUpitem : MonoBehaviour
{
   [SerializeField] private PlayerCtrl player = null;

   private void Awake()
   {
       player = GetComponent<PlayerCtrl>();
   }

   private void OnTriggerEnter(Collider _other)
   {
       if (_other.CompareTag("Player"))
       {
           _other.GetComponent<PlayerCtrl>().AddBulletSpeed(1f);
           Destroy(gameObject);
       }
   }
}

GamaManager.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Photon.Pun;
using Photon.Realtime;
using UnityEngine.SceneManagement;

using UnityEngine.UI;
using TMPro;
using System.Text;

public class GameManager : MonoBehaviourPunCallbacks
{
   [SerializeField] private GameObject playerPrefab = null;
   [SerializeField] private GameObject[] itemPrefab = null;
   [SerializeField] private GameObject rangeObject;
   [SerializeField] private BoxCollider rangeCollider;
   [SerializeField] private GameObject[] itemPrefabs;
   [SerializeField]private Button startButton = null;
   [SerializeField]private TextMeshProUGUI playerListText = null;    
   [SerializeField] private TMP_Text countdownText;
   private GameObject[] playerGoList = new GameObject[4];
   private float startTime;
   private GameObject go = null;
   private int isDead = 0;

   Vector3 Return_RandomPosition()
   {
       Vector3 originPosition = rangeObject.transform.position;
       float range_X = rangeCollider.bounds.size.x;
       float range_Z = rangeCollider.bounds.size.z;

       range_X = Random.Range((range_X / 2) * -1, range_X / 2);
       range_Z = Random.Range((range_Z / 2) * -1, range_Z / 2);
       Vector3 RandomPostion = new Vector3(range_X, 0f, range_Z);

       Vector3 respawnPosition = originPosition + RandomPostion;
       return respawnPosition;
   }

   IEnumerator RandomRespawn_Coroutine()
   {
       while (true)
       {
           yield return new WaitForSeconds(1f);

           // Randomly select one of the item prefabs from the array
           GameObject randomPrefab = itemPrefabs[Random.Range(0, itemPrefabs.Length)];

           // Instantiate the selected prefab at a random position
           GameObject instantiatedItem = Instantiate(randomPrefab, Return_RandomPosition(), Quaternion.identity);
       }
   }


   private void Awake()
   {
       rangeCollider = rangeObject.GetComponent<BoxCollider>();
       if (PhotonNetwork.IsMasterClient)
       {
           startButton.onClick.AddListener(() =>
           {
               photonView.RPC("SpawnPlayer", RpcTarget.All, null);
               startButton.gameObject.SetActive(false);
           });
       }
       startButton.gameObject.SetActive(false);
   }

   private void Update()
   {
       Debug.Log(isDead);
   }
   [PunRPC]
   private IEnumerator StartGame()
   {
       countdownText.text = "3";
       startTime = Time.realtimeSinceStartup;
       yield return new WaitForSecondsRealtime(1);
       countdownText.text = "2";
       yield return new WaitForSecondsRealtime(1);
       countdownText.text = "1";
       yield return new WaitForSecondsRealtime(1);
       countdownText.text = "GO!";
       yield return new WaitForSecondsRealtime(1);
       countdownText.gameObject.SetActive(false);
       Time.timeScale = 1f; // 게임 시작
       StartCoroutine(RandomRespawn_Coroutine());

   }


[PunRPC]
   private void SpawnPlayer()
   {
       if (playerPrefab != null)
       {
           if (countdownText != null)
           {
               StartCoroutine(StartGame());
               Time.timeScale = 0f; //게임 정지   
           }
           GameObject go = PhotonNetwork.Instantiate(
               playerPrefab.name,
               new Vector3(
                   Random.Range(-10.0f, 10.0f),
                   0.0f,
                   Random.Range(-10.0f, 10.0f)),
               Quaternion.identity,
               0);
           //go.GetComponent<PlayerCtrl>().SetMaterial(photonView.Owner.ActorNumber - 1);
       }
   }

   // PhotonNetwork.LeaveRooom 함수가 호출되면 호출
   public override void OnLeftRoom()
   {
       Debug.Log("Left Room");

       SceneManager.LoadScene("Launcher");
   }

   // 플레이어가 입장할 때 호출되는 함수
   public override void OnPlayerEnteredRoom(Player otherPlayer)
   {
       Debug.LogFormat("Player Entered Room: {0}",
                       otherPlayer.NickName);

       // 누군가 접속하면 전체 클라이언트에서 함수 호출
       //photonView.RPC("ApplyPlayerList", RpcTarget.All);

       photonView.RPC("ApplyPlayerListText", RpcTarget.All);

       if (PhotonNetwork.CurrentRoom.PlayerCount == PhotonNetwork.CurrentRoom.MaxPlayers &&
           PhotonNetwork.IsMasterClient)
       {
           startButton.gameObject.SetActive(true);
       }
   }

   [PunRPC]
   public void ApplyPlayerListText()
   {
       StringBuilder sb = new StringBuilder();
       
       sb.AppendLine(PhotonNetwork.CurrentRoom.PlayerCount + " / " + PhotonNetwork.CurrentRoom.MaxPlayers);
       
       Dictionary<int, Player> players = PhotonNetwork.CurrentRoom.Players;
       for (int i = 0; i < PhotonNetwork.CurrentRoom.PlayerCount; ++i)
       {
           sb.AppendLine(players[i + 1].NickName);
       }
       
       playerListText.text = sb.ToString();
   }

   //[PunRPC]
   //public void ApplyPlayerList()
   //{
   //    // 현재 방에 접속해 있는 플레이어의 수
   //    Debug.LogError("CurrentRoom PlayerCount : " + PhotonNetwork.CurrentRoom.PlayerCount);

   //    // 현재 생성되어 있는 모든 포톤뷰 가져오기
   //    PhotonView[] photonViews = FindObjectsOfType<PhotonView>();

   //    // 매번 재정렬을 하는게 좋으므로 플레이어 게임오브젝트 리스트를 초기화
   //    System.Array.Clear(playerGoList, 0, playerGoList.Length);

   //    // 현재 생성되어 있는 포톤뷰 전체와
   //    // 접속중인 플레이어들의 액터넘버를 비교해,
   //    // 액터넘버를 기준으로 플레이어 게임오브젝트 배열을 채움
   //    for (int i = 0; i < PhotonNetwork.CurrentRoom.PlayerCount; ++i)
   //    {
   //        // 키는 0이 아닌 1부터 시작
   //        int key = i + 1;
   //        for (int j = 0; j < photonViews.Length; ++j)
   //        {
   //            // 만약 PhotonNetwork.Instantiate를 통해서 생성된 포톤뷰가 아니라면 넘김
   //            if (photonViews[j].isRuntimeInstantiated == false) continue;
   //            // 만약 현재 키 값이 딕셔너리 내에 존재하지 않는다면 넘김
   //            if (PhotonNetwork.CurrentRoom.Players.ContainsKey(key) == false) continue;

   //            // 포톤뷰의 액터넘버
   //            int viewNum = photonViews[j].Owner.ActorNumber;
   //            // 접속중인 플레이어의 액터넘버
   //            int playerNum = PhotonNetwork.CurrentRoom.Players[key].ActorNumber;

   //            // 액터넘버가 같은 오브젝트가 있다면,
   //            if (viewNum == playerNum)
   //            {
   //                // 실제 게임오브젝트를 배열에 추가
   //                playerGoList[playerNum - 1] = photonViews[j].gameObject;
   //                // 게임오브젝트 이름도 알아보기 쉽게 변경
   //                playerGoList[playerNum - 1].name = "Player_" + photonViews[j].Owner.NickName;
   //            }
   //        }
   //    }

   //    // 디버그용
   //    PrintPlayerList();
   //}

   //private void PrintPlayerList()
   //{
   //    foreach(GameObject go in playerGoList)
   //    {
   //        if (go != null)
   //        {
   //            Debug.LogError(go.name);
   //        }
   //    }
   //}

   // 플레이어가 나갈 때 호출되는 함수
   public override void OnPlayerLeftRoom(Player otherPlayer)
   {
       Debug.LogFormat("Player Left Room: {0}",
                       otherPlayer.NickName);
   }

   public void LeaveRoom()
   {
       Debug.Log("Leave Room");

       PhotonNetwork.LeaveRoom();

       startButton.gameObject.SetActive(true);
   }

   public void SetDead(int _int)
   {
       isDead += _int;
   }
}

PhotonLauncher.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;


// Photon.PunBehaviour 사용안함
public class PhotonLauncher : MonoBehaviourPunCallbacks
{
   [SerializeField] private string gameVersion = "0.0.1";
   [SerializeField] private byte maxPlyaerPerRoom = 4;

   [SerializeField] private string nickName = string.Empty;

   [SerializeField] private Button connectButton = null;


   private void Awake()
   {
       // 마스터가 PhotonNetwork.LoadLevel()을 호출하면,
       // 모든 플레이어가 동일한 레벨을 자동으로 로드
       PhotonNetwork.AutomaticallySyncScene = true;
   }

   private void Start()
   {
       connectButton.interactable = true;
   }

   // Connect Button이 눌러지면 호출
   public void Connect()
   {
       if(string.IsNullOrEmpty(nickName))
       {
           Debug.Log("NickName is empty");
           return;
       }

       if (PhotonNetwork.IsConnected)
       {
           PhotonNetwork.JoinRandomRoom();
       }
       else
       {
           Debug.LogFormat("Connect : {0}", gameVersion);

           PhotonNetwork.GameVersion = gameVersion;
           // 포톤 클라우드에 접속을 시작하는 지점
           // 접속에 성공하면 OnConnectedToMaster 메서드 호출
           PhotonNetwork.ConnectUsingSettings();
       }
   }

   // InputField_NickName과 연결해 닉네임을 가져옴
   public void OnValueChangedNickName(string _nickName)
   {
       nickName = _nickName;

       // 유저 이름 지정
       PhotonNetwork.NickName = nickName;
   }

   public override void OnConnectedToMaster()
   {
       Debug.LogFormat("Connected to Master: {0}", nickName);
       
       connectButton.interactable = false;

       PhotonNetwork.JoinRandomRoom();
   }

   public override void OnDisconnected(DisconnectCause cause)
   {
       Debug.LogWarningFormat("Disconnected: {0}", cause);

       connectButton.interactable = true;

       // 방을 생성하면 OnJoinedRoom 호출
       Debug.Log("Create Room");
       PhotonNetwork.CreateRoom(
           null,
           new RoomOptions {
               MaxPlayers = maxPlyaerPerRoom });
   }

   public override void OnJoinedRoom()
   {
       Debug.Log("Joined Room");

       // 마스터가 동시에 게임을 시작하게하는 구조가 아니기 때문에 각자 씬을 부르면 됨
       //PhotonNetwork.LoadLevel("Room");
       SceneManager.LoadScene("Room");
   }

   public override void OnJoinRandomFailed(short returnCode, string message)
   {
       Debug.LogErrorFormat("JoinRandomFailed({0}): {1}", returnCode, message);

       connectButton.interactable = true;

       Debug.Log("Create Room");
       PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = maxPlyaerPerRoom });
   }
}

PlayerCtrl.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Photon.Pun;


public class PlayerCtrl : MonoBehaviourPun
{
   private Rigidbody rb = null;
   [SerializeField] private GameObject bulletPrefab = null;
   [SerializeField] private Color[] colors = null;
   [SerializeField] private float speed = 3.0f;
   private float addBulletSpeed = 0f;
   [SerializeField]private GameManager go = null;


   private int hp = 3;
   private bool isDead = false;
   public bool isActive = false;

   private void Awake()
   {
       rb = this.GetComponent<Rigidbody>();
   }

   private void Start()
   {
       isDead = false;

       this.GetComponent<MeshRenderer>().material.color = colors[photonView.Owner.ActorNumber - 1];
       
   }


   private void Update()
   {
       if (!photonView.IsMine) return;
       if (isDead)
       {
           Debug.Log(isDead);
       };

       if (Input.GetKey(KeyCode.W))
           rb.AddForce(Vector3.forward * speed);
       if (Input.GetKey(KeyCode.S))
           rb.AddForce(Vector3.back * speed);
       if (Input.GetKey(KeyCode.A))
           rb.AddForce(Vector3.left * speed);
       if (Input.GetKey(KeyCode.D))
           rb.AddForce(Vector3.right * speed);

       if (Input.GetMouseButtonDown(0)) ShootBullet();
       LookAtMouseCursor();



   }

   private void OnBecameInvisible()
   { 
       {
           // 화면 밖으로 벗어나면 반대편으로 순간이동
           Vector3 viewportPosition = Camera.main.WorldToViewportPoint(transform.position);

           if (viewportPosition.x < 0f) // 왼쪽에서 나갔을 때
           {
               transform.position = Camera.main.ViewportToWorldPoint(new Vector3(1f, viewportPosition.y, viewportPosition.z));
           }
           else if (viewportPosition.x > 1f) // 오른쪽에서 나갔을 때
           {
               transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0f, viewportPosition.y, viewportPosition.z));
           }
           else if (viewportPosition.y < 0f) // 아래에서 나갔을 때
           {
               transform.position = Camera.main.ViewportToWorldPoint(new Vector3(viewportPosition.x, 1f, viewportPosition.z));
           }
           else if (viewportPosition.y > 1f) // 위에서 나갔을 때
           {
               transform.position = Camera.main.ViewportToWorldPoint(new Vector3(viewportPosition.x, 0f, viewportPosition.z));
           }
       }

   }
   public void SetMaterial(int _playerNum)
   {
       Debug.LogError(_playerNum + " : " + colors.Length);
       if (_playerNum > colors.Length) return;

       this.GetComponent<MeshRenderer>().material.color = colors[_playerNum - 1];
   }

   private void ShootBullet()
   {
       if (bulletPrefab)
       {
           GameObject go = PhotonNetwork.Instantiate(
               bulletPrefab.name,
               this.transform.position,
               Quaternion.identity);
           go.GetComponent<Bullet>().Shoot(this.gameObject, this.transform.forward, addBulletSpeed);
       }
   }

   public void LookAtMouseCursor()
   {
       Vector3 mousePos = Input.mousePosition;
       Vector3 playerPos = Camera.main.WorldToScreenPoint(this.transform.position);
       Vector3 dir = mousePos - playerPos;
       float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
       this.transform.rotation = Quaternion.AngleAxis(-angle + 90.0f, Vector3.up);
   }

   [PunRPC]
   public void ApplyHp(int _hp)
   {
       hp = _hp;
       Debug.LogErrorFormat("{0} Hp: {1}",
           PhotonNetwork.NickName,
           hp
           );

       if (hp <= 0)
       {
           Debug.LogErrorFormat("Destroy: {0}", PhotonNetwork.NickName);
           go.GetComponent<GameManager>().SetDead(1);
           isDead = true;
           PhotonNetwork.Destroy(this.gameObject);
       }
   }

   [PunRPC]
   public void OnDamage(int _dmg)
   {
       hp -= _dmg;
       photonView.RPC("ApplyHp", RpcTarget.Others, hp);
   }

   [PunRPC]
   public void AddSpeed(float _speed)
   {
       speed += _speed;
   }

   [PunRPC]
   public void AddBulletSpeed(float _speed)
   {
      addBulletSpeed += _speed;
   }

}

SpeedUpItem.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpeedUpItem : MonoBehaviour
{
    [SerializeField] private PlayerCtrl player = null;

    private void Awake()
    {
        player = GetComponent<PlayerCtrl>();
    }

    private void OnTriggerEnter(Collider _other)
    {
        if (_other.CompareTag("Player"))
        {
            _other.GetComponent<PlayerCtrl>().AddSpeed(1f);
            Destroy(gameObject);
        }
    }
}

TitleUpscale.cs

using UnityEngine;

public class TitleUpscale : MonoBehaviour
{
   private float maxSize = 1.2f;
   private float minSize = 0.8f;
   private float defaultTransSize = 1f;
   private float transSize = 0.5f;
   private bool isScalingUp = true;

   private void Update()
   {
       // 크기가 최대 크기에 도달하면 축소 상태로 변경
       if (defaultTransSize >= maxSize)
       {
           isScalingUp = false;
       }
       // 크기가 최소 크기에 도달하면 확대 상태로 변경
       else if (defaultTransSize <= minSize)
       {
           isScalingUp = true;
       }

       // 확대 또는 축소 상태에 따라 크기 변경
       if (isScalingUp)
       {
           defaultTransSize += transSize * Time.deltaTime;
       }
       else
       {
           defaultTransSize -= transSize * Time.deltaTime;
       }

       // 오브젝트 크기 변경
       transform.localScale = new Vector3(defaultTransSize, defaultTransSize, defaultTransSize);
   }
}
profile
게임 개발자가 될사람

0개의 댓글