【UnityRPG游戏制作】NPC交互逻辑、动玩法

在这里插入图片描述


👨‍💻个人主页:@元宇宙-秩沅

👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!

👨‍💻 本文由 秩沅 原创
👨‍💻 收录于专栏:就业宝典

🅰️推荐专栏

⭐-软件设计师高频考点大全



文章目录

    • 前言
    • 🎶(==二==) NPC逻辑相关
    • (==1==) NPC范围检测
    • (==2==) NPC动画添加
    • (==3==) NPC和玩家的攻击受伤交互(事件中心)
    • (==4==) NPC的受伤特效添加
    • (==5==) NPC的死亡特效添加
    • 🅰️


前言


🎶( NPC逻辑相关



1 NPC范围检测


在这里插入图片描述

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//-------------------------------
//-------功能: NPC交互脚本
//-------创建者:         -------
//------------------------------

public class NPCContorller : MonoBehaviour
{
    public PlayerContorller playerCtrl;

    //范围检测
    private void OnTriggerEnter(Collider other)
    {
        playerCtrl.isNearby  = true;
    }
    private void OnTriggerExit(Collider other)
    {
        playerCtrl.isNearby = false;
    }
}


2 NPC动画添加


在这里插入图片描述
请添加图片描述


3 NPC和玩家的攻击受伤交互(事件中心)


  • EnemyController 敌人

   using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

//-------------------------------
//-------功能:  敌人控制器
//-------创建者:         -------
//------------------------------

public class EnemyController : MonoBehaviour
{
    public GameObject player;   //对标玩家
    public Animator animator;   //对标动画机
    public GameObject enemyNPC; //对标敌人
    public int hp;              //血量
    public Image hpSlider;      //血条
    private int attack = 10;    //敌人的攻击力
    public float CD_skill ;         //技能冷却时间

    private void Start()
    {
       
        enemyNPC = transform.GetChild(0).gameObject;
        animator = enemyNPC.GetComponent<Animator>();
        SendEvent();  //发送相关事件
    }

    private void Update()
    {
        CD_skill += Time.deltaTime; //CD一直在累加

    }

    /// <summary>
    /// 发送事件
    /// </summary>
    private void SendEvent()
    {
        //传递怪兽攻击事件(也是玩家受伤时)
        EventCenter.GetInstance().AddEventListener(PureNotification.PLAYER_INJURY, (int attack) =>
        {
            animator.SetBool("attack",true ); //攻击动画激活     
        });

        //传递怪兽受伤事件(玩家攻击时)
        EventCenter.GetInstance().AddEventListener(PureNotification.PLAYER_ATTRACK, ( ) =>
        { 
                animator.SetBool("hurt", true);  //受伤动画激活
        });

        //传递怪兽死亡事件
        EventCenter.GetInstance().AddEventListener(PureNotification.NPC_Died , () =>
        {      
                animator.SetBool("died", true);  //死亡动画激活
                gameObject.SetActive(false);     //给物体失活
                //暴金币
        });

    }

    //碰撞检测
    private void OnCollisionStay(Collision collision)
    {
        if (collision.gameObject.tag == "Player") //检测到如果是玩家的标签
        {
         
            if(CD_skill > 2f)  //攻击动画的冷却时间
            {
                Debug.Log("怪物即将攻击");
                CD_skill = 0;
                //触发攻击事件
                EventCenter.GetInstance().EventTrigger(PureNotification.PLAYER_INJURY, Attack());
               
            }    
    
        }
    }



    /// <summary>
    /// 传递攻击力
    /// </summary>
    /// <returns></returns>
    public  int  Attack()
    {
        return attack;
    }
   
    //碰撞检测
    private void OnCollisionExit(Collision collision)
    {
        if (collision.gameObject.tag == "Player") //检测到如果是玩家的标签
        {
            animator.SetBool("attack", false);       
            collision.gameObject.GetComponent<PlayerContorller>().animator .SetBool("hurt", false);

        }
    }


    //范围触发检测
    private void OnTriggerStay(Collider other)
    {
      if(other.tag == "Player")  //检测到如果是玩家的标签
        {
            //让怪物看向玩家
            transform.LookAt(other.gameObject.transform.position);
            //并且向其移动
            transform.Translate(Vector3.forward * 1 * Time.deltaTime);
        
        }

    }
 
}


  • PlayerContorller玩家
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UIElements;
using static UnityEditor.Experimental.GraphView.GraphView;

//-------------------------------
//-------功能: 玩家控制器
//-------创建者:        
//------------------------------

public class PlayerContorller : MonoBehaviour
{
    //-----------------------------------------
    //---------------成员变量区-----------------
    //-----------------------------------------

    public float  speed = 1;         //速度倍量
    public Rigidbody rigidbody;      //刚体组建的声明
    public Animator  animator;       //动画控制器声明
    public GameObject[] playersitem; //角色数组声明
    public bool isNearby = false;    //人物是否在附近
    public float CD_skill ;         //技能冷却时间
    public int curWeaponNum;        //拥有武器数
    public int attack ;             //攻击力
    public int defence ;            //防御力
  

    //-----------------------------------------
    //-----------------------------------------


    void Start()
    {
        rigidbody = GetComponent<Rigidbody>();

        SendEvent();//发送事件给事件中心
    }
    void Update()
    {
        CD_skill += Time.deltaTime;       //CD一直在累加
        InputMonitoring();
    }
        void FixedUpdate()
    {
        Move();
    }


    /// <summary>
    /// 更换角色[数组]
    /// </summary>
    /// <param name="value"></param>
    public void ChangePlayers(int value)
    {
        for (int i = 0; i < playersitem.Length; i++)
        {
            if (i == value)
            {
                animator = playersitem[i].GetComponent<Animator>();
                playersitem[i].SetActive(true);
            }
            else
            {
                playersitem[i].SetActive(false);
            }
        }
    }
  
    /// <summary>
    ///玩家移动相关
    /// </summary>
    private void Move()
    {
        //速度大小
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
    
        if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
        {
            //方向
            Vector3 dirction = new Vector3(horizontal, 0, vertical);
            //让角色的看向与移动方向保持一致
            transform.rotation = Quaternion.LookRotation(dirction);
            rigidbody.MovePosition(transform.position + dirction * speed * Time.deltaTime);
            animator.SetBool("walk", true);
            //加速奔跑
            if (Input.GetKey(KeyCode.LeftShift) )
            {
                animator.SetBool("run", true);
                animator.SetBool("walk", true);                
                rigidbody.MovePosition(transform.position + dirction * speed*3 * Time.deltaTime);
            }
            else 
            {
                animator.SetBool("run", false);;
                animator.SetBool("walk", true);
            }            
        }
        else 
        {
            animator.SetBool("walk", false);
        }
    }


    /// <summary>
    /// 键盘监听相关
    /// </summary>
    public void InputMonitoring()
    {
        //人物角色切换
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            ChangePlayers(0);
        }

        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            ChangePlayers(1);
        }

        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            ChangePlayers(2);
        }
        //范围检测弹出和NPC的对话框
        if (isNearby && Input.GetKeyDown(KeyCode.F))
        {          
            //发送通知打开面板
            GameFacade.Instance.SendNotification(PureNotification.SHOW_PANEL, "NPCTipPanel");
        
        }
        //打开背包面板
        if ( Input.GetKeyDown(KeyCode.Tab))
        {
            //发送通知打开面板
            GameFacade.Instance.SendNotification(PureNotification.SHOW_PANEL, "BackpackPanel");

        }
        //打开角色面板
        if ( Input.GetKeyDown(KeyCode.C))
        {
            //发送通知打开面板
            GameFacade.Instance.SendNotification(PureNotification.SHOW_PANEL, "RolePanel");
        }

        //攻击监听
        if (Input.GetKeyDown(KeyCode.Space) && CD_skill >= 1.0f) //按下空格键攻击,并且技能恢复冷却
        {

            if (curWeaponNum > 0)  //有武器时的技能相关
            {
                animator.speed = 2;
                animator.SetTrigger("Attack2");
            }
            else                  //没有武器时的技能相关
            {
                animator.speed = 1;
                animator.SetTrigger("Attack1");
            }

            CD_skill = 0;

            #region
            //技能开始冷却

            //    audioSource.clip = Resources.Load<AudioClip>("music/01");
            //    audioSource.Play();
            //    cd_Put = 0;
            //var enemys = GameObject.FindGameObjectsWithTag("enemy");
            //foreach (GameObject enemy in enemys)
            //{
            //    if (enemy != null)
            //    {
            //        if (Vector3.Distance(enemy.transform.position, this.transform.position) <= 5)
            //        {
            //            enemy.transform.GetComponent<_03EnemyCtrl>().SubSelf(50);
            //        }
            //    }
            //}
            //var bosses = GameObject.FindGameObjectsWithTag("boss");
            //foreach (GameObject boss in bosses)
            //{
            //    if (boss != null)
            //    {
            //        if (Vector3.Distance(boss.transform.position, this.transform.position) <= 5)
            //        {
            //            boss.transform.GetComponent<boss>().SubHP();
            //        }
            //    }
            //}
            #endregion
        }

        //if (Input.GetKeyDown(KeyCode.E))
        //{
        //    changeWeapon = !changeWeapon;
        //}
        //if (Input.GetKeyDown(KeyCode.Q))
        //{
        //    AddHP();
        //    diaPanel.USeHP();
        //}
        //if (enemys != null && enemys.transform.childCount <= 0 && key != null)
        //{
        //    key.gameObject.SetActive(true);
        //}


    }


    /// <summary>
    /// 发送事件
    /// </summary>
    private void SendEvent()
    {
        //传递玩家攻击事件
        EventCenter.GetInstance().AddEventListener(PureNotification.PLAYER_ATTRACK, () =>
        {
           
        });

        //传递玩家受伤事件(怪物攻击时)
        EventCenter.GetInstance().AddEventListener(PureNotification.PLAYER_INJURY , (int attack) =>
        {
            animator.SetBool("hurt", true);
           Debug.Log(attack + "掉血了");                                 
        });   
    }
}


