Code Samples

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using Michsky.UI.ModernUIPack;
using System;
using System.Linq;

public class PlayFabLogin : MonoBehaviour
{
[Header(“Create Input Fields”)]
public TMP_InputField createEmailInput;
public TMP_InputField createUsernameInput;
public TMP_InputField createPasswordInput;
[Space(20)]

[Header(“Login input fields”)]
public TMP_InputField loginEmailInput;
public TMP_InputField loginPasswordInput;
[Space(20)]

[Header(“Text boxes”)]
public Text signInErrorTextbox;
public Text welcomeText;
[Space(20)]

[Header(“Panels”)]
public GameObject accountOptionsPanel;
public GameObject createAccountPanel;
public GameObject accountLoginPanel;
public GameObject loggingInPanel;
public GameObject loggedInPanel;
[Space(20)]

[Header(“Variables- Dont edit”)]
private string email;
public string username;
private string password;
private string playFabID;
[Space(20)]

[Header(“Auto Login”)]
public bool automaticLoginOnStart = false;


[Header(“Modal Window Error”)]
public ModalWindowManager errorWindow;
[Space(20)]

[Header(“Remember Me Checkbox”)]
public Toggle rememberMeCheckboxLogin;
public Toggle rememberMeCheckboxCreate;


// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;

#region Remember me checkbox

rememberMeCheckboxLogin = rememberMeCheckboxLogin.GetComponent<Toggle>();
string loginBool = PlayerPrefs.GetString(“LoginOnStartup”, “false”);
if (loginBool == “true”)
{
automaticLoginOnStart = true;
rememberMeCheckboxCreate.isOn = true;
rememberMeCheckboxLogin.isOn = true;
}
else
{
automaticLoginOnStart = false;
}

#endregion

accountOptionsPanel.SetActive(true);
loggingInPanel.SetActive(false);
createAccountPanel.SetActive(false);
accountLoginPanel.SetActive(false);
loggedInPanel.SetActive(false);

createEmailInput = createEmailInput.GetComponent<TMP_InputField>();
createUsernameInput = createUsernameInput.GetComponent<TMP_InputField>();
createPasswordInput = createPasswordInput.GetComponent<TMP_InputField>();

loginEmailInput = loginEmailInput.GetComponent<TMP_InputField>();
loginPasswordInput = loginPasswordInput.GetComponent<TMP_InputField>();


if (automaticLoginOnStart)
{
if (PlayerPrefs.HasKey(“Email”) && PlayerPrefs.HasKey(“Password”))
{
if (PlayerPrefs.GetString(“Email”) != string.Empty && PlayerPrefs.GetString(“Password”) != string.Empty)
{
AuthenticateWithPlayFab(PlayerPrefs.GetString(“Email”), PlayerPrefs.GetString(“Password”));
}
}
}
}

private void Update()
{
if (accountLoginPanel.activeInHierarchy)
{
if (loginEmailInput.isFocused)
{
if (Input.GetKeyDown(“tab”))
{
loginPasswordInput.ActivateInputField();
}
}

if (loginPasswordInput.isFocused && loginPasswordInput.text != string.Empty)
{
if (Input.GetKeyDown(“return”))
{
LoginSubmitLoginDetails();
}
}
}
if (createAccountPanel.activeInHierarchy)
{
if (createUsernameInput.isFocused)
{
if (Input.GetKeyDown(“tab”))
{
createEmailInput.ActivateInputField();
}
}
if (createEmailInput.isFocused)
{
if (Input.GetKeyDown(“tab”))
{
createPasswordInput.ActivateInputField();
}
}
if (createPasswordInput.isFocused && createPasswordInput.text != string.Empty)
{
if (Input.GetKeyDown(“return”))
{
CreateSubmitLoginDetails();
}
}

}
} //currently just used for hotkeys on login

private void AuthenticateWithPlayFab(string emailAddress, string passwordEntered)
{
accountLoginPanel.SetActive(false);
loggingInPanel.SetActive(true);

if (automaticLoginOnStart)
{
//put this under a conditional for remember me at some point
PlayerPrefs.SetString(“Email”, emailAddress);
Debug.Log($”Saved Email: {PlayerPrefs.GetString(“Email”)}”);
PlayerPrefs.SetString(“Password”, passwordEntered);
Debug.Log($”Saved Password: {PlayerPrefs.GetString(“Password”)}”);
PlayerPrefs.Save();
}

Debug.Log($”Logging in with saved credentials… {PlayerPrefs.GetString(“Email”)}, {PlayerPrefs.GetString(“Password”)}”);

var request = new LoginWithEmailAddressRequest { Email = emailAddress, Password = passwordEntered };

PlayFabClientAPI.LoginWithEmailAddress(request, OnPlayfabLoginSuccess, OnPlayfabLoginFail);
}

private void OnPlayfabLoginSuccess(LoginResult obj)
{
LogMessage(“Playfab authenticated. Requesting photon token”);
playFabID = obj.PlayFabId;
//check if login was new — TO BE DONE

MakeARequestForAccountDetails(playFabID);

PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
{ PhotonApplicationId = PhotonNetwork.PhotonServerSettings.AppSettings.AppIdRealtime },
AuthenticatedWithPhoton,
OnTotalFail);
}

private void MakeARequestForAccountDetails(string playFabID)
{
var request = new GetAccountInfoRequest { PlayFabId = playFabID };
PlayFabClientAPI.GetAccountInfo(request, AccountDetailsRequestSuccess, AccountDetailsRequestFail);
}

private void AccountDetailsRequestSuccess(GetAccountInfoResult result)
{
PlayerPrefs.SetString(“Username”, result.AccountInfo.Username);
PlayerPrefs.Save();

Debug.Log($”Username successfully retrieved! Username: {result.AccountInfo.Username}”);
}

