一、效果展示
二、创建Photon账号以及申请中国区服务
1、国外链接:https://www.photonengine.com/
2、国内链接:https://vibrantlink.com/
三、Unity导入PUN2插件并修改设置
1、在AssetStore搜索PUN2,并导入PUN2插件,导入时会让你填写APPID,导入成功会多出一个Photon文件夹
2、修改相应设置
2.1打开Photon->PhotonRealtime->Code->LoadBalancingClient.cs,修改其中一句代码
2.2打开Photon->PtotonUnityNetworking->Resources->PhotonServerSettings
四、场景搭建
五、代码
4.1Piece.cs,挂载在两颗棋子身上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
public enum PieceColor
{
Black = 0,
White = 1
}
public class Piece : MonoBehaviour
{
public int row;
public int col;
public PieceColor pieceColor = PieceColor.Black;
[PunRPC]
public void SetRowColValue(int[] rowColValue)
{
if (rowColValue.Length != 2)
return;
row = rowColValue[0];
col = rowColValue[1];
}
}
4.2PlayerTest01.cs,挂载在Player01身上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using System.Linq;
using UnityEngine.UI;
public class PlayerTest01 : MonoBehaviour
{
public PieceColor pieceColor = PieceColor.Black;
private PhotonView pv;
private int row; //行
private int col; //列
public GameObject Black_Piece;
public GameObject White_Piece;
public List<Piece> currentPieceList = new List<Piece>();
public PlayerState playerState = PlayerState.NotReady;
// Start is called before the first frame update
void Start()
{
pv = this.GetComponent<PhotonView>();
if (pv.IsMine)
{
GameObject.FindObjectOfType<NetWorkManager>().SetSelfText(pieceColor);
}
else
{
GameObject.FindObjectOfType<NetWorkManager>().SetHostileText(pieceColor);
}
}
// Update is called once per frame
void Update()
{
if (!pv.IsMine) //判断是否为当前客户端
return;
if (GameObject.FindObjectOfType<NetWorkManager>().playerTurn != pieceColor)
return;
if (GameObject.FindObjectOfType<NetWorkManager>().gameState != GameState.Ready)
return;
var players = GameObject.FindObjectsOfType<PlayerTest01>();
foreach (var item in players)
{
if (item.playerState != PlayerState.Ready)
{
return;
}
}
PlayerChess();
}
public void PlayerChess()
{
GameObject newPiece;
Piece currentPiece = new Piece();
if (Input.GetMouseButtonDown(0))
{
Vector2 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition); //屏幕坐标转换为世界坐标
row = (int)(pos.x + 7.5f);
col = (int)(pos.y + 7.5f);
//Debug.Log("x = " + row + " y = " + col);
int[] rowColValue = {
row, col };
if (row >= 0 && row < 15 && col >= 0 && col < 15)
{
//避免重复落子
currentPieceList = GameObject.FindObjectsOfType<Piece>().ToList();
foreach (var item in currentPieceList)
{
if (item.row == row && item.col == col)
{
return;
}
}
if (pieceColor == PieceColor.Black)
{
if (Black_Piece != null)
{
newPiece = PhotonNetwork.Instantiate(Black_Piece.name, new Vector3(row - 7, col - 7), Black_Piece.transform.rotation);
newPiece.GetComponent<PhotonView>().RPC("SetRowColValue", RpcTarget.All, rowColValue); //同步数据
currentPiece = newPiece.GetComponent<Piece>();
GameObject.FindObjectOfType<NetWorkManager>().gameObject.GetComponent<PhotonView>().RPC("SetUIFollowPos", RpcTarget.All, newPiece.transform.position);
}
}
else
{
if (White_Piece != null)
{
newPiece = PhotonNetwork.Instantiate(White_Piece.name, new Vector3(row - 7, col - 7), White_Piece.transform.rotation);
newPiece.GetComponent<PhotonView>().RPC("SetRowColValue", RpcTarget.All, rowColValue);
currentPiece = newPiece.GetComponent<Piece>();
GameObject.FindObjectOfType<NetWorkManager>().gameObject.GetComponent<PhotonView>().RPC("SetUIFollowPos", RpcTarget.All, newPiece.transform.position);
}
}
GameObject.FindObjectOfType<NetWorkManager>().PlayMarkingAudio();
currentPieceList = GameObject.FindObjectsOfType<Piece>().ToList();
bool isFive = IsWinning(currentPieceList, currentPiece);
if (isFive)
{
//Debug.Log(currentPiece.pieceColor + "获胜!");
GameObject.FindObjectOfType<NetWorkManager>().gameObject.GetComponent<PhotonView>().RPC("GameOver", RpcTarget.All, pieceColor);
}
//修改落子Turn
GameObject.FindObjectOfType<NetWorkManager>().gameObject.GetComponent<PhotonView>().RPC("ChangeTurn", RpcTarget.All);
}
else
{
return;
}
}
}
private bool IsWinning(List<Piece> currentList, Piece currentPiece)
{
bool result = false;
List<Piece> currentColorList = currentList.Where(en => en.pieceColor == currentPiece.pieceColor).ToList();
//List<Piece> currentColorList = new List<Piece>();
//foreach (var item in currentList)
//{
// if(item.pieceColor==currentPiece.pieceColor)
// {
// currentColorList.Add(item);
// }
//}
var upList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.Up);
var downList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.Down);
var leftList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.Left);
var rightList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.Right);
var leftTopList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.LeftTop);
var rightDownList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.RightDown);
var leftDownList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.LeftDown);
var rightTopList = GetSamePieceByDirection(currentColorList, currentPiece, PieceDirection.RightTop);
//Debug.Log(upList.Count + ":" + downList.Count + ":" + leftList.Count + ":" + rightList.Count
// + ":" + leftTopList.Count + ":" + rightDownList.Count + ":" + leftDownList.Count + ":" + rightTopList.Count);
if (upList.Count + downList.Count + 1 >= 5 || leftList.Count + rightList.Count + 1 >= 5 ||
leftTopList.Count + rightDownList.Count + 1 >= 5 || leftDownList.Count + rightTopList.Count + 1 >= 5)
{
result = true;
}
return result;
}
private List<Piece> GetSamePieceByDirection(List<Piece> currentColorList, Piece currentPiece, PieceDirection direction)
{
List<Piece> result = new List<Piece>();
switch (direction)
{
case PieceDirection.Up:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row && item.col == currentPiece.col + 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.Up);
result.AddRange(resultList);
}
}
break;
case PieceDirection.Down:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row && item.col == currentPiece.col - 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.Down);
result.AddRange(resultList);
}
}
break;
case PieceDirection.Left:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row - 1 && item.col == currentPiece.col)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.Left);
result.AddRange(resultList);
}
}
break;
case PieceDirection.Right:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row + 1 && item.col == currentPiece.col)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.Right);
result.AddRange(resultList);
}
}
break;
case PieceDirection.LeftTop:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row - 1 && item.col == currentPiece.col + 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.LeftTop);
result.AddRange(resultList);
}
}
break;
case PieceDirection.RightDown:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row + 1 && item.col == currentPiece.col - 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.RightDown);
result.AddRange(resultList);
}
}
break;
case PieceDirection.LeftDown:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row - 1 && item.col == currentPiece.col - 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.LeftDown);
result.AddRange(resultList);
}
}
break;
case PieceDirection.RightTop:
foreach (var item in currentColorList)
{
if (item.row == currentPiece.row + 1 && item.col == currentPiece.col + 1)
{
result.Add(item);
var resultList = GetSamePieceByDirection(currentColorList, item, PieceDirection.RightTop);
result.AddRange(resultList);
}
}
break;
default:
break;
}
return result;
}
[PunRPC]
public void SetPieceColor(PieceColor color)
{
pieceColor = color;
}
[PunRPC]
public void SetPlayerReady()
{
playerState = PlayerState.Ready;
if (pv.IsMine)
{
GameObject.FindObjectOfType<NetWorkManager>().selfReadyText.text = "已准备";
}
else
{
GameObject.FindObjectOfType<NetWorkManager>().hostileReadyText.text = "已准备";
}
}
[PunRPC]
public void SetAgainButtonText()
{
if (pv.IsMine)
{
GameObject.FindObjectOfType<NetWorkManager>().againButtonText.text = "再来一局";
GameObject.FindObjectOfType<NetWorkManager>().againButtonText.transform.parent.GetComponent<Button>().interactable = false;
}
else
{
GameObject.FindObjectOfType<NetWorkManager>().againButtonText.text = "接受挑战";
}
}
[PunRPC]
public void AgainGame()
{
GameObject.FindObjectOfType<NetWorkManager>().gameOverText.gameObject.SetActive(false);
currentPieceList = GameObject.FindObjectsOfType<Piece>().ToList();
foreach (var item in currentPieceList)
{
Destroy(item.gameObject);
}
GameObject.FindObjectOfType<NetWorkManager>().turnText.gameObject.SetActive(true);
GameObject.FindObjectOfType<NetWorkManager>().UIFollowTransform.position = new Vector3(10, 0, 0);
GameObject.FindObjectOfType<NetWorkManager>().againButtonText.text = "再来一局";
GameObject.FindObjectOfType<NetWorkManager>().turnText.text = "黑方落子";
GameObject.FindObjectOfType<NetWorkManager>().againButtonText.transform.parent.GetComponent<Button>().interactable = true;
GameObject.FindObjectOfType<NetWorkManager>().playerTurn = PieceColor.Black;
GameObject.FindObjectOfType<NetWorkManager>().gameState = GameState.Ready;
}
[PunRPC]
public void ShowTurnText()
{
GameObject.FindObjectOfType<NetWorkManager>().turnText.text = "黑方落子";
}
[PunRPC]
public void HideTurnText()
{
GameObject.FindObjectOfType<NetWorkManager>().turnText.text = "";
}
}
public enum PieceDirection
{
Up = 0,
Down = 1,
Left = 2,
Right = 3,
LeftTop = 4,
RightDown = 5,
LeftDown = 6,
RightTop = 7
}
public enum PlayerState
{
NotReady = 0,
Ready = 1
}
4.3NetWorkManager.cs,挂载在名叫NetWorkManager的空物体身上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun; //1、引入命名空间
using Photon.Realtime;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public enum GameState
{
Ready = 1,
GameOver = 2
}
public class NetWorkManager : MonoBehaviourPunCallbacks //2、修改继承基类
{
public GameObject player;
public PieceColor playerTurn = PieceColor.Black;
public GameState gameState = GameState.Ready;
public AudioSource markingMusic;
public AudioSource bgMusic;
public Text readyButtonText;
public Text selfPieceText;
public Text selfReadyText;
public Text hostilePieceText;
public Text hostileReadyText;
public Text turnText;
public Text winnerText;
public Text gameOverText;
public Sprite readyButtonSelectedSprite;
private int bgMusicButtonClickNums = 0;
public Button bgMusicButton;
public Sprite bgMusicOff;
public Sprite bgMusicOn;
public Text againButtonText;
public Transform UIFollowTransform;
// Start is called before the first frame update
void Start()
{
SetUIState();
PhotonNetwork.ConnectUsingSettings(); //3、连接服务器
}
public override void OnConnectedToMaster()
{
base.OnConnectedToMaster();
Debug.Log("成功连接服务器!");
//4、创建或者加入房间
RoomOptions roomOptions = new RoomOptions {
MaxPlayers = 2 };
PhotonNetwork.JoinOrCreateRoom("test", roomOptions, TypedLobby.Default);
}
public override void OnJoinedRoom()
{
base.OnJoinedRoom();
Debug.Log("创建或者加入房间成功!");
//5、创建联网玩家
if (player == null)
return;
GameObject newplayer = PhotonNetwork.Instantiate(player.name, Vector3.zero, Quaternion.identity);
if (PhotonNetwork.IsMasterClient)
{
newplayer.GetComponent<PhotonView>().RPC("SetPieceColor", RpcTarget.All, PieceColor.Black);
}
else
{
newplayer.GetComponent<PhotonView>().RPC("SetPieceColor", RpcTarget.All, PieceColor.White);
}
}
[PunRPC]
public void ChangeTurn()
{
playerTurn = playerTurn == PieceColor.Black ? PieceColor.White : PieceColor.Black;
turnText.text = playerTurn == PieceColor.Black ? "黑方落子" : "白方落子";
}
[PunRPC]
public void GameOver(PieceColor winColor)
{
gameState = GameState.GameOver;
turnText.gameObject.SetActive(false);
if (gameOverText)
{
winnerText.text = winColor == PieceColor.Black ? "黑子胜!" : "白子胜!";
gameOverText.gameObject.SetActive(true);
//winnerText.gameObject.SetActive(true);
}
}
[PunRPC]
public void SetUIFollowPos(Vector3 pos)
{
UIFollowTransform.position = pos;
}
public void PlayMarkingAudio() //播放落子音效
{
if (markingMusic)
{
markingMusic.Play();
}
}
public void OnBGMusicButtonClick() //关闭背景音乐
{
if (bgMusic)
{
bgMusicButtonClickNums += 1;
if (bgMusicButtonClickNums % 2 == 0)
{
bgMusicButton.GetComponent<Image>().sprite = bgMusicOn;
bgMusic.Play();
}
else if (bgMusicButtonClickNums % 2 == 1)
{
bgMusicButton.GetComponent<Image>().sprite = bgMusicOff;
bgMusic.Pause();
}
}
}
public void OnReadyButtonClick()
{
int index = 0;
readyButtonText.text = "已准备";
readyButtonText.transform.parent.GetComponent<Image>().sprite = readyButtonSelectedSprite;
var players = GameObject.FindObjectsOfType<PlayerTest01>();
if (players.Length >= 2)
{
foreach (var item in players)
{
if (item.playerState == PlayerState.Ready)
{
index += 1;
}
if (index >= 1)
{
item.GetComponent<PhotonView>().RPC("ShowTurnText", RpcTarget.All);
}
}
}
foreach (var item in players)
{
if (item.GetComponent<PhotonView>().IsMine)
{
item.GetComponent<PhotonView>().RPC("SetPlayerReady", RpcTarget.All);
}
}
readyButtonText.transform.parent.GetComponent<Button>().enabled = false;
}
public void SetUIState()
{
readyButtonText.text = "准备";
selfPieceText.text = "";
selfReadyText.text = "";
hostilePieceText.text = "";
hostileReadyText.text = "";
turnText.text = "";
//winnerText.gameObject.SetActive(false);
gameOverText.gameObject.SetActive(false);
}
public void SetSelfText(PieceColor pieceColor)
{
selfPieceText.text = pieceColor == PieceColor.Black ? "黑方" : "白方";
selfReadyText.text = "未准备";
}
public void SetHostileText(PieceColor pieceColor)
{
hostilePieceText.text = pieceColor == PieceColor.Black ? "黑方" : "白方";
hostileReadyText.text = "未准备";
}
public void OnAgainButtonClick()
{
var players = GameObject.FindObjectsOfType<PlayerTest01>();
if (againButtonText.text == "接受挑战")
{
foreach (var item in players)
{
item.GetComponent<PhotonView>().RPC("AgainGame", RpcTarget.All);
}
return;
}
foreach (var item in players)
{
if (item.GetComponent<PhotonView>().IsMine)
{
item.GetComponent<PhotonView>().RPC("SetAgainButtonText", RpcTarget.All);
}
}
}
}
六、项目链接
链接:https://pan.baidu.com/s/1hwjlGhbAL8z_HbDbjh_C_A
提取码:x41b