I made a simple multiplayer quiz game. At the end of the quiz I want to display the scores of both players. Is it possible to get PlayerPrefs value from another player?
I use Photon PUN.
Well yes sure it is!
You could send a simple request RPC like e.g.
// Pass in the actor number of the player you want to get the score from
public void GetScore(int playerId)
{
// Get the Player by ActorNumber
var targetPlayer = Player.Get(playerId);
// Get your own ID so the receiver of the request knows who to answer to
var ownId = PhotonNetwork.LocalPlayer.ActorNumber;
// Call the GetScoreRpc on the target player
// passing in your own ID so the target player knows who to answer to
photonView.RPC(nameof(GetScoreRpc), targetPlayer, ownId);
}
[PunRpc]
private void GetScoreRpc(int requesterId)
{
// Get the requester player via the ActorNumber
var requester = Player.Get(requesterId);
// Fetch your score from the player prefab
// -1 indicates that there was an error e.g. no score exists so far
// up to you how you deal with that case
var ownScore = PlayerPrefs.GetInt("Score", -1);
// Get your own ID so the receiver knows who answered him
var ownId = PhotonNetwork.LocalPlayer.ActorNumber;
// Call the OnReceivedPlayerScore on the player who originally sent the request
photonView.RPC(nameof(OnReceivedPlayerScore), ownId, ownScore);
}
[PunRpc]
private void OnReceivedPlayerScore(int playerId, int score)
{
// Get the answering player by ActorNumber
var player = Player.Get(playerId);
// Do whatever you want with the information you received e.g.
if(score < 0)
{
Debug.LogError($"Could not get score from player \"{player.NickName}\"!");
}
else
{
Debug.Log($"Player \"{player.NickName}\" has a score of {score}!");
}
}
Related
I want to make a team vs team game using mirror in Unity.
This game goes by rounds, so once one team eliminates the members of the other team, the winner team gets one point and when a team get a certain number of points, the game ends.
To select teamm the player selects in a dropdown menu in a previous scene which team wants, and store it in the PlayerPrefs, and then when the player gameobject is instantiated, I get the PlayerPrefs and pass it to the Game Manager.
playerTeam = PlayerPrefs.GetInt("Team");
GameManager.sharedIstance.AddNewPlayer(playerId, playerTeam);`
Then in the GameManager method I update the numberOfPlayers in team
public void AddNewPlayer(int playerID, int team)
{
ActivePlayers.Add(playerID);
//Cuando se aƱaden los jugadores se incrementa el contador de jugadores en el equipo correspondiente
switch (team)
{
case 0:
numberOfPlayerTeam1++;
break;
case 1:
numberOfPlayerTeam2++;
break;
}
This works as intended and the players are separated in diferent teams so they can play.
At the end I restart the scene to play again but both players now belong to the same team
private NetworkManager Room
{
get
{
if (room != null) { return room; }
return room = NetworkManager.singleton;
}
}
private void RestartRound()
{
Room.ServerChangeScene("InGameScene");
}
This game also uses Playfab and also tried to store there the team info, and get the playerPrefs updated by the GetUserData and SetUserData methods
public void SetUserData()
{
PlayFabClientAPI.UpdateUserData(new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Player", PlayerPrefs.GetInt("Team").ToString()}
}
},
result => Debug.Log("Successfully updated user data"),
error => {
Debug.Log("Got error setting user data Ancestor to Arthur");
Debug.Log(error.GenerateErrorReport());
});
}
public void GetUserData(string myPlayFabeId)
{
PlayFabClientAPI.GetUserData(new GetUserDataRequest()
{
PlayFabId = myPlayFabeId,
Keys = null
}, result => {
Debug.Log("Got user data:");
if (result.Data == null || !result.Data.ContainsKey("Team")) Debug.Log("Team");
else
{
PlayerPrefs.SetInt("Team", Int32.Parse(result.Data["Player"].Value));
}
}, (error) => {
Debug.Log("Got error retrieving user data:");
Debug.Log(error.GenerateErrorReport());
});
}
And then when the Player is instantiated
PlayfabController.sharedInstance.GetUserData(PlayerPrefs.GetString("PlayFabId"));
playerTeam = PlayerPrefs.GetInt("Team");
But the result it's the same. The first round works as intented, but in the next rounds, all player changes to the same team.
Could you tell me how can I persist the team selection data between rounds please?
The PlayerPrefs are variables that are stored in your user registry. So if you're testing on the same computer, these variables ends the same.
So, my question is. Do you test it on the same computer using Parallel Sync or are you using different devices ?
I have a system where a player can create a room and then other players can join that room. At any point the master client can change scenes for everyone in the room and they can start playing but other players can still join the room and will instantly get their scenes synced.
However I would like to show the players that are choosing a room to join whether or not the game in that room has already begun. I decided to do that by using the customproperties of a room to save an integer which can be either 0 (players are still waiting) or 1 (players are in game). I set the custom properties after getting a callback on the master client that the room was created, however the custom properties don't change after I use SetCustomProperties.
public override void OnCreatedRoom()
{
base.OnCreatedRoom();
ExitGames.Client.Photon.Hashtable roomProps = new ExitGames.Client.Photon.Hashtable();
roomProps["inGame"] = 0;
PhotonNetwork.CurrentRoom.SetCustomProperties(roomProps);
}
public void StartLobbyGame() {
ExitGames.Client.Photon.Hashtable roomProps = new ExitGames.Client.Photon.Hashtable();
roomProps["inGame"] = 1;
PhotonNetwork.CurrentRoom.SetCustomProperties(roomProps);
PhotonNetwork.LoadLevel("InGame");
}
Any idea why that is?
You are creating an empty hashtable, so it doesn't contains the key "inGame".
You need to add it first before accessing it using roomProps["inGame"] = 0;
You can add keys like that :
ExitGames.Client.Photon.Hashtable roomProps = new ExitGames.Client.Photon.Hashtable() { {"inGame", 0} };
or
roomProps.Add("inGame", 0);
I fixed my issue by adding the custom property to the room options before creating the room with those options. After that in my start game method i change the value of the property from 0 to 1.
public void CreateRoom(string name)
{
RoomOptions ropts = new RoomOptions() { IsOpen = true, IsVisible = true, MaxPlayers = 8 };
ExitGames.Client.Photon.Hashtable roomProps = new ExitGames.Client.Photon.Hashtable();
roomProps.Add("inGame", 0);
ropts.CustomRoomProperties = roomProps;
PhotonNetwork.CreateRoom(name, ropts);
}
public void StartLobbyGame() {
PhotonNetwork.CurrentRoom.CustomProperties["inGame"] = 1;
PhotonNetwork.LoadLevel("InGame");
}
Hi Guys I am converting a single player Sudoko game into a multiplayer game (right now 2 players) using Photon in Unity.
The basic logic of the Sudoku game is that there are 300 puzzle data already loaded in it. A random number between 1 to 300 is picked up and the corresponding puzzle is loaded.
But the problem I am facing is even though I have made sure that the same number is getting picked up for both the client and the master server, different puzzles are getting loaded.
So basically I script called MultiManager attached to the MultiManager GameObject in the Sudoku screen.The script looks something like this.
void Start()
{
PV = GetComponent<PhotonView>();
if (PhotonNetwork.IsMasterClient)
{
puzzleIndex = Random.Range(0, 300);
PV.RPC("RPC_PuzzleIndex", RpcTarget.Others, puzzleIndex);
}
gameManager = FindObjectOfType(typeof(GameManager)) as GameManager;
gameManager.PlayNewGame("easy");
}
[PunRPC]
void RPC_PuzzleIndex(int puzzleIndexNUmber)
{
puzzleIndex = puzzleIndexNUmber;
}
So in the GameManager script you have these functions:
public void PlayNewGame(string groupId)
{
// Get the PuzzleGroupData for the given groupId
for (int i = 0; i < puzzleGroups.Count; i++)
{
PuzzleGroupData puzzleGroupData = puzzleGroups[i];
if (groupId == puzzleGroupData.groupId)
{
PlayNewGame(puzzleGroupData);
return;
}
}
}
private void PlayNewGame(PuzzleGroupData puzzleGroupData)
{
// Get a puzzle that has not yet been played by the user
PuzzleData puzzleData = puzzleGroupData.GetPuzzle();
// Play the game using the new puzzle data
PlayGame(puzzleData);
}
And in the PuzzleGroupData class you have this function :
public PuzzleData GetPuzzle()
{
return new PuzzleData(puzzleFiles[MultiManager.puzzleIndex], shiftAmount, groupId);
}
I don't quite get as to whats wrong which is happening. I tried to use other variations like keeping that random number outside of the condition inside of PhotonNetwork.isMasterClient and all, but doesn't work.
If anyone can help it would be great. By the way this Sudoku game was purchased and I am trying to convert it to a mutliPlayer game
Since the master is usually the first one in a room so also the first one getting Start called I think what happens is that your other clients are simply not connected yet when the RPC is called.
Further it might also happen (actually pretty likely) that Start is called before the RPC has the chance to be received.
I would rather actually wait until you have the value and do
void Start()
{
PV = GetComponent<PhotonView>();
if (PhotonNetwork.IsMasterClient)
{
PV.RPC(name of(RPC_PuzzleIndex), RpcTarget.AllBuffered, Random.Range(0, 300));
}
}
[PunRPC]
void RPC_PuzzleIndex(int puzzleIndexNUmber)
{
puzzleIndex = puzzleIndexNUmber;
gameManager = FindObjectOfType(typeof(GameManager)) as GameManager;
gameManager.PlayNewGame("easy");
}
This way
the RpcTarget.AllBuffered makes sure that also clients joining later will receive the call
there is no way you start a game without receiving the random value first
With this code I get always current score while I want to save high score I try everything to solve it but find nothing.
I want to save hgscr which is highscore , when I call with loadPlayer() I want to compare with topScore which is current score. After all that I call current score and highscore data to my score page.
Player page
if (isStarted == true)
{
if (rb2d.velocity.y > 0 && transform.position.y > topScore)
{
topScore = transform.position.y; // Current Score
}
scoreText.text = "Score: " + Mathf.Round(topScore).ToString();
}
PlayerData data = SaveSystem.LoadPlayer();
if (topScore > data.hgscrp) // current score > where I get highscore data from save page
{
hgscr = topScore; // save highs score for display on score page and compare current score after game restart
scsc = Mathf.Round(topScore).ToString(); // save current score for display on score page
SaveSystem.SavePlayer(this);
}
else
{
scsc = Mathf.Round(topScore).ToString();
SaveSystem.SavePlayer(this);
}
}
Save Page
public string cscore;
public float hgscrp;
public PlayerData (Controller player)
{
cscore = player.scsc;
hgscrp = player.hgscr;
}
Instead of using save/load, try this:
unity has a PlayerPrefs class which allows you to save variables which stay the same through restarting the game or switching scenes so if you used :
PlayerPrefs.SetFloat("VARIABLE NAME", number);
If you want to save a highs core this is perfect and to access the saved variable use:
PlayerPrefs.GetFloat("VARIABLE NAME");
I hope this works, it did for me :)
This is the code that receives raw data from other person and converts it. for right now it is supposed to add the object added from the other player to where the other player added it on the second players screen.
public void OnRealTimeMessageReceived(bool isReliable, string senderId, byte[] data)
{
byte messageVersion = (byte)data[0];
// Let's figure out what type of message this is.
char messageType = (char)data[1];
if (messageType == 'U' && data.Length == _updateMessageLength)
{
float posX = System.BitConverter.ToSingle(data, 2);
float posY = System.BitConverter.ToSingle(data, 6);
// We'd better tell our GameController about this.
if (updateListener != null)
{
updateListener.UpdateReceived(senderId, posX, posY);
}
}
}
This code sends out a message through google play services to the other player.
public void SendMyUpdate(GameObject childObj)
{
_updateMessage.Clear();
_updateMessage.Add(_protocolVersion);
_updateMessage.Add((byte)'U');
_updateMessage.AddRange(System.BitConverter.GetBytes(childObj));
byte[] messageToSend = _updateMessage.ToArray();
PlayGamesPlatform.Instance.RealTime.SendMessageToAll(false, messageToSend);
}
and this game is like tic tac toe
For a simple game like Tic Tac Toe, I would recommend you communicate the game state in a much more basic level.
Assume you have the state of your game in a 3x3 char array. Each element of the array is either
' '
'X'
'O'
Now whenever a player does their move, you update the client's local copy of the array. Then you can easily send this 3x3 array over the network. The receiving client can update their array accordingly, and so on.