首页 > 编程语言 >Godot.NET C#IOC重构(11):攻击与死亡

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

时间:2024-05-03 23:33:20浏览次数:27  
标签:11 Godot C# Hurtbox private System AnimationEnum using public

目录

前言

这次来深刻了解一下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秒,则开始walk
                case 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

    }
}

结果

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

标签:11,Godot,C#,Hurtbox,private,System,AnimationEnum,using,public
From: https://www.cnblogs.com/gclove2000/p/18171718

相关文章

  • Linux(centos7)实现git push到gitee
    1.找到需要提交的文夹目录cd目的目录2.初始化git仓库gitinit看见最下面的InitializedemptyGitrepositoryin就是初始化成功了3.配置提交人信息gitconfig--globaluser.name“你想填的名字”gitconfig--globaluser.email"你的邮箱"最后查看一下是否正确gi......
  • Codeforces Round 943 (Div. 3)
    CodeforcesRound943(Div.3)A.Maximize?题意:给定x,求一个范围在[1,x)的数字y,内使得gcd(x,y)+y最大,输出任意的y思路:数据范围很小,暴力枚举即可voidsolve(){intx;cin>>x;inty=1,ma=0;for(inti=1;i<x;i++){intres=__gc......
  • B. Prefiquence
    题解a为b的前缀,只需要设置两个指针即可,l1指向a中当前需要比较的字符,l2指向b中当前字符;如果a[l1]==b[l2]则l1++,l2++否则l2++。code #include<bits/stdc++.h>usingnamespacestd;constintN=2e5+5;intmain(){intt;cin>>t;while(t--){intn,m;......
  • requestVideoFrameCallback
    requestVideoFrameCallback:将新视频帧发送到合成器时运行的回调函数requestVideoFrameCallback()的用法与Window.requestAnimationFrame()相同。您可以使用它来运行一个回调函数,该函数在下一个视频帧发送到合成器时执行某些操作。当合成下一个视频帧时,再次调用requestVid......
  • 交叉编译tcpdump
    1.下载源码gitclonehttps://github.com/the-tcpdump-group/libpcap.gitgitclonehttps://github.com/the-tcpdump-group/tcpdump.git2.交叉编译libpcap执行shautogen.sh生成configure设置交叉编译链./configure--host=arm-linux-gnueabihf设置install环境,将Makefile......
  • 11_二值选择模型
    第11章二值选择模型11.1二值选择模型的例子解释变量是离散的,不影响回归。比如虚拟变量被解释变量是离散的,不适合进行OLS回归。离散选择模型、定性反应模型最常见的:二值选择行为定义线性概率模型(LinearProbilityModel)$$\left{\begin{array}P(y=1|x)=F(x,......
  • 下载和安装anaconda
    下载anaconda官网下载:https://www.anaconda.com/清华园镜像:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/这里我用的是清华园镜像下载的安装anaconda找到下载好的.exe文件,双击运行,会弹出下面的界面,点击Next然后点击IAgree前两步一般不会出问题,!!!这里请......
  • CF1968E.Cells Arrangement-构造(给个和题解不同的做法)
    link:https://codeforces.com/problemset/problem/1968/E题意:需要构造一个\(n\timesn\)的棋盘,在上面放\(n\)枚棋子,设集合\(\mathcal{H}\)表示两两之间曼哈顿距离构成的集合,要让\(|\mathcal{H}|\)最大。给出放棋子的方案。首先说说题解的做法…考虑把距离为奇数和偶数的......
  • m基于LDPC编译码的matlab误码率仿真,对比SP,MS,NMS以及OMS四种译码算法
    1.算法仿真效果matlab2022a仿真结果如下:    2.算法涉及理论知识概要       低密度奇偶校验码(LDPC)译码是现代通信系统中一种高效的错误校正技术,广泛应用于无线通信、卫星通信和数据存储等领域。LDPC码因其良好的纠错性能和接近香农极限的潜力而受到重视。本文......
  • Codeforces 1129E Legendary Tree
    考虑让选取的集合更加特殊,不妨就让\(S=\{x\}\)。那么这个时候能发现询问\((S=\{x\},T,v)\)得到的就是以\(x\)为根时\(v\)的子树内\(T\)中的点的数量。考虑定个根,不妨为\(1\),同时令\(S=\{1\}\)。那么询问\((\{1\},\{1,\cdotsn\}\backslash\{1,x\},x)......