【制作100个unity游戏之24】unity制作一个3D动物AI生态系统游戏2(附项目源码)

简介: 【制作100个unity游戏之24】unity制作一个3D动物AI生态系统游戏2(附项目源码)

前言

欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第24篇中,我们将探索如何用unity制作一个3D动物AI生态系统游戏,我会附带项目源码,以便你们更好理解它。

添加捕食者

修改AnimalState,为了方便我就直接贴出全部代码吧,大概就是在原基础上添加了追逐状态和事件处理

using System.Collections;
using UnityEngine;
using UnityEngine.AI;

// 定义动物状态的枚举类型
public enum AnimalState
{
    Idle,   // 空闲状态
    Moving,  // 移动状态
    Chase  // 追逐状态
}

// 必须附加到具有 NavMeshAgent 组件的游戏对象上
[RequireComponent(typeof(NavMeshAgent))]
public class Animal : MonoBehaviour
{
    [Header("动物一次移动的距离"), SerializeField]
    private float wanderDistance = 50f;
    [Header("动物的行走速度"), SerializeField]
    private float walkSpeed = 5f;
    [Header("动物行走的最大时间"), SerializeField]
    private float maxWalkTime = 6f;

    [Header("动物休息的时间"), SerializeField]
    private float idleTime = 5f;

    [Header("奔跑速度"), SerializeField]
    private float runSpeed = 8f;

    [Header("生命值"), SerializeField]
    private int health = 10;

    protected NavMeshAgent navMeshAgent;  // 存储 NavMeshAgent 组件的引用
    protected AnimalState currentState = AnimalState.Idle;  // 存储当前动物的状态,默认为 Idle

    private void Start()
    {
        InitialiseAnimal();  // 初始化动物
    }

    // 初始化动物
    protected virtual void InitialiseAnimal()
    {
        navMeshAgent = GetComponent<NavMeshAgent>();  // 获取 NavMeshAgent 组件的引用
        navMeshAgent.speed = walkSpeed;  // 设置动物的行走速度
        currentState = AnimalState.Idle;  // 将当前状态设置为 Idle
        UpdateState();  // 更新动物的状态
    }

    // 更新动物的状态
    protected virtual void UpdateState()
    {
        switch (currentState)
        {
            case AnimalState.Idle:  // 如果当前状态是 Idle
                HandleIdleState();  // 处理空闲状态
                break;
            case AnimalState.Moving:  // 如果当前状态是 Moving
                HandleMovingState();  // 处理移动状态
                break;
            case AnimalState.Chase:  // 如果当前状态是 Chase
                HandleChaseState();  // 处理追逐状态
                break;
        }
    }

    // 获取距离起点一定距离内的随机 NavMesh 位置
    protected Vector3 GetRandomNavMeshPosition(Vector3 origin, float distance)
    {
        for (int i = 0; i < 5; i++)
        {
            Vector3 randomDirection = Random.insideUnitSphere * distance;  // 在球形区域内生成一个随机方向
            randomDirection += origin;  // 将随机方向与起点相加,计算出随机点的位置
            NavMeshHit navMeshHit;
            if (NavMesh.SamplePosition(randomDirection, out navMeshHit, distance, NavMesh.AllAreas))
            {
                // 如果找到了 NavMesh 上的可行走位置,返回该位置
                return navMeshHit.position;
            }
        }
        return origin;
    }

    protected virtual void HandleChaseState()
    {
        StopAllCoroutines();
    }


    // 处理空闲状态
    protected virtual void HandleIdleState()
    {
        StartCoroutine(WaitToMove());  // 等待一段时间后转换到移动状态
    }

    // 等待一段时间后转换到移动状态
    private IEnumerator WaitToMove()
    {
        float waitTime = Random.Range(idleTime / 2, idleTime * 2);  // 随机生成等待时间
        yield return new WaitForSeconds(waitTime);  // 等待一段时间
        Vector3 randomDestination = GetRandomNavMeshPosition(transform.position, wanderDistance);  // 获取随机位置
        navMeshAgent.SetDestination(randomDestination);  // 设置 NavMeshAgent 的目标位置
        SetState(AnimalState.Moving);  // 将状态设置为 Moving
    }

    // 处理移动状态
    protected virtual void HandleMovingState()
    {
        StartCoroutine(WaitToReachDestination());  // 等待到达目的地后转换到空闲状态
    }