private void AccountDetailsRequestFail(PlayFabError result)
{
Debug.Log($”Error on username retrieval! Error: {result}”);
}

private void OnPlayfabLoginFail(PlayFabError obj)
{
Debug.Log($”Playfab login failed {(int)obj.Error}”);
if ((int)obj.Error == 1142)
{
ErrorDisplay(“Login Error!”, “Password was incorrect!”);
}
else if ((int)obj.Error == 1001)
{
ErrorDisplay(“Account does not exist!”, “The email you entered is not linked with a registered account”);
}
else
{
ErrorDisplay(“Unknown Error”, $”Please contact support for assistance stating error code: {(int)obj.Error}”);
}
//accountCreateFailPanel.SetActive(true);
}

public void CreateNewPlayfabAccount(string newUsername, string newEmail, string newPassword)
{
var register = new RegisterPlayFabUserRequest { Email = newEmail, Password = newPassword, Username = newUsername };
email = newEmail;
password = newPassword;
username = newUsername;
Debug.Log($”Email: {email}, Password: {password}, Username: {username}”);
PlayFabClientAPI.RegisterPlayFabUser(register, OnRegisterSuccess, OnRegisterFailure);
createAccountPanel.SetActive(false);
loggingInPanel.SetActive(true);
}

private void OnRegisterSuccess(RegisterPlayFabUserResult result)
{
Debug.Log(“Register was a success!”);

AuthenticateWithPlayFab(email, password);
}

private void OnRegisterFailure(PlayFabError error)
{
LogMessage(error.GenerateErrorReport());

if ((int)error.Error == 1009)
{
ErrorDisplay(“Account Creation Error!”, “Username already exists. Please try again.”);
PlayerPrefs.SetString(“Username”, string.Empty);
PlayerPrefs.Save();
}
else if ((int)error.Error == 1006)
{
ErrorDisplay(“Account Creation Error!”, “Email already exists!”);
PlayerPrefs.SetString(“Email”, string.Empty);
PlayerPrefs.Save();
}
else
{
ErrorDisplay(“Unknown Error”, $”Please contact support stating error code: {(int)error.Error}”);
}

//accountCreateFailPanel.SetActive(true);
//signInErrorTextbox.text = $”There was a logging into this account. \nPlease try again. \nIf you are still having problems, there’s not much we can do right now cause this is still an app in development. \nGet over it. \nErrorCode: {error.GenerateErrorReport()}”;
}

private void AuthenticatedWithPhoton(GetPhotonAuthenticationTokenResult obj)
{
LogMessage(“Photon Token Aquired: …” + obj.PhotonCustomAuthenticationToken + “… Authenication Complete”);
var customAuth = new AuthenticationValues { AuthType = CustomAuthenticationType.Custom };
customAuth.AddAuthParameter(“username”, playFabID);
customAuth.AddAuthParameter(“token”, obj.PhotonCustomAuthenticationToken);
PhotonNetwork.AuthValues = customAuth;

loggingInPanel.SetActive(false);
loggedInPanel.SetActive(true);
welcomeText.text = $”Welcome, {PlayerPrefs.GetString(“Username”)}”;
}

private void OnTotalFail(PlayFabError obj)
{
LogMessage(obj.GenerateErrorReport());
ErrorDisplay(“It really hit the fan with this one!”, $”You can try again or you’ll need to contact support with error code: {(int)obj.Error}”);
}

private void LogMessage(string message)
{
Debug.Log($”Playfab script: {message}”);

}

#region Buttons

public void CreateSubmitLoginDetails()
{
email = createEmailInput.text;
username = createUsernameInput.text;
password = createPasswordInput.text;

bool hasCapital = false;
bool hasLowercase = false;
bool hasNumber = false;

string capitals = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”;
string lowercase = “abcdefghijklmnopqrstuvwxyz”;
string numbers = “0123456789”;

foreach (char letter in capitals)
{
if (password.Contains(letter))
{
hasCapital = true;
}
}
foreach (char letter in lowercase)
{
if (password.Contains(letter))
{
hasLowercase = true;
}
}
foreach (char number in numbers)
{
if (password.Contains(number))
{
hasNumber = true;
}
}

if (!hasCapital || !hasLowercase || !hasNumber)
{
ErrorDisplay(“Weak Password!”, “Make sure your password contains at least one lowercase letter, one uppercase letter, and one number!”);
return;
}
else
{
PlayerPrefs.SetString(“Email”, email);
PlayerPrefs.SetString(“Username”, username);
PlayerPrefs.Save();

CreateNewPlayfabAccount(username, email, password);

if (rememberMeCheckboxCreate.isOn == true)
{
automaticLoginOnStart = true;
PlayerPrefs.SetString(“LoginOnStartup”, “true”);
}
else
{
automaticLoginOnStart = false;
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
}
}
}

public void LoginSubmitLoginDetails()
{
email = loginEmailInput.text;
password = loginPasswordInput.text;
AuthenticateWithPlayFab(email, password);

if (rememberMeCheckboxLogin.isOn == true)
{
automaticLoginOnStart = true;
PlayerPrefs.SetString(“LoginOnStartup”, “true”);
}
else
{
automaticLoginOnStart = false;
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
}
}

public void LogOut()
{
accountLoginPanel.SetActive(true);
loggedInPanel.SetActive(false);

loginEmailInput.text = string.Empty;
loginPasswordInput.text = string.Empty;

PlayerPrefs.SetString(“Username”, string.Empty);
PlayerPrefs.SetString(“Email”, string.Empty);
PlayerPrefs.SetString(“Password”, string.Empty);
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
PlayerPrefs.Save();

automaticLoginOnStart = false;
rememberMeCheckboxLogin.isOn = false;
PlayFabClientAPI.ForgetAllCredentials();
}

