[Photon] Multiplayer Card Game Help

Hello!

I’ve been racking my head for a couple of days now, and I can’t seem to figure this out.

Basically, I am making a small card game which is multi player (basically Cards Against Humanity, but a online version). You start the game up, either host a game, or join a game and get into it. Your cards will spawn in front of you (C), when you click (A). These cards will have text on them, but only you can see this text, as the other player will see “Answer”.

When you press (B), it will draw a card to (D), but this text will show to both players, and it needs to be the same question. However, when Player 2 joins, he/she will draw theirs card like I have explained above, but they will show in (E). These cards will also have text on them, but will have “Answer” on them just like above.

Player 2’s view will be exactly the same as above, with Player 1’s cards being where (E) is. Each Player will also click a card and move it to (D), next to the (B) card. These will show their respective text to every player.

Reference Image: Imgur: The magic of the Internet

With the explanation out of the way, here is what I have so far:

Player 1: Imgur: The magic of the Internet

Player 1 hosts, joins the room and then clicks Answer, he gets his answer cards at the bottom. However, this lists 20 cards instead of 10, 2 on top of each other (which is why there is overlapping text). I have no idea why this happens. Anyway, he then clicks Question and the question card is pulled and works fine.

Player 2: Imgur: The magic of the Internet

Player 2 joins, and this shows. As you can see, the cards for Player 1 show as different text (which is not the text I want), but in the wrong position. They should be at the top, and not here. As you can also see, the Question card is there, but is also different text, which I also don’t want, it should be the same text as what is in Player 1. What is not seen in this screen shot is that when Player 2 clicks “Answer”, his cards show at the top, and not the bottom like I want them too.

Moving onto the code… it’s messy and isn’t done in the best way it could probably be done, but it’s my first game (I know, multi player with a first game!?)

GameMaster.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System;


public class GameMaster : Photon.MonoBehaviour {


	public GameObject BlackCard;									// The white card we draw answers from
	public GameObject WhiteCard;									// The black card we draw questions from


	public Camera player1camera;									// Player One's camera
	public Camera player2camera;									// Player Two's camera


	public static List<string> _questions = new List<string> ();			// Questions list
	public List<string> _answers = new List<string> ();				// Answers list




	public int Points = 0;											// The amount of points the player has
	public int numberOfCards = 10;									// The number of cards to deal to the player


	private GameObject CardBase;									// The cardbase that questions/answers will go on
	private int cardWidth = 2;										// The width of the card


	private RoomInfo room;
	private static PhotonView ScenePhotonView;


	// Use this for initialization
	void Start () {


	}


	public void Awake() {
		// in case we started this demo with the wrong scene being active, simply load the menu scene
		if (!PhotonNetwork.connected) {
			Application.LoadLevel("Menu");
			return;
		}


		MakeAnswers ();
		MakeQuestions ();


		// When the server connects, add the deck cards to the board
		//CardBase = PhotonNetwork.Instantiate("BlackCard", new Vector3(-1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0)), 0);
		//CardBase = PhotonNetwork.Instantiate("WhiteCard", new Vector3(1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0)), 0);


		CardBase = Instantiate(BlackCard, new Vector3(-1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0))) as GameObject;
		CardBase = Instantiate(WhiteCard, new Vector3(1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0))) as GameObject;
	}
	
	// Update is called once per frame
	void Update () {


		// Debug Shit
		if(Input.GetKeyDown(KeyCode.A)) {
			Points++;
		}


	}
	
	void OnGUI() {
		GUI.Label (new Rect (Screen.width - 100, Screen.height - 20, 100, 20), Points + " Points");


		GUILayout.Label("Room: " + PhotonNetwork.room.name);
		GUILayout.Label("Players: ");
		
		foreach (PhotonPlayer player in PhotonNetwork.playerList) {
			GUILayout.Label("ID: " + player.ID + " Name: " + player.name);
		}
		
		if (GUILayout.Button("Leave room")) {
			PhotonNetwork.LeaveRoom();
			PhotonNetwork.LoadLevel("Menu");
		}


	}


	public void SetUp() {
		// When the server connects, add the deck cards to the board
		CardBase = Instantiate(BlackCard, new Vector3(-1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0))) as GameObject;
		CardBase = Instantiate(WhiteCard, new Vector3(1, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0))) as GameObject;


		Debug.Log ("I setup, yay!");
	}


	public void MakeQuestions() {


		WebClient client = new WebClient();
		Stream stream = client.OpenRead("http://awkwardgamers.co.uk/cah/questions.txt");
		
		using (StreamReader r = new StreamReader(stream)) {
			
			string line;
			
			while((line = r.ReadLine()) != null) {
				_questions.Add (line);
			}
			
		}
	}


	public void MakeAnswers() {


		WebClient client = new WebClient();
		Stream stream = client.OpenRead("http://awkwardgamers.co.uk/cah/answers.txt");


		using (StreamReader r = new StreamReader(stream)) {


			string line;


			while((line = r.ReadLine()) != null) {
				_answers.Add (line);
			}


		}
	}


}

