二人目が入室した時点でゲーム開始にする(RPCの活用)


移動許可
using UnityEngine;
using Photon.Pun;
public class PlayerController : MonoBehaviourPunCallbacks
{
private CharacterController controller;
private Vector3 moveDir = Vector3.zero;
private float gravity = 20f;
private float verticalVelocity;
public float speed;
public float jumpPower;
private Animator animator;
// ★追加
public bool canMove { get; set; }
void Start()
{
controller = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
// ★追加
canMove = false;
}
void Update()
{
if (!photonView.IsMine)
{
return;
}
// ★追加
if (canMove == false)
{
return;
}
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
if (InputManager.isa.Player.Jump.triggered)
{
verticalVelocity = jumpPower;
animator.SetTrigger("Jump");
}
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
}
Vector2 movement2 = InputManager.isa.Player.Move.ReadValue<Vector2>();
Vector3 movementV = new Vector3(0, 0, movement2.y).normalized;
Vector3 movementH = new Vector3(movement2.x, 0, 0).normalized;
Vector3 forward = Camera.main.transform.forward;
forward.y = 0;
Vector3 right = Camera.main.transform.right;
moveDir = forward * movementV.z + right * movementH.x;
if (moveDir.magnitude >= 0.1f)
{
transform.rotation = Quaternion.LookRotation(moveDir);
}
animator.SetFloat("Move", moveDir.magnitude);
Vector3 finalMove = moveDir * speed;
finalMove.y = verticalVelocity;
if (controller.enabled)
{
controller.Move(finalMove * Time.deltaTime);
}
}
}
攻撃許可
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;
using TMPro;
public class AttackController : MonoBehaviourPunCallbacks
{
public GameObject shotPoint;
private float throwForce;
private float throwAngle;
private GameObject targetMark;
private Vector3 currentTargetPos;
private float launchAngle = 75f;
private int num = 0;
private int attacks = 5;
public AudioClip changeSound;
public Sprite[] attackImages;
private Image attackIcon;
private int attackPoint = 5;
private TextMeshProUGUI attackPointLabel;
private float timer = 0f;
private float interval = 5.0f;
// ★追加
public bool canAttack { get; set; }
void Start()
{
if (!photonView.IsMine)
{
return;
}
targetMark = GameObject.Find("TargetMark");
attackIcon = GameObject.Find("AttackIcon").GetComponent<Image>();
attackIcon.sprite = attackImages[num];
attackPointLabel = GameObject.Find("AttackPointLabel").GetComponent<TextMeshProUGUI>();
attackPointLabel.text = "" + attackPoint;
// ★追加
canAttack = false;
}
void Update()
{
if (!photonView.IsMine)
{
return;
}
// ★追加
if (canAttack == false)
{
return;
}
if (InputManager.isa.Player.AttackChange.triggered)
{
num = (num + 1) % attacks;
AudioSource.PlayClipAtPoint(changeSound, Camera.main.transform.position);
attackIcon.sprite = attackImages[num];
}
if (InputManager.isa.Player.Throw.triggered)
{
if (num == 0 && attackPoint >= 1)
{
ThrowBomb();
attackPoint -= 1;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 1 && attackPoint >= 3)
{
Targetshoot();
attackPoint -= 3;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 2 && attackPoint >= 10)
{
SetDrone();
attackPoint -= 10;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 3 && attackPoint >= 30)
{
SetAmateras();
attackPoint -= 30;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 4 && attackPoint >= 1)
{
BeamShot();
attackPoint -= 1;
attackPointLabel.text = "" + attackPoint;
}
}
IncreasePoint();
}
void ThrowBomb()
{
throwForce = 10f;
throwAngle = 45f;
GameObject bomb = PhotonNetwork.Instantiate("Bomb", shotPoint.transform.position, Quaternion.identity);
Rigidbody bombRb = bomb.GetComponent<Rigidbody>();
Vector3 forceDirection = Quaternion.AngleAxis(-throwAngle, transform.right) * transform.forward;
bombRb.AddForce(forceDirection * throwForce, ForceMode.VelocityChange);
}
void Targetshoot()
{
Vector3 screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
Ray ray = Camera.main.ScreenPointToRay(screenCenter);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
currentTargetPos = hit.point;
targetMark.transform.position = hit.point;
Shoot();
}
}
void Shoot()
{
GameObject bomb = PhotonNetwork.Instantiate("Bomb", shotPoint.transform.position, Quaternion.identity);
Rigidbody bombRb = bomb.GetComponent<Rigidbody>();
Vector3 diff = currentTargetPos - shotPoint.transform.position;
float h = diff.y;
diff.y = 0;
float distance = diff.magnitude;
float g = Physics.gravity.magnitude;
float angle = launchAngle * Mathf.Deg2Rad;
float cosA = Mathf.Cos(angle);
float tanA = Mathf.Tan(angle);
float denominator = 2 * cosA * cosA * (distance * tanA - h);
if (denominator <= 0)
{
return;
}
float velocity = Mathf.Sqrt((g * distance * distance) / denominator);
Vector3 velocityVec = diff.normalized * velocity * cosA;
velocityVec.y = velocity * Mathf.Sin(angle);
bombRb.linearVelocity = velocityVec;
}
void SetDrone()
{
PhotonNetwork.Instantiate("Drone", shotPoint.transform.position, Quaternion.identity);
}
void SetAmateras()
{
PhotonNetwork.Instantiate("Amateras", shotPoint.transform.position, Quaternion.identity);
}
void BeamShot()
{
Vector3 screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
Ray ray = Camera.main.ScreenPointToRay(screenCenter);
RaycastHit hit;
Vector3 targetPoint = ray.origin + (ray.direction * 100f);
if (Physics.Raycast(ray, out hit))
{
targetPoint = hit.point;
targetMark.transform.position = hit.point;
}
GameObject beam = PhotonNetwork.Instantiate("Beam", shotPoint.transform.position, Quaternion.identity);
beam.transform.LookAt(targetPoint);
Rigidbody beamRb = beam.GetComponent<Rigidbody>();
if (beamRb != null)
{
float beamSpeed = 50f;
beamRb.useGravity = false;
Vector3 direction = (targetPoint - shotPoint.transform.position).normalized;
beamRb.AddForce(direction * beamSpeed, ForceMode.VelocityChange);
}
}
void IncreasePoint()
{
timer += Time.deltaTime;
if (timer >= interval)
{
attackPoint += 1;
attackPointLabel.text = "" + attackPoint;
timer = 0;
}
}
}
タイマー作動
using UnityEngine;
using TMPro;
using Photon.Pun;
using ExitGames.Client.Photon;
public class TimeManager : MonoBehaviourPunCallbacks
{
public TextMeshProUGUI timeLabel;
public float initialTime = 100f;
private float remainingTime;
private bool isGameFinished = false;
// ★追加
public bool canTime { get; set; }
void Start()
{
remainingTime = initialTime;
if (PhotonNetwork.IsMasterClient)
{
UpdateRoomTimeProrerty(initialTime);
}
// ★追加
canTime = false;
}
void Update()
{
// ★追加
if (canTime == false)
{
return;
}
if (PhotonNetwork.IsMasterClient)
{
if (isGameFinished)
{
return;
}
remainingTime -= Time.deltaTime;
if (remainingTime <= 0)
{
remainingTime = 0;
isGameFinished = true;
PhotonNetwork.LoadLevel("Result");
}
UpdateRoomTimeProrerty(remainingTime);
}
}
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
base.OnRoomPropertiesUpdate(propertiesThatChanged);
if (propertiesThatChanged.ContainsKey("RemainingTime"))
{
float networkTime = (float)propertiesThatChanged["RemainingTime"];
DisplayTime(networkTime);
}
}
void UpdateRoomTimeProrerty(float time)
{
Hashtable props = new Hashtable { { "RemainingTime", time } };
PhotonNetwork.CurrentRoom.SetCustomProperties(props);
}
void DisplayTime(float timeToDisplay)
{
int minutes = Mathf.FloorToInt(timeToDisplay / 60);
int seconds = Mathf.FloorToInt(timeToDisplay % 60);
timeLabel.text = string.Format("Time {0:0}:{1:00}", minutes, seconds);
}
}