4 NPC的受伤特效添加


请添加图片描述

    /// <summary>
    /// 碰撞检测
    /// </summary>
    /// <param name="collision"></param>
    private void OnCollisionStay(Collision collision)
    {
        //若碰到敌人,并进行攻击
        if (collision.gameObject.tag == "enemy" && Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("造成伤害");
            enemyController = collision.gameObject.GetComponent<EnemyController>();
            //触发攻击事件
            enemyController.animator.SetBool("hurt", true);  //怪物受伤动画激活
            enemyController.transform.GetChild(2).GetChild(0).GetComponent<ParticleSystem>().Play();
            enemyController.hp -= attack;//减少血量
            enemyController. hpSlider.fillAmount = (enemyController.hp / 100.0f);
            if (enemyController.hp <= 0) //死亡判断
            {
                collision.transform.GetChild(0).GetComponent<Animator>() .SetBool("died", true);  //死亡动画激活
                                                                                                  //播放动画
                collision.transform.GetChild(2).GetChild(0).GetComponent<ParticleSystem>().Play();
                collision. gameObject.SetActive(false); //将敌人失活
                //暴钻石(实例化)
                Instantiate(Resources.Load<GameObject>("Perfab/Prop/damon"), collision.transform.position , Quaternion.identity);
                Destroy(collision.gameObject, 3);
            }
        }
    }

