Unity学习笔记:联网游戏Pixel Adventure 1学习过程&纠错心得

Unity学习笔记:联网游戏Pixel Adventure 1学习过程&纠错心得、

之前学校教了一些网络游戏编程的相关内容,跟着学完了感觉还是不会,但是做能联网的游戏又很重要,正好前不久刷到一个合适的教程,B站弹幕评论区一致好评讲的很好,用到的Photon技术学长也推荐,正好最近工程实践项目做得告一段落,于是决定把这个教程找来学学。
https://www.bilibili.com/video/BV1rJ411D7VJ?spm_id_from=333.999.0.0
在这里插入图片描述
这个帖子用来记录自己学习途中遇到的一些问题和解决办法,类似于纠错本。
用到的资源链接:
https://assetstore.unity.com/packages/2d/characters/pixel-adventure-1-155360
用到的Photon:
https://dashboard.photonengine.com/en-US

1.资源包加入到我的资源之后点击在Unity中打开没反应

参考链接:
https://blog.csdn.net/qq_15020543/article/details/83382527?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2aggregatepagefirst_rank_ecpm_v1~rank_v31_ecpm-1-83382527-null-null.pc_agg_new_rank&utm_term=%E5%9C%A8unity%E5%95%86%E5%BA%97%E6%89%93%E5%BC%80%E8%B5%84%E6%BA%90%E6%B2%A1%E5%8F%8D%E5%BA%94&spm=1000.2123.3001.4430
但是我就是用的Hub,所以对我来说没什么帮助。
最后我新建了一个空白项目,刚打开就发现可以自动出现自己的资源:
在这里插入图片描述
点击右下角,下载之后导入资源包:
(顺便提一句这个好像还是我们工程实践老师提到过的说什么Unity新的Package模式还是什么?我也有点记不太清了)
在这里插入图片描述

2.绑定App ID到Pun 2

在这里插入图片描述

把自己创建项目的AppID复制下来,粘贴到导入Photon2之后出现的窗口里。
![在这里插入图片描述](https://img-blog.csdnimg.cn/b2d76129db654c45ad3e0a5c2034bfe0.png
在这里插入图片描述
在这里插入图片描述
Setting这里版本号随便写个数字1
在这里插入图片描述
调整信息显示的类别,希望显示所有信息,比如网络连接情况
在这里插入图片描述
教程在这里找:
在这里插入图片描述

3.导入

在这里插入图片描述
如果不能拖拽添加观察,就手动加上对应脚本
在这里插入图片描述
Trigger要放在最后一个选项
在这里插入图片描述
进入一次房间要生成一个玩家,所以玩家需要做成Prefab,如果需要网络化,那么Prefab要添加到Photon文件夹中。
在这里插入图片描述

4.网页出现error无法正常加载

网页Bug,把error删掉就行
在这里插入图片描述
在这里插入图片描述
回车即可

第一集使用到的C#代码:

建一个空物体改名NetWorkLauncher,然后把这个脚本附加上去

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class Launcher : MonoBehaviourPunCallbacks//继承这个类可以得到服务器的反馈资料
{
    // Start is called before the first frame update
    void Start()
    {
        PhotonNetwork.ConnectUsingSettings();//链接服务器
    }

    public override void OnConnectedToMaster()//是否连接到游戏大厅,主服务器
    {
        base.OnConnectedToMaster();
        Debug.Log("连接成功!");

        //所有进入同一房间的玩家会在一个屏幕上显示
        PhotonNetwork.JoinOrCreateRoom("Room", new Photon.Realtime.RoomOptions() { MaxPlayers = 4 }, default);
        //MaxPlayer最大可20个,default可以换成其他房间属性

    }
    public override void OnJoinedRoom()
    {
        base.OnJoinedRoom();
        PhotonNetwork.Instantiate("Player", new Vector3(1, 1, 0), Quaternion.identity, 0);
    }
    // Update is called once per frame
    void Update()
    {
         
    }
}

挂在Player身上的代码(只有网络相关功能,没有玩家移动转身之类的内容)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
/// <summary>
/// 本脚本用于控制玩家的移动
/// </summary>
public class PlayerMovement : MonoBehaviourPun
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(!photonView.IsMine&&PhotonNetwork.IsConnected)//如果观察的角色是当前客户端并且服务器在运行就继续反之return
        {
            return;
        }
    }
}

挂上这两脚本之后,应该能实现运行游戏自动生成玩家和Build Settings窗口和运行模式窗口的玩家同步

5.报错Can not Instantiate before the client joined/created a room. State: ConnectedToMasterServer

