UnityAI——动物迁徙中的跟随实现实例(一)

简介: UnityAI——动物迁徙中的跟随实现实例

大家好,我是七七,今天来给大家介绍的是Unity中用操控行为实现的跟随领队行为。

看本文若是想了解和实现,只看本文即可,若是想彻底弄透,建议从七七的游戏AI专栏开始看。

废话不多说,先上视频:

image.png

跟随队长

我们的目标是让后面的人跟着领头的人,并遵循一些规则

对于领头的人:

  1. 随机地移动
  2. 检测前方是否有人

对于跟随的人;

  1. 跟的不要太近
  2. 人与人直接不要拥挤
  3. 如果发现挡道领头人路了,赶紧让开

我们只需要实现这些规则,就可以得到理想的效果,这与神经网络的思想类似,下面我们就来实现这些规则。

规则1

这个脚本是挂载领头人身上的,目的是在前方LEADER_BEHIND_DIST处画一个圆球,若是说前方有人,则让这些人避开。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawGizmos : MonoBehaviour
{
    public float evadeDistance;
    public Vector3 center;
    private Vehicle vehicleScript;
    private float LEADER_BEHIND_DIST;
    void Start()
    {
        vehicleScript = GetComponent<Vehicle>();
        LEADER_BEHIND_DIST = 2.0f;
    }
    void Update()
    {
        center = transform.position + vehicleScript.velocity.normalized * LEADER_BEHIND_DIST;
    }
    void OnDrawGizoms()
    {
        Gizmos.DrawWireSphere(center, evadeDistance);
    }
}

规则2

这个脚本是挂在一个空物体上的,目的是生成多个跟随者

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateBotsForFollowLeader : MonoBehaviour
{
    public GameObject botPrefab;
    public GameObject leader;
    public int botCount;
    public float minX = -5f;
    public float maxX = 5.0f;
    public float minZ = -5.0f;
    public float maxZ = 5.0f;
    public float Yvalue = 1.026003f;
    void Start()
    {
        Vector3 spawnPosition;
        GameObject bot;
        for(int i = 0; i < botCount; i++)
        {
            spawnPosition = new Vector3(Random.Range(minX, maxX), Yvalue, Random.Range(minZ, maxZ));//随机产生一个生成位置
            bot = Instantiate(botPrefab, spawnPosition, Quaternion.identity) as GameObject;
            bot.GetComponent<SteeringForLeaderFollowing>().leader = leader;
            bot.GetComponent<SteeringForEvade>().target = leader;
            bot.GetComponent<SteeringForEvade>().enabled = false;
            bot.GetComponent<EvadeController>().leader = leader;
        }
    }
}

规则3

这个脚本是挂在跟随者身上的,是为了确定跟随者的路径目标点,即领导人身后LEADER_BEHIND_DIST处

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(SteeringForArrive))]
public class SteeringForLeaderFollowing : Steering
{
    public Vector3 target;
    private Vector3 desiredVelocity;//预期速度
    private Vehicle m_vehicle;//获得被操控的AI角色
    private float maxSpeed;
    private bool isPlanar;
    public GameObject leader;
    private Vehicle leaderController;
    private Vector3 leaderVelocity;
    private float LEADER_BEHIND_DIST=2.0f;
    private SteeringForArrive arriveScript;
    private Vector3 randomOffset;
    void Start()
    {
        m_vehicle = GetComponent<Vehicle>();
        maxSpeed = m_vehicle.maxSpeed;
        isPlanar = m_vehicle.isPlanar;
        leaderController=leader.GetComponent<Vehicle>();
        arriveScript= GetComponent<SteeringForArrive>();//为抵达行为指定目标点
        arriveScript.target = new GameObject("arriveTarget");
        arriveScript.target.transform.position = leader.transform.position;
    }
   public override Vector3 Force()
    {
        leaderVelocity = leaderController.velocity;
        target=leader.transform.position+LEADER_BEHIND_DIST*(-leaderVelocity).normalized;//计算目标点
        arriveScript.target.transform.position = target;
        return new Vector3(0, 0, 0);
    }
}

规则4