    // 等待到达目的地后转换到空闲状态
    private IEnumerator WaitToReachDestination()
    {
        float startTime = Time.time;  // 记录开始移动的时间
        while (navMeshAgent.pathPending || navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance && navMeshAgent.isActiveAndEnabled)  // 当还未到达目的地时循环
        {
            if (Time.time - startTime >= maxWalkTime)  // 如果超过了最大行走时间
            {
                navMeshAgent.ResetPath();  // 重置路径
                SetState(AnimalState.Idle);  // 将状态设置为 Idle
                yield break;  // 结束函数的执行
            }
            CheckChaseConditions();  // 检查是否满足追逐条件
            yield return null;  // 等待下一帧
        }
        // 到达目的地后将状态设置为 Idle
        SetState(AnimalState.Idle);
    }

    // 将动物的状态设置为指定的状态
    protected void SetState(AnimalState newState)
    {
        if (currentState == newState)  // 如果新状态与当前状态相同,直接返回
        {
            return;
        }
        currentState = newState;  // 更新当前状态
        OnStateChanged(newState);  // 触发状态改变事件
    }

    // 状态改变事件的处理函数
    protected virtual void OnStateChanged(AnimalState newState)
    {
        if (newState == AnimalState.Moving)
            navMeshAgent.speed = walkSpeed;
        if (newState == AnimalState.Chase)
            navMeshAgent.speed = runSpeed;
        UpdateState();
    }

    // 接收到伤害时的处理函数
    public virtual void RecieveDamage(int damage)
    {
        health -= damage;
        if (health <= 0)
            Die();
    }

    // 死亡时的处理函数
    protected virtual void Die()
    {
        StopAllCoroutines();
        Destroy(gameObject);
    }

    // 检查是否满足追逐条件的函数
    protected virtual void CheckChaseConditions() { }
}

新增Prey,基础Animal,定义猎物的行为脚本

using System.Collections;
using UnityEngine;
// 表示一种猎物动物
public class Prey : Animal
{
    [SerializeField, Header("检测范围")] private float detectionRange = 10f;
    [SerializeField, Header("逃离的最大距离")] private float escapeMaxDistance = 80f;
    private Predator currentPredator = null;   // 当前追逐的捕食者

    // 警报猎物,传入捕食者对象
    public void AlertPrey(Predator predator)
    {
        SetState(AnimalState.Chase);   // 设置状态为追逐
        currentPredator = predator;   // 设置当前捕食者
        StartCoroutine(RunFromPredator());   // 开始逃离捕食者
    }

    // 逃离捕食者的协程
    private IEnumerator RunFromPredator()
    {
        // 等待捕食者进入检测范围
        while (currentPredator == null || Vector3.Distance(transform.position, currentPredator.transform.position) > detectionRange)
        {
            yield return null;
        }

        // 捕食者进入检测范围,开始逃离
        while (currentPredator != null && Vector3.Distance(transform.position, currentPredator.transform.position) <= detectionRange)
        {
            RunAwayFromPredator();   // 逃离捕食者
            yield return null;
        }

        // 捕食者超出范围,向最终位置逃离并回到空闲状态 
        if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance > navMeshAgent.stoppingDistance)
        {
            yield return null;
        }
        SetState(AnimalState.Idle);   // 设置状态为空闲
    }

    // 逃离捕食者的方法
    private void RunAwayFromPredator()
    {
        if (navMeshAgent != null && navMeshAgent.isActiveAndEnabled)
        {
            if (!navMeshAgent.pathPending && navMeshAgent.remainingDistance < navMeshAgent.stoppingDistance)
            {
                // 计算逃离方向,即当前位置与捕食者位置的反向向量
                Vector3 runDirection = transform.position - currentPredator.transform.position;

                // 根据逃离方向和逃离的最大距离,计算逃离的目标位置
                Vector3 escapeDestination = transform.position + runDirection.normalized * (escapeMaxDistance * 2);

                // 设置导航代理的目标位置为随机的逃离目标位置
                navMeshAgent.SetDestination(GetRandomNavMeshPosition(escapeDestination, escapeMaxDistance));
            }
        }
    }

    // 处理猎物死亡的方法
    protected override void Die()
    {
        StopAllCoroutines();
        base.Die();
    }

    // 在场景视图中绘制检测范围的方法
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.green;
        Gizmos.DrawWireSphere(transform.position, detectionRange);
    }
}

新增Predator,同样继承Animal,定义捕食者的行为脚本

using System.Collections;
using UnityEngine;

