即把玩家要操控的角色生成出来。GameManager里面Start时实例化角色。
原先只有两个人,再加入一个人,会切换到3人的场景。但原先的两个人当前战斗数据会被重置,这是不合理的。
我们来让之前的玩家数据不被重置。
a、PlayerManager 声明的静态字段LocalPlayerInstance 记录本地玩家实例化的。 Awake赋值,并在加载新场景时,不销毁当前角色。 b、但在重新加载新场景时,GameManager 脚本 Start时会再次实例化角色,于是一个玩家就有了两个角色。所以GameManager Start时根据判断 LocalPlayerInstance 是否为空,确定是否已经实例化了角色。
若从3人房切换到2人房,房间变小了。若切换后原先在地面上的角色悬空了,会出Bug。
所以增加判断:若切换后没踩在地板上,则位置回到出生位置(原点高空)。
方法:PlayerManager 脚本Start时增加加载完场景时的委托,增加的委托事件判断当前角色位置
解决当跳跃时触发激光,会造成自身减血的现象。
这是因为激光与自身角色控制器的触发器检测碰撞了,我们要检测激光不是接触的自身才行,避免自己碰撞掉血。解决办法:
if (other.GetComponentInParent<PhotonView>().IsMine)
return;
Health -= 0.1f;
现在我们可以测试看看,如果发现连接不上,就换成中国区Appid试试,我隔了一天申请通过了,现在你申请的应该也好了。
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
}
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、代码赋值
将下代码挂到机器人身上,并赋值。
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都赋值一下,接下来要进行测试了。
还有,记得关闭离线模式哦
落头上了哈哈
好啦,本系列暂告一段落🧸 大家还有什么问题,欢迎在下方留言!