【unity之IMGUI实践】敌方逻辑封装实现【六】

👨💻个人主页:@元宇宙-秩沅
👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅!
👨💻 本文由 秩沅 原创
👨💻 收录于专栏:unityUI专题篇

⭐通用API实现抽象行为封装【五】⭐
文章目录
- ⭐通用API实现抽象行为封装【五】⭐
- 🎶前言
- 🎶(==A==)UML
- 🎶(==B==)需求分析
- 🎶(==C==)行为实现——炮台的自动检测并攻击
- 🎶(==D==)行为实现——敌军坦克的移动路线和检测攻击
- 总结:
🎶前言


🅰️
🎶(A)UML

🎶(B)需求分析


🎶(C)行为实现——炮台的自动检测并攻击

😶🌫️:步骤实现
1.炮台的行为逻辑封装:旋转,触发检测,发射炮弹及特效
2.检测玩家后自动瞄准攻击
3.玩家扣血,更新血条,触发保护罩特效及死亡
——————————————
涉及到四个脚本
炮台封装
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 炮台的行为逻辑实现
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class battery : TankFather
{public AudioSource shootMusic; //发射音效public GameObject shootball; //发射的子弹类型public float shootSpeed = 1000f; //子弹的速度 public Transform shootTransform; //发射的组件信息public bool shootSwitch = false;//射击检测参数public Transform player; //闯入者private float endTime = 8f; //子弹发射间隔的时间private void Start(){//属性初始化赋值Head = transform.GetChild(0);maxBlood = 500;nowBlood = 500;attack = 20; HeadSpeed = 50;//射击音效关闭shootMusic.enabled = false;}private void Update(){ if (shootSwitch == false) //不停的旋转{Head.transform.Rotate(Vector3.up * HeadSpeed * Time.deltaTime);} else {Head.transform.LookAt(player);//倒计时发射子弹endTime = Mathf.MoveTowards(endTime, 0, 0.1f);if(endTime <= 0){Fire();endTime = 3f;}} }//玩家进入范围内就开始射击private void OnTriggerEnter(Collider other){if(other.tag == "Player"){shootSwitch = true;player = other.transform;}}//受伤检测private void OnTriggerStay(Collider other){float off = Vector3.Distance(other.transform.position, transform.position);if (other.gameObject.tag == "bullet" && off < 2){//添加子弹挂载的目标坦克,方便获取该子弹的攻击力,与受伤逻辑相结合BulletMove ball = other.gameObject.GetComponent<BulletMove>();TankFather ballTank = ball.Tank.GetComponent<TankFather>();//当子弹不是自己打的到自己身上的时候if (ballTank.tag != gameObject.tag){//扣血Heart(ballTank);}}}//玩家出去后就停止射击private void OnTriggerExit(Collider other){if (other.tag == "Player"){shootSwitch = false;}}//开火重写public override void Fire(){//开启射击音效shootMusic.enabled = true;shootMusic.Play();GameObject ball = Instantiate(shootball, shootTransform.position , shootTransform.rotation);BulletMove movScript = ball.GetComponent<BulletMove>();Rigidbody shootBall = ball.GetComponent<Rigidbody>();shootBall.AddForce(shootTransform .transform.forward * shootSpeed );movScript.Tank =gameObject ; //声明子弹是由谁打出去的}}
坦克基类更新
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:
//___________功能: 坦克基类——集中子类相同点
//___________创建者:______秩沅______
//___________________________________
//-------------------------------------
public abstract class TankFather : MonoBehaviour
{//攻击和防御相关public int attack;public int defence; public float nowBlood;public float maxBlood;//移动和转速相关public int moveSpeed;public int RotateSpeed;public int HeadSpeed;public Transform Head;//击败特效public GameObject diedEffect;//收到伤害打开保护罩的特效public GameObject ProtectEffectMain;public GameObject ProtectEffectOther;private void Awake(){// ProtectEffectMain = Resources.Load<GameObject>(@"Prefabs/OherResoure/Protect1");// ProtectEffectOther = Resources.Load<GameObject>(@"Prefabs/OherResoure/Protect2");}//受伤行为public virtual void Heart(TankFather other){//当攻击力大于防御力时才生效if (other.attack - defence > 0){nowBlood -= (other.attack - defence);}if (nowBlood <= 0){nowBlood = 0;Death();}if (gameObject.tag == "Player")//如果是主玩家才更新血条{//更新血条GamePlane.SingleInstance.UpdataBlood(maxBlood, nowBlood);//实例化保护罩的特效 GameObject eff = Instantiate(ProtectEffectMain, transform.position, transform.rotation);Destroy(eff,1f);}}//死亡行为public virtual void Death(){//将特效实例化相关逻辑GameObject effect = Instantiate(diedEffect, this.transform.position ,this.transform.rotation);AudioSource soudClip = effect.GetComponent<AudioSource>();soudClip.enabled = MusicContol.SingleMusicContol.nowMusicData.soundSwitch;soudClip.volume = MusicContol.SingleMusicContol.nowMusicData.soundRoll ;soudClip.mute = false;soudClip.playOnAwake = true;//死亡后展示死亡面板if (gameObject.tag == "Player"){Destroy(gameObject, 2F);DiedPlane.SingleInstance.Show();}elseDestroy(gameObject);}//开火行为public abstract void Fire(); //子类中每一个的开火方式都不同,作为抽象方法}
主坦克类更新
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:
//___________功能: 坦克的移动和旋转
//___________创建者:_______秩沅_______
//_____________________________________
//-------------------------------------
public class MainTank : TankFather
{//主坦克专有特征public Weapon nowWeapon;//特征属性初始化private void Awake(){Head = transform.GetChild(1).GetChild(0);maxBlood = 1000;nowBlood = 1000;attack = 30;defence = 10;moveSpeed = 5;RotateSpeed = 50;HeadSpeed = 500;}private void Update(){//坦克的移动 = 大小*方向transform.Translate(Input.GetAxis("Vertical") *Vector3.forward*moveSpeed *Time.deltaTime );//坦克的旋转 = 大小*轴向transform.Rotate(Input.GetAxis("Horizontal") *Vector3.up *RotateSpeed *Time .deltaTime );//头部炮管的旋转 = 大小*轴向Head.Rotate(Input.GetAxis ("Mouse X") *Vector3.up*HeadSpeed*Time .deltaTime );//左键发射炮弹if(Input.GetMouseButtonDown(0)){Fire();}}//捡武器行为public void ChangeWeapon(GameObject weapon){if (nowWeapon != null) nowWeapon.Vanish(); //销毁当前武器nowWeapon = weapon.GetComponent<Weapon>(); //头部留有存放武器的位置weapon.gameObject.transform.position = Head.GetChild(0).transform.position ;weapon.gameObject.transform.rotation = Head.GetChild(0).transform.rotation;weapon.gameObject.transform.SetParent(Head.GetChild(0));attack += nowWeapon.attack;}//开火行为重写public override void Fire() {nowWeapon.Shoot(); }//被子弹打到private void OnTriggerEnter(Collider other){if(other.tag == "bullet"){try{//添加子弹挂载的目标坦克,方便获取该子弹的攻击力,与受伤逻辑相结合BulletMove ball = other.GetComponent<BulletMove>();TankFather ballTank = ball.Tank.GetComponent<TankFather>();//当子弹不是自己打的到自己身上的时候if (ballTank.tag != "Player"){//扣血Heart(ballTank);}}catch{throw;}}}}
子弹发射更新
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目: ______________
//___________功能: 子弹的逻辑相关
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class BulletMove : MonoBehaviour
{public GameObject Tank; //挂载在哪个坦克上public GameObject DeidEffect;public AudioSource distorySound; //销毁的音效private void Start(){}//子弹的销毁及特效private void OnTriggerEnter(Collider other){if (other.CompareTag("Environment")|| other.CompareTag("Enemy")){if (DeidEffect != null){GameObject eff = Instantiate(DeidEffect, transform.position, transform.rotation);//音效控制distorySound = eff.GetComponent<AudioSource>();distorySound.enabled = MusicContol.SingleMusicContol.nowMusicData.soundSwitch;distorySound.volume = MusicContol.SingleMusicContol.nowMusicData.soundRoll;eff.AddComponent<SelfDestroy>();}Destroy(this.gameObject,2f); } }}
🎶(D)行为实现——敌军坦克的移动路线和检测攻击

😶🌫️:步骤实现
- 1.指定移动位置,设置朝向
- 2.行为逻辑封装。开火,受伤
- 3.自动检测闯入者
———— --------------————
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//-------------------------------------
//—————————————————————————————————————
//___________项目:
//___________功能:敌方坦克逻辑封装
//___________创建者:秩沅_______________
//_____________________________________
//-------------------------------------
public class EnemyTank:TankFather
{//随机移动点的位置数组public Transform[] randomPosition;//目标位置private Transform target;//目标坦克public Transform Player;//检测范围public float distance = 10f;public AudioSource shootMusic; //发射音效public GameObject shootball; //发射的子弹类型public float shootSpeed = 1000f; //子弹的速度 public Transform[] shootTransform; //发射的组件信息public bool shootSwitch = false; private float endTime = 3f; //子弹发射间隔的时间private void Start(){//属性初始化赋值maxBlood = 500;nowBlood = 500;attack = 30;HeadSpeed = 50;//射击音效关闭shootMusic.enabled = false;moveSpeed = 10f;//先随机整一个目标点RandomPosition();}private void Update(){ transform.LookAt(target);//始终超自己的正方向移动transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime); //当距离差不多相等时,再随机目标点if(Vector3.Distance(transform .position ,target .position)< 0.5f){RandomPosition();}//范围检测if (Vector3 .Distance(transform .position ,Player.position )<= distance && Player !=null ){//炮口瞄准玩家Head.transform.LookAt(Player);//倒计时发射子弹endTime = Mathf.MoveTowards(endTime, 0, 0.1f);if (endTime <= 0){Fire();endTime = 3f;} }}//随机指向一个移动点public void RandomPosition(){if (randomPosition.Length != 0)target = randomPosition[Random.Range(0, randomPosition.Length)];}//触发检测private void OnTriggerEnter(Collider other){if (other.gameObject.tag == "bullet" ){//添加子弹挂载的目标坦克,方便获取该子弹的攻击力,与受伤逻辑相结合BulletMove ball = other.gameObject.GetComponent<BulletMove>();TankFather ballTank = ball.Tank.GetComponent<TankFather>();//当子弹不是自己打的到自己身上的时候if (ballTank.tag != gameObject.tag){//扣血Heart(ballTank);}}}public override void Fire(){//开启射击音效shootMusic.enabled = true;shootMusic.Play();for (int i = 0; i < shootTransform.Length ; i++){GameObject ball = Instantiate(shootball, shootTransform[i].position, shootTransform[i].rotation);BulletMove movScript = ball.GetComponent<BulletMove>();Rigidbody shootBall = ball.GetComponent<Rigidbody>();shootBall.AddForce(shootTransform[i].transform.forward * shootSpeed);movScript.Tank = gameObject; //声明子弹是由谁打出去的}}}
问题:
1.受到伤害,开启了保护罩但是不扣血
2.敌方坦克,原地打转,未按规定路线移动
解决:
1.子弹检测逻辑错误
2.位置空点绑定在对象身上变成了子对象因此无法达到效果
总结:

- 1.检测触发的方式:①触发器检测②向量距离检测
- 2.多点指定移动,加入向量距离判断,重合的机率小,故此不能 A物体距离 == B物体距离
- 3.子坦克继承了父类脚本,引用传递时直接用父类即可获得该子类,(原因父类名字相同,但是子类名字不同,无法确定,所以里氏替换作用在此体现)
⭐相关文章⭐
⭐【2023unity游戏制作-mango的冒险】-6.关卡设计
⭐【2023unity游戏制作-mango的冒险】-5.攻击系统的简单实现
⭐【2023unity游戏制作-mango的冒险】-4.场景二的镜头和法球特效跟随
⭐【2023unity游戏制作-mango的冒险】-3.基础动作和动画API实现
⭐【2023unity游戏制作-mango的冒险】-2.始画面API制作
⭐【2023unity游戏制作-mango的冒险】-1.场景搭建
⭐“狂飙”游戏制作—游戏分类图鉴(网易游学)
⭐本站最全-unity常用API大全(万字详解),不信你不收藏
你们的点赞👍 收藏⭐ 留言📝 关注✅是我持续创作,输出优质内容的最大动力!
相关文章:
【unity之IMGUI实践】敌方逻辑封装实现【六】
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:uni…...
llvm向用户抛出warning、error信息
1、抛出error信息并终止程序 使用DiagnosticInfoUnsupported可以向用户抛出error信息并且终止程序,效果如同report_fatal_error、Error。后端用法如下: void xxxx::reportErrorMsg(const MachineFunction &MF)const {const Function &F MF.ge…...
微服务学习笔记-----Nacos安装教程(Windows和Linux版本)
Nacos安装教程 Nacos安装指南1.Windows安装1.1.下载安装包1.2.解压1.3.端口配置1.4.启动1.5.访问 2.Linux安装2.1.安装JDK2.2.上传安装包2.3.解压2.4.端口配置2.5.启动 3.Nacos的依赖 Nacos安装指南 1.Windows安装 开发阶段采用单机安装即可。 1.1.下载安装包 在Nacos的Git…...
程序员面试系列,docker常见面试题
原文链接 什么是Docker?它的主要作用是什么?Docker和虚拟机之间有什么区别?Docker的主要组件有哪些?Docker镜像和容器的区别是什么?如何构建Docker镜像?请简要描述构建过程。如何创建和启动一个Docker容器…...
Linux centos7.x系统将/home磁盘分配给/
1.解除挂载并删除/home卷 umount /home如果出现以下报错 : 可以使用以下命令查看哪些进程在占用 fuser -mv /home杀死这些进程就行 kill -9 进程号然后再执行umount /home就可以成功了 , 同时执行以下命令把逻辑卷删除了 lvremove /dev/centos/home…...
根据数组元素为对象,对元素对象的某一属性进行排序
前言: 开发过程中,前端难免需要对数据进行操作,比如比较常见的操作就是对数组元素进行排序 对数组元素对基本类型的进行排序 const arr [2,4,1,3,9,5]arr.sort((a,b)>a-b) //[1, 2, 3, 4, 5, 9] arr.sort((a,b)>b-a) //[9, 5, 4, 3,…...
mysql(三)用户权限管理
目录 前言 一、概述 二、用户权限类型 三、用户赋权 四、权限删除 五、删除用户 前言 为什么要设置用户权限? MySQL设置用户管理权限的主要目的是为了确保数据库的安全性和数据的机密性。以下是一些原因: 1. 安全性:MySQL是一个开源的关系型…...
字节JAVA岗位面试总结汇总
主要拷打了 redis+mysql+网络+系统+java+算法,面试问题主要集中在 mysql、redis、网络这三部门, Redis 相关 介绍一下redis数据库? Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。 Redis…...
29-使用RocketMQ做削峰处理
1、初识RocketMQ 1.1、Apache 下载RocketMQ https://downloads.apache.org/rocketmq/ 1.2、RocketMQ官方网站 https://rocketmq.apache.org/zh/ 1.3、RocketMQ在GitHub文档 https://github.com/alibaba/spring-cloud-alibaba/wiki/RocketMQ 1.4、RocketMQ官方网站文档 …...
ELK 使用kibana查询和分析nginx日志
背景:使用kibana查询和分析nginx请求日志,方便开发人员查询系统日志和分析系统问题。 setp 1、定义Index patterns 2、定义Discover(Search 查询数据) 3、定义Visualizations 3.1 定义Vertical Bar 3.2 、Choose a source 3.3、定义图表 4、定义…...
mybatisplus自定义xml的sql语句进行自动分页
1、xxxMapper.xml定义 <select id"leftJoinPageList" resultMap"MonitoringDataResult"parameterType"com.ktt.carbon.verification.domain.bo.MonitoringDataBo">SELECT d.* from carbon_monitoring_data d LEFT JOIN carbon_monitoring…...
ChatGPT:人工智能开启智能交流新篇章
一、ChatGPT:智能交流的新里程碑 ChatGPT是OpenAI基于GPT技术的最新版本,采用深度学习模型,通过预训练和微调的方式,使其能够理解和生成自然语言,从而实现与人类更自然、流畅的对话和交流。 二、ChatGPT的技术原理与优…...
关于anki的一些思考
文章目录 通常情况下选择什么模板制卡?一张填空卡片的填空数量到底要多少才合适? 通常情况下选择什么模板制卡? 通常情况是指知识是以一段文字的形式呈现,而不是这些:单词、选择题、成语等(这些都可以定制…...
【动态规划刷题 1 】 第N个泰波那契数 三步问题
第N个泰波那契数 链接: 第N个泰波那契数 1137 . 第 N 个泰波那契数 泰波那契序列 Tn 定义如下: T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n,请返回第 n 个泰波那契数 Tn 的值。 示例 1: 输入:…...
【踩坑】三种方式解决 Homebrew failing to install - fatal: not in a git directory
问题描述 解决方法一 添加安全目录,没有测试。 git config --global --add safe.directory /opt/homebrew/Library/Taps/homebrew/homebrew- git config --global --add safe.directory /opt/homebrew/Library/Taps/homebrew/homebrew-cask 解决方法二 取消挂载这…...
零信任安全解决方案
什么是零信任 零信任网络架构 (ZTNA) 或零信任安全是一种新的组织网络安全方法。它旨在修复传统基于边界的安全性中的缺陷并简化网络设计。 它以“永不信任,始终验证”的原则运作。这意味着,无论用户或设备位于何处,…...
如何创建高级 CSS 下拉菜单
效果展示 实现思路及部分代码 1、定义整体页面结构 从上述的效果展示图可以看出,页面的整体结构应该需要一个总菜单容器来装载父级菜单项,并且对应的父级菜单项应该有对应的菜单子项。子菜单是分类的话,我们还需要额外在扩展对应的容器来装…...
java中判断list是否为空
java中判断list是否为空是日常代码中经常遇到的问题。最近发现一个Utils提供的方法可以一步判断。 废话不多说,直接上代码! ArrayList<String> arrayList new ArrayList<>(); System.out.println("集合1:" Collecti…...
龙芯3A5000板卡在高性能工作站的应用方案-迅为电子
将龙芯3A5000应用于高性能工作站时,可以考虑以下方案: 多核计算能力:龙芯3A5000拥有多核心处理器,具备强大的计算能力。在高性能工作站中,可以利用多核心的处理能力来支持复杂的工程设计、科学计算和数据处理任务。…...
WebSocket心跳机制
WebSocket是HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。 1、创建webSocket // Create WebSocket connection. const sock…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