// 表示一种捕食者动物
public class Predator : Animal
{
    [SerializeField, Header("检测范围,用于检测猎物")] private float detectionRange = 20f;
    [SerializeField, Header("追逐的最长时间")] private float maxChaseTime = 10f;
    [SerializeField, Header("咬伤伤害值")] private int biteDamage = 3;
    [SerializeField, Header("咬伤冷却时间")] private float biteCooldown = 1f;
    private Prey currentChaseTarget;   // 当前追逐的猎物

    // 检查追逐条件
    protected override void CheckChaseConditions()
    {
        if (currentChaseTarget)
            return;

        // 获取检测范围内的所有 collider,存储到数组中
        Collider[] colliders = new Collider[10];
        int numColliders = Physics.OverlapSphereNonAlloc(transform.position, detectionRange, colliders);
        for (int i = 0; i < numColliders; i++)
        {
            // 如果该 collider 绑定的游戏物体上有 Prey 组件,则该游戏物体为猎物
            Prey prey = colliders[i].GetComponent<Prey>();
            if (prey != null)
            {
                StartChase(prey);   // 开始追逐该猎物
                return;
            }
        }

        currentChaseTarget = null;
    }

    // 开始追逐指定的猎物
    private void StartChase(Prey prey)
    {
        currentChaseTarget = prey;
        SetState(AnimalState.Chase);   // 设置状态为追逐状态
    }

    // 处理追逐状态
    protected override void HandleChaseState()
    {
        if (currentChaseTarget != null)
        {
            currentChaseTarget.AlertPrey(this);   // 提醒猎物有捕食者正在追逐它
            StartCoroutine(ChasePrey());   // 开始追逐猎物的协程
        }
        else
        {
            SetState(AnimalState.Idle);   // 如果没有猎物,则回到空闲状态
        }
    }

    // 追逐猎物的协程
    private IEnumerator ChasePrey()
    {
        float startTime = Time.time;
        while (currentChaseTarget != null && Vector3.Distance(transform.position, currentChaseTarget.transform.position) > navMeshAgent.stoppingDistance)
        {
            if (Time.time - startTime >= maxChaseTime || currentChaseTarget == null)
            {
                StopChase();   // 如果超时或者目标不存在,则停止追逐
                yield break;
            }
            SetState(AnimalState.Chase);   // 设置状态为追逐状态
            navMeshAgent.SetDestination(currentChaseTarget.transform.position);   // 设置目标位置为猎物的位置
            yield return null;
        }

        // 如果猎物还存在,则对猎物造成伤害
        if (currentChaseTarget)
        {
            currentChaseTarget.RecieveDamage(biteDamage);
        }

        yield return new WaitForSeconds(biteCooldown);   // 等待咬伤冷却时间

        currentChaseTarget = null;
        HandleChaseState();   // 继续处理追逐状态
        CheckChaseConditions();   // 检查是否可以继续追逐其他猎物
    }

    // 停止追逐
    private void StopChase()
    {
        navMeshAgent.ResetPath();
        currentChaseTarget = null;
        SetState(AnimalState.Moving);   // 设置状态为移动状态
    }

    // 绘制检测范围的 gizmos
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, detectionRange);
    }
}

挂载新脚本,并配置参数,这里可以设置捕猎者速度大于动物,确保可以狩猎成功

记得给动物添加碰撞体,不然捕猎者无法检测到动物发起攻击

同样修改动物和捕猎者导航网格停止距离的值,这里我设置为3

注意:导航网格停止距离的值默认为0,如果不设置会影响动物的逃跑功能和捕猎者的咬伤功能

羊参数配置

狼参数配置

效果

image.png

动画控制

修改Animal

private Animator animator;

animator = GetComponentInChildren<Animator>();

// 状态改变事件的处理函数
protected virtual void OnStateChanged(AnimalState newState)
{
    animator?.CrossFadeInFixedTime(newState.ToString(), 0.5f);

    //...
}

看看CrossFadeInFixedTime官方文档解释,实现一个淡入淡出的动画效果

效果

image.png

源码

源码在最后一期