フラグで許可する
using UnityEngine;
// ★追加
using Photon.Pun;
using TMPro;
using Unity.VisualScripting;
public class GameDirector : MonoBehaviourPunCallbacks // ★変更
{
public TextMeshProUGUI statusLabel;
private bool isStart = false;
public TimeManager tm;
// ゲームの実行速度を60fpsに抑えて計算資源を効率化する
void Awake()
{
Application.targetFrameRate = 60;
}
void Start()
{
statusLabel.text = "READY....";
}
void Update()
{
// マスタークライアントが「2人揃ったか」を監視する
if (PhotonNetwork.IsMasterClient && !isStart)
{
if (PhotonNetwork.CurrentRoom.PlayerCount == 2)
{
// 2人揃ったら、全クライアントに向けてゲーム開始を通知する
photonView.RPC(nameof(StartGameRPC), RpcTarget.AllViaServer);
isStart = true;
}
}
}
[PunRPC]
void StartGameRPC()
{
// 「Go」と表示(数秒後に消す)
statusLabel.text = "GO!";
Invoke(nameof(ClearStatusLabel), 2);
// プレーヤーを動けるようにする
// プレーヤーが攻撃ができるようにする(+AttackPointが増加するようにする)
GameObject[] players = GameObject.FindGameObjectsWithTag("Player");
foreach (var p in players)
{
PhotonView pv = p.GetComponent<PhotonView>();
if (pv != null && pv.IsMine)
{
// フラグで移動を許可する
p.GetComponent<PlayerController>().canMove = true;
// フラグで攻撃を許可する
p.GetComponent<AttackController>().canAttack = true;
}
}
// フラグでタイマーを動かす
tm.canTime = true;
}
void ClearStatusLabel()
{
statusLabel.text = "";
}
}




