【Unity小技巧】一个脚本实现控制3D远程/近战敌人AI

简介: 【Unity小技巧】一个脚本实现控制3D远程/近战敌人AI

烘培导航地图

选中地面,设置为静态导航

点击烘培,可行走区域

选中一些障碍物,也设置为静态导航

选择为不适合步行

重新点击烘培,一些障碍物区域就不可以行走了

配置敌人导航数据

给敌人加导航组件

注意:

增大角速度,是为了让敌人旋转更加快

配置停止距离和关闭自动刹车是为了防止敌人切换为待机动画,不会滑动

简单配置敌人动画

动画基础使用:新版角色动画的具体使用

敌人AI脚本

零基础带你从小白到超神29——导航系统

using UnityEngine;
using UnityEngine.AI;

public class EnemyAiTutorial : MonoBehaviour
{
    NavMeshAgent agent; // 导航代理
    Animator animator;
    Transform player; // 玩家的Transform对象
    public LayerMask whatIsPlayer; // 碰撞检测所需的LayerMask
    [Header("敌人的生命值")]
    public float health;

    [Space]
    [Header("巡逻相关")]
    [Header("巡逻范围")]

    public float walkPointRange;
    bool walkPointSet;//是否设置了巡逻点
    Vector3 walkPoint;//巡逻点

    [Space]
    [Header("攻击相关")]
    [Header("攻击间隔时间")]
    public float timeBetweenAttacks;
    [Header("每次攻击时间")]
    public float timeAttack;
    [Header("攻击所使用的物体(子弹)")]
    public GameObject projectile;
    bool isAttack;
    bool alreadyAttacked;//是否已经攻击过

    [Space]
    [Header("状态相关")]
    [Header("是否是近战攻击")]
    public bool isMeleeAttack;
    [Header("远程攻击点")]
    public Transform remoteAttackPoint;
    [Header("视野范围和攻击范围")]
    public float sightRange;
    public float attackRange;
    //玩家是否在视野范围和攻击范围内
    public bool playerInSightRange;
     public bool playerInAttackRange;
    [Header("速度")]
    public float walkSpeed = 1.2f;
    public float runSpeed = 5f;
    bool isIdle;

    private void Awake()
    {
        player = GameObject.Find("Player").transform; // 查找到名为"PlayerObj"的游戏物体,并获取其Transform组件
        agent = GetComponent<NavMeshAgent>(); // 获取自身的导航代理组件
        animator = GetComponent<Animator>();
    }