目录
相关文章
|
25天前
|
存储 人工智能 缓存
tauri2.0+vite6接入deepseek-v3电脑端ai流式多轮聊天对话系统
原创重磅新作tauri2.0+vite6+deepseek-v3+arco-design实战客户端AI流式聊天对话系统。整合 Tauri2.x 接入 DeepSeek-V3 大模型。支持多窗口浅色+暗黑主题、代码高亮、本地会话缓存。
84 5
|
27天前
|
机器学习/深度学习 人工智能 运维
探讨AI数字人软件系统的开发与部署策略
随着科技发展,人工智能成为经济转型的关键驱动力,AI数字人软件系统在各行业广泛应用。本文探讨其开发与部署策略,助力企业和开发者参考。开发策略包括需求分析、技术选型、模块化设计、数据驱动及安全性保障;部署策略涵盖硬件环境、软件配置、分布式与云端部署以及运维保障,推动系统智能化与稳定性提升。
|
1月前
|
人工智能 运维 Prometheus
“服务器罢工前的预言术”:用AI预测系统状态真香指南
“服务器罢工前的预言术”:用AI预测系统状态真香指南
40 4
|
1月前
|
数据采集 传感器 人工智能
船厂复杂环境下的多模态AI安防系统技术实践
本方案针对船厂复杂工业场景,设计了五层分布式AI安防系统架构:数据采集层(海康摄像头+气体传感器)、预处理层(动态光照补偿)、特征引擎层(YOLOv8s检测+ESRGAN增强+ByteTrack跟踪)和规则决策层。同时,实现交通违规检测、龙门吊防撞及人员滞留监测等关键模块,并通过两阶段小目标检测、工业干扰优化与边缘计算加速解决工程挑战。系统采用边缘-中心协同架构,支持REST API与MQTT/ZMQ通信,技术验证数据显示其准确率高达92.4%,障碍物识别延迟平均仅850ms。
55 1
船厂复杂环境下的多模态AI安防系统技术实践
|
1月前
|
人工智能 前端开发 搜索推荐
LangGraph实战教程:构建会思考、能记忆、可人工干预的多智能体AI系统
本文介绍了使用LangGraph和LangSmith构建企业级多智能体AI系统的完整流程。从简单的ReAct智能体开始,逐步扩展至包含身份验证、人工干预、长期内存管理和性能评估的复杂架构。文章详细讲解了状态管理、工具集成、条件流程控制等关键技术,并对比了监督者架构与群体架构的优劣。通过系统化的方法,展示了如何构建可靠、可扩展的AI系统,为现代AI应用开发提供了坚实基础。*作者:Fareed Khan*
141 0
LangGraph实战教程:构建会思考、能记忆、可人工干预的多智能体AI系统
|
2月前
|
数据采集 人工智能 算法
面向AI应用开发的开源能源管理系统
人工智能在能源管理中发挥关键作用,通过优化资源分配、智能消费管理、精准监测预测以及改善客户体验等多方面推动行业转型。MyEMS作为重要工具,基于Python语言集成AI技术,实现数据采集处理、负荷预测、能源优化控制、故障诊断预警及可视化展示等功能,提供全面智能化解决方案,助力可持续发展与能源效率提升。
68 0
|
2月前
|
机器学习/深度学习 人工智能 监控
基于AI视觉的泳池安全监控系统技术解析
本方案针对泳池安全管理的技术挑战,提出基于边缘计算与云平台的混合架构系统。通过改进YOLOv8模型实现92.7%溺水检测精度,结合LSTM分析异常姿态,多特征融合提升水面静止及呼吸检测能力。同时,安全员行为识别、图像增强模块有效应对环境干扰和监管盲区问题。系统采用DeepSORT优化多目标追踪,硬件配置支持实时视频流分析,实际应用中平均溺水识别时间仅2.3秒,显著优于人工检测。未来将探索多模态感知融合与自适应学习机制,进一步提升系统性能。
68 0
|
2月前
|
机器学习/深度学习 人工智能 运维
AI加持的系统性能优化:别让你的服务器“累趴下”
AI加持的系统性能优化:别让你的服务器“累趴下”
147 12
|
2月前
|
存储 人工智能 自然语言处理
构建智能AI记忆系统:多智能体系统记忆机制的设计与技术实现
本文探讨了多智能体系统中记忆机制的设计与实现,提出构建精细化记忆体系以模拟人类认知过程。文章分析了上下文窗口限制的技术挑战,并介绍了四种记忆类型:即时工作记忆、情节记忆、程序性记忆和语义知识系统。通过基于文件的工作上下文记忆、模型上下文协议的数据库集成以及RAG系统等技术方案,满足不同记忆需求。此外,高级技术如动态示例选择、记忆蒸馏和冲突解决机制进一步提升系统智能化水平。总结指出,这些技术推动智能体向更接近人类认知的复杂记忆处理机制发展,为人工智能开辟新路径。
183 5
构建智能AI记忆系统:多智能体系统记忆机制的设计与技术实现

热门文章

最新文章