public void IAlreadyHaveAnAccount()
{
createAccountPanel.SetActive(false);
accountLoginPanel.SetActive(true);

if (automaticLoginOnStart)
{
rememberMeCheckboxLogin.isOn = true;
}
else
{
rememberMeCheckboxLogin.isOn = false;
}
}

public void IDontHaveAnAccount()
{
accountLoginPanel.SetActive(false);
createAccountPanel.SetActive(true);

if (automaticLoginOnStart)
{
rememberMeCheckboxCreate.isOn = true;
}
else
{
rememberMeCheckboxCreate.isOn = false;
}
}

public void CreateAccountPanel() //From account options
{
createAccountPanel.SetActive(true);
accountOptionsPanel.SetActive(false);

if (automaticLoginOnStart)
{
rememberMeCheckboxCreate.isOn = true;
}
else
{
rememberMeCheckboxCreate.isOn = false;
}
}

public void LogInToAccountPanel()// from account options
{
accountLoginPanel.SetActive(true);
accountOptionsPanel.SetActive(false);

if (automaticLoginOnStart)
{
rememberMeCheckboxLogin.isOn = true;
}
else
{
rememberMeCheckboxLogin.isOn = false;
}
}

public void ErrorAcceptCreate()
{
errorWindow.CloseWindow();
loggingInPanel.SetActive(false);
createAccountPanel.SetActive(true);

if (automaticLoginOnStart)
{
rememberMeCheckboxCreate.isOn = true;
}
else
{
rememberMeCheckboxCreate.isOn = false;
}
}

public void ErrorAcceptLogin()
{
errorWindow.CloseWindow();
loggingInPanel.SetActive(false);
accountLoginPanel.SetActive(true);

if (automaticLoginOnStart)
{
rememberMeCheckboxLogin.isOn = true;
PlayerPrefs.SetString(“LoginOnStartup”, “true”);
PlayerPrefs.Save();
}
else
{
rememberMeCheckboxLogin.isOn = false;
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
PlayerPrefs.Save();
}
}

#endregion

public void ErrorDisplay(string errorTitle, string errorMessage)
{
errorWindow.titleText = errorTitle;
errorWindow.descriptionText = errorMessage;
errorWindow.UpdateUI();
errorWindow.OpenWindow();
}

public void RememberMeCheckboxLogin()
{
if (rememberMeCheckboxLogin.isOn)
{

automaticLoginOnStart = true;
PlayerPrefs.SetString(“LoginOnStartup”, “true”);
PlayerPrefs.Save();
Debug.Log(“Automatic Login turned on”);
}
else
{
automaticLoginOnStart = false;
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
PlayerPrefs.Save();
Debug.Log(“Automatic Login turned off”);
}
}

public void RememberMeCheckboxCreate()
{
if (rememberMeCheckboxCreate.isOn)
{
automaticLoginOnStart = true;
PlayerPrefs.SetString(“LoginOnStartup”, “true”);
PlayerPrefs.Save();
Debug.Log(“Automatic Login turned on”);

}
else
{
automaticLoginOnStart = false;
PlayerPrefs.SetString(“LoginOnStartup”, “false”);
PlayerPrefs.Save();
Debug.Log(“Automatic Login turned off”);
}
}
}

using ExitGames.Client.Photon;
using Michsky.UI.ModernUIPack;
using Photon.Pun;
using Photon.Realtime;
using System;
using UnityEngine;