在这里插入图片描述
经过回看视频检查,发现是创建房间的函数绑定错误,绑成了之前那个应该在第二集开头就被删除的脚本(顺便,可以不删除脚本,把挂有这个脚本的物体删除就行了)
在这里插入图片描述
改成新写的JoinOrCreateRoom之后,问题解决
在这里插入图片描述
没有报错了。
在这里插入图片描述
之前报错是因为这个按钮点击调用了那个被移除的脚本里面的函数,相当于无效点击,自然也没有创建房间,所以报错Can not Instantiate before the client joined/created a room. State: ConnectedToMasterServer

6.角色翻转的时候,角色身上的名字也一起翻转

在这里插入图片描述
获取Sprite Renderer组件的Flip参数即可,不使用自己写的代码
因为我没写老师那么完善的代码,他这里面一些变量我也不太知道怎么定义的,就只大致填个框架了。
在这里插入图片描述
看弹幕有人说这么写因为没有Photon View Sprite Renderer,所以可能会造成无法同步的情况
我试着找了一下能View Sprite Renderer的脚本,但是并没有找到,又去百度了一下,还没有找到合适的答案
发现一位码友写的链接很有营养:
https://blog.csdn.net/ninesnow_c/article/details/106699608
在这里插入图片描述

第二集使用到的C#代码:

为了不报错,我把Flip的部分注释掉了:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;

/// <summary>
/// 本脚本用于控制玩家的移动
/// </summary>
public class PlayerMovement : MonoBehaviourPun
{
    public Text nameText;
    public SpriteRenderer sprite;
    private void Awake()
    {
        sprite = GetComponent<SpriteRenderer>();
        if(photonView.IsMine)//如果观察到的角色是自己,就把自己的名字给这个对象
        {
            nameText.text = PhotonNetwork.NickName;
        }
        else//把正主的名字给这个对象,看到的这个角色是谁就是谁的名字
        {
            nameText.text = photonView.Owner.NickName;
        }
    }
    public void Flip()//翻转
    {
        //if(xVelocity<0)
        //{
        //    sprite.flipX = true;
        //}
        //else if(xVelocity>0)
        //{
        //    sprite.flipX = false;
        //}
    }
    // Update is called once per frame
    void Update()
    {
        if(!photonView.IsMine&&PhotonNetwork.IsConnected)//如果观察的角色是当前客户端并且服务器在运行就继续反之return
        {
            return;
        }
    }
}

