首先,将PUN设为离线模式,先来进行本地测试。等发布时,再取消勾选改为联网模式。
为什么设置,可参考:传送门
Robot Kyle 从Assets拖到层级面板,进行如下配置:
a、指定机器人状态机:Kyle Robot
b、挂载如下代码:
该代码负责控制机器人运动,WAD运动,跑起来后右键跳跃。
using Photon.Pun;
using UnityEngine;
public class PlayerAnimatorManager : MonoBehaviourPun
{
#region Private Fields
[SerializeField]
float directionDampTime = 0.25f;
Animator animator;
#endregion
#region Mono CallBacks
void Start()
{
animator = GetComponent<Animator>();
}
void Update()
{
//教程参考:https://skode.blog.csdn.net/article/details/106356112
if (PhotonNetwork.IsConnected == true && photonView.IsMine == false)
return;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
// 只有在我们跑步的时,按下右键才允许跳跃。
if (stateInfo.IsName("Base Layer.Run") && Input.GetButtonDown("Fire2"))
animator.SetTrigger("Jump");
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical") < 0 ? 0 : Input.GetAxis("Vertical");
animator.SetFloat("Speed", h * h + v * v);
animator.SetFloat("Direction", h, directionDampTime, Time.deltaTime);
}
#endregion
}
为机器人添加 CharacterController,调整Center等,属性如下:
创建 Resources 文件夹,将Robot Kyle拖到Resources制成预制体。
为机器人添加如下脚本,勾选 FollwOnStart
该脚本的FollowOnStart,为离线模式,该功能是在离线模式下,让摄像机自动找到人物跟随。在发布时的联网状态下,需取消勾选,自己写代码判断哪个人物是自己的,来跟随。
你的Camera要为 MainCamera
using UnityEngine;
// Camera work. Follow a target
public class Skode_CameraWork : MonoBehaviour
{
#region Fields
[Tooltip("在局部x-z平面到目标的距离")]
public float distance = 7.0f;
[Tooltip("我们希望相机高于目标的高度")]
public float height = 3.0f;
[Tooltip("相机高度的平滑时滞")]
public float heightSmoothLag = 0.3f;
[Tooltip("允许相机垂直于目标,例如,提供更多的景色和较少的地面")]
public Vector3 centerOffset = Vector3.zero;
[Tooltip("如果预制组件被光子网络改变,则将此设置为false,并在需要时手动调用OnStartFollowing()")]
public bool followOnStart = false;
// cached transform of the target
Transform cameraTransform;
// maintain a flag internally to reconnect if target is lost or camera is switched
bool isFollowing;
// Represents the current velocity, this value is modified by SmoothDamp() every time you call it.
float heightVelocity;
// Represents the position we are trying to reach using SmoothDamp()
float targetHeight = 100000.0f;
#endregion
#region Mono Callbacks
void Start()
{
// Start following the target if wanted.
if (followOnStart)
OnStartFollowing();
}
void LateUpdate()
{
// The transform target may not destroy on level load,
// so we need to cover corner cases where the Main Camera is different everytime we load a new scene, and reconnect when that happens
if (cameraTransform == null && isFollowing)
OnStartFollowing();
// only follow is explicitly declared
if (isFollowing)
Apply();
}
#endregion
#region Public Methods
/// <summary>
/// Raises the start following event.
/// Use this when you don't know at the time of editing what to follow, typically instances managed by the photon network.
/// </summary>
public void OnStartFollowing()
{
cameraTransform = Camera.main.transform;
isFollowing = true;
// we don't smooth anything, we go straight to the right camera shot
Cut();
}
#endregion
#region Private Methods
/// <summary>
/// Follow the target smoothly
/// </summary>
void Apply()
{
Vector3 targetCenter = transform.position + centerOffset;
// Calculate the current & target rotation angles
float originalTargetAngle = transform.eulerAngles.y;
float currentAngle = cameraTransform.eulerAngles.y;
// Adjust real target angle when camera is locked
float targetAngle = originalTargetAngle;
currentAngle = targetAngle;
targetHeight = targetCenter.y + height;
// Damp the height
float currentHeight = cameraTransform.position.y;
currentHeight = Mathf.SmoothDamp(currentHeight, targetHeight, ref heightVelocity, heightSmoothLag);
// Convert the angle into a rotation, by which we then reposition the camera
Quaternion currentRotation = Quaternion.Euler(0, currentAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
cameraTransform.position = targetCenter;
cameraTransform.position += currentRotation * Vector3.back * distance;
// Set the height of the camera
cameraTransform.position = new Vector3(cameraTransform.position.x, currentHeight, cameraTransform.position.z);
// Always look at the target
SetUpRotation(targetCenter);
}
/// <summary>
/// Directly position the camera to a the specified Target and center.
/// </summary>
void Cut()
{
float oldHeightSmooth = heightSmoothLag;
heightSmoothLag = 0.001f;
Apply();
heightSmoothLag = oldHeightSmooth;
}
/// <summary>
/// Sets up the rotation of the camera to always be behind the target
/// </summary>
/// <param name="centerPos">Center position.</param>
void SetUpRotation(Vector3 centerPos)
{
Vector3 cameraPos = cameraTransform.position;
Vector3 offsetToCenter = centerPos - cameraPos;
// Generate base rotation only around y-axis
Quaternion yRotation = Quaternion.LookRotation(new Vector3(offsetToCenter.x, 0, offsetToCenter.z));
Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset);
}
#endregion
}
在机器人Head下新建如图所示两个cube作为激光射线
只使用一个Collider就好,并作为触发器,避免作为碰撞器将别人碰飞
机器人添加下方脚本,并将Beams赋值给它
实现:当按下鼠标左键,打开激光。松开左键,关闭激光。
在网络中多人玩,还要考虑: 我按下了鼠标左键,那场景中的各个机器人,怎么判断我是属于谁,你按下鼠标左键我要不要执行程序? if (photonView.IsMine),便实现了此功能。判断这个机器人是不是我的。是的话,执行程序。
using UnityEngine;
using Photon.Pun;
public class PlayerManager : MonoBehaviour
{
#region Parameters
public GameObject beams;
//当用户开火时,为True
bool IsFiring;
#endregion
#region Mono CallBacks
void Awake()
{
beams.SetActive(false);
}
void Update()
{
if (PhotonNetwork.IsConnected == true && photonView.IsMine)
ProcessInputs();
if (IsFiring != beams.activeSelf)
beams.SetActive(IsFiring);
}
#endregion
#region Private Methods
void ProcessInputs()
{
//鼠标左键
if (Input.GetButtonDown("Fire1"))
IsFiring = true;
if (Input.GetButtonUp("Fire1"))
IsFiring = false;
}
#endregion
}
目标:
当射线击中时,扣0.1血,一直击中,每秒0.1。 当生命值0时,离开房间。
1、GameManager改为单例
2、PlayerManager 更新如下:
using UnityEngine;
using Photon.Pun;
public class PlayerManager : MonoBehaviourPunCallbacks
{
#region Parameters
public GameObject beams;
public float Health = 1f;
//当用户开火时,为True
bool IsFiring;
#endregion
#region Mono CallBacks
void Awake()
{
beams.SetActive(false);
}
void Update()
{
if (Health <= 0f)
GameManager.ins.Skode_LeaveRoom();
if (PhotonNetwork.IsConnected == true && photonView.IsMine)
ProcessInputs();
if (IsFiring != beams.activeSelf)
beams.SetActive(IsFiring);
}
#endregion
#region Private Methods
void ProcessInputs()
{
//鼠标左键
if (Input.GetButtonDown("Fire1"))
IsFiring = true;
if (Input.GetButtonUp("Fire1"))
IsFiring = false;
}
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
}
大家还有什么问题,欢迎在下方留言!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有