namespace PhotonNetworkingCustomScripts
{
public class HostLauncher : MonoBehaviourPunCallbacks
{
#region public fields
[Header(“Panels”)]

public GameObject connectingPanel;
public GameObject createGigPanel;
public GameObject clientLauncher;

[Space(20)]

[Header(“Modal Window Error”)]
public ModalWindowManager errorWindow;
[Space(20)]

#endregion

#region private fields

[Tooltip(“The maximum number of players per room. When a room is full, it can’t be joined by new players, and so new room will be created”)]
[SerializeField]
private byte maxPlayersPerRoom = 4;
private string gameVersion = “1”;
private string roomName;
private bool isConnecting;
private Hashtable customRoomProperties;

#endregion

private void Awake()
{
PhotonNetwork.AutomaticallySyncScene = true;
}

private void Start()
{
connectingPanel.SetActive(false);
}

public void ConnectToMasterServer()
{

}


public void Connect()
{
customRoomProperties = new Hashtable();
//V = videoTime
//U = URL
//P = playing bool, 1 is stopped, 2 is playing
//C1 = chrome key settings
//C2 = chrome key difference settings
//C3 = luma settings
//C4 = luma difference settings
//R = Red value settings
//G = Green value settings
//B = Blue value settings
//B1 = blur x settings
//B2 = blur y settings
//B3 = blur iterations settings
//E1 = edge settings
//E2 = power settings
//SS = screen size

string URL = PlayerPrefs.GetString(“Stream URL”);
customRoomProperties.Add(“V”, 0);
customRoomProperties.Add(“U”, URL);
customRoomProperties.Add(“P”, 1);

#region Get saved chrome key settings

float dChroma = PlayerPrefs.GetFloat(“Chroma Max Difference”, 0.5f);
float dChromaT = PlayerPrefs.GetFloat(“Chroma Tolerance”, 0.05f);
float dLuma = PlayerPrefs.GetFloat(“Chroma Luma Max”, 0.5f);
float dLumaT = PlayerPrefs.GetFloat(“Chroma Luma Tolerance”, 0.05f);
customRoomProperties.Add(“C1”, dChroma);
customRoomProperties.Add(“C2”, dChromaT);
customRoomProperties.Add(“C3”, dLuma);
customRoomProperties.Add(“C4”, dLumaT);

float redValue = PlayerPrefs.GetFloat(“Red Slider”, 0);
float greenValue = PlayerPrefs.GetFloat(“Green Slider”, 256);
float blueValue = PlayerPrefs.GetFloat(“Blue Slider”, 0);
customRoomProperties.Add(“R”, redValue);
customRoomProperties.Add(“G”, greenValue);
customRoomProperties.Add(“B”, blueValue);

#endregion


#region Get saved blur settings

float blurX = PlayerPrefs.GetFloat(“Blur X”, 8f);
float blurY = PlayerPrefs.GetFloat(“Blur Y”, 8f);
int blurIterations = PlayerPrefs.GetInt(“Blur Iterations”, 2);
customRoomProperties.Add(“B1”, blurX);
customRoomProperties.Add(“B2”, blurY);
customRoomProperties.Add(“B3”, blurIterations);

#endregion

#region Get saved Edge settings

float edge = PlayerPrefs.GetFloat(“Edge”, 0.5f);
float power = PlayerPrefs.GetFloat(“Power”, 0.5f);

customRoomProperties.Add(“E1”, edge);
customRoomProperties.Add(“E2”, power);
#endregion

#region Get YouTubeScreenSettings

float screenSize = PlayerPrefs.GetFloat(“YouTube Screen Size”, 1f);
customRoomProperties.Add(“SS”, screenSize);

#endregion

connectingPanel.SetActive(true);
createGigPanel.SetActive(false);
clientLauncher.SetActive(false);

roomName = PlayerPrefs.GetString(“Room Name”, string.Empty);
Debug.Log($”Player prefs room name is {roomName}”);

if (PhotonNetwork.IsConnected)
{
if (roomName == string.Empty)
{
clientLauncher.SetActive(true);
createGigPanel.SetActive(true);
ErrorDisplay(“Room name empty!”, “You must enter a room name…”);

return;
}

//get number of players
int maxPlayers = PlayerPrefs.GetInt(“Number Of Attendees”);
maxPlayersPerRoom = Convert.ToByte(maxPlayers);

PhotonNetwork.NickName = PlayerPrefs.GetString(“Username”);

var roomOptions = new RoomOptions { MaxPlayers = maxPlayersPerRoom, CustomRoomProperties = customRoomProperties, PublishUserId = true };

PhotonNetwork.CreateRoom(roomName, roomOptions);
Debug.Log(“PhotonNetwork has created a room”);
}

else
{
isConnecting = PhotonNetwork.ConnectUsingSettings();
PhotonNetwork.GameVersion = gameVersion;
Debug.Log(“Photon network wasn’t connected Host”);
}
}

#region MonoBehaviourPunCallbacks Callbacks


public override void OnConnectedToMaster()
{
connectingPanel.SetActive(false);

if (roomName == string.Empty)
{
createGigPanel.SetActive(true);
clientLauncher.SetActive(true);
Debug.Log(“Room name is empty! OnConnectedToMaster(Host)”);
ErrorDisplay(“Room name empty!”, “You must enter a room name…”);
return;
}

if(isConnecting)
{
int maxPlayers = PlayerPrefs.GetInt(“Number Of Attendees”);
maxPlayersPerRoom = Convert.ToByte(maxPlayers);
PhotonNetwork.NickName = PlayerPrefs.GetString(“Username”);
PhotonNetwork.CreateRoom(roomName, new RoomOptions { MaxPlayers = maxPlayersPerRoom, CustomRoomProperties = customRoomProperties, PublishUserId = true });
Debug.Log(“OnConnectedToMaster() was called by Host Launcher”);
isConnecting = false;
}
}


public override void OnDisconnected(DisconnectCause cause)
{
connectingPanel.SetActive(false);
createGigPanel.SetActive(true);
clientLauncher.SetActive(true);
isConnecting = false;
Debug.LogWarningFormat(“OnDisconnected() was called by Host Launcher with reason {0}”, cause);
ErrorDisplay(“Disconnected from room…”, “You were disconnected while connecting. You will be returned to the main menu. Please try again. If you are still experiencing difficulties, contact support”);
}

public override void OnCreateRoomFailed(short returnCode, string message)
{
createGigPanel.SetActive(true);
clientLauncher.SetActive(true);
Debug.Log(“OnCreateRoomFailed() was called by Host Launcher. Creating a room failed, refer to ondisconnected perhaps? ID.\n Returing to menu”);
ErrorDisplay(“Failed To Create Room”, “You will be returned to the main menu. Please try again. If you are still experiencing difficulties, contact support”);
}

public override void OnJoinedRoom()
{
PhotonNetwork.LoadLevel(PlayerPrefs.GetInt(“VenueIndex”, 1));
Debug.Log(“OnJoinedRoom() called by Host Launcher. This host has joined a room that previously existed, so what the fuck is goin on?? Loaded into arena”);
}

public override void OnCreatedRoom()
{
//PhotonNetwork.LoadLevel(1);
Debug.Log(“OnCreatedRoom was called by host launcher. This host has created a new room for a gig and loaded into the arena successfully”);
}


#endregion

private void ErrorDisplay(string errorTitle, string errorMessage)
{
errorWindow.titleText = errorTitle;
errorWindow.descriptionText = errorMessage;
errorWindow.UpdateUI();
errorWindow.OpenWindow();
}
}

}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class PlayerController : MonoBehaviourPun
{
public Rigidbody tankRigid;

public float throttleForceCompensation = 150000f;
public float turningSpeed = 2f;
private float accelerationControl = 0.06f;
public float decelerationSpeedNoThrottle = 1f;
public float brakePower = 2f;
public float maxThrottleValue = 10f;
public float minThrottleValue = -10f;
private float throttleValue = 0f;
private float turningValue = 0f;
private float speed = 0f;

#region Terrain collider

public Rigidbody terrainObjectColliderFront;
public GameObject terrainObjectMarkerFront;

public Rigidbody terrainObjectColliderRear;
public GameObject terrainObjectMarkerRear;

private float maxSpeed = 1f;
private float minSpeed = 1f;

#endregion

#region Upside Down Detector

public Rigidbody upsideDownDetector;
public GameObject upsideDownMarker;

#endregion

#region Bools — Grounded, drivingMode, terrainCollision, Exploded

private bool isGrounded;
private bool driveMode;
public bool terrainCollisionFront;
public bool terrainCollisionRear;
public bool tankExploded = false;

#endregion

#region Gun

[Header(“Gun”)]
public float rotationSpeed = 2f;
public float maxYlook = 30f;
public float minYlook = -30f;

public GameObject gunRotationPoint;
public GameObject gunBarrelBase;
public GameObject tankBody;

private float lookValueY;
private float lookValueX;
[Space(20)]

#endregion

#region Camera

[Header(“Camera”)]
public GameObject cameraGameobject;
public GameObject cameraMarkerForwardFollower;
public GameObject cameraMarkerBackwardFollower;
public GameObject cameraMarkerAim;
private float followSpeed = 1f;
public float followSpeedInDriveMode = 1f;
public float followSpeedInAimMode = 20f;

#endregion

#region Game menu

public GameObject gameMenuPanel;

#endregion

#region Missile Launcher

public MissileLauncher missileLauncher;

#endregion

#region UI name tag

[Header(“UI name tag”)]

public GameObject uiPrefab;
private GameObject uiPrefInstance;
public Vector3 uiLocation;

#endregion


// Start is called before the first frame update
void Start()
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
cameraGameobject.SetActive(true);
tankRigid = GetComponent<Rigidbody>();
isGrounded = false;
driveMode = true;
terrainCollisionFront = false;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;

missileLauncher = missileLauncher.GetComponent<MissileLauncher>();
}

