前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >PUN ☀️九、玩家网络实例化与昵称显示

PUN ☀️九、玩家网络实例化与昵称显示

作者头像
星河造梦坊官方
发布2024-08-15 21:12:34
发布2024-08-15 21:12:34
8000
代码可运行
举报
运行总次数:0
代码可运行

🟥 目标

1️⃣ 玩家网络实例化

即把玩家要操控的角色生成出来。GameManager里面Start时实例化角色。

2️⃣ 实现战斗数据不重置

原先只有两个人,再加入一个人,会切换到3人的场景。但原先的两个人当前战斗数据会被重置,这是不合理的。

我们来让之前的玩家数据不被重置。

a、PlayerManager 声明的静态字段LocalPlayerInstance 记录本地玩家实例化的。 Awake赋值,并在加载新场景时,不销毁当前角色。 b、但在重新加载新场景时,GameManager 脚本 Start时会再次实例化角色,于是一个玩家就有了两个角色。所以GameManager Start时根据判断 LocalPlayerInstance 是否为空,确定是否已经实例化了角色。

3️⃣ 位置重置

若从3人房切换到2人房,房间变小了。若切换后原先在地面上的角色悬空了,会出Bug。

所以增加判断:若切换后没踩在地板上,则位置回到出生位置(原点高空)。

方法:PlayerManager 脚本Start时增加加载完场景时的委托,增加的委托事件判断当前角色位置

4️⃣ 激光碰撞判断

解决当跳跃时触发激光,会造成自身减血的现象。

这是因为激光与自身角色控制器的触发器检测碰撞了,我们要检测激光不是接触的自身才行,避免自己碰撞掉血。解决办法:

  • 设置自身的Tag,触发检测Tag再决定是否减血。
  • PlayerManager脚本判断射线碰撞到的角色是否是自己,不是的话再减血(此处采用)
代码语言:javascript
代码运行次数:0
运行
复制
if (other.GetComponentInParent<PhotonView>().IsMine)
    return;
 
Health -= 0.1f;

现在我们可以测试看看,如果发现连接不上,就换成中国区Appid试试,我隔了一天申请通过了,现在你申请的应该也好了。

🟧 代码编写

🚩 PlayerManager

代码语言:javascript
代码运行次数:0
运行
复制
using UnityEngine;
using Photon.Pun;
 
public class PlayerManager : MonoBehaviourPunCallbacks, IPunObservable
{
    #region Parameters
 
    public GameObject beams;
 
    //记录本地玩家实例化
    public static GameObject LocalPlayerInstance;
 
    public float Health = 1f;
 
    //当用户开火时,为True
    bool IsFiring;
 
    #endregion
 
 
    #region Mono CallBacks
 
    void Awake()
    {
        beams.SetActive(false);
 
        if (PhotonNetwork.IsConnected == true && photonView.IsMine)
            LocalPlayerInstance = gameObject;
 
        DontDestroyOnLoad(gameObject);
    }
 
    void Start()
    {
        //当重新加载场景时,检测改脚本所赋值的角色是否踩在空中,若是,则回到出生点重新降落。
        UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
 
        if (PhotonNetwork.IsConnected && photonView.IsMine)
            GetComponent<Skode_CameraWork>().OnStartFollowing();
    }
 
    void Update()
    {
        if (Health <= 0f)
            GameManager.ins.Skode_LeaveRoom();
 
        if (PhotonNetwork.IsConnected == true && photonView.IsMine)
            ProcessInputs();
 
        if (IsFiring != beams.activeSelf)
            beams.SetActive(IsFiring);
    }
 
    void OnTriggerEnter(Collider other)
    {
        if (!photonView.IsMine && !other.CompareTag("beam"))
            return;
 
        Health -= 0.1f;
    }
 
    void OnTriggerStay(Collider other)
    {
        if (!photonView.IsMine && !other.CompareTag("beam"))
            return;
 
        //乘以增量时间,防止因为帧率FPS不同,扣血不同(举例:不乘,每帧执行一次扣血,卡的人比流畅的人扣血少)
        Health -= 0.1f * Time.deltaTime;
    }
 
    #endregion
 
 
    #region PUN CallBacks
 
    public override void OnDisable()
    {
        base.OnDisable();
        UnityEngine.SceneManagement.SceneManager.sceneLoaded -= OnSceneLoaded;
    }
 