This is attached to an empty GameObject called __GameMaster. It does the heavy lifting, such as the GUI, making the answers and questions and holding the amount of cards that the game will have.

DrawCards.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;


public class DrawCards : Photon.MonoBehaviour {
	
	public RaycastHit hit = new RaycastHit();
	public Ray ray;


	public static bool questionActive = false;								// Is there a question on the playing field?
	public bool myAnswer = false;									// Has the player given an answer to the current question?
	public bool cardsDrawn = false;									// Has the player drawn their white answer cards?
	public int myCards = 0;											// How many cards the player has, not really used atm
	public int swappedCards = 0;									// How many cards has been swapped
	public int maxSwapped = 3;										// The max amount of cards that can be swapped


	private Transform myTransform;
	private float cardScale = 1.8f;


	private GameObject CardBase;									// The cardbase that questions/answers will go on
	private int cardWidth = 2;										// The width of the card


	private System.Random rnd = new System.Random();				// Random setup


	void Update() {


		GameMaster gameMaster = GameObject.Find ("__GameMaster").GetComponent<GameMaster>();


		// Check to see if it is "mine"
		//if (photonView.isMine) {


			ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			if(Input.GetMouseButtonDown(0)) {


				if(Physics.Raycast(ray, out hit)) {


					myTransform = hit.transform;


					if(myTransform.tag == "WhiteCard"  cardsDrawn == false) {
					Draw (gameMaster.numberOfCards, 2);
					}


					if(myTransform.tag == "BlackCard"  cardsDrawn == true) {
						Draw (1, 1);
					}


					if(myTransform.tag == "PlayerCard"  swappedCards < maxSwapped  questionActive == true) {
						GameObject card = hit.collider.gameObject;


						MoveCard(card);
					}


				}
			}


		//}


	}


	void OnMouseEnter() {


		if(!photonView.isMine) {
			return;
		}


		myTransform = gameObject.transform;


		if(myTransform.tag == "PlayerCard" || myTransform.tag == "PlayerCardSelected" || myTransform.tag == "QuestionCard") {
			myTransform.localScale = new Vector3(myTransform.localScale.x * cardScale, myTransform.localScale.y * cardScale, myTransform.localScale.z * cardScale);


			Vector3 position = myTransform.position;
			position.y = 1;
			myTransform.position = position;


			//photonView.RPC("SizeUp", PhotonTargets.Others, myTransform);
		}


	}
	
	void OnMouseExit() {


		if(!photonView.isMine) {
			return;
		}


		myTransform = gameObject.transform;


		if(myTransform.tag == "PlayerCard" || myTransform.tag == "PlayerCardSelected" || myTransform.tag == "QuestionCard") {
			myTransform.localScale = new Vector3(myTransform.localScale.x / cardScale, myTransform.localScale.y / cardScale, myTransform.localScale.z / cardScale);


			Vector3 position = myTransform.position;
			position.y = 0;
			myTransform.position = position;


			//photonView.RPC("SizeDown", PhotonTargets.Others, myTransform);
		}


		if(myTransform.tag == "PlayerCard" || myTransform.tag == "PlayerCardSelected") {
			ResetSize (myTransform);
		}
	}


	public void Draw(int amount, int cardType) {
		
		GameMaster gameMaster = GameObject.Find ("__GameMaster").GetComponent<GameMaster>();
		
		// Blank Question Card
		if(cardType == 1) {
			if(questionActive == false) {


				GameObject cardBase1 = PhotonNetwork.Instantiate("QuestionCardBlank", new Vector3(-3, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0)), 0);
				cardBase1.name = "Question Card";
				
				// Draw the text
				GameObject cardText = cardBase1.transform.FindChild("Text").gameObject;
				string s = GameMaster._questions[rnd.Next (GameMaster._questions.Count)];


				cardText.GetComponent<TextMesh>().text = s.Replace ("|", "\n");
				
				GameMaster._questions.Remove (s);
				questionActive = true;


			}else{
				//Debug.Log ("There is already a question on the playing field.");
			}
			
		}
		
