Godot.NET C#IOC重构(11):攻击与死亡

news/2024/10/12 10:27:47

目录
  • 前言
  • 带上伤害
      • Hitbox
      • Hurtbox
    • 实现效果
  • 渐变淡出
  • 添加受攻击效果
    • Hurtbox
    • 完善Enemy状态机
    • 结果
  • 剩下的都是逻辑完善的部分了,后面的我就跳过了。

前言

这次来深刻了解一下Godot中的伤害计算

带上伤害

我们将之前的Hitbox和HurtBox进行了一下简单的修改

Hitbox

using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace GodotNet_LegendOfPaladin2.GlobalClass
{[GlobalClass]public partial class Hitbox:Area2D{[Export]public int Damage = 1;/// <summary>/// 在实例化事件中添加委托/// </summary>public Hitbox() {AreaEntered += Hitbox_AreaEntered;}/// <summary>/// 当有Area2D进入时/// </summary>/// <param name="area"></param>private void Hitbox_AreaEntered(Area2D area){//当进入的节点是继承Area2D的HurtBox的时候if (area is Hurtbox){OnAreaEnterd((Hurtbox)area);}}/// <summary>/// 攻击判断/// </summary>/// <param name="area"></param>public void OnAreaEnterd(Hurtbox area){//GD.Print($" {Owner.Name} [Hit] {area.Owner.Name}");area.Hurt(this);}}}

Hurtbox

using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace GodotNet_LegendOfPaladin2.GlobalClass
{[GlobalClass]public partial class Hurtbox : Area2D{public event Action<Hitbox> HurtCallback;public event Action DieCallback;[Export]public int Health = 100;public Hurtbox(){HurtCallback += Hurt;DieCallback += Hurtbox_DieCallback;}private void Hurtbox_DieCallback(){GD.Print($"{Owner.Name} is Die");}/// <summary>/// 造成伤害/// </summary>/// <param name="num"></param>/// <param name="owner"></param>public void Hurt(Hitbox hitbox){Health -= hitbox.Damage;GD.Print($"{hitbox.Owner.Name} [Hit] {Owner.Name} in {hitbox.Damage} damage, Health = {Health}");if (Health <= 0){Hurtbox_DieCallback();}}}
}

实现效果

渐变淡出

添加受攻击效果

Hurtbox

按照我的想法,委托事件比信号更好用。

using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace GodotNet_LegendOfPaladin2.GlobalClass
{[GlobalClass]public partial class Hurtbox : Area2D{/// <summary>/// 注册伤害和死亡的委托事件/// </summary>public event Action<Hitbox> HurtCallback;public event Action DieCallback;[Export]public int Health = 100;public Hurtbox(){}/// <summary>/// 造成伤害/// </summary>/// <param name="num"></param>/// <param name="owner"></param>public void Hurt(Hitbox hitbox){Health -= hitbox.Damage;GD.Print($"{hitbox.Owner.Name} [Hit] {Owner.Name} in {hitbox.Damage} damage, Health = {Health}");HurtCallback?.Invoke(hitbox);if (Health <= 0){DieCallback?.Invoke();}}}
}

完善Enemy状态机

using Bogus;
using Godot;
using GodotNet_LegendOfPaladin2.GlobalClass;
using GodotNet_LegendOfPaladin2.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace GodotNet_LegendOfPaladin2.SceneModels
{public class EnemySceneModel : ISceneModel{private PrintHelper printHelper;private CharacterBody2D characterBody2D;private CollisionShape2D collisionShape2D;private Sprite2D sprite2D;private AnimationPlayer animationPlayer;public RayCast2D WallCheck { get; private set; }public RayCast2D FloorCheck { get; private set; }public RayCast2D PlayerCheck { get; private set; }public Hitbox Hitbox { get; private set; }public Hurtbox Hurtbox { get; private set; }public enum DirectionEnum{Left = -1, Right = 1}//设置正向的方向private DirectionEnum direction = DirectionEnum.Right;public DirectionEnum Direction{get => direction;//这个是一个生命周期的问题,属性的设置比树节点的加载更早//,所以我们会在Ready里面使用Direction = Direction来触发get函数set{if (characterBody2D != null && direction != value){//printHelper.Debug($"设置朝向,{value}");var scale = characterBody2D.Scale;//注意反转是X=-1。比如你左反转到右是X=-1,你右又反转到左也是X=-1。不是X=-1就是左,X=1就是右。scale.X = -1;characterBody2D.Scale = scale;direction = value;}}}public enum AnimationEnum{Hit, Idle, Run, Walk,Die}public AnimationEnum Animation = AnimationEnum.Idle;/// <summary>/// 动画持续时间/// </summary>private float animationDuration = 0;/// <summary>/// 最大速度/// </summary>public int MaxSpeed { get; set; }/// <summary>/// 加速度/// </summary>public int AccelerationSpeed { get; set; }/// <summary>/// Animation类型/// </summary>public int AnimationType { get; set; }public EnemySceneModel(PrintHelper printHelper){this.printHelper = printHelper;printHelper.SetTitle(nameof(EnemySceneModel));}public EnemySceneModel() { }public override void Process(double delta){animationDuration = (float)Mathf.MoveToward(animationDuration, 99, delta);SetAnimation();Move(delta);Direction = Direction;}public override void Ready(){characterBody2D = Scene.GetNode<CharacterBody2D>("CharacterBody2D");collisionShape2D = characterBody2D.GetNode<CollisionShape2D>("CollisionShape2D");sprite2D = characterBody2D.GetNode<Sprite2D>("Sprite2D");animationPlayer = characterBody2D.GetNode<AnimationPlayer>("AnimationPlayer");WallCheck = Scene.GetNode<RayCast2D>("CharacterBody2D/RayCast/WallCheck");FloorCheck = Scene.GetNode<RayCast2D>("CharacterBody2D/RayCast/FloorCheck");PlayerCheck = Scene.GetNode<RayCast2D>("CharacterBody2D/RayCast/PlayerCheck");Hitbox = Scene.GetNode<Hitbox>("CharacterBody2D/Hitbox");Hurtbox = Scene.GetNode<Hurtbox>("CharacterBody2D/Hurtbox");Hurtbox.HurtCallback += Hurtbox_HurtCallback;Hurtbox.DieCallback += Hurtbox_DieCallback;PlayAnimation();printHelper.Debug("加载成功!");printHelper.Debug($"当前朝向是:{Direction}");Direction = Direction;}private void Hurtbox_DieCallback(){printHelper.Debug("Boar is die");Animation = AnimationEnum.Die;}private void Hurtbox_HurtCallback(Hitbox hitbox){printHelper.Debug($"{hitbox.Owner.Name} [Hit] {Scene.Name} in {hitbox.Damage} damage, Health = {Hurtbox.Health}");Animation = AnimationEnum.Hit;}#region 动画状态机public void PlayAnimation(){var animationStr = string.Format("{0}_{1}", AnimationType, Animation);//printHelper.Debug($"播放动画,{animationStr}");animationPlayer.Play(animationStr);}public void SetAnimation(){//如果检测到玩家,就直接跑起来if (PlayerCheck.IsColliding()){//printHelper.Debug("检测到玩家,开始奔跑");Animation = AnimationEnum.Run;animationDuration = 0;}switch (Animation){//如果站立时间大于2秒,则开始散步case AnimationEnum.Idle:if (animationDuration > 2){//printHelper.Debug("站立时间过长,开始移动");Animation = AnimationEnum.Walk;animationDuration = 0;//如果撞墙,则反转if (WallCheck.IsColliding() || !FloorCheck.IsColliding()){if (Direction == DirectionEnum.Left){Direction = DirectionEnum.Right;}else{Direction = DirectionEnum.Left;}}//Direction = Direction;}break;//如果检测到墙或者没检测到地面或者动画时间超过4秒,则开始walkcase AnimationEnum.Walk:if ((WallCheck.IsColliding() || !FloorCheck.IsColliding()) || animationDuration > 4){Animation = AnimationEnum.Idle;animationDuration = 0;//printHelper.Debug("开始闲置");}break;//跑动不会立刻停下,当持续时间大于2秒后站立发呆case AnimationEnum.Run:if (animationDuration > 2){//printHelper.Debug("追逐时间到达上限,停止");Animation = AnimationEnum.Idle;animationDuration = 0;}break;case AnimationEnum.Die:if (!animationPlayer.IsPlaying()){Scene.QueueFree();}break;case AnimationEnum.Hit:if(!animationPlayer.IsPlaying()){Animation = AnimationEnum.Idle;}break;}PlayAnimation();}#endregion#region 物体移动public void Move(double delta){var velocity = characterBody2D.Velocity;velocity.Y += ProjectSettingHelper.Gravity * (float)delta;switch (Animation){case AnimationEnum.Idle:velocity.X = 0;break;case AnimationEnum.Walk:velocity.X = MaxSpeed / 3;break;case AnimationEnum.Run:velocity.X = MaxSpeed;break;}velocity.X = velocity.X * (int)Direction;characterBody2D.Velocity = velocity;//printHelper.Debug(JsonConvert.SerializeObject(characterBody2D.Velocity));characterBody2D.MoveAndSlide();}#endregion}
}

结果

剩下的都是逻辑完善的部分了,后面的我就跳过了。

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

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

相关文章

快速批量重命名文件(夹)

首先,需要用到的这个工具:度娘网盘 提取码:qwu2 蓝奏云 提取码:2r1z 我这里处理这4个文本,实际可以处理任意数量的文本和文件夹1、打开工具,进入文件批量复制版块2、点击“重命名”3、把要重命名的文件或者文件夹全部拖入进去,这里我把文件改为"文本01.txt、文本02…

如何批量复制多个文件到多个目录中(提取匹配法)

首先,需要用到的这个工具:度娘网盘 提取码:qwu2 蓝奏云 提取码:2r1z 具体操作1、情景再现 我这里创建了3个数字命名的文件夹和一些带有数字命名的图片文件。(这里仅做演示作用,实际操作的数量肯定巨大。)观察一下发现,图片分2种命名:一种是数字.png,另一种是-数字.pn…

精武杯(计算机与手机)

精武杯(计算机与手机) 1.请综合分析计算机和手机检材,计算机最近一次登录的账户名是 admin火眼分析中就可以找到请综合分析计算机和手机检材,计算机最近一次插入的USB存储设备串号是S3JKNX0JA05097Y同样也是在分析中找到的3、请综合分析计算机和⼿机检材,谢弘的房间号是()…

基于深度学习网络的十二生肖图像分类matlab仿真

1.算法运行效果图预览 2.算法运行软件版本 matlab2022a3.算法理论概述GoogLeNet主要由一系列的Inception模块堆叠而成,每个Inception模块包含多个并行的卷积层,以不同的窗口大小处理输入数据,然后将结果整合在一起。假设某一层的输入特征图表示为X∈ℝ^(HWC),四个分支分别应…

蓝桥杯-k倍区间

给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。 你能求出数列中总共有多少个 K 倍区间吗? 输入格式 第一行包含两个整数 N 和 K。 以下 N 行每行包含一个整数 Ai。 输出格式 输出一个整…

im即时通讯源码/仿微信app源码+php即时通讯源码带红包+客服+禁言等系统php+uniapp开发

即时通讯(IM)系统是现代互联网应用中不可或缺的一部分,它允许用户进行实时的文本、语音、视频交流。随着技术的发展,IM系统的功能越来越丰富,如红包、客服、禁言等。本文将探讨如何使用PHP语言开发一个功能完备的即时通讯系统,包括源码解析、系统架构、关键功能实现等。 仓…

CF1968E.Cells Arrangement-构造(给个和题解不同的做法)

link:https://codeforces.com/problemset/problem/1968/E 题意:需要构造一个 \(n\times n\) 的棋盘,在上面放 \(n\) 枚棋子,设集合 \(\mathcal{H}\) 表示两两之间曼哈顿距离构成的集合,要让 \(|\mathcal{H}|\) 最大。给出放棋子的方案。首先说说题解的做法…考虑把距离为奇…

可持久化 树

Nityacke 的部分没多少,主要是 lxl 的部分可持久化可持久化线段树注意到 这里的内容 可能包括了 狭义的 可持久化线段树,可持久化权值线段树,”主席树“,可持久化 \(Trie\)...Luogu P3919 【模板】可持久化线段树 1(可持久化数组) 特定版本 单点修改,特定版本 单点查询,…