挂在Level1场景的空物体改名GameManager上的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class GameManager : MonoBehaviourPunCallbacks
{
    public GameObject readyButton;

    public void ReadyToPlay()
    {
        readyButton.SetActive(false);
        PhotonNetwork.Instantiate("Player", new Vector3(1, 1, 0), Quaternion.identity, 0);
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

挂在Login场景中的NetworkLauncher(空物体改名字)上的脚本NetworkLauncher

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class NetworkLauncher : MonoBehaviourPunCallbacks
{
    public GameObject loginUI;
    public GameObject nameUI;
    public InputField roomName;
    public InputField playerName;

    // Start is called before the first frame update
    void Start()
    {
        PhotonNetwork.ConnectUsingSettings();
    }
    public override void OnConnectedToMaster()
    {
        //base.OnConnectedToMaster();
        nameUI.SetActive(true);//如果连接到服务器,登录UI就会显示出来
    }
    public void PlayButton()
    {
        nameUI.SetActive(false);
        PhotonNetwork.NickName = playerName.text;//名字传输到网络当中
        loginUI.SetActive(true);//启用登录UI
    }
   public void JoinOrCreateButton() 
    {
        //如果没有名字,不能点击按钮
        if(roomName.text.Length<2)
        {
            return;
        }
        loginUI.SetActive(false);

        RoomOptions options = new RoomOptions { MaxPlayers = 4 };
        PhotonNetwork.JoinOrCreateRoom(roomName.text, options, default);//有就加入,没有就创建

    }

    public override void OnJoinedRoom()
    {
        base.OnJoinedRoom();
        PhotonNetwork.LoadLevel(1);
    }
}

7.无法进入同一房间

这个物体是B站网友提出的,我自己倒是没有遇到。
修改Fixed Region,强制进入同一服务器
在这里插入图片描述
把下图最下方红框里面网速最快的国家代号填进Fixed Region,这样就能保证客户端都进入这个服务器
在这里插入图片描述

8.Ctrl+鼠标点击查看方法详情

在这里插入图片描述

9.指定位置生成预制体并设置父物体

这段代码比较有参考价值,我之前也一直不太会写这种,现在遇到了就专门记下来:
在这里插入图片描述

10.报错ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.

百度了一下这句话,大部分是因为数组越界造成的。
在这里插入图片描述
但是我仔细检查了我那点少得可怜的关于数组的代码,好像并没有越界的风险?
而且多反复Build几次之后,出现了新的报错,是Player和RoomListNameButton没有把预制体拖给脚本,所以实例化失败,把这俩问题解决之后所有奇奇怪怪的问题都奇迹般地消失了。
运行效果:
在这里插入图片描述

第三集使用到的C#代码:

挂在Login场景里面空物体上RoomListManager的,关于更新房间列表的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class RoomListManager : MonoBehaviourPunCallbacks
{
    public GameObject roomNamePreb;
    public Transform gridLayout;//content

    public override void OnRoomListUpdate(List<RoomInfo> roomList)
    {
        for(int i=0;i<gridLayout.childCount;i++)
        {
            //移除所有房间
            if(gridLayout.GetChild(i).gameObject.GetComponentInChildren<Text>().text==roomList[i].Name)
            {
                Destroy(gridLayout.GetChild(i).gameObject);//移除的是UI按钮
                //房间里面没人了需要移除房间
                if(roomList[i].PlayerCount==0)
                {
                    roomList.Remove(roomList[i]);//移除该房间
                }
            }
        }
        foreach(var room in roomList)//遍历房间列表
        {
            //对象,位置,旋转角度
            GameObject newRoom = Instantiate(roomNamePreb, gridLayout.position, Quaternion.identity);
           //按钮身上的Text改成房间名字
            newRoom.GetComponentInChildren<Text>().text = room.Name +"("+room.PlayerCount+" 人)";//可以自由DIY房间需要显示的信息
            //生成的预制体的父物体设置为Content
            newRoom.transform.SetParent(gridLayout);
        }
    }
}

挂在主角行动,负责主角位置同步和主角移动(没有写,可根据需要自行添加主角左右移动之类的代码):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using UnityEngine.UI;

/// <summary>
/// 本脚本用于控制玩家的移动
/// </summary>
public class PlayerMovement : MonoBehaviourPun
{
    public Text nameText;
    public SpriteRenderer sprite;
    private void Awake()
    {
        sprite = GetComponent<SpriteRenderer>();
        if(photonView.IsMine)//如果观察到的角色是自己,就把自己的名字给这个对象
        {
            nameText.text = PhotonNetwork.NickName;
        }
        else//把正主的名字给这个对象,看到的这个角色是谁就是谁的名字
        {
            nameText.text = photonView.Owner.NickName;
        }
    }
    public void Flip()//翻转
    {
        //if(xVelocity<0)
        //{
        //    sprite.flipX = true;
        //}
        //else if(xVelocity>0)
        //{
        //    sprite.flipX = false;
        //}
    }
    // Update is called once per frame
    void Update()
    {
        if(!photonView.IsMine&&PhotonNetwork.IsConnected)//如果观察的角色是当前客户端并且服务器在运行就继续反之return
        {
            return;
        }
    }
}

挂在Level1场景的空物体GameManager身上的脚本GameManager:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;

public class GameManager : MonoBehaviourPunCallbacks
{
    public GameObject readyButton;

    public void ReadyToPlay()
    {
        readyButton.SetActive(false);
        PhotonNetwork.Instantiate("Player", new Vector3(1, 1, 0), Quaternion.identity, 0);
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

挂在Login场景上的NetworkLauncher上的脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

public class NetworkLauncher : MonoBehaviourPunCallbacks
{
    public GameObject loginUI;
    public GameObject nameUI;
    public InputField roomName;
    public InputField playerName;

    public GameObject roomListUI;

    // Start is called before the first frame update
    void Start()
    {
        PhotonNetwork.ConnectUsingSettings();
    }
    public override void OnConnectedToMaster()
    {
        //base.OnConnectedToMaster();
        nameUI.SetActive(true);//如果连接到服务器,登录UI就会显示出来
        Debug.Log("Connecter to the Master");
        PhotonNetwork.JoinLobby();//加入游戏大厅,这样才可以读取RoomList

    }
    public void PlayButton()
    {
        nameUI.SetActive(false);
        PhotonNetwork.NickName = playerName.text;//名字传输到网络当中
        loginUI.SetActive(true);//启用登录UI
        //如果加入大厅,则显示列表UI
        if(PhotonNetwork.InLobby)
        {
            roomListUI.SetActive(true);
        }
    }
   public void JoinOrCreateButton() 
    {
        //如果没有名字,不能点击按钮
        if(roomName.text.Length<2)
        {
            return;
        }
        loginUI.SetActive(false);

        RoomOptions options = new RoomOptions { MaxPlayers = 4 };
        PhotonNetwork.JoinOrCreateRoom(roomName.text, options, default);//有就加入,没有就创建

    }

    public override void OnJoinedRoom()
    {
        base.OnJoinedRoom();
        PhotonNetwork.LoadLevel(1);
    }
}

层级关系如图:
Login场景:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
UI层级:
在这里插入图片描述
Level1场景:
在这里插入图片描述
在这里插入图片描述
完整的项目我也会上传CSDN空间,非常简略,除了我提到的这些以外没别的功能。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值