【unity实战】使用Unity实现动作游戏的攻击 连击 轻重攻击和打击感
最终效果
文章目录
- 最终效果
- 前言
- 素材下载:
- 玩家移动跳跃控制
- 攻击动画配置
- 轻攻击
- 重攻击
- 攻击时禁止移动和攻击移动补偿
- 敌人击退和播放受击动画
- 受击特效
- 攻击停顿和屏幕震动
- 局部顿帧(补充)
- 参考
- 源码
- 完结
前言
注意本文为自己的学习记录笔记,主要是对游戏攻击 连击 轻重攻击和打击感进行探究,其中打击感实现一般依靠播放受击动画、击退、攻击特效、时停和屏幕震动反馈等来实现,如果你有其他的好方法也欢迎补充。
素材下载:
人物
https://legnops.itch.io/red-hood-character
敌人
https://jesse-m.itch.io/skeleton-pack
环境
https://szadiart.itch.io/pixel-fantasy-caves
攻击特效
https://v-ktor.itch.io/pixelated-attackhit-animations
玩家移动跳跃控制
public class PlayerController : MonoBehaviour
{[Header("移动和跳跃参数")] public float moveSpeed; // 移动速度public float jumpForce; // 跳跃力量new private Rigidbody2D rigidbody; // 刚体组件private Animator animator; // 动画控制器private float input; // 输入private bool isGround; // 是否在地面上[SerializeField] private LayerMask layer; // 地面碰撞层[SerializeField] private Vector3 check; // 地面检测向量void Start(){rigidbody = GetComponent<Rigidbody2D>();animator = GetComponent<Animator>();}void Update(){input = Input.GetAxisRaw("Horizontal");isGround = Physics2D.OverlapCircle(transform.position + new Vector3(check.x, check.y, 0), check.z, layer);animator.SetFloat("Horizontal", rigidbody.velocity.x);animator.SetFloat("Vertical", rigidbody.velocity.y);animator.SetBool("isGround", isGround);Move();Attack();}void Move(){// 根据输入来移动角色rigidbody.velocity = new Vector2(input * moveSpeed, rigidbody.velocity.y);// 处理跳跃if (Input.GetButtonDown("Jump") && isGround){rigidbody.velocity = new Vector2(0, jumpForce);animator.SetTrigger("Jump"); // 触发跳跃动画}// 根据水平速度方向更新角色朝向if (rigidbody.velocity.x < 0)transform.localScale = new Vector3(-1, 1, 1); // 向左else if (rigidbody.velocity.x > 0)transform.localScale = new Vector3(1, 1, 1); // 向右}private void OnDrawGizmos(){Gizmos.DrawWireSphere(transform.position + new Vector3(check.x, check.y, 0), check.z);}}
攻击动画配置
攻击动画分为轻攻击和重攻击
轻攻击
重攻击
[Header("攻击")]
public float interval = 2f; // 攻击间隔时间
private float timer; // 计时器
private bool isAttack; // 是否正在攻击
private string attackType; // 攻击类型
private int comboStep; // 连击步骤void Update()
{//...Attack();
}void Attack()
{// 轻攻击输入检测if (Input.GetKeyDown(KeyCode.Return) && !isAttack){isAttack = true;attackType = "Light";comboStep++; // 连击步骤加一if (comboStep > 3)comboStep = 1; // 连击步骤循环timer = interval; // 设置计时器animator.SetTrigger("LightAttack"); // 触发轻攻击动画animator.SetInteger("ComboStep", comboStep); // 设置连击步骤参数}// 重攻击输入检测if (Input.GetKeyDown(KeyCode.RightShift) && !isAttack){isAttack = true;attackType = "Heavy";comboStep++; // 连击步骤加一if (comboStep > 3)comboStep = 1; // 连击步骤循环timer = interval; // 设置计时器animator.SetTrigger("HeavyAttack"); // 触发重攻击动画animator.SetInteger("ComboStep", comboStep); // 设置连击步骤参数}// 处理连击计时器if (timer != 0){timer -= Time.deltaTime;if (timer <= 0){timer = 0;comboStep = 0; // 重置连击步骤}}
}//攻击结束
public void AttackOver()
{isAttack = false;
}
配置每个
攻击动画,在执行的位置执行攻击结束事件,通常攻击结束事件都不会放在动画的最后一帧,因为连击一般都存在预输入,也就是在上一个动画还未结束时就进行输入,这样能很好的提升combo的连贯性
效果
攻击时禁止移动和攻击移动补偿
攻击时我们不希望玩家还能移动,但是简单粗暴的禁止移动又会影响我们的攻击操作手感,在死亡细胞等游戏中,攻击时会朝前方以一个较小的速度移动,这样可以一定程度的补偿攻击时无法移动的缺陷
[Header("攻击补偿速度")]
public float lightSpeed; // 轻攻击速度
public float heavySpeed; // 重攻击速度void Move()
{// 如果玩家没有在攻击状态下,根据输入来移动角色if (!isAttack)rigidbody.velocity = new Vector2(input * moveSpeed, rigidbody.velocity.y);else{// 如果正在攻击,则根据攻击类型设置速度if (attackType == "Light")rigidbody.velocity = new Vector2(transform.localScale.x * lightSpeed, rigidbody.velocity.y);else if (attackType == "Heavy")rigidbody.velocity = new Vector2(transform.localScale.x * heavySpeed, rigidbody.velocity.y);}// ...
}
配置
效果
敌人击退和播放受击动画
配置敌人受击动画
配置玩家每个动画的攻击范围
新增Enemy 敌人脚本,实现击退和受击动画
public class Enemy : MonoBehaviour
{public float speed; // 敌人的移动速度private Vector2 direction; // 受击时的移动方向private bool isHit; // 是否正在受击状态private AnimatorStateInfo info; // 动画状态信息private Animator animator; // 敌人的主动画控制器new private Rigidbody2D rigidbody; // 敌人的刚体组件void Start(){// 获取组件的引用animator = transform.GetComponent<Animator>();rigidbody = transform.GetComponent<Rigidbody2D>();}void Update(){info = animator.GetCurrentAnimatorStateInfo(0); // 获取当前动画状态信息if (isHit){rigidbody.velocity = direction * speed; // 根据受击方向设置速度if (info.normalizedTime >= .6f)isHit = false; // 当动画播放超过60%时结束受击状态}}// 外部调用,使敌人进入受击状态public void GetHit(Vector2 direction){transform.localScale = new Vector3(-direction.x, 1, 1); // 根据受击方向调整朝向isHit = true; // 进入受击状态this.direction = direction; // 设置受击方向animator.SetTrigger("Hit"); // 播放主动画的受击动画状态}
}
修改PlayerController,调用击退敌人
private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag("Enemy")){// 根据角色朝向确定敌人受击方向if (transform.localScale.x > 0)other.GetComponent<Enemy>().GetHit(Vector2.right); // 右侧受击else if (transform.localScale.x < 0)other.GetComponent<Enemy>().GetHit(Vector2.left); // 左侧受击}
}
效果
受击特效
特效动画配置
修改Enemy
private Animator hitAnimator; // 敌人的受击特效动画控制器hitAnimator = transform.GetChild(0).GetComponent<Animator>(); // 敌人的受击特效动画控制器在子对象中// 外部调用,使敌人进入受击状态public void GetHit(Vector2 direction){//...hitAnimator.SetTrigger("Hit"); // 播放受击特效动画}
效果
攻击停顿和屏幕震动
新增AttackSense
public class AttackSense : MonoBehaviour
{private static AttackSense instance;public static AttackSense Instance{get{if (instance == null)instance = FindObjectOfType<AttackSense>(); // 查找当前场景中的 AttackSense 实例return instance;}}private bool isShake; // 是否正在进行摄像机震动// 暂停游戏一段时间public void HitPause(int duration){StartCoroutine(Pause(duration));}// 使用协程实现暂停功能IEnumerator Pause(int duration){float pauseTime = duration / 60f; // 将帧数转换为实际暂停时间Time.timeScale = 0.2f; // 将游戏时间缩放设为0.2yield return new WaitForSecondsRealtime(pauseTime); // 等待指定的暂停时间Time.timeScale = 1; // 恢复游戏时间正常}// 触发摄像机震动效果public void CameraShake(float duration, float strength){if (!isShake) // 如果当前没有进行震动StartCoroutine(Shake(duration, strength));}// 使用协程实现摄像机震动效果IEnumerator Shake(float duration, float strength){isShake = true; // 标记正在进行震动Transform camera = Camera.main.transform; // 获取主摄像机的 Transform 组件Vector3 startPosition = camera.position; // 记录摄像机震动前的初始位置while (duration > 0){// 将摄像机位置随机偏移一定范围来模拟震动效果camera.position = Random.insideUnitSphere * strength + startPosition;duration -= Time.deltaTime; // 每帧减去时间yield return null; // 等待下一帧}camera.position = startPosition; // 震动结束后将摄像机位置恢复到初始位置isShake = false; // 结束震动状态}
}
修改PlayerController调用
[Header("打击感")]
public float shakeTime; // 摇晃时间
public int lightPause; // 轻攻击暂停时间
public float lightStrength; // 轻攻击相机震动强度
public int heavyPause; // 重攻击暂停时间
public float heavyStrength; // 重攻击相机震动强度private void OnTriggerEnter2D(Collider2D other)
{if (other.CompareTag("Enemy")){// 根据攻击类型处理打击感if (attackType == "Light"){AttackSense.Instance.HitPause(lightPause); // 轻攻击暂停AttackSense.Instance.CameraShake(shakeTime, lightStrength); // 相机震动}else if (attackType == "Heavy"){AttackSense.Instance.HitPause(heavyPause); // 重攻击暂停AttackSense.Instance.CameraShake(shakeTime, heavyStrength); // 相机震动}// 根据角色朝向确定敌人击退方向if (transform.localScale.x > 0)other.GetComponent<Enemy>().GetHit(Vector2.right); // 右侧受击else if (transform.localScale.x < 0)other.GetComponent<Enemy>().GetHit(Vector2.left); // 左侧受击}
}
配置参数
最终效果
局部顿帧(补充)
前面的顿帧这个思路其实不太好,可以看看有的游戏,他们不是所有物体都停顿的,一般是攻击者和受击者停顿,其他的不受影响。animator有个scale播放速度scale值应该可以实现这种效果,连续攻击可能用局部顿帧好一点,下面大概分享一下思路
public class AttackController : MonoBehaviour
{public Animator animator;public float slowMotionTimeScale = 0.5f; // 慢动作时的时间缩放值public void PerformAttack(){StartCoroutine(AttackCoroutine());}IEnumerator AttackCoroutine(){// 播放攻击动画前先设置慢动作animator.speed = slowMotionTimeScale;// 等待攻击动画播放完成yield return new WaitForSeconds(animator.GetCurrentAnimatorStateInfo(0).length / slowMotionTimeScale);// 恢复正常时间缩放animator.speed = 1f;}
}
在这个示例中,PerformAttack 方法可以被调用来开始攻击动作。在攻击动作开始时,时间缩放被设置为 slowMotionTimeScale,然后通过 Coroutine 等待攻击动画播放完成后,再恢复为正常速度。
通过这种方法,你可以在游戏中实现局部的动画停顿效果,而不是整体减速,从而增强游戏的视觉冲击力和玩家的体验。
参考
https://www.bilibili.com/video/BV1fX4y1G7tv
源码
整理好我会放上来
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~
相关文章:

【unity实战】使用Unity实现动作游戏的攻击 连击 轻重攻击和打击感
最终效果 文章目录 最终效果前言素材下载:玩家移动跳跃控制攻击动画配置轻攻击重攻击 攻击时禁止移动和攻击移动补偿敌人击退和播放受击动画受击特效攻击停顿和屏幕震动局部顿帧(补充)参考源码完结 前言 注意本文为自己的学习记录笔记&#…...

ELK 企业实战7
ELKkafkafilebeat企业内部日志分析系统 1、组件介绍 1、Elasticsearch: 是一个基于Lucene的搜索服务器。提供搜集、分析、存储数据三大功能。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的ÿ…...

linux 下neo4j的安装
一、neo4j简介 Neo4j 是一个高性能的 NoSQL 图形数据库,它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。Neo4j 也可以被看作是一个高性能的图引擎,该引擎具有成熟数据库的所有特性。 neo4j与jdk版本对应 neo4j的版本需要与jdk版本相适配,否则容易出现安装失…...

Flink ProcessFunction不同流异同及应用场景
ProcessFunction系列对比概览 函数类别关键特性应用场景示例ProcessFunction基础类,处理单个事件,支持事件时间、水位线、状态管理、定时器。单独处理每个事件,执行复杂逻辑,如基于事件内容动态响应。KeyedProcessFunction基于键…...

Matplotlib 文本
可以使用 xlabel、ylabel、text向图中添加文本 mu, sigma 100, 15 x mu sigma * np.random.randn(10000)# the histogram of the data n, bins, patches plt.hist(x, 50, densityTrue, facecolorg, alpha0.75)plt.xlabel(Smarts) plt.ylabel(Probability) plt.title(Histo…...

信创产业政策,信创测试方面
信创产业的政策支持主要体现在多个方面,这些政策旨在推动产业的快速发展,加强自主创新能力,保障国家信息安全,以及促进产业结构的优化升级。 首先,政府通过财政支持、税收优惠等方式,加大对信创产业的资金…...

微信云数据库迁移到unicloud云数据库
背景 早期只有一个微信小程序,后来了解到uniapp的跨端解决方案,开始从小程序代码迁移到uniapp。对于后端采用的微信云开发方案,迁移的时候主要要解决从openid的用户体系转移到unicloud提供的uni-id体系(使用uid)。 方案 利用微信云数据库的…...

快速上手文心一言指令
“文心一言”指的是百度公司开发的自然语言处理与生成技术,它类似于ChatGPT,是一种基于大规模语言模型的AI对话系统,能够理解和生成自然语言文本,进行问答、创作等多种任务。由于“文心一言”是一个复杂的系统,其内部指…...

零基础STM32单片机编程入门(五)FreeRTOS实时操作系统详解及实战含源码视频
文章目录 一.概要二.什么是实时操作系统三.FreeRTOS的特性四.FreeRTOS的任务详解1.任务函数定义2.任务的创建3.任务的调度原理 五.CubeMX配置一个FreeRTOS例程1.硬件准备2.创建工程3.调试FreeRTOS任务调度 六.CubeMX工程源代码下载七.讲解视频链接地址八.小结 一.概要 FreeRTO…...

leetCode.96. 不同的二叉搜索树
leetCode.96. 不同的二叉搜索树 题目思路 代码 // 方法一:直接用卡特兰数就行 // 方法二:递归方法 class Solution { public:int numTrees(int n) {// 这里把 i当成整个结点,j当成左子树最左侧结点,并一次当根节点尝试// f[ i ] f[ j - 1…...

PyAutoGUI 使用详解
文章目录 简介PyAutoGUI 的原理安装 PyAutoGUI基本使用示例鼠标控制键盘控制截屏图像识别消息框 高级功能防止误操作多屏幕支持鼠标平滑移动 结论 简介 PyAutoGUI 是一个用于自动化控制鼠标和键盘的 Python 库。它可以帮助开发者编写脚本,以模拟用户在计算机上的操…...

MySQL——备份
为什么要备份? 保证重要的数据不丢失 方便数据转移 MySQL数据库备份方式: 1. 直接拷贝物理文件 2. 在可视化工具中手动导出 —— 在想要导出的表或者库中,右键选择备份或导出 3. 使用命令行导出 mysqldump ——cmd打开命令行 —…...

科东软件精彩亮相华南工博会,展现未来工业前沿技术
近日,华南国际工业博览会在深圳成功举办。科东软件携众多前沿技术、解决方案及最新应用案例精彩亮相,为参展观众带来了一场工业智能的科技盛宴。 鸿道操作系统(Intewell) 科东软件重点展示了鸿道操作系统(Intewell&…...

详解flink sql, calcite logical转flink logical
文章目录 背景示例FlinkLogicalCalcConverterBatchPhysicalCalcRuleStreamPhysicalCalcRule其它算子FlinkLogicalAggregateFlinkLogicalCorrelateFlinkLogicalDataStreamTableScanFlinkLogicalDistributionFlinkLogicalExpandFlinkLogicalIntermediateTableScanFlinkLogicalInt…...

PostgreSQL的系统视图pg_statio_all_indexes
PostgreSQL的系统视图pg_statio_all_indexes 在 PostgreSQL 数据库中,pg_statio_all_indexes 视图提供了有关所有索引的 I/O 活动的统计信息。这些统计信息对于了解索引的使用情况和性能调优非常有帮助。 pg_statio_all_indexes 视图的结构 以下是 pg_statio_all…...

【C++ Primer Plus学习记录】函数和C-风格字符串
将字符串作为参数时意味着传递的是地址,但可以使用const来禁止对字符串参数进行修改。 假设要将字符串作为参数传递给函数,则表示字符串的方式有三种: (1)char数组 (2)用引号括起来的字符串常…...

力扣双指针算法题目:移动零
1.题目 . - 力扣(LeetCode) 2.思路解析 这个题目的思路和“使用递归排序快速排序解决数组的排序问题”相同 class solution { public:void QuickSort(vector<int>& nums, int left, int right){if (left > right) return;int key left…...

day60---面试专题(微服务面试题-参考回答)
微服务面试题 **面试官:**Spring Cloud 5大组件有哪些? 候选人: 早期我们一般认为的Spring Cloud五大组件是 Eureka : 注册中心Ribbon : 负载均衡Feign : 远程调用Hystrix : 服务熔断Zuul/Gateway : 网关 随着SpringCloudAlibba在国内兴起 , …...

laravel+phpoffice+easyexcel实现导入
资源包下载地址 https://download.csdn.net/download/QiZong__BK/89503486 easy-excel下载: "dcat/easy-excel": "^1.0", 命令行: composer require dcat/easy-excel 前端代码 <!doctype html> <html lang"en&…...

Spring Boot集成多数据源的最佳实践
Spring Boot集成多数据源的最佳实践 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 为什么需要多数据源? 在实际的应用开发中,有时候…...

Java项目:基于SSM框架实现的班主任助理管理系统【ssm+B/S架构+源码+数据库+开题报告+毕业论文】
一、项目简介 本项目是一套基于SSM框架实现的班主任助理管理系统 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse或者idea 确保可以运行! 该系统功能完善、界面美观、操作简单、功…...
数据在内存中的存储方式
🌟🌟作者主页:ephemerals__ 🌟🌟所属专栏:C语言 目录 前言 一、整数的存储 二、大小端字节序及其判断 1.什么是大小端 2.为什么有大小端 3.用c语言编写程序判断大小端 三、浮点数的存储 1.浮点数…...

Selenium 监视数据收发
实际上,在我提供的示例中,确实使用了浏览器实例。webdriver.Chrome()这行代码正是创建了一个Chrome浏览器的WebDriver实例。Selenium Wire扩展了标准的Selenium WebDriver,允许你通过这个浏览器实例来监听网络请求。 当你运行类似这样的代码…...

基于 STM32 的智能睡眠呼吸监测系统设计
本设计的硬件构成: STM32F103C8T6单片机最小系统板(包含3.3V稳压电路时钟晶振电路复位电路(上电自复位,手动复位)),心率传感器、气压传感器、液晶显示、按键、蜂鸣器、LED灯、蓝牙模块组合而成…...

Spring的事务管理、AOP实现底层
目录 spring的事务管理是如何实现的? Spring的AOP的底层实现原理 spring的事务管理是如何实现的? 首先,spring的事务是由aop来实现的,首先要生成具体的代理对象,然后按照aop的整套流程来执行具体的操作逻辑ÿ…...

基于SpringBoot的篮球竞赛预约平台
你好,我是计算机学姐码农小野!如果你对篮球竞赛预约平台感兴趣或有相关需求,欢迎私信联系我。 开发语言: Java 数据库: MySQL 技术: SpringBootMySql 工具: MyEclipse、Tomcat 系统展示…...

学生用小台灯什么牌子的好?列举出几款学生用台灯推荐
眼睛是我们感知世界的窗口,但近年来,儿童青少年的视力健康却受到了严重困扰。数据显示,近视问题在儿童群体中呈现出明显的增长趋势,这给他们的学习和生活带来了诸多不便。虽然现代科技的快速发展使得电子产品成为了我们生活中不可…...

软件测试面试题:项目中的MQ是如何测试的?
通常,咱们会从两个方面来考虑:正常情况和异常情况。 首先,咱们得确保消息队列在正常工作时结果正确。比如,消息发送出去的时候,所有的字段都得齐全,接收方收到的消息也得一样。咱们得确保系统能够正确无误…...

Python爬取国家医保平台公开数据
国家医保服务平台数据爬取python爬虫数据爬取医疗公开数据 定点医疗机构查询定点零售药店查询医保机构查询药品分类与代码查询 等等,数据都能爬 接口地址:/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital 签名参数:signData {dat…...

B站大课堂-自动化精品视频(个人存档)
基础知识 工业通信协议 Modbus 施耐德研发,有基于以太网的 ModbusTCP 协议和使用 485/232 串口通信的 ModbusRTU/ASCII。 Modbus 协议面世较早、协议简洁高效、商用免费、功能灵活、实现简单,是目前应用最广泛的现场总线协议。 我的笔记里边有一些推荐…...