5 NPC的死亡特效添加


请添加图片描述

   /// <summary>
   /// 碰撞检测
   /// </summary>
   /// <param name="collision"></param>
   private void OnCollisionStay(Collision collision)
   {
       //若碰到敌人,并进行攻击
       if (collision.gameObject.tag == "enemy" && Input.GetKeyDown(KeyCode.Space))
       {
           Debug.Log("造成伤害");
           enemyController = collision.gameObject.GetComponent<EnemyController>();
           //触发攻击事件
           enemyController.animator.SetBool("hurt", true);  //怪物受伤动画激活
           enemyController.transform.GetChild(2).GetChild(0).GetComponent<ParticleSystem>().Play();
           enemyController.hp -= attack;//减少血量
           enemyController. hpSlider.fillAmount = (enemyController.hp / 100.0f);
           if (enemyController.hp <= 0) //死亡判断
           {
               collision.transform.GetChild(0).GetComponent<Animator>() .SetBool("died", true);  //死亡动画激活
                                                                                                 //播放动画
               collision.transform.GetChild(2).GetChild(0).GetComponent<ParticleSystem>().Play();
               collision. gameObject.SetActive(false); //将敌人失活
               //暴钻石(实例化)
               Instantiate(Resources.Load<GameObject>("Perfab/Prop/damon"), collision.transform.position , Quaternion.identity);
               Destroy(collision.gameObject, 3);
           }
       }
   }

