首页 > 分享 > UnityAI——动物迁徙中的跟随实现实例

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

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

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

废话不多说,先上视频:

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

对于领头的人:

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

对于跟随的人;

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

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

规则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;

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;

private Rigidbody theRigidbody;

private Vector3 moveDistance;

void Start()

{

controller = GetComponent<CharacterController>();

theRigidbody = GetComponent<Rigidbody>();

moveDistance = new Vector3(0, 0, 0);

base.Start();

}

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)

controller.SimpleMove(velocity);

else if (theRigidbody == null || !theRigidbody.isKinematic)

transform.position += moveDistance;

else

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;

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;

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);

}

}

第三步

创建一个空物体,起名为follersGenerator,用于生成跟随者,并添加脚本

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;

}

}

}

第四步

创建一个方块预设,作为跟随者,挂上下列脚本:

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class AILocomotion : Vehicle

{

private CharacterController controller;

private Rigidbody theRigidbody;

private Vector3 moveDistance;

void Start()

{

controller = GetComponent<CharacterController>();

theRigidbody = GetComponent<Rigidbody>();

moveDistance = new Vector3(0, 0, 0);

base.Start();

}

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)

controller.SimpleMove(velocity);

else if (theRigidbody == null || !theRigidbody.isKinematic)

transform.position += moveDistance;

else

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 SteeringForArrive : Steering

{

public bool isPlanar = true;

public float arrivalDistance = 0.3f;

public float characterRadius = 1.2f;

public float slowDownDistance;

public GameObject target;

private Vector3 desiredVelocity;

private Vehicle m_vehicle;

private float maxSpeed;

void Start()

{

m_vehicle = GetComponent<Vehicle>();

maxSpeed = m_vehicle.maxSpeed;

isPlanar = m_vehicle.isPlanar;

}

public override Vector3 Force()

{

Vector3 toTarget = target.transform.position - transform.position;

Vector3 desiredVelocity;

Vector3 returnForce;

if (isPlanar)

toTarget.y = 0;

float distance = toTarget.magnitude;

if (distance > slowDownDistance)

{

desiredVelocity = toTarget.normalized * maxSpeed;

returnForce = desiredVelocity - m_vehicle.velocity;

}

else

{

desiredVelocity = toTarget - m_vehicle.velocity;

returnForce = desiredVelocity - m_vehicle.velocity;

}

return returnForce;

}

void OnDrawGizmos()

{

Gizmos.DrawWireSphere(target.transform.position, slowDownDistance);

}

}

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;

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);

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class Radar : MonoBehaviour

{

private Collider[] colliders;

private float timer = 0;

public List<GameObject> neighbors;

public float checkInterval = 0.3f;

public float detectRadius = 10f;

public LayerMask layersChecked;

void Start()

{

neighbors = new List<GameObject>();

}

void Update()

{

timer += Time.deltaTime;

if(timer > checkInterval)

{

neighbors.Clear();

colliders = Physics.OverlapSphere(transform.position, detectRadius, layersChecked);

for(int i = 0; i < colliders.Length; i++)

{

if (colliders[i].GetComponent<Vehicle>())

neighbors.Add(colliders[i].gameObject);

}

timer = 0;

}

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class SteeringForSeparation : Steering

{

public float comforDistance = 1;

public float multiplierInsideComfortDistance = 2;

public override Vector3 Force()

{

Vector3 steeringForce = new Vector3(0, 0, 0);

foreach(GameObject s in GetComponent<Radar>().neighbors)

{

if ((s != null) && (s != this.gameObject))

{

Vector3 toNeighbor = transform.position - s.transform.position;

float length=toNeighbor.magnitude;

steeringForce += toNeighbor.normalized / length;

if (length < comforDistance)

steeringForce *= multiplierInsideComfortDistance;

}

}

return steeringForce;

}

}

using System.Collections;

using System.Collections.Generic;

using UnityEngine;

public class SteeringForEvade :Steering

{

public GameObject target;

private Vector3 desiredVelocity;

private Vehicle m_vehicle;

private float maxSpeed;

void Start()

{

m_vehicle = GetComponent<Vehicle>();

maxSpeed = m_vehicle.maxSpeed;

}

public override Vector3 Force()

{

Vector3 toTarget = target.transform.position - transform.position;

float lookaheadTime = toTarget.magnitude / (maxSpeed + target.GetComponent<Vehicle>().velocity.magnitude);

desiredVelocity = (transform.position - (target.transform.position+target.GetComponent<Vehicle>().velocity*lookaheadTime)).normalized * maxSpeed;

return (desiredVelocity - m_vehicle.velocity);

}

}

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;

}

}

}

收尾

最后再给各个角色装上刚体,设置好Leader等参数就可以了。

很多行为我们都可以通过设定规则来实现,可能乍一看行为很难摸索,但慢慢分析出其中的规则并逐一实现后,问题往往就会被解决

相关知识

Unity宠物跟随
UML类图实例 (动物)
动物迁徙
动物的运动与动物对环境的反应.pptx
动物大迁徙的原因
你还能说出哪些生物影响和适应环境的实例
动物行为与适应的实际应用和研究.pptx
动物羽毛的实例—印第安风情头饰
雅思阅读:动物迁徙知多少?
鸟类为何迁徙?

网址: UnityAI——动物迁徙中的跟随实现实例 https://m.mcbbbk.com/newsview455439.html

所属分类:萌宠日常
上一篇: 陪伴犬证办理条件
下一篇: 地下城与勇士:大家来探讨一下你的