#region NameTag position update and add it to the synced list of prefabs on NameTags (network node)

uiLocation = new Vector3(
transform.position.x,
transform.position.y + 5f,
transform.position.z);

uiPrefInstance = PhotonNetwork.Instantiate(uiPrefab.name, uiLocation, Quaternion.identity);
uiPrefInstance.transform.SetParent(GameObject.Find(“PlayerCardParent”).transform);
uiPrefInstance.transform.LookAt(cameraGameobject.transform);
uiPrefInstance.SetActive(false);

#endregion
}

private void Update()
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
if (!tankExploded)
{
if (Input.GetKeyDown(“f”))
{
if (driveMode)
{
followSpeed = followSpeedInAimMode;
driveMode = false;
}
else
{
followSpeed = followSpeedInDriveMode;
driveMode = true;
}
}
}

if (Input.GetKeyDown(“e”))
{
if (gameMenuPanel.activeInHierarchy)
{
gameMenuPanel.SetActive(false);
this.enabled = true;
missileLauncher.enabled = true;
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
else
{
gameMenuPanel.SetActive(true);
this.enabled = false;
missileLauncher.enabled = false;
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
}
}
}

// Update is called once per frame
void FixedUpdate()
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
if (!tankExploded)
{
#region Throttle controls

speed = tankRigid.velocity.sqrMagnitude;

if (isGrounded)
{
throttleValue += Mathf.Clamp(Input.GetAxis(“Vertical”), minSpeed, maxSpeed) * accelerationControl;
throttleValue = (throttleValue > maxThrottleValue) ? maxThrottleValue : throttleValue;
throttleValue = (throttleValue < minThrottleValue) ? minThrottleValue : throttleValue;
Vector3 movement = transform.forward * throttleValue * Time.deltaTime;
tankRigid.MovePosition(tankRigid.position + movement);


turningValue = Input.GetAxis(“Horizontal”);
Quaternion rotation = Quaternion.Euler(0f, turningValue * turningSpeed, 0f);
tankRigid.MoveRotation(tankRigid.rotation * rotation);

if (Input.GetKeyDown(“space”))
{
Debug.Log(“Braking”);
throttleValue -= brakePower * Time.deltaTime;
movement = transform.forward * throttleValue * Time.deltaTime;
}
}
if (Mathf.Approximately(Input.GetAxis(“Vertical”), 0f))
{
if (throttleValue > 0)
{
throttleValue -= decelerationSpeedNoThrottle * Time.deltaTime;
Vector3 movement = transform.forward * throttleValue * Time.deltaTime;
}
else if (throttleValue < 0)
{
throttleValue += decelerationSpeedNoThrottle * Time.deltaTime;
Vector3 movement = transform.forward * throttleValue * Time.deltaTime;
}
}


#endregion

#region Gun

lookValueY += Input.GetAxis(“Mouse X”);
lookValueX += Input.GetAxis(“Mouse Y”);

lookValueX = Mathf.Clamp(lookValueX, minYlook, maxYlook);
lookValueY = Mathf.Clamp(lookValueY, minYlook, maxYlook);

gunRotationPoint.transform.localEulerAngles = new Vector3(-lookValueX, lookValueY, 0);

#endregion

#region Camera follower

if (driveMode)
{
if (Input.GetAxis(“Vertical”) >= 0)
{
//reset camera speed
if (Mathf.Approximately(followSpeed, followSpeedInAimMode))
{
StartCoroutine(CameraSpeedReset());
}

CameraFollower(cameraMarkerForwardFollower);
}
else
{
CameraFollower(cameraMarkerBackwardFollower);
followSpeed = followSpeedInAimMode;
}
}
else
{
CameraFollower(cameraMarkerAim);
}

#endregion

#region Terrain object collider follower

TerrainColliderFollower(upsideDownDetector, upsideDownMarker);

#endregion

#region Tank updside down follower

TerrainColliderFollower(terrainObjectColliderFront, terrainObjectMarkerFront);
TerrainColliderFollower(terrainObjectColliderRear, terrainObjectMarkerRear);

#endregion

#region Terrain Collision


if (terrainCollisionFront)
{
throttleValue = 0;
maxSpeed = 0f;
}
else
{
maxSpeed = 1f;
minSpeed = -1f;
}

if (terrainCollisionRear)
{
throttleValue = 0;
minSpeed = 0f;
}
else
{
maxSpeed = 1f;
minSpeed = -1f;
}

 

#endregion

#region NameTag position update

uiLocation = new Vector3(
transform.position.x,
transform.position.y + 5f,
transform.position.z);

uiPrefInstance.transform.position = uiLocation;

uiPrefInstance.transform.LookAt(cameraGameobject.transform);

#endregion
}


}

}

