과제 목록
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);
}
}