    private void Update()
    {
        // 检查玩家是否在视野范围或攻击范围内
        playerInSightRange = Physics.CheckSphere(transform.position, sightRange, whatIsPlayer);
        playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, whatIsPlayer);
        // 根据玩家位置和状态进行相应的行为
        if (!playerInSightRange && !playerInAttackRange) Patroling();
        if (playerInSightRange && !playerInAttackRange) ChasePlayer();
        if (playerInAttackRange && playerInSightRange) AttackPlayer();
    }

    private void Patroling()
    {
        if (!walkPointSet) SearchWalkPoint(); // 如果没有设置巡逻点,则搜索巡逻点

        if (walkPointSet)
        {
            agent.speed = walkSpeed; // 将导航代理的速度设置为5
            //TODO设置巡逻速度,播放走路动画
            animator.SetBool("Walk", true);
            animator.SetBool("Run", false);
            agent.SetDestination(walkPoint); // 设置巡逻点为目标点
        }


        Vector3 distanceToWalkPoint = transform.position - walkPoint;

        // 已到达巡逻点
        if (distanceToWalkPoint.magnitude < 1f)
        {
            //TODO:播放待机动画,休息3-5秒,也可以等待机动画执行完再进行下一步
            animator.SetBool("Walk", false);
            animator.SetBool("Run", false);

            if (!isIdle)
            {
                Invoke(nameof(SetWalkPointSet), Random.Range(3, 6));
            }

            isIdle = true;
        }
    }

    void SetWalkPointSet()
    {
        isIdle = false;
        walkPointSet = false;
    }

    private void SearchWalkPoint()
    {
        // 在指定范围内随机生成一个巡逻点
        float randomZ = Random.Range(-walkPointRange, walkPointRange);
        float randomX = Random.Range(-walkPointRange, walkPointRange);

        walkPoint = new Vector3(transform.position.x + randomX, transform.position.y, transform.position.z + randomZ);
        // SamplePosition表示判断该点是不是导航允许到达的地方
        NavMeshHit hit;
        if (NavMesh.SamplePosition(walkPoint, out hit, walkPointRange, 1))
        {
            walkPoint = hit.position;
            walkPointSet = true;
        }
    }

    private void ChasePlayer()
    {
        //判断是否在攻击
        if(isAttack) return;

        //TODO设置追击速度,播放奔跑动画
        agent.speed = runSpeed; // 将导航代理的速度设置为5
        animator.SetBool("Walk", false);
        animator.SetBool("Run", true);
        agent.SetDestination(player.position); // 设置导航代理的目标点为玩家位置
    }

    private void AttackPlayer()
    {
        // 已到达目标点附近
        if ((transform.position - player.position).magnitude < 1.5f)
        {
            // 停止移动
            agent.SetDestination(transform.position);
        } 

        if (!alreadyAttacked)
        {
            //面向玩家
            transform.LookAt(player);

            //是否是近战攻击
            if (isMeleeAttack)
            {
                animator.SetBool("Walk", false);
                animator.SetBool("Run", false);
                //TODO播放近战攻击动画
                animator.SetTrigger("Punch");
            }
            else
            {
                ///攻击代码
                Rigidbody rb = Instantiate(projectile, remoteAttackPoint.position, Quaternion.identity).GetComponent<Rigidbody>();
                rb.AddForce(transform.forward * 32f, ForceMode.Impulse);
                rb.AddForce(transform.up * 8f, ForceMode.Impulse);
                ///攻击代码结束
            }

            alreadyAttacked = true;
            Invoke(nameof(ResetAttack), timeBetweenAttacks);

            //攻击时间
            isAttack = true;
            Invoke(nameof(ResetIsAttack), timeAttack);
        }
    }

    private void ResetIsAttack()
    {
        isAttack = false;
    }

    private void ResetAttack()
    {
        alreadyAttacked = false;
    }

    public void TakeDamage(int damage)
    {
        health -= damage;

        // 如果生命值小于等于0,则摧毁自身
        //TODO: 播放死亡动画
        if (health <= 0) Invoke(nameof(DestroyEnemy), 0.5f);
    }

    private void DestroyEnemy()
    {
        Destroy(gameObject);
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, attackRange); // 在编辑器中绘制攻击范围的圆
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, sightRange); // 在编辑器中绘制视野范围的圆形
    }
}

挂载脚本,配置参数,这里以一个近战敌人为例子

效果

image.png

目录
相关文章
|
17天前
|
人工智能 vr&ar
GeneMAN:上海AI Lab联合北大等高校推出的3D人体模型创建框架
GeneMAN是由上海AI实验室、北京大学、南洋理工大学和上海交通大学联合推出的3D人体模型创建框架。该框架能够从单张图片中生成高保真度的3D人体模型,适用于多种应用场景,如虚拟试衣、游戏和娱乐、增强现实和虚拟现实等。
47 7
GeneMAN:上海AI Lab联合北大等高校推出的3D人体模型创建框架
|
3月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
216 3
|
4月前
|
机器学习/深度学习 人工智能 编解码
|
4月前
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
101 0
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
3D智能导诊系统源码,基于AI引擎,针对患者的病情及症状,结合性别年龄特征,智能推荐医院科室
智能导诊系统是一款基于AI技术的医疗辅助工具,利用自然语言处理和机器学习分析患者病情,精准推荐科室和医生。系统支持按性别分类导诊,设有3D人体模型辅助定位症状,界面简洁易操作。采用B/S架构,可无缝对接HIS数据库,支持多种接入形式,包括公众号、小程序和App,有效提升就诊效率并减轻医护人员负担。
|
4月前
|
机器学习/深度学习 人工智能 算法
|
5月前
|
机器学习/深度学习 人工智能 算法
|
4月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
221 6
|
4月前
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
295 5
|
3月前
|
测试技术 C# 图形学
掌握Unity调试与测试的终极指南:从内置调试工具到自动化测试框架,全方位保障游戏品质不踩坑,打造流畅游戏体验的必备技能大揭秘!
【9月更文挑战第1天】在开发游戏时,Unity 引擎让创意变为现实。但软件开发中难免遇到 Bug,若不解决,将严重影响用户体验。调试与测试成为确保游戏质量的最后一道防线。本文介绍如何利用 Unity 的调试工具高效排查问题,并通过 Profiler 分析性能瓶颈。此外,Unity Test Framework 支持自动化测试,提高开发效率。结合单元测试与集成测试,确保游戏逻辑正确无误。对于在线游戏,还需进行压力测试以验证服务器稳定性。总之,调试与测试贯穿游戏开发全流程,确保最终作品既好玩又稳定。
165 4
下一篇
DataWorks