private void TerrainColliderFollower(Rigidbody follower, GameObject marker)
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
follower.transform.position = new Vector3(marker.transform.position.x,
marker.transform.position.y,
marker.transform.position.z);

follower.transform.rotation = Quaternion.Euler(marker.transform.eulerAngles.x,
marker.transform.eulerAngles.y,
marker.transform.rotation.z);
}
}

private void CameraFollower(GameObject cameraMarker)
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
if (!tankExploded)
{
cameraGameobject.transform.position = Vector3.Lerp(
cameraGameobject.transform.position,
cameraMarker.transform.position,
1 / followSpeed * Time.deltaTime);

float currentXangle = cameraGameobject.transform.eulerAngles.x;
float wantedXangle = cameraMarker.transform.eulerAngles.x;

float currentYangle = cameraGameobject.transform.eulerAngles.y;
float wantedYangle = cameraMarker.transform.eulerAngles.y;

float currentZangle = cameraGameobject.transform.eulerAngles.z;
float wantedZangle = cameraMarker.transform.rotation.z;

currentXangle = Mathf.LerpAngle(currentXangle, wantedXangle, 1 / followSpeed * Time.deltaTime);
currentYangle = Mathf.LerpAngle(currentYangle, wantedYangle, 1 / followSpeed * Time.deltaTime);
currentZangle = Mathf.LerpAngle(currentZangle, wantedZangle, 1 / followSpeed * Time.deltaTime);

cameraGameobject.transform.rotation = Quaternion.Euler(currentXangle, currentYangle, currentZangle);
}
}
}


private void OnCollisionStay(Collision collision)
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
if (collision.gameObject.tag == “Terrain”)
{
isGrounded = true;
}
}
}

private IEnumerator TankCollisionSpeedReduction(bool forward)
{
if (photonView.IsMine || !PhotonNetwork.IsConnected)
{
if (forward)
{
while (throttleValue > 0)
{
throttleValue -= decelerationSpeedNoThrottle * Time.deltaTime * 2;
yield return null;
}
terrainCollisionFront = false;
}
else
{
while (throttleValue < 0)
{
throttleValue += decelerationSpeedNoThrottle * Time.deltaTime * 2;
yield return null;
}
terrainCollisionFront = false;
}
}
}

private IEnumerator CameraSpeedReset()
{
yield return new WaitForSeconds(0.5f);
followSpeed = followSpeedInDriveMode;
}

}