🅰️


⭐【Unityc#专题篇】之c#进阶篇】

⭐【Unityc#专题篇】之c#核心篇】

⭐【Unityc#专题篇】之c#基础篇】

⭐【Unity-c#专题篇】之c#入门篇】

【Unityc#专题篇】—进阶章题单实践练习

⭐【Unityc#专题篇】—基础章题单实践练习

【Unityc#专题篇】—核心章题单实践练习


你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/590563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信息泄露.

一&#xff0c;遍历目录 目录遍历&#xff1a;没有过滤目录相关的跳转符号&#xff08;例如&#xff1a;../&#xff09;&#xff0c;我们可以利用这个目录找到服务器中的每一个文件&#xff0c;也就是遍历。 tipe&#xff1a;依次点击文件就可以找到flag 二&#xff0c;phpi…

栈的磁盘优化:降低存取成本的算法与实现

栈的磁盘优化&#xff1a;降低存取成本的算法与实现 问题背景简单实现方法的分析实现方法PUSH操作POP操作成本分析渐近分析 优化实现方法实现方法成本分析渐近分析 进一步优化&#xff1a;双页管理策略实现方法管理策略成本分析 伪代码示例C代码示例结论 问题背景 在具有有限快…

【JAVA基础之反射】反射详解

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 1.反射 1.1 概述 是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b; 对于任意一个对象&#xff0c;都能够调用它…

15、ESP32 Wifi

ESP32 的 WIFI 功能是模块内置的&#xff0c;通过 ESP32 的基础库调用一些函数就可以轻松使用它。 Wifi STA 模式&#xff1a; 让 ESP32 连接附近 WIFI&#xff0c;可以上网访问数据。 // 代码显示搜索连接附近指定的 WIFI // 通过 pin 按键可断开连接#include <WiFi.h>…

C语言实现左旋字符串、左旋字符串找子串、杨氏矩阵找数字、 判断有序数列等介绍

文章目录 前言一、左旋字符串1. 左旋字符串12. 左旋字符串2 二、杨氏矩阵1. 结构体返回数字在杨氏矩阵中的位置2. 行列数字的地址返回数字在杨氏矩阵中的位置 三、一个字符串左旋能否得到另一个字符串1. 一个一个左旋并判断2. 使用库函数 四、判断有序数列总结 前言 C语言实现…

ubuntu修改/etc/resolve.conf总是被重置

ubuntu修改/etc/resolve.conf总是被重置 其实处理来很简单&#xff0c;根据英文提示删除/etc/resolve.conf,那是一个软链接&#xff0c;重新创建/etc/resolve.conf rm /etc/resolve.conf vi /etc/resolve.conf 添加nameserver 223.5.5.5

抖音TikTok34.5.3最新解锁全球绿色版

软件名称】TikTok 【软件版本】v34.4.5 【软件大小】173m 【适用平台】安卓 【软件简介】 TikTok是一款玩转音乐创意的短影音应用&#xff0c;更是年轻人的交友社群。在这里每个人都可以拍出 属于自己的创意影片&#xff0c;跟着音乐的节奏&#xff0c;你可以尽情拍 摄多种…

计算机毕业设计PHP+vue体检预约管理系统d1yu38

防止在使用不同数据库时&#xff0c;由于底层数据库技术不同造成接口程序紊乱的问题。通过本次系统设计可以提高自己的编程能力&#xff0c;强化对所学知识的理解和运用 本系统是一个服务于医院先关内容的网站&#xff0c;在用户打开网站的第一眼就要明白网站开发的目的&#x…

深度学习500问——Chapter08:目标检测(6)

文章目录 8.3.7 RetinaNet 8.3.7 RetinaNet 研究背景 Two-Stage 检测器&#xff08;如Faster R-CNN、FPN&#xff09;效果好&#xff0c;但速度相对慢。One-Stage 检测器&#xff08;如YOLO、SSD&#xff09;速度快&#xff0c;但效果一般。 作者对one-stage检测器准确率不高…