    public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.IsWriting)
        {
            // 我们拥有这个角色:把我们的数据发送给其他人
            stream.SendNext(IsFiring);
            stream.SendNext(Health);
        }
        else
        {
            // 网络角色,接收数据
            IsFiring = (bool)stream.ReceiveNext();
            Health = (float)stream.ReceiveNext();
        }
    }
 
    #endregion
 
 
    #region Private Methods
 
    void OnSceneLoaded(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode loadingMode)
    {
        CalledOnLevelWasLoaded(scene.buildIndex);
    }
 
    void CalledOnLevelWasLoaded(int level)
    {
        // 检查我们是否在竞技场外面,如果是这样,移动到竞技场中心的安全地带
        if (!Physics.Raycast(transform.position, -Vector3.up, 5f))
        {
            transform.position = new Vector3(0f, 5f, 0f);
        }
    }
 
    void ProcessInputs()
    {
        //鼠标左键
        if (Input.GetButtonDown("Fire1"))
            IsFiring = true;
 
        if (Input.GetButtonUp("Fire1"))
            IsFiring = false;
    }
 
    #endregion
}

🚩 GameManager

代码语言:javascript
代码运行次数:0
运行
复制
using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
 
public class GameManager : MonoBehaviourPunCallbacks
{
    public static GameManager ins;
 
    [Tooltip("用来代表玩家的预置体")]
    public GameObject playerPrefab;
 
 
    #region Mono CallBacks
 
    private void Awake()
    {
        ins = this;
    }
 
    private void Start()
    {
        //若本地玩家第一次进游戏场景,还未生成角色,则生成一个。
        //且这个角色通过使用PhotonNetwork.Instantiate进行同步
        if (PlayerManager.LocalPlayerInstance == null)
            PhotonNetwork.Instantiate(playerPrefab.name, new Vector3(0f, 5f, 0f), Quaternion.identity, 0);
    }
 
    #endregion
 
 
    #region Public Methods
 
    //离开服务器房间Btn
    public void Skode_LeaveRoom()
    {
        //不允许主客户端离开房间
        if (!PhotonNetwork.IsMasterClient)
            PhotonNetwork.LeaveRoom();
    }
 
    #endregion
 
 
    #region PUN Callbacks
 
    /// <summary>
    /// 本地玩家离开服务器房间时回调
    /// </summary>
    public override void OnLeftRoom()
    {
        // 加载大厅场景
        SceneManager.LoadScene(0);
    }
 
    /// <summary>
    /// 其他玩家连接房间时的回调(不是自己)
    /// </summary>
    public override void OnPlayerEnteredRoom(Player other)
    {
        print(other.NickName + "    加入房间");
 
        //根据当前玩家的人数,主客户端加载对应场景
        if (PhotonNetwork.IsMasterClient)
            LoadArena();
    }
 
    //当玩家离开房间或变得不活动时调用。
    public override void OnPlayerLeftRoom(Player other)
    {
        print(other.NickName + "    离开了房间");
 
        //根据当前玩家的人数,主客户端加载对应场景
        if (PhotonNetwork.IsMasterClient)
            LoadArena();
    }
 
    #endregion
 
 
    #region Private Methods
 
    void LoadArena()
    {
        //Photon分为主客户端、其他客户端。只有主客户端才可进行加载房间。
        //根据当前房间人数加载对应场景。该方法会使其他玩家会自动加入主客户端的房间
        PhotonNetwork.LoadLevel("Room for " + PhotonNetwork.CurrentRoom.PlayerCount);
    }
 
    #endregion
}

🟨 血条、昵称显示

1、创建UI

在人物下创建3D Slider血条,并且有文本框用于显示名字。

若是滑动条即使是满值也不到头,只需改下滑动条下Fill Area 的 Right值就好了。

在这里插入图片描述
在这里插入图片描述

2、代码赋值

将下代码挂到机器人身上,并赋值。

代码语言:javascript
代码运行次数:0
运行
复制
using UnityEngine;
using UnityEngine.UI;
 
public class PlayerUI : MonoBehaviour
{
    #region  Parameters
 
    [Tooltip("显示玩家名字的UI文本")]
    public Text playerNameText;
 
    [Tooltip("健康值Slider")]
    public Slider playerHealthSlider;
 
    [Tooltip("用于获取生命值赋值给血条")]
    public PlayerManager target;
 
    #endregion
 
 
    #region Mono Callbacks
 
    void Start()
    {
        playerNameText.text = target.photonView.Owner.NickName;
    }
 
    void Update()
    {
        playerHealthSlider.value = target.Health;
    }
 
    #endregion
}

若现在还没把机器人放到 Resources里,现在就要放进去了。已经放进去的Apply一下。

将 Resources 里的机器人预制体赋值给GameManager,删掉面板的机器人。

各个场景的 GameManager都赋值一下,接下来要进行测试了。

还有,记得关闭离线模式哦

🟩 最终效果展示:

落头上了哈哈

好啦,本系列暂告一段落🧸 大家还有什么问题,欢迎在下方留言!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 🟥 目标
    • 1️⃣ 玩家网络实例化
    • 2️⃣ 实现战斗数据不重置
    • 3️⃣ 位置重置
    • 4️⃣ 激光碰撞判断
  • 🟧 代码编写
    • 🚩 PlayerManager
    • 🚩 GameManager
  • 🟨 血条、昵称显示
  • 🟩 最终效果展示:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档