using Photon.Pun;
using Photon.Realtime;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TankWarsNetworking
{
public class StagingArea : MonoBehaviourPunCallbacks, IPunObservable
{

[Header(“Tank Pads and locations”)]

public GameObject[] blueTankPads;
public List<GameObject> blueTankPadInstances;
public GameObject[] redTankPads;
public List<GameObject> redTankPadInstances;
public GameObject tankPadInstances;
public GameObject tankPad;

[Space(20)]

[Header(“Camera”)]

public GameObject[] cameraPositions;
public GameObject cameraGameobject;
public int currentCameraPosition = 0; //position based on num of players in room

[Space(20)]

[Header(“Photon prefabs”)]

public GameObject stagingTank;
public GameObject playerTag;

[Space(20)]

[Header(“Currently assigned assets”)]
public GameObject playerTankAsset;
public GameObject currentTankPad;
public GameObject playerTagInstance;

[Header(“Position of tank + 5f”)]
public Vector3 UIpos;

private ExitGames.Client.Photon.Hashtable playerProperties;
private int numPlayersInRoom;

private List<Player> blueTeamPlayers;
private List<Player> redTeamPlayers;

private bool isTesting = true;

// Start is called before the first frame update
void Start()
{
#region Spawn tank pads

//Use the tank pad spawn points, spawn in the networked tank pads and get a reference to them
//If you are joining the game as a client, grab a reference to all the networked prefabs and store them

blueTankPadInstances = new List<GameObject>();
redTankPadInstances = new List<GameObject>();

if (PhotonNetwork.IsMasterClient)
{
foreach (GameObject pad in blueTankPads)
{
playerTankAsset = PhotonNetwork.InstantiateRoomObject(tankPad.name, pad.transform.position, pad.transform.rotation);
blueTankPadInstances.Add(playerTankAsset);
TankSpawnPads tankSpawnPad = playerTankAsset.GetComponent<TankSpawnPads>();
tankSpawnPad.spawnPoint = new Vector3(
pad.transform.position.x,
pad.transform.position.y + 5f,
pad.transform.position.z);
tankSpawnPad.rotation = pad.transform.rotation;
playerTankAsset.transform.SetParent(tankPadInstances.transform);
}

foreach (GameObject pad in redTankPads)
{
playerTankAsset = PhotonNetwork.InstantiateRoomObject(tankPad.name, pad.transform.position, pad.transform.rotation);
redTankPadInstances.Add(playerTankAsset);
TankSpawnPads tankSpawnPad = playerTankAsset.GetComponent<TankSpawnPads>();
tankSpawnPad.spawnPoint = new Vector3(
pad.transform.position.x,
pad.transform.position.y + 5f,
pad.transform.position.z);
tankSpawnPad.rotation = pad.transform.rotation;
playerTankAsset.transform.SetParent(tankPadInstances.transform);
}

LoadInPlayers();
}
else
{
StartCoroutine(FindTankPads());
}

#endregion

blueTeamPlayers = new List<Player>();
redTeamPlayers = new List<Player>();

//Load in the players on a coroutine
//LoadInPlayers();
}

private void Update()
{
//Move the camera in update depending on number of players in the game
CameraFollower(cameraPositions[currentCameraPosition]);

}


public override void OnPlayerEnteredRoom(Player newPlayer)
{
numPlayersInRoom = PhotonNetwork.CountOfPlayers;

if (PhotonNetwork.IsMasterClient)
{
//set player priveleges
}

if (newPlayer == PhotonNetwork.LocalPlayer)
{

}

#region Camera Positions

CallCameraPosition(numPlayersInRoom);

#endregion
}

public override void OnPlayerLeftRoom(Player otherPlayer)
{
numPlayersInRoom = PhotonNetwork.CountOfPlayers;

#region Camera Positions

CallCameraPosition(numPlayersInRoom);

#endregion
}

private string TeamOrganiser()
{
//check players in room and assign a team colour based on which team needs players
if (PhotonNetwork.CountOfPlayers % 2 == 0)
{
return “Red”;
}
else
{
return “Blue”;
}
}


private void CallCameraPosition(int num)
{
//for assigning the camera position depending on number of players in the room
switch (num)
{
case 1:
currentCameraPosition = 0;
break;
case 2:
currentCameraPosition = 0;
break;
case 3:
currentCameraPosition = 1;
break;
case 4:
currentCameraPosition = 1;
break;
case 5:
currentCameraPosition = 2;
break;
case 6:
currentCameraPosition = 2;
break;
case 7:
currentCameraPosition = 3;
break;
case 8:
currentCameraPosition = 3;
break;
}
}

private void CameraFollower(GameObject cameraMarker)
{
cameraGameobject.transform.position = Vector3.Lerp(
cameraGameobject.transform.position,
cameraMarker.transform.position,
1 * Time.deltaTime);

float currentXangle = cameraGameobject.transform.eulerAngles.x;
float wantedXangle = cameraMarker.transform.eulerAngles.x;

float currentYangle = cameraGameobject.transform.eulerAngles.y;
float wantedYangle = cameraMarker.transform.eulerAngles.y;

float currentZangle = cameraGameobject.transform.eulerAngles.z;
float wantedZangle = cameraMarker.transform.rotation.z;

currentXangle = Mathf.LerpAngle(currentXangle, wantedXangle, 1 * Time.deltaTime);
currentYangle = Mathf.LerpAngle(currentYangle, wantedYangle, 1 * Time.deltaTime);
currentZangle = Mathf.LerpAngle(currentZangle, wantedZangle, 1 * Time.deltaTime);

cameraGameobject.transform.rotation = Quaternion.Euler(currentXangle, currentYangle, currentZangle);
}

private GameObject SpawnTank(Vector3 position, Quaternion rotation)
{
GameObject playerTank = PhotonNetwork.Instantiate(stagingTank.name, position, rotation);
return playerTank;
}

private void DebugPlayerList()
{
foreach (Player player in PhotonNetwork.PlayerList)
{
Debug.Log($”{(string)player.CustomProperties[“Team”]}: {player.NickName}”);
}
}

private IEnumerator FindTankPads()
{
yield return new WaitForSeconds(1f);
GameObject[] tankpads = GameObject.FindGameObjectsWithTag(“TankPad”);
for (int i = 0; i < tankpads.Length; i++)
{
if (i < 4)
{
blueTankPadInstances.Add(tankpads[i]);
tankpads[i].transform.SetParent(tankPadInstances.transform);
}
else
{
redTankPadInstances.Add(tankpads[i]);
tankpads[i].transform.SetParent(tankPadInstances.transform);
}
}

LoadInPlayers();
}

private void LoadInPlayers()
{
//yield return new WaitForSeconds(2f);

if (PhotonNetwork.IsMasterClient)
{
//spawn tank and get reference to the object
playerTankAsset = SpawnTank(blueTankPadInstances[0].GetComponent<TankSpawnPads>().spawnPoint, blueTankPadInstances[0].GetComponent<TankSpawnPads>().rotation);
SpawnPlayerTag();
UIpos = playerTankAsset.transform.position;
playerTagInstance.transform.position = UIpos;

//change assigned pad to true and get a reference
blueTankPadInstances[0].GetComponent<TankSpawnPads>().isPadTaken = true;
currentTankPad = blueTankPadInstances[0];

//set player properties
playerProperties = new ExitGames.Client.Photon.Hashtable();
playerProperties.Add(“Kills”, 0);
playerProperties.Add(“Alive”, true);
playerProperties.Add(“Health”, 100f);
playerProperties.Add(“Team”, “Blue”);
PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);

//set num of players in room and add to team lists
numPlayersInRoom = PhotonNetwork.CountOfPlayers;
DebugPlayerList();
}
else
{
string teamColour = TeamOrganiser();
Debug.Log($”Team {teamColour}”);
/*
#region Update all existing player staging tank names

GameObject[] stagingTanks = GameObject.FindGameObjectsWithTag(“StagingTank”);

foreach (GameObject tank in stagingTanks)
{
StagingTank st = tank.GetComponent<StagingTank>();
st.playerNameText.text = st.player.NickName;
}

#endregion
*/
if (teamColour == “Red”)
{
for (int i = 0; i < redTankPadInstances.Count; i++)
{
Debug.Log($”Tank pad instances: {redTankPadInstances.Count}”);
TankSpawnPads tsp = redTankPadInstances[i].GetComponent<TankSpawnPads>();
if (!tsp.isPadTaken)
{
Debug.Log($”Spawning to {i} pad”);
playerTankAsset = SpawnTank(tsp.spawnPoint, tsp.rotation);

SpawnPlayerTag();
UIpos = playerTankAsset.transform.position;
playerTagInstance.transform.position = UIpos;

//got to get the ownership to change whether or not pad is taken and get a reference to the pad
tsp.photonView.TransferOwnership(PhotonNetwork.LocalPlayer);
tsp.isPadTaken = true;
currentTankPad = redTankPadInstances[i];

//set player properties
playerProperties = new ExitGames.Client.Photon.Hashtable();
playerProperties.Add(“Kills”, 0);
playerProperties.Add(“Alive”, true);
playerProperties.Add(“Health”, 100f);
playerProperties.Add(“Team”, “Red”);
PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);

DebugPlayerList();
break;
}
else
{
Debug.Log($”{i} Pad taken”);
}
}
}
else
{
Debug.Log(“Team colour was blue”);
for (int i = 0; i < blueTankPadInstances.Count; i++)
{
TankSpawnPads tsp = blueTankPadInstances[i].GetComponent<TankSpawnPads>();
if (!tsp.isPadTaken)
{
Debug.Log($”Pad {i} wasn’t taken”);
playerTankAsset = SpawnTank(tsp.spawnPoint, tsp.rotation);

SpawnPlayerTag();
UIpos = playerTankAsset.transform.position;
playerTagInstance.transform.position = UIpos;

tsp.photonView.TransferOwnership(PhotonNetwork.LocalPlayer);
tsp.isPadTaken = true;
currentTankPad = blueTankPadInstances[i];

playerProperties = new ExitGames.Client.Photon.Hashtable();
playerProperties.Add(“Kills”, 0);
playerProperties.Add(“Alive”, true);
playerProperties.Add(“Health”, 100f);
playerProperties.Add(“Team”, “Blue”);
PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);

DebugPlayerList();
break;
}
else
{
Debug.Log($”{i} Pad taken”);
}
}
}
}

}