这个脚本是挂在跟随者身上的,目的是为了避免跟随者挡住领导人的路

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EvadeController : MonoBehaviour
{
    public GameObject leader;
    private Vehicle leaderLocomotion;
    private Vehicle m_vehicle;
    private bool isPlanar;
    private Vector3 leaderAhead;
    private float LEADER_BEHIND_DIST;
    private Vector3 dist;
    public float evadeDistance;
    private float sqrEvadeDistance;
    private SteeringForEvade evadeScript;
    void Start()
    {
        leaderLocomotion = leader.GetComponent<Vehicle>();
        evadeScript= GetComponent<SteeringForEvade>();
        m_vehicle= GetComponent<Vehicle>();
        isPlanar=m_vehicle.isPlanar;
        LEADER_BEHIND_DIST = 2.0f;
        sqrEvadeDistance=sqrEvadeDistance*sqrEvadeDistance;
    }
    void Update()
    {
        leaderAhead=leader.transform.position+leaderLocomotion.velocity.normalized*LEADER_BEHIND_DIST;  //计算领队前方的一个点
        dist = transform.position - leaderAhead;
        if (isPlanar)
        {
            dist.y = 0;
        }
        if(dist.sqrMagnitude < sqrEvadeDistance)
        {
            evadeScript.enabled = true;
            Debug.DrawLine(transform.position, leader.transform.position);
        }
        else
        {
            evadeScript.enabled = false;
        }
    }
}

实现

前提

有3个基类

UnityAI——操控行为编程的主要基类-CSDN博客

第一步

创建一个场景,一个Plane

第二步