		// White Answer Card
		if(cardType == 2) {
			if(myCards < gameMaster.numberOfCards) {
				for(int cnt = 0; cnt < amount; cnt++) {
					
					if(photonView.isMine) {
						Debug.Log ("Spawned my cards");


						GameObject cardBase2 = PhotonNetwork.Instantiate("PlayerCardBlank", new Vector3((cardWidth * cnt) - 9, 0, -5), Quaternion.Euler(new Vector3(90, 0, 0)), 0);
						cardBase2.name = cnt.ToString();
						
						myCards = gameMaster.numberOfCards;
						
						// Draw the text
						GameObject cardText = cardBase2.transform.FindChild("Text").gameObject;
						string s = gameMaster._answers[rnd.Next (gameMaster._answers.Count)];


						cardText.GetComponent<TextMesh>().text = s.Replace ("|", "\n");
						
						gameMaster._answers.Remove (s);
						cardsDrawn = true;


					}else{
						Debug.Log ("Spawned another player's cards");


						GameObject cardBase2 = PhotonNetwork.Instantiate("PlayerCardBlank", new Vector3((cardWidth * cnt) - 9, 0, 5), Quaternion.Euler(new Vector3(90, 0, 0)), 0);
						cardBase2.name = cnt.ToString();
						
						myCards = gameMaster.numberOfCards;
						
						// Draw the text
						GameObject cardText = cardBase2.transform.FindChild("Text").gameObject;
						string s = gameMaster._answers[rnd.Next (gameMaster._answers.Count)];
						
						cardText.GetComponent<TextMesh>().text = "Answer";
						
						gameMaster._answers.Remove (s);
						cardsDrawn = true;
					}


				}
			}else{
				//Debug.Log ("You already have the max number of cards");
			}
		}
		
		// The answer the player chose
		if(cardType == 3) {
			if(myAnswer == false) {
				
				//CardBase = PhotonNetwork.Instantiate(BlankPlayerCardPrefab, new Vector3(3, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0)), 0) as GameObject;
				GameObject cardBase3 = PhotonNetwork.Instantiate("PlayerCardBlank", new Vector3(3, 0, 0), Quaternion.Euler(new Vector3(90, 0, 0)), 0);
				cardBase3.name = "Player 1 Answer";
				
				myAnswer = true;
				
			}else{
				//Debug.Log ("You already have the max number of cards");
			}
		}
	}
	
	//[RPC]
	public void MoveCard(GameObject go) {
		
		DrawCards drawCards = GameObject.Find ("WhiteCard(Clone)").GetComponent<DrawCards>();
		
		// If there is no answer card already there then...
		// If there is, then move back the currently selected card and then move the newly selected card
		
		Transform myTrans = go.transform;
		
		if(myAnswer == false) {
			Vector3 temp = new Vector3 (3, 0, 0);
			go.transform.position = temp;
			go.transform.tag = "PlayerCardSelected";
			
			myCards -= 1;
			
			myAnswer = true;
		}else{
			
			// Move the old card back
			GameObject oldgo = GameObject.FindGameObjectWithTag("PlayerCardSelected");
			float oldGoName = float.Parse(oldgo.name);
			
			Vector3 temp2 = new Vector3 ((cardWidth * oldGoName) - 9, 0, -5);
			oldgo.transform.position = temp2;
			oldgo.transform.tag = "PlayerCard";
			
			// Then move the new card to the board
			
			Vector3 temp = new Vector3 (3, 0, 0);
			go.transform.position = temp;
			go.transform.tag = "PlayerCardSelected";
			
			swappedCards++;
			
		}
		
		drawCards.ResetSize(myTrans);
		
	}


	public void ResetSize(Transform myTrans) {
		myTrans.localScale = new Vector3(1, 1, 1);


		Vector3 position = myTrans.position;
		position.y = 0;
		myTrans.position = position;
	}
	
}

This is attached to each card prefab, so that players can hover over them, spawn them and choose them.

There is also a Menu.cs, but all this does is do the multi player bit at the start – such as hosting a game, and joining then moving to the new scene (Level 1).

Sorry for the massive long winded explanation, and if anyone could help me get on the right foot that would be amazing. I have tried a few ways and it seems one step forward, a few back!

Thank you!

If players aren’t seeing something they should be, you need to send RPCs with the data and display them to the correct player depending on if the photonView is theirs or not.