【Unity6版】BattleOnline(全38回)
他のコースを見る

移動許可
using UnityEngine;
using Photon.Pun;
public class PlayerController : MonoBehaviourPunCallbacks
{
private CharacterController controller;
private Vector3 moveDir = Vector3.zero;
private float gravity = 20f;
private float verticalVelocity;
public float speed;
public float jumpPower;
private Animator animator;
// ★追加
public bool canMove { get; set; }
void Start()
{
controller = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
// ★追加
canMove = false;
}
void Update()
{
if (!photonView.IsMine)
{
return;
}
// ★追加
if (canMove == false)
{
return;
}
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
if (InputManager.isa.Player.Jump.triggered)
{
verticalVelocity = jumpPower;
animator.SetTrigger("Jump");
}
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
}
Vector2 movement2 = InputManager.isa.Player.Move.ReadValue<Vector2>();
Vector3 movementV = new Vector3(0, 0, movement2.y).normalized;
Vector3 movementH = new Vector3(movement2.x, 0, 0).normalized;
Vector3 forward = Camera.main.transform.forward;
forward.y = 0;
Vector3 right = Camera.main.transform.right;
moveDir = forward * movementV.z + right * movementH.x;
if (moveDir.magnitude >= 0.1f)
{
transform.rotation = Quaternion.LookRotation(moveDir);
}
animator.SetFloat("Move", moveDir.magnitude);
Vector3 finalMove = moveDir * speed;
finalMove.y = verticalVelocity;
if (controller.enabled)
{
controller.Move(finalMove * Time.deltaTime);
}
}
}
攻撃許可
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;
using TMPro;
public class AttackController : MonoBehaviourPunCallbacks
{
public GameObject shotPoint;
private float throwForce;
private float throwAngle;
private GameObject targetMark;
private Vector3 currentTargetPos;
private float launchAngle = 75f;
private int num = 0;
private int attacks = 5;
public AudioClip changeSound;
public Sprite[] attackImages;
private Image attackIcon;
private int attackPoint = 5;
private TextMeshProUGUI attackPointLabel;
private float timer = 0f;
private float interval = 5.0f;
// ★追加
public bool canAttack { get; set; }
void Start()
{
if (!photonView.IsMine)
{
return;
}
targetMark = GameObject.Find("TargetMark");
attackIcon = GameObject.Find("AttackIcon").GetComponent<Image>();
attackIcon.sprite = attackImages[num];
attackPointLabel = GameObject.Find("AttackPointLabel").GetComponent<TextMeshProUGUI>();
attackPointLabel.text = "" + attackPoint;
// ★追加
canAttack = false;
}
void Update()
{
if (!photonView.IsMine)
{
return;
}
// ★追加
if (canAttack == false)
{
return;
}
if (InputManager.isa.Player.AttackChange.triggered)
{
num = (num + 1) % attacks;
AudioSource.PlayClipAtPoint(changeSound, Camera.main.transform.position);
attackIcon.sprite = attackImages[num];
}
if (InputManager.isa.Player.Throw.triggered)
{
if (num == 0 && attackPoint >= 1)
{
ThrowBomb();
attackPoint -= 1;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 1 && attackPoint >= 3)
{
Targetshoot();
attackPoint -= 3;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 2 && attackPoint >= 10)
{
SetDrone();
attackPoint -= 10;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 3 && attackPoint >= 30)
{
SetAmateras();
attackPoint -= 30;
attackPointLabel.text = "" + attackPoint;
}
else if (num == 4 && attackPoint >= 1)
{
BeamShot();
attackPoint -= 1;
attackPointLabel.text = "" + attackPoint;
}
}
IncreasePoint();
}
void ThrowBomb()
{
throwForce = 10f;
throwAngle = 45f;
GameObject bomb = PhotonNetwork.Instantiate("Bomb", shotPoint.transform.position, Quaternion.identity);
Rigidbody bombRb = bomb.GetComponent<Rigidbody>();
Vector3 forceDirection = Quaternion.AngleAxis(-throwAngle, transform.right) * transform.forward;
bombRb.AddForce(forceDirection * throwForce, ForceMode.VelocityChange);
}
void Targetshoot()
{
Vector3 screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
Ray ray = Camera.main.ScreenPointToRay(screenCenter);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
currentTargetPos = hit.point;
targetMark.transform.position = hit.point;
Shoot();
}
}
void Shoot()
{
GameObject bomb = PhotonNetwork.Instantiate("Bomb", shotPoint.transform.position, Quaternion.identity);
Rigidbody bombRb = bomb.GetComponent<Rigidbody>();
Vector3 diff = currentTargetPos - shotPoint.transform.position;
float h = diff.y;
diff.y = 0;
float distance = diff.magnitude;
float g = Physics.gravity.magnitude;
float angle = launchAngle * Mathf.Deg2Rad;
float cosA = Mathf.Cos(angle);
float tanA = Mathf.Tan(angle);
float denominator = 2 * cosA * cosA * (distance * tanA - h);
if (denominator <= 0)
{
return;
}
float velocity = Mathf.Sqrt((g * distance * distance) / denominator);
Vector3 velocityVec = diff.normalized * velocity * cosA;
velocityVec.y = velocity * Mathf.Sin(angle);
bombRb.linearVelocity = velocityVec;
}
void SetDrone()
{
PhotonNetwork.Instantiate("Drone", shotPoint.transform.position, Quaternion.identity);
}
void SetAmateras()
{
PhotonNetwork.Instantiate("Amateras", shotPoint.transform.position, Quaternion.identity);
}
void BeamShot()
{
Vector3 screenCenter = new Vector3(Screen.width / 2, Screen.height / 2, 0);
Ray ray = Camera.main.ScreenPointToRay(screenCenter);
RaycastHit hit;
Vector3 targetPoint = ray.origin + (ray.direction * 100f);
if (Physics.Raycast(ray, out hit))
{
targetPoint = hit.point;
targetMark.transform.position = hit.point;
}
GameObject beam = PhotonNetwork.Instantiate("Beam", shotPoint.transform.position, Quaternion.identity);
beam.transform.LookAt(targetPoint);
Rigidbody beamRb = beam.GetComponent<Rigidbody>();
if (beamRb != null)
{
float beamSpeed = 50f;
beamRb.useGravity = false;
Vector3 direction = (targetPoint - shotPoint.transform.position).normalized;
beamRb.AddForce(direction * beamSpeed, ForceMode.VelocityChange);
}
}
void IncreasePoint()
{
timer += Time.deltaTime;
if (timer >= interval)
{
attackPoint += 1;
attackPointLabel.text = "" + attackPoint;
timer = 0;
}
}
}
タイマー作動
using UnityEngine;
using TMPro;
using Photon.Pun;
using ExitGames.Client.Photon;
public class TimeManager : MonoBehaviourPunCallbacks
{
public TextMeshProUGUI timeLabel;
public float initialTime = 100f;
private float remainingTime;
private bool isGameFinished = false;
// ★追加
public bool canTime { get; set; }
void Start()
{
remainingTime = initialTime;
if (PhotonNetwork.IsMasterClient)
{
UpdateRoomTimeProrerty(initialTime);
}
// ★追加
canTime = false;
}
void Update()
{
// ★追加
if (canTime == false)
{
return;
}
if (PhotonNetwork.IsMasterClient)
{
if (isGameFinished)
{
return;
}
remainingTime -= Time.deltaTime;
if (remainingTime <= 0)
{
remainingTime = 0;
isGameFinished = true;
PhotonNetwork.LoadLevel("Result");
}
UpdateRoomTimeProrerty(remainingTime);
}
}
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
base.OnRoomPropertiesUpdate(propertiesThatChanged);
if (propertiesThatChanged.ContainsKey("RemainingTime"))
{
float networkTime = (float)propertiesThatChanged["RemainingTime"];
DisplayTime(networkTime);
}
}
void UpdateRoomTimeProrerty(float time)
{
Hashtable props = new Hashtable { { "RemainingTime", time } };
PhotonNetwork.CurrentRoom.SetCustomProperties(props);
}
void DisplayTime(float timeToDisplay)
{
int minutes = Mathf.FloorToInt(timeToDisplay / 60);
int seconds = Mathf.FloorToInt(timeToDisplay % 60);
timeLabel.text = string.Format("Time {0:0}:{1:00}", minutes, seconds);
}
}