创建一个Cube作为领队,起名为Leader,为其挂上三个脚本,如下所示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AILocomotion : Vehicle
{
    private CharacterController controller;  //AI�Ľ�ɫ������
    private Rigidbody theRigidbody;
    private Vector3 moveDistance;//AI��ɫÿ�ε��ƶ�����
    void Start()
    {
        controller = GetComponent<CharacterController>();
        theRigidbody = GetComponent<Rigidbody>();
        moveDistance = new Vector3(0, 0, 0);
        base.Start();//���û����start��������������ij�ʼ��
    }
    //������ز�����FixedUpdate�и���
    void FixedUpdate()
    {
        velocity += acceleration * Time.fixedDeltaTime;//�����ٶ�
        if (velocity.sqrMagnitude > sqrMaxSpeed)   //��������ٶ�
        velocity = velocity.normalized * maxSpeed;
        moveDistance = velocity * Time.fixedDeltaTime;
        if (isPlanar)  
        {
            velocity.y = 0;
            moveDistance.y = 0;
        }
        if (controller != null)//����Ѿ�ΪAI��ɫ���ӽ�ɫ����������ô���ý�ɫ������ʹ���ƶ�
            controller.SimpleMove(velocity);
        //�����ɫ��û��ɫ��������ҲûRigidbody
        //����Rigidbody����Ҫ�ɶ���ѧ�ķ�ʽ�������ƶ�
        else if (theRigidbody == null || !theRigidbody.isKinematic)
            transform.position += moveDistance;
        else //��Rigidbody���ƽ�ɫ���˶�
            theRigidbody.MovePosition(theRigidbody.position+moveDistance);
        if(velocity.sqrMagnitude>0.00001)//���³�������ٶȴ���һ����ֵ��Ϊ�˷�ֹ������
        {
            Vector3 newForward = Vector3.Slerp(transform.forward, velocity, damping * Time.deltaTime);
            if(isPlanar)
                newForward.y = 0;
            transform.forward = newForward;
        }
        //�������߶���
        gameObject.GetComponent<Animation>().Play("walk");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SteeringForWander : Steering
{
    public float wanderRadius; //徘徊半径
    public float wanderDistance; //徘徊距离
    public float wanderJitter; //每秒加到目标的随即位移的最大值
    public bool isPlanar;
    private Vector3 desiredVelocity;//预期速度
    private Vehicle m_vehicle;//获得被操控的AI角色
    private float maxSpeed;
    private Vector3 circleTarget;
    private Vector3 wanderTarget;
    void Start()
    {
        m_vehicle = GetComponent<Vehicle>();
        maxSpeed = m_vehicle.maxSpeed;
        isPlanar = m_vehicle.isPlanar;
        circleTarget = new Vector3(wanderRadius * 0.707f, 0, wanderRadius * 0.707f);  //选取与安全上的一个点作为初始点
    }
    public override Vector3 Force()
    {
        Vector3 randomDisplacement = new Vector3((Random.value - 0.5f) * 2 * wanderJitter, (Random.value - 0.5f) * 2 * wanderJitter, (Random.value - 0.5f) * 2 * wanderJitter);
        if (isPlanar)
            randomDisplacement.y = 0;
        circleTarget+=randomDisplacement;//将随机位移加到初始点上
        circleTarget = wanderRadius * circleTarget.normalized;//由于新位置很可能不在圆周上,因此需要投影到圆周上
        wanderTarget = m_vehicle.velocity.normalized * wanderDistance + circleTarget + transform.position;//之前计算出的值是相对于AI的,需要转换为世界坐标
        desiredVelocity = (wanderTarget - transform.position).normalized * maxSpeed;
        return (desiredVelocity - m_vehicle.velocity);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DrawGizmos : MonoBehaviour
{
    public float evadeDistance;
    public Vector3 center;
    private Vehicle vehicleScript;
    private float LEADER_BEHIND_DIST;
    void Start()
    {
        vehicleScript = GetComponent<Vehicle>();
        LEADER_BEHIND_DIST = 2.0f;
    }
    void Update()
    {
        center = transform.position + vehicleScript.velocity.normalized * LEADER_BEHIND_DIST;
    }
    void OnDrawGizoms()
    {
        Gizmos.DrawWireSphere(center, evadeDistance);
    }
}


相关文章
|
机器学习/深度学习
基于PaddleGAN精准唇形合成模型实现美女表白视频
基于PaddleGAN精准唇形合成模型实现美女表白视频
624 0
基于PaddleGAN精准唇形合成模型实现美女表白视频
|
2月前
|
人工智能
姿态识别+康复训练矫正+代码+部署(AI 健身教练来分析深蹲等姿态)-2
姿态识别+康复训练矫正+代码+部署(AI 健身教练来分析深蹲等姿态)-2
149 2
|
2月前
|
机器学习/深度学习 人工智能 算法
姿态识别+康复训练矫正+代码+部署(AI 健身教练来分析深蹲等姿态)-1
姿态识别+康复训练矫正+代码+部署(AI 健身教练来分析深蹲等姿态)-1
192 1
|
2月前
|
编解码 移动开发 人工智能
分享4个策略经营、5动作冒险、8角色扮演、8体育竞速、18飞行射击和30棋牌安卓游戏源码
分享4个策略经营、5动作冒险、8角色扮演、8体育竞速、18飞行射击和30棋牌安卓游戏源码
42 0
|
7月前
UnityAI——动物迁徙中的跟随实现实例(二)
UnityAI——动物迁徙中的跟随实现实例
|
定位技术 图形学
Unity3D——射击游戏(多地图,多人物,枪支切换,驾车,扔手雷等功能,堪比小型和平精英)
Unity3D——射击游戏(多地图,多人物,枪支切换,驾车,扔手雷等功能,堪比小型和平精英)
Unity3D——射击游戏(多地图,多人物,枪支切换,驾车,扔手雷等功能,堪比小型和平精英)
|
机器学习/深度学习 自然语言处理 算法
谷歌让机器人充当大语言模型的手和眼,一个任务拆解成16个动作一气呵成
谷歌让机器人充当大语言模型的手和眼,一个任务拆解成16个动作一气呵成
171 0
|
算法 计算机视觉
CV:利用人工智能算法让古代皇帝画像以及古代四大美女画像动起来(模仿偶像胡歌剧中角色表情动作)
CV:利用人工智能算法让古代皇帝画像以及古代四大美女画像动起来(模仿偶像胡歌剧中角色表情动作)
CV:利用人工智能算法让古代皇帝画像以及古代四大美女画像动起来(模仿偶像胡歌剧中角色表情动作)
|
人工智能 算法 vr&ar
「缸中之脑」成真?动态电极绕过眼睛直接刺激大脑,在盲人脑海画出字母
最新研究绕过眼睛,通过动态电极刺激大脑,直接让天生的盲人脑海中出现字母!「智子倒计时」、「缸中之脑」、「黑客帝国」,让人分不清虚拟还是现实的直接意识输入,或许真的离我们不远了。
226 0
「缸中之脑」成真?动态电极绕过眼睛直接刺激大脑,在盲人脑海画出字母
|
传感器 算法 iOS开发
Cuptime 2 智能水杯:从数据到游戏,为了让你健康喝水也是操碎了心|评测
麦开一直以来与国内很多智能硬件公司比较不一样,那就是研发的产品几乎都是原创的,而且获得的成绩也不错,这点都比较难得。Cuptime就是其代表作之一,智能水杯可是麦开首创的产品,当时连国外也没有这种产品,一年销售了超过10万台,后面很多智能水杯产品或多或少的也在参考Cuptime。
387 0
Cuptime 2 智能水杯:从数据到游戏,为了让你健康喝水也是操碎了心|评测