using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Realtime;
using UnityEngine.UI;
using TMPro;
using Unity.VisualScripting;
using UnityEngine.SceneManagement;
using ExitGames.Client.Photon;
using System;
using System.Reflection;
using UnityEditor;
using System.Linq;
public class Scene3Timer : MonoBehaviourPunCallbacks
{
public GameObject Image1;
public GameObject Image2;
public GameObject Image3;
public GameObject Image4;
public GameObject Image5;
public GameObject Sit;
public GameObject Sit2;
public TMP_Text timerText;
public GameObject Rule1;
public TMP_Text liveText1;
public TMP_Text liveText2;
public TMP_Text liveText3;
public static bool RuleDescriptEnd = false;
public TMP_Text PressEText;
private CanvasGroup canvasGroup1;
private CanvasGroup canvasGroup2;
private CanvasGroup canvasGroup3;
private CanvasGroup canvasGroup4;
private CanvasGroup canvasGroup5;
private CanvasGroup ruleText1;
private CanvasGroup ruleText2;
private CanvasGroup ruleText3;
public float fadeDuration = 1f; // 페이드 지속 시간
public TMP_Text DeathEnding;
List<string> deathPlayersInfo = new List<string>();
public GameObject Round1Question;
public GameObject Round1Result;
public GameObject Roundwait;
public GameObject[] Round1Text;
public TMP_Text[] Playername;
public TMP_Text[] Playernumber;
public TMP_Text resultnumber;
public TMP_Text resultnotice;
public GameObject[] RoundTitles;
private bool timerEnded = false;
public TMP_Text PlayerInputField;
public PhotonView PV;
public Player winner;
public TMP_Text PlayerHealth;
void Awake()
{
Image1.SetActive(false);
Image2.SetActive(false);
Image3.SetActive(false);
Image4.SetActive(false);
Image5.SetActive(false);
canvasGroup1 = Image1.GetComponent<CanvasGroup>();
canvasGroup2 = Image2.GetComponent<CanvasGroup>();
canvasGroup3 = Image3.GetComponent<CanvasGroup>();
canvasGroup4 = Image4.GetComponent<CanvasGroup>();
canvasGroup5 = Image5.GetComponent<CanvasGroup>();
Rule1.SetActive(false);
liveText1.gameObject.SetActive(false);
liveText2.gameObject.SetActive(false);
liveText3.gameObject.SetActive(false);
ruleText1 = liveText1.GetComponent<CanvasGroup>();
ruleText2 = liveText2.GetComponent<CanvasGroup>();
ruleText3 = liveText3.GetComponent<CanvasGroup>();
Round1Question.SetActive(false);
Round1Result.SetActive(false);
}
void Start()
{
StartCoroutine(GameSequence());
}
IEnumerator GameSequence()
{
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RuleDescript());
yield return PrepareForRound();
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RoundGame(2));
yield return PrepareForRound();
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RoundGame(3));
yield return PrepareForRound();
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RoundGame(4));
yield return PrepareForRound();
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RoundGame(5));
yield return PrepareForRound();
yield return StartCoroutine(TimerCoroutine(30));
yield return StartCoroutine(RoundGame(6));
}
[PunRPC]
void StartEndGameSequence()
{
StartCoroutine(EndGameSequence());
}
IEnumerator TimerCoroutine(int duration)
{
timerEnded = false;
var wait = new WaitForSeconds(1f);
if (PhotonNetwork.IsMasterClient)
{
while (duration > 0)
{
PV.RPC("ShowTimer", RpcTarget.All, duration);
duration--;
yield return wait;
}
PV.RPC("ShowTimer", RpcTarget.All, duration); // 마지막 시간 업데이트
PV.RPC("NotifyTimerEnd", RpcTarget.All); // 모든 클라이언트에 타이머 종료 알림
}
else
{
// 마스터 클라이언트가 아닌 경우, 마스터 클라이언트의 타이머 종료 알림을 기다립니다.
yield return new WaitUntil(() => timerEnded); // `timerEnded`는 타이머 종료 상태를 나타내는 bool 변수입니다.
}
}
[PunRPC]
void NotifyTimerEnd()
{
timerEnded = true; // 모든 클라이언트에서 타이머가 끝났음을 나타내는 변수를 true로 설정합니다.
// 필요한 경우, 여기에서 다음 단계로 진행하는 로직을 구현할 수도 있습니다.
}
[PunRPC]
IEnumerator EndGameSequence()
{
PressEText.gameObject.SetActive(false);
Image1.SetActive(true);
StartCoroutine(FadeCanvasGroup(canvasGroup1, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(4);
Image2.SetActive(true);
StartCoroutine(FadeCanvasGroup(canvasGroup2, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(4);
Image1.SetActive(false);
Image3.SetActive(true);
StartCoroutine(FadeCanvasGroup(canvasGroup3, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(4);
Image2.SetActive(false);
Image4.SetActive(true);
StartCoroutine(FadeCanvasGroup(canvasGroup4, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(5);
Image3.SetActive(false);
ExitGames.Client.Photon.Hashtable playerProperties = PhotonNetwork.LocalPlayer.CustomProperties;
int scene3order = (int)PhotonNetwork.LocalPlayer.CustomProperties["Health"];
AssignNewMasterClient3();
if (scene3order > 0)
{
SceneManager.LoadScene("Main");
}
else if (scene3order <= 0)
{
Image5.SetActive(true);
Image4.SetActive(false);
PhotonNetwork.LeaveRoom();
PhotonNetwork.Disconnect();
}
}
[PunRPC]
void ShowTimer(int number)
{
timerText.text = number.ToString(); //타이머 갱신
}
[PunRPC]
void UpdateDeathPlayersInfo(string playersInfo)
{
DeathEnding.text = string.Join("\n", playersInfo) + "\n심판자의 처형을 받아 장렬히 산화했습니다.";
}
[PunRPC]
private IEnumerator FadeCanvasGroup(CanvasGroup cg, float start, float end, float duration)
{
float elapsedTime = 0f;
while (elapsedTime < duration)
{
cg.alpha = Mathf.Lerp(start, end, elapsedTime / duration);
elapsedTime += Time.deltaTime;
yield return null;
}
cg.alpha = end;
}
private IEnumerator RuleDescript()
{
timerText.gameObject.SetActive(false);
Sit.SetActive(false);
Sit2.SetActive(false);
Rule1.SetActive(true);
liveText1.gameObject.SetActive(true);
liveText2.gameObject.SetActive(true);
StartCoroutine(FadeCanvasGroup(ruleText1, 0f, 1f, fadeDuration));
StartCoroutine(FadeCanvasGroup(ruleText2, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(6);
liveText2.gameObject.SetActive(false);
liveText3.gameObject.SetActive(true);
StartCoroutine(FadeCanvasGroup(ruleText3, 0f, 1f, fadeDuration));
yield return new WaitForSeconds(6);
Rule1.SetActive(false);
RuleDescriptEnd = true;
Round1Question.SetActive(true);
Roundwait.SetActive(false);
foreach (GameObject title in RoundTitles)
{
title.SetActive(false);
}
RoundTitles[0].SetActive(true);
timerText.gameObject.SetActive(true);
}
public void EnterNumber()
{
ExitGames.Client.Photon.Hashtable playerPickNumbers = new ExitGames.Client.Photon.Hashtable();
//플레이어가 선택한 숫자를 넣어주는 해쉬테이블생성
string inputnumber = PlayerInputField.text.Trim();
inputnumber = inputnumber.Replace("\u200B", "");
int playerPickValue = int.Parse(inputnumber);
playerPickNumbers.Add("ChooseNumber", playerPickValue);
PhotonNetwork.LocalPlayer.SetCustomProperties(playerPickNumbers);
foreach (GameObject textObject in Round1Text)
{
textObject.SetActive(false);
}
Roundwait.SetActive(true);
}
private IEnumerator RoundGame(int round)
{
timerText.gameObject.SetActive(false);
Round1Question.SetActive(false);
Round1Result.SetActive(true);
float total = 0;
int count = 0;
List<Player> playersWhoChoseZero = new List<Player>(); // 0을 선택한 모든 플레이어
List<Player> playersWhoChoseHundred = new List<Player>(); // 100을 선택한 모든 플레이어
Dictionary<int, List<Player>> numberChoices = new Dictionary<int, List<Player>>();
foreach (Player player in PhotonNetwork.PlayerList)
{
if (player.CustomProperties.TryGetValue("ChooseNumber", out object chooseNumberObj) && chooseNumberObj is int chooseNumber)
{
total += chooseNumber;
count++;
if (!numberChoices.ContainsKey(chooseNumber))
{
numberChoices[chooseNumber] = new List<Player>();
}
numberChoices[chooseNumber].Add(player);
if (chooseNumber == 0)
{
playersWhoChoseZero.Add(player);
}
else if (chooseNumber == 100)
{
playersWhoChoseHundred.Add(player);
}
}
}
bool allChoseSameNumber = numberChoices.Count == 1; // 모든 플레이어가 같은 숫자를 선택한 경우
bool zeroAndHundredOnly = numberChoices.Keys.All(k => k == 0 || k == 100); // 0과 100만 선택된 경우
if (count == 0)
{
// 모든 플레이어가 숫자를 선택하지 않았으므로 End Game Sequence를 실행
if (PhotonNetwork.IsMasterClient)
{
PV.RPC("StartEndGameSequence", RpcTarget.All);
}
yield break; // 코루틴 종료
}
float average = count > 0 ? total / count : 0;
float resultNumber = average * 0.8f; // 계산된 평균의 0.8배
numberChoices = numberChoices.Where(kvp => kvp.Value.Count == 1).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
Player closestPlayer = null;
float closestDistance = float.MaxValue;
bool exactMatch = false;
foreach (var entry in numberChoices)
{
float distance = Mathf.Abs(entry.Key - resultNumber);
if (distance < closestDistance)
{
closestDistance = distance;
closestPlayer = entry.Value.First();
}
if (Mathf.RoundToInt(resultNumber) == Mathf.RoundToInt(entry.Key) && entry.Value.Count == 1)
{
exactMatch = true;
}
}
// 가장 결과에 가까운 플레이어 찾기
if (allChoseSameNumber)
{
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
{
Playername[i].text = PhotonNetwork.PlayerList[i].NickName;
if (PhotonNetwork.PlayerList[i].CustomProperties.TryGetValue("ChooseNumber", out object chooseNumberObj))
{
Playernumber[i].text = chooseNumberObj is int chooseNumber ? chooseNumber.ToString() : "N/A";
}
else
{
Playernumber[i].text = "N/A";
}
}
resultnumber.text = "승자 없음";
resultnotice.text = "모두가 같은 숫자를 선택";
}
else if (zeroAndHundredOnly)
{
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
{
Playername[i].text = PhotonNetwork.PlayerList[i].NickName;
if (PhotonNetwork.PlayerList[i].CustomProperties.TryGetValue("ChooseNumber", out object chooseNumberObj))
{
Playernumber[i].text = chooseNumberObj is int chooseNumber ? chooseNumber.ToString() : "N/A";
}
else
{
Playernumber[i].text = "N/A";
}
}
resultnumber.text = "100";
resultnotice.text = "0과 100을 선택한 플레이어만 존재, 100을 선택한 플레이어 승리";
}
else
{
if (closestPlayer != null)
{
resultnumber.text = resultNumber.ToString("F0");
if (closestPlayer != null)
{
resultnotice.text = $"평균 숫자 {average:F2} * 0.8 = {resultNumber:F2}로 \n평균에서 가장 가까운, {closestPlayer.NickName} 승리";
}
else
{
resultnotice.text = "승자 없음";
}
for (int i = 0; i < PhotonNetwork.PlayerList.Length; i++)
{
Playername[i].text = PhotonNetwork.PlayerList[i].NickName;
if (PhotonNetwork.PlayerList[i].CustomProperties.TryGetValue("ChooseNumber", out object chooseNumberObj))
{
Playernumber[i].text = chooseNumberObj is int chooseNumber ? chooseNumber.ToString() : "N/A";
}
else
{
Playernumber[i].text = "N/A";
}
}
}
}
yield return new WaitForSeconds(8);
Round1Result.SetActive(false);
if (zeroAndHundredOnly)
{
List<Player> winners = playersWhoChoseHundred.ToList();
DecreaseHealthForAllExceptWinner(winners, false);
}
else if (allChoseSameNumber)
{
// 모든 플레이어가 같은 숫자를 선택한 경우
foreach (var player in PhotonNetwork.PlayerList)
{
// 모든 플레이어의 체력 1 감소
DecreaseHealthForAllExceptWinner(new List<Player>(), false);
}
}
else
{
if (closestPlayer != null)
{
DecreaseHealthForAllExceptWinner(new List<Player> { closestPlayer }, exactMatch);
}
}
Round1Question.SetActive(true);
foreach (GameObject title in RoundTitles)
{
title.SetActive(false);
}
RoundTitles[round - 1].SetActive(true);
timerText.gameObject.SetActive(true);
foreach (GameObject textObject in Round1Text)
{
textObject.SetActive(true);
}
Roundwait.SetActive(false);
}
void AssignNewMasterClient3()
{
if ((int)PhotonNetwork.MasterClient.CustomProperties["Health"] <= 0)
{
Player[] players = PhotonNetwork.PlayerList;
foreach (Player player in players)
{
if ((int)player.CustomProperties["Health"] > 0)
{
PhotonNetwork.SetMasterClient(player);
break;
}
}
}
}
private IEnumerator PrepareForRound()
{
PhotonNetwork.LocalPlayer.SetCustomProperties(new ExitGames.Client.Photon.Hashtable { { "ChooseNumber", null } });
yield return null;
}
void DecreaseHealthForAllExceptWinner(List<Player> winners, bool exactMatch)
{
if (PhotonNetwork.IsMasterClient)
{
foreach (Player player in PhotonNetwork.PlayerList)
{
if (!winners.Contains(player))
{
int healthDecreaseAmount = exactMatch ? 2 : 1;
int currentHealth = player.CustomProperties.ContainsKey("Health") ? (int)player.CustomProperties["Health"] : 3;
int newHealth = Mathf.Max(currentHealth - healthDecreaseAmount, 0);
ExitGames.Client.Photon.Hashtable props = new ExitGames.Client.Photon.Hashtable { { "Health", newHealth } };
player.SetCustomProperties(props);
if (newHealth <= 0)
{
string personality = player.CustomProperties["Personality"] as string;
string nickname = player.NickName as string;
deathPlayersInfo.Add("자칭 " + personality + " " + nickname + ",\n");
string deathPlayersStr = string.Join("\n", deathPlayersInfo);
PV.RPC("UpdateDeathPlayersInfo", RpcTarget.AllBuffered, deathPlayersStr);
PV.RPC("StartEndGameSequence", RpcTarget.All);
}
}
}
}
}
public override void OnPlayerPropertiesUpdate(Player targetPlayer, ExitGames.Client.Photon.Hashtable changedProps)
{
base.OnPlayerPropertiesUpdate(targetPlayer, changedProps);
// 체력 정보가 변경되었는지 확인합니다.
if (changedProps.ContainsKey("Health"))
{
// 변경된 체력 값을 가져옵니다.
int updatedHealth = (int)changedProps["Health"];
// 현재 로컬 플레이어의 체력 정보를 업데이트합니다.
if (targetPlayer == PhotonNetwork.LocalPlayer)
{
PlayerHealth.text = $"현재 체력 : {updatedHealth}";
}
}
}
}
완성!
테스트케이스를 만들것
잘작동
0선택한애들 다피깎
전부다 피 1깎임
평균 값 찾고 10이 승리 나머지 1깎
전부승리로 다음스테이지로넘김
0 null null은 배제하자,..,.ㅋㅋㅋㅋㅋㅋ
0 null null 인 경우에도 달성, 0인놈 승리.
그러나 0 100 null 일 경우에는, null인놈이랑 0인놈 둘다 패배 아마? 이거 체크해보자.
완성!