PUN ☀️六、机器人基础设置:运动、相机、攻击与生命值

简介: PUN ☀️六、机器人基础设置:运动、相机、攻击与生命值

🟥 效果展示

首先,将PUN设为离线模式,先来进行本地测试。等发布时,再取消勾选改为联网模式。

为什么设置,可参考:传送门


🟧 机器人运动

Robot Kyle 从Assets拖到层级面板,进行如下配置:

1️⃣ 状态机及状态机控制

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
}


2️⃣ 添加角色控制器

为机器人添加 CharacterController,调整Center等,属性如下:


3️⃣ 制作预制体

创建 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
}


🟩 攻击系统

1️⃣ 激光射线

在机器人Head下新建如图所示两个cube作为激光射线


2️⃣ 碰撞器设置

只使用一个Collider就好,并作为触发器,避免作为碰撞器将别人碰飞

  • 将右眼激光的Collider移除,左眼Collider拉大包裹住两个cube
  • 勾选Collider的 isTrigger
  • 将带Collider射线的tag设为 beam


3️⃣ 激光控制

机器人添加下方脚本,并将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
}


4️⃣ 预制体Apply一下


🟦 生命值系统

目标:

当射线击中时,扣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
}


相关文章
|
7月前
|
机器人
剑指 Offer 13:机器人的运动范围
剑指 Offer 13:机器人的运动范围
56 0
|
机器人 Windows
QQ机器人有哪些?QQ机器人怎么设置?
随着QQ群的活跃,越来越多的群组需要用机器人来管理群,比较流行的QQ机器人有哪些?QQ机器人又需要怎么设置?目前市面上有很多QQ群机器人,其中比较流行的有第十代qq机器人、酷q机器人等。这些机器人都有各自的特点和功能,可以满足不同的需求,具体需要怎么设置机器人呢?下面就拿第十代QQ机器人给大家举例。
|
4月前
|
数据可视化 机器人 Python
实例9:四足机器人运动学正解平面RR单腿可视化
本文是关于四足机器人正向运动学(FK)的实例教程,通过Python编程实现了简化的mini pupper平面二连杆模型的腿部可视化,并根据用户输入的关节角计算出每个关节相对于基坐标系的坐标。
80 1
|
4月前
|
数据可视化 算法 机器人
实例10:四足机器人运动学逆解可视化与实践
本文是关于四足机器人逆运动学(IK)的实例教程,介绍了逆运动学的概念、求解方法、多解情况和工作空间,并通过Python编程实现了简化的mini pupper平面二连杆模型的逆运动学可视化,包括单腿舵机的校准和动态可视化运动学计算结果。
225 0
|
7月前
|
NoSQL 机器人 Windows
ROS机器人编程技术控制两只小海龟的编队运动
ROS机器人编程技术控制两只小海龟的编队运动
259 1
|
7月前
|
机器人 Python
Moveit + Gazebo实现联合仿真:ABB yumi双臂机器人( 二、双臂协同运动实现 )
Moveit + Gazebo实现联合仿真:ABB yumi双臂机器人( 二、双臂协同运动实现 )
|
7月前
|
机器学习/深度学习 人工智能 机器人
[译][AI 机器人] Atlas的电动新时代,不再局限于人类运动范围的动作方式
波士顿动力宣布液压Atlas机器人退役,推出全新电动Atlas,旨在实现更广泛的实际应用。这款全电动机器人将拓展人类运动范围,解决复杂工业挑战。现代汽车公司将参与其商业化进程,作为测试应用场景。波士顿动力计划与创新客户合作,逐步迭代Atlas的应用,打造高效、实用的移动机器人解决方案。Atlas将结合强化学习和计算机视觉等先进技术,通过Orbit软件平台进行管理,未来将在真实世界中发挥超越人类能力的作用。
|
人工智能 算法 机器人
【目标识别】自适应多机器人编队,可在运动和能见度约束下包围和跟踪目标(Matlab代码实现)
【目标识别】自适应多机器人编队,可在运动和能见度约束下包围和跟踪目标(Matlab代码实现)
105 0
|
算法 机器人 C++
剑指offer(C++)-JZ13:机器人的运动范围(算法-回溯)
剑指offer(C++)-JZ13:机器人的运动范围(算法-回溯)
|
传感器 Ubuntu 机器人
【5. ROS机器人的运动控制】
【5. ROS机器人的运动控制】
510 0
【5. ROS机器人的运动控制】