![0a6de46b05336424f60f5db9dac74782.png](https://i-blog.csdnimg.cn/blog_migrate/f2b2a6bd5088d78fbb43804a2ffdaf63.jpeg)
基于Photon Cloud的Unity多人游戏开发日志目录
Berkeley Zhou:基于Photon Cloud的Unity多人游戏开发日志_目录zhuanlan.zhihu.com![84f36ee4916af274f668970e7c01b46b.png](https://i-blog.csdnimg.cn/blog_migrate/bafe69488e451b64b98835914326396b.jpeg)
上一次我们讲到如何创建一个虚拟房间并加入
Berkeley Zhou:基于Photon Cloud的Unity多人游戏开发日志_房间,对战的开始zhuanlan.zhihu.com![84f36ee4916af274f668970e7c01b46b.png](https://i-blog.csdnimg.cn/blog_migrate/bafe69488e451b64b98835914326396b.jpeg)
现在该离开大厅进入我们的游戏了
是的,我们需要一个新的场景了
暂且叫它PlayGround吧
建一个60x60的地面
![ab9a0c533ecdeb865c38ca0427475c62.png](https://i-blog.csdnimg.cn/blog_migrate/0f184b4573d8fadbe449513e88c4765e.jpeg)
这个地面白的辣眼睛,我用一款插件给他上一个测试贴图
插件名称叫做Forceling World Grid
以前是支持全版本的,不知道为啥现在只支持2019版本了QAQ
![b386590f0ce4fb09eb345159bfe43757.png](https://i-blog.csdnimg.cn/blog_migrate/e674b4f5770f789c2c6e77f4a1d2b616.jpeg)
用上插件的效果
![779aa183d9b263307fac6649043a17d6.png](https://i-blog.csdnimg.cn/blog_migrate/86deb4cf4f21509e507c5d7c212a36be.jpeg)
不仅不辣眼睛了,还有标尺。简直是Demo好伙伴
想要我介绍这个插件的可以评论区反馈一下
好了言归正传,我们赶紧把场景搭完
![fcaa6b0d3df1d05f00378e4dce0138b9.png](https://i-blog.csdnimg.cn/blog_migrate/c1cc672379088f1470e8abc337b07376.jpeg)
新场景建立完成,我们回到熟悉的ConnectManager里面
再在OnJoinedRoom()回调函数里面加上如下内容
public override void OnJoinedRoom()
{
Debug.Log("Join successful!");
if (PhotonNetwork.CurrentRoom.PlayerCount == 1)
{
Debug.Log("Initiative load level.");
PhotonNetwork.LoadLevel(1);
}
base.OnJoinedRoom();
}
这段代码什么意思呢
就是说,如果房间里只有一个人,我们就主动载入新场景
我知道你现在非常疑惑,但是问题我们慢慢解决
首先我们看一下载入场景的代码PhotonNetwork.LoadLevel(1);
这就和以前的SceneManager.LoadScene()方法截然不同了,我们现在使用的是网络载入
然后就是LoadLevel(1)这个1在哪里
熟悉场景载入的同学应该就知道了,这是在BuildSettings里面设置好的,我们现在去设置一下
![8df2086b6a144927570c6401c7227b75.png](https://i-blog.csdnimg.cn/blog_migrate/3ca923781b558f2d90de86adf99557ae.jpeg)
然后我们再来回顾一下,如果房间里的玩家数量是一个,我们就主动载入场景,那这个玩家是谁呢?
当然就是我们自己啦!
所以只有在房间里只有自己的时候我们要主动载入场景
因为在Photon的定义中,刚刚是你调用了Create()函数创建你的房间,你就是房主
那如果其他玩家加入房间怎么办呢?
这个时候我们就要设置一个重要的参数了
在Start()函数里面写上如下代码
void Start()
{
//Connect();
PhotonNetwork.AutomaticallySyncScene = true;
}
这句PhotonNetwork.AutomaticallySyncScene =true;就是在说:
如果你不是房主,你就得听房主的话,跟着房主同步载入场景
你的房主在那个场景,你就要在哪个场景
这些都写好了,我们看下成果
![80ce8111bfe9ef4b34a62fe53cb83289.png](https://i-blog.csdnimg.cn/blog_migrate/91cda769f71da60c5c681c58e768eab7.jpeg)
传 统 艺 能
但是等等,你觉得这期就这么结束了吗???
我不要你觉得,我要我觉得
我觉得还可以改进一些内容(•̀ロ•́) ✧ ~~
![8eeddd800da5c0c5281a6a06c49f0971.png](https://i-blog.csdnimg.cn/blog_migrate/ae5a1359522c55a40e2f5a8f8024ca09.jpeg)
还记得这个加入游戏的按钮吗,理论上必须要连接上服务器才能能加入房间
但是我们没有写这样的限制
我们回到ConnectManager里面,加一个序列化变量
[Tooltip("<加入游戏>按钮")]
[SerializeField]
Button joinRoomButton;
然后改写一下连接上和断开连接的回调函数
public override void OnConnected()
{
Debug.Log("Connect successful!");
if (joinRoomButton!=null)
joinRoomButton.interactable = true;
base.OnConnected();
}
public override void OnDisconnected(DisconnectCause cause)
{
if (joinRoomButton!=null)
joinRoomButton.interactable = false;
base.OnDisconnected(cause);
}
这里写if(joinRoomButton!=null)也是为了解耦,让加入房间的按钮不是必须存在的。
然后Start()函数也可以改一改
void Start()
{
//Connect();
PhotonNetwork.AutomaticallySyncScene = true;
if (joinRoomButton != null)
{
if (PhotonNetwork.IsConnected)
{
joinRoomButton.interactable = true;
}
else
{
joinRoomButton.interactable = false;
}
}
}
测试一下
![4682e785572e3667ecc3508e8550e4bd.png](https://i-blog.csdnimg.cn/blog_migrate/1ce1b92299e746cee5357fb30a3389d3.jpeg)
![4aa49f9a426f0e3e1c94e618343bd5fc.png](https://i-blog.csdnimg.cn/blog_migrate/96292bd2522c4d06564289d5d36b1c66.jpeg)
完全成功
晾出代码,收工睡觉
ConnectManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Realtime;
using Photon.Pun;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ConnectManager : MonoBehaviourPunCallbacks
{
#region 序列化变量
[Tooltip("最大房间玩家数量")]
[SerializeField]
byte maxPlayerNumber = 4;
[Tooltip("<加入游戏>按钮")]
[SerializeField]
Button joinRoomButton;
#endregion
#region GameVersion
string gameVersion = "2";
#endregion
// Start is called before the first frame update
void Start()
{
//Connect();
PhotonNetwork.AutomaticallySyncScene = true;
if (joinRoomButton != null)
{
if (PhotonNetwork.IsConnected)
{
joinRoomButton.interactable = true;
}
else
{
joinRoomButton.interactable = false;
}
}
}
// Update is called once per frame
void Update()
{
}
#region Public Methods
/// <summary>
/// 连接方法,如果已经连接上了Debug一下
/// </summary>
/// <returns></returns>
public void Connect()
{
if (PhotonNetwork.IsConnected)
{
Debug.Log("Already Connected");
}
else
{
PhotonNetwork.GameVersion = gameVersion;
PhotonNetwork.ConnectUsingSettings();
}
}
public void JoinRoom()
{
//如果还没有连上服务器
if (!PhotonNetwork.IsConnected)
{
Connect();
}
else
{
PhotonNetwork.JoinRandomRoom();
}
}
#endregion
#region PUN Callbacks
public override void OnConnected()
{
Debug.Log("Connect successful!");
if (joinRoomButton!=null)
joinRoomButton.interactable = true;
base.OnConnected();
}
public override void OnDisconnected(DisconnectCause cause)
{
if (joinRoomButton!=null)
joinRoomButton.interactable = false;
base.OnDisconnected(cause);
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = maxPlayerNumber });
Debug.Log("Join room failed, create one.");
base.OnJoinRandomFailed(returnCode, message);
}
public override void OnJoinedRoom()
{
Debug.Log("Join successful!");
if (PhotonNetwork.CurrentRoom.PlayerCount == 1)
{
Debug.Log("Initiative load level.");
PhotonNetwork.LoadLevel(1);
}
base.OnJoinedRoom();
}
#endregion
}
InputFieldManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InputFieldManager : MonoBehaviour
{
#region Required Compoments
public InputField userNameInputField;
public IOManager ioManager;
#endregion
// Start is called before the first frame update
void Start()
{
//如果存在玩家用户名的储存文件
if (ioManager.UserNameExist())
{
Debug.Log(ioManager.ReadUserName());
userNameInputField.text = ioManager.ReadUserName();
}
}
// Update is called once per frame
void Update()
{
}
}
IOManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class IOManager : MonoBehaviour
{
#region File Names
[Tooltip("玩家用户名信息存储地址")]
[SerializeField]
string userNameFileName = "/UserID.txt";
#endregion
#region Public Field
#endregion
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
#region Public Method
/// <summary>
/// 写入玩家用户名
/// </summary>
/// <param name="name"></param>
public void WriteUserName(string name)
{
string filePath = Application.dataPath + userNameFileName;
//文件读写流
StreamWriter sw;
//文件地址信息
FileInfo fi = new FileInfo(filePath);
//如果文件不存在
if (!fi.Exists)
{
sw = fi.CreateText();
}
//如果存在
else
{
//销毁文件
File.Delete(filePath);
sw = fi.CreateText();
}
sw.WriteLine(name);
//关闭&销毁流
sw.Close();
sw.Dispose();
}
/// <summary>
/// 读取玩家的用户名
/// </summary>
/// <returns></returns>
public string ReadUserName()
{
string filePath = Application.dataPath + userNameFileName;
//先判断一下文件是否存在
if (!File.Exists(filePath))
{
Debug.Log("User name file donot exist.");
return null;
}
//打开文件读取流
StreamReader sr = File.OpenText(filePath);
string userName = sr.ReadLine();
sr.Close();
sr.Dispose();
return userName;
}
public bool UserNameExist()
{
string filePath = Application.dataPath + userNameFileName;
//先判断一下文件是否存在
if (File.Exists(filePath))
{
return true;
}
else
{
return false;
}
}
#endregion
}