Unity使用Photon插件实现联机五子棋

一、效果展示

效果展示

二、创建Photon账号以及申请中国区服务

1、国外链接:https://www.photonengine.com/

注册Photon账号
创建APP

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

猜你喜欢

转载自blog.csdn.net/qq_44887198/article/details/129202503