链表经典面试题下

目录 如有帮助&#xff0c;还望三连支持&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 题目一&#xff1a;141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 题目二&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 题目三&#xff1a;…

为什么选择OpenNJet?OpenNJet下一代云原生应用引擎!OpenNJet开发实战!

前言导读 在当今这个数字化转型加速的时代&#xff0c;云原生技术已成为企业和开发者构建现代应用的首选路径。OpenNJet作为新一代云原生应用引擎&#xff0c;在国内外技术社区受到了广泛关注。 本文将深入探讨OpenNJet的特点、优势以及在开发实践中的应用&#xff0c;带您全…

Java 笔记 13:Java 数组内容,数组的声明、创建、初始化、赋值等,以及内存分析

一、前言 记录时间 [2024-05-03] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 02&#xff1a;Java 开发环境的搭建&#xff0c;IDEA / Notepad / JDK 安装及环境配置&#xff0c;编写第一个 Java 程序 Java 笔记 …

C++ | Date 日期类详解

目录 简介 日期类总代码 | Date 类的定义 & 构造 & Print 类的定义 构造函数 & Print 比较类&#xff0c;如<、>、<...... 值加减类&#xff0c;如、-、、-...... 加减类具体分类 判断某个月有多少天 GetMonthDay 日期类 / &#xff08;- / -&…

场景文本检测识别学习 day08(无监督的Loss Function、代理任务)

无监督的Loss Function&#xff08;无监督的目标函数&#xff09; 根据有无标签&#xff0c;可以将模型的学习方法分为&#xff1a;无监督、有监督两种。而自监督是无监督的一种无监督的目标函数可以分为以下几种&#xff1a; 生成式网络的做法&#xff0c;衡量模型的输出和固…

protobuf在配置文件管理上的应用

TextFormat::ParseFromString 是 Google Protocol Buffers&#xff08;通常简称为 Protobuf&#xff09;库中的一个函数&#xff0c;用于从文本格式解析消息。Protobuf 是一种用于序列化结构化数据的库&#xff0c;它允许你定义数据的结构&#xff0c;然后自动生成源代码来处理…

【实用推荐】7个靠谱赚钱软件,宅家也能轻松赚钱!

在数字化浪潮下&#xff0c;如何在家轻松赚取收益成为许多人关注的焦点。软件市场的蓬勃发展为我们提供了多种选择&#xff0c;但面对琳琅满目的赚钱应用&#xff0c;许多人感到无从下手&#xff0c;担心选择不当。本文将为您揭示这些软件背后的奥秘&#xff0c;助您找到最适合…

【副本向】高等级副本全流程开发

副本的创建 1.从配置表通过副本ID获取此副本参数 Tab_CopyScene rCopyScene TableManager.GetCopySceneByID(m_CopySceneID);if (rCopyScene ! null){//只要配置了组队的Rule&#xff0c;就是组队模式&#xff0c;否则就是单人模式bool bSolo true;for (int n 0; n < rCo…

禅道项目管理系统 身份验证漏洞分析QVD-2024-15263

前言 最近不怎么更新了&#xff01;向小伙伴说明下 我不是什么组织 更不什么经销号&#xff08;尽管csdn有很多经销广告号&#xff09; 一确实是下岗了&#xff01;忙着为找工作而发愁。简历都投出去如同石沉大海能不愁吗!.哎...... 二是忙着论文及材料的事...…

观察者模式实战:解密最热门的设计模式之一

文章目录 前言一、什么是观察者模式二、Java实现观察者模式2.1 观察者接口2.2 具体观察者2.3 基础发布者2.4 具体发布者2.5 消息发送 三、Spring实现观察者模式3.1 定义事件类3.2 具体观察者3.3 具体发布者3.4 消息发送 总结 前言 随着系统的复杂度变高&#xff0c;我们就会采…

电商独立站最重要的功能设置:多语言转换和代运系统搭建

什么是独立站&#xff1f; 多语言模式切换 1 搭建电商独立站在我看来最简单的理解&#xff0c;就是独立的网站。 如果你在跨境圈子呆了一段时间&#xff0c;独立站是一个避不开且火热的一个词&#xff0c;并且也是所有的B2B、B2C商家都在运营和布局的市场。 独立站的优势有哪…