private void SpawnPlayerTag()
{
playerTagInstance = PhotonNetwork.Instantiate(playerTag.name, UIpos, Quaternion.identity);
}


#region Buttons

public void SwitchTeam()
{
Debug.Log(“Attempting to switch team”);
if ((string)PhotonNetwork.LocalPlayer.CustomProperties[“Team”] == “Red”)
{
if (blueTeamPlayers.Count == 4)
{
Debug.LogError(“Blue Team is full!”);
return;
}
else
{
for (int i = 0; i < blueTankPadInstances.Count; i++)
{
TankSpawnPads tsp = blueTankPadInstances[i].GetComponent<TankSpawnPads>();
if (!tsp.isPadTaken)
{
//transfer ownership of pad so pad can be set as taken
Debug.Log($”Pad {i} wasn’t taken”);
tsp.photonView.TransferOwnership(PhotonNetwork.LocalPlayer);

//set old pad as free, set new pad as taken and get a reference to the new pad
currentTankPad.GetComponent<TankSpawnPads>().isPadTaken = false;
tsp.isPadTaken = true;
currentTankPad = blueTankPadInstances[i];

//set player tank to pad
playerTankAsset.transform.position = tsp.spawnPoint;
playerTankAsset.transform.rotation = tsp.rotation;
/*
//update player card colour
StagingTank st = playerTankAsset.GetComponent<StagingTank>();
st.img.color = st.blue;
*/
//update player props
playerProperties[“Team”] = “Blue”;
PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);

//update player lists to sync across network
redTeamPlayers.Remove(PhotonNetwork.LocalPlayer);
blueTeamPlayers.Add(PhotonNetwork.LocalPlayer);
DebugPlayerList();
break;
}
else
{
Debug.Log($”{i} Pad taken”);
}
}
}
}
else
{
if (redTeamPlayers.Count == 4)
{
Debug.LogError(“Red Team is full!”);
return;
}
else
{
for (int i = 0; i < redTankPadInstances.Count; i++)
{
TankSpawnPads tsp = redTankPadInstances[i].GetComponent<TankSpawnPads>();
if (!tsp.isPadTaken)
{
Debug.Log($”Pad {i} wasn’t taken”);
tsp.photonView.TransferOwnership(PhotonNetwork.LocalPlayer);
currentTankPad.GetComponent<TankSpawnPads>().isPadTaken = false;
tsp.isPadTaken = true;
currentTankPad = redTankPadInstances[i];

playerTankAsset.transform.position = tsp.spawnPoint;
playerTankAsset.transform.rotation = tsp.rotation;
/*
StagingTank st = playerTankAsset.GetComponent<StagingTank>();
st.img.color = st.red;
*/

playerProperties[“Team”] = “Red”;
PhotonNetwork.LocalPlayer.SetCustomProperties(playerProperties);

blueTeamPlayers.Remove(PhotonNetwork.LocalPlayer);
redTeamPlayers.Add(PhotonNetwork.LocalPlayer);
DebugPlayerList();
break;
}
else
{
Debug.Log($”{i} Pad taken”);
}
}
}
}
}

public void StartMatch()
{
if(PhotonNetwork.IsMasterClient)
{
PhotonNetwork.LoadLevel(2);
Debug.Log(“Loading main arena”);
}
}

public void LeaveLobby()
{
PhotonNetwork.LeaveRoom();
}

public override void OnLeftRoom()
{
PhotonNetwork.LoadLevel(0);
}

#endregion
}
}