フラグで許可する
using UnityEngine;
// ★追加
using Photon.Pun;
using TMPro;
using Unity.VisualScripting;
public class GameDirector : MonoBehaviourPunCallbacks // ★変更
{
public TextMeshProUGUI statusLabel;
private bool isStart = false;
public TimeManager tm;
// ゲームの実行速度を60fpsに抑えて計算資源を効率化する
void Awake()
{
Application.targetFrameRate = 60;
}
void Start()
{
statusLabel.text = "READY....";
}
void Update()
{
// マスタークライアントが「2人揃ったか」を監視する
if (PhotonNetwork.IsMasterClient && !isStart)
{
if (PhotonNetwork.CurrentRoom.PlayerCount == 2)
{
// 2人揃ったら、全クライアントに向けてゲーム開始を通知する
photonView.RPC(nameof(StartGameRPC), RpcTarget.AllViaServer);
isStart = true;
}
}
}
[PunRPC]
void StartGameRPC()
{
// 「Go」と表示(数秒後に消す)
statusLabel.text = "GO!";
Invoke(nameof(ClearStatusLabel), 2);
// プレーヤーを動けるようにする
// プレーヤーが攻撃ができるようにする(+AttackPointが増加するようにする)
GameObject[] players = GameObject.FindGameObjectsWithTag("Player");
foreach (var p in players)
{
PhotonView pv = p.GetComponent<PhotonView>();
if (pv != null && pv.IsMine)
{
// フラグで移動を許可する
p.GetComponent<PlayerController>().canMove = true;
// フラグで攻撃を許可する
p.GetComponent<AttackController>().canAttack = true;
}
}
// フラグでタイマーを動かす
tm.canTime = true;
}
void ClearStatusLabel()
{
statusLabel.text = "";
}
}




二人目が入室した時点でゲーム開始にする(RPCの活用)