当前位置: 首页 > news >正文

Unity2D游戏制作入门 | 12(之人物受伤和死亡的逻辑动画)

上期链接:Unity2D游戏制作入门 | 11(之人物属性及伤害计算)-CSDN博客

上期我们聊到了人物的自身属性和受伤时的计算,我们先给人物和野猪挂上属性和攻击属性的代码,然后通过触发器触发受伤的事件。物体(人物也好敌人也行)受伤时通常是在被攻击者的内部进行计算的(这是有好处的,比如使用人物更复杂的血量计算方式,我们在人物内部让它自己自动计算就好了),我们使用关键词this来将Attacker内部的变量的访问权限赋给Character,然后我们又使用了计时器,让被攻击的物体在受到攻击后可以有短暂的无敌时间,计时器的写法你还知道吗?先创建三个变量一个布尔二个浮点,创建新的能赋给人物无敌的函数,然后判断人物如果不如那么人物的无敌状态就是True,然后赋给无敌时间(一个浮点变量我们是在Unity窗口手动赋给的,另一个浮点变量是内部进行使用它,在函数判断人物是否处在无敌时才用公共无敌时间赋给那个私有的浮点变量,这样就在内部激活了人物的无敌时间),我们在update中计算人物无敌的倒计时,到点了就切换人物无敌状态为flase,然后在人物的Character中的TakeDamage函数中,我们判断人物如果不是无敌则进入扣血规则,然后如果人物的当前血量足够扣除一次血量则正常减血(如果人物血量为2敌人攻击为5,那么人物直接判断血量归零),不然人物死亡,而无敌状体的赋给与否全在人物扣血那部分功能中执行,如果人物血量归零那么将无法触发无敌状态。总的来说,上次就是多了两份通用的代码文件,分别是物体的属性和攻击(仅对需要这些的物体有用,如果是场景的死物一般不给属性如血量,也可以给看你设定,攻击应该是不要加上去的,除了陷阱啥的),虽然多了两份代码,我们还是要弄清两份代码之间的访问和运行的逻辑,以及什么时候用它们。这期我们看看角色的 受伤和死亡的逻辑和动画 。代码先下方:

public class PlayerAnimations : MonoBehaviour
{private Animator anim;//创建好这个组件变量后,如果不知道如何通关代码控制组件,可以去看代码手册private Rigidbody2D rb;//这个2D不能忽略,不然不报错但是人物跑不起来。private Player_control playercon;//人物控制private physicsCheck physicsCheck;private void Awake(){physicsCheck = GetComponent<physicsCheck>();anim = GetComponent<Animator>();rb= GetComponent<Rigidbody2D>();playercon = GetComponent<Player_control>();}private void Update(){SetAnimatons();//每帧时时检测,判断是否需要切换动画。}public void SetAnimatons()//需要做很多动画的切换,我们用这个函数来执行所有的动画切换。{anim.SetBool("isGround", physicsCheck.isGround);anim.SetFloat("velocityX",math.abs(rb.velocity.x));anim.SetFloat("velocityY",rb.velocity.y);anim.SetBool("shift", playercon.isShift);anim.SetBool("isDead", playercon.isDead);}public void PlayerHurt(){anim.SetTrigger("hurt");}}
public class Player_control : MonoBehaviour
{public PlayerInputControl inputControl;public Vector2 inputDirection;//public变量表示一个公开的方法,它代表我在Unity窗口中可以查看得到。private Rigidbody2D rb;private physicsCheck physicsCheck;//创建物理检测变量private SpriteRenderer rbSprite;[Header("基本参数")]public float speed;public float walkSpeed;public float jumpForce;public float hurtForce;[Header("按键按下")]public bool isShift=false;[Header("状态")]public bool isHurt;public bool isDead;private void Awake(){physicsCheck = GetComponent<physicsCheck>();rb= GetComponent<Rigidbody2D>();inputControl = new PlayerInputControl();inputControl.GamePlayer.Jump.started += Jump;//按下空格那一瞬间执行事件Jump//inputControl.GamePlayer.Walk.performed += Walk;rbSprite = GetComponent<SpriteRenderer>();}private void OnEnable(){inputControl.Enable();}private void OnDisable(){inputControl.Disable();}private void Update(){inputDirection = inputControl.GamePlayer.Move.ReadValue<Vector2>();isShift= Keyboard.current.shiftKey.isPressed;//检测按键}private void FixedUpdate()//固定频率运行,即0.02秒执行一次。跟物理有关的放在这执行{if (!isHurt){if (isShift && physicsCheck.isGround)Walk();elseMove();}}public void Move(){rb.velocity = new Vector2(inputDirection.x*speed*Time.deltaTime,rb.velocity.y);//人物翻转if(inputDirection.x>0)rbSprite.flipX = false;if(inputDirection.x<0)rbSprite.flipX = true;}private void Jump(InputAction.CallbackContext obj){if (physicsCheck.isGround){rb.AddForce(jumpForce * transform.up, ForceMode2D.Impulse);//第一个参数表示给哪个方向施加力}}}private void Walk(){rb.velocity = new Vector2(inputDirection.x * walkSpeed * Time.deltaTime, rb.velocity.y);//人物翻转if (inputDirection.x > 0)rbSprite.flipX = false;if (inputDirection.x < 0)rbSprite.flipX = true;}public void GetHurt(Transform attcker){isHurt = true;//受伤了//接下来执行反弹,不过前提是先把人物的速度停下来。rb.velocity = Vector2.zero;//表示物体的xy轴速度全设置为了。//接下来计算受伤的方向,然后ta要朝反方向弹射。Vector2 dir=new Vector2((transform.position.x-attcker.position.x),0).normalized;/*这里对上行代码进行说明,dir是direction方向的简写。计算方向我们就用人物坐标减去野猪或是其他的attacker的坐标对于x轴来说,如果人物在敌人左边那么它应该是负数,所以我们根据正负数作为它的方向乘上它的反冲力hurtForce(现实加速的效果)。dir算完后,我们需要不是数值的大小,而是方向值(我们按下键盘时dir有-1和1两种数值)。如果人物离野猪很远,那么x的值会非常大,乘反弹力会更大反而离得近数值会很小,所以我们要把数值归一化,即用到normalized的方法。*/rb.AddForce(dir*hurtForce,ForceMode2D.Impulse);//添加瞬时的力反弹人物}public void PlayerDead(){isDead = true;inputControl.GamePlayer.Disable();}
}
public class Character : MonoBehaviour
{[Header("基本属性")]public float maxHp;//最大血量public float currentHp;//当前血量[Header("受伤无敌")]public float invincibleTime;//无敌时间private float invincibleCounter;//一个计数器,内部计算即可,不需要在窗口可以看得到public bool invincible;//为了能看见无敌,我们创建一个布尔值public UnityEvent<Transform> Ontakedamage;public UnityEvent Ondie;private void Start()//开始游戏时,要满血{currentHp = maxHp;}private void Update(){if(invincible){invincibleCounter-=Time.deltaTime;if(invincibleCounter <= 0){invincible = false;}}}//受到伤害public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能减血{currentHp -= attcker.damage;//如果学过python,你会知道这行代码等于currentHp = currentHp - attcker.damage;TriggerInvincible();//触发无敌//执行受伤Ontakedamage?.Invoke(attcker.transform);}else{currentHp=0;//触发死亡Ondie?.Invoke();}}//受伤触发无敌private void TriggerInvincible(){if(!invincible){invincible= true;invincibleCounter = invincibleTime;}}
}
public class HurtAninmation : StateMachineBehaviour
{override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){animator.GetComponent<Player_control>().isHurt = false;}
}

正文:

玩家如果受到伤害,那么应该有对应的受伤动画,甚至血量归零时人物播放死亡的动画。找到我们之前的素材,我们可以先看看guid指导的动画内容,找到受伤的内容。我们先点击player,然后创建人物的动画文件(一定放在人物动画管理的文件下,这样方便找),然后创建人物的hurt动画,用右边的那四张图片(我们之前切割好的),然后Samples采样率我们调整到合适的数值(14的话感觉还是有点快了所以我选了9)。
在这里插入图片描述

死亡动画编号为42-53。
在这里插入图片描述

先将Animator中出现的我们刚刚创建的两个动画删去,我们注意到我们的人物在任何情况下都可能受伤,如我们跑步撞到野猪,在空中碰到敌人,这些都可能使人物受伤。如果人物受伤,应该凌驾在所有动画之上(我们先前制作的所有动画,如跳跃、闲置、跑步等),接下来我们创建新的方法。先不调用受伤动画,来看一个有意思的方法(UP话)。玩家如果进行受伤的状态, 那么玩家应该有闪烁的状态来表示玩家在这个阶段是受伤无敌的状态。我们在下图的这个地方创建新的动画的Layer图层注意这些图层的名字下有一条线
在这里插入图片描述

我们点击动画图层右边的齿轮可以发现,有一个名为Weight权重的东西,这个权重会影响当前的这一层的动画的播放,你可以理解为:它的优先级是多少。下面的Blending为混合模式,Override是完全覆盖的意思。我们先将HurtLayer动画图层的权重拉到1,然后混合模式切换成Additive(叠加)模式即当前层动画不会覆盖之前层(BaseLayer)的动画,在之前层的基础上为它进行添加。

在这里插入图片描述

我们在这个新地方创建新的空的状态,然后创建新的受伤动画即bule_hurt2。在这里我们不调用任何的图片,现在录制我们的动画片段。

在这里插入图片描述

这个地方关键,我们去到人物的右边的组件Sprite Renderer,看到Color我们修改它RGB的通道,也可以修改它的阿尔法值,怎么说呢就是修改物体的透明程度(1的话就显示,0就隐身了),如果是改RGB中的值人物就会变色如变成红色等。然后我们在动画管理下的Add Property,找到对应组件的功能,即我们找到Sprite Renderer下的控制color的选项即可。
在这里插入图片描述

我们先在BaseLayer中删除我们创建的bule_hurt2动画,然后添加到HurtLayer中去。对了,hutr2一个六帧,采样率设置6即可,然后可以可以拖拽右边的6个点到1:0的位置,然后再0:2、 0:4 、1:0的位置分别设置阿尔法值为0.5、1、0.5。弄好后链接一根线到bule_hurt2,再创建一个新的参数为trigger类型的名称取hurt(你会注意到它右边是圆形的图案这是触发器)。在触发hurt2的条件中添加hurt参数这个条件(其他的条件如退出时间、转换时间都弄为无或是0,和之前的那些动画差不多就行),一旦hurt(左边红框的圆圈内)被勾选了即启动了,那么会自动播放这个受伤的动画。
在这里插入图片描述

如果要由播放受伤的动画播放完了,我们需要回到之间的动画所以设置受伤播放完后回到初始的状态,这里返回的条件就设置为无,即什么都不加。

在这里插入图片描述

我们进入到代码把它测试一下,我们打开代码PlayerAnimations。trigger的方法我们不能在update中执行,它是单次执行的函数,所以创建一个新的函数。

....
public void PlayerHurt(){anim.SetTrigger("hurt");}

那么我们时候执行调用PlayerHurt()呢?应该在Character代码中去执行:受伤我们需要播放人物的动画,以及人物被弹走不能再往前走(当然,我们受伤被弹走一般是不允许进行键盘操作的),甚至我们需要播放受伤的声音。这里又很关键了,试想一下,除了刚刚提到要被弹飞等事件,也可能还要调整一下我们ui的显示,就在受伤后有很多事情需要去执行。想让一次受伤去触发其他各种各样的代码或以后做UI都要来执行对应的方法,我们需要使用Unity的事件的方式。

public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能减血{currentHp -= attcker.damage;//如果学过python,你会知道这行代码等于currentHp = currentHp - attcker.damage;TriggerInvincible();//执行受伤}else{currentHp=0;//触发死亡}}

接上面的内容,我们需要调用Unity的命名空间,接下来创建这些事件,我们先创建一个类型为UnityEvent的变量(现在要先弄受伤的事件),然后再public UnityEvent<>的尖括号中,我们可以传入一些参数,例如在受伤时希望每次受伤都能按受伤的这个方向的反方向被击退,无论敌人还是人物都应该是这样的。传递方向进去,其实也就是坐标,那么我们Transform类型的组件传进去。

using UnityEngine.Events;
public UnityEvent<Transform> Ontakedamage;

可能上面代码看得不是很懂,返回unity窗口就能直观地看到了(记得先保存写完的代码):Character组件就多了事情的内容了。这个东西是unity自带的,它的好处是以后我们学习UI时,点击的时候也会有这种事件的处理方式。在这个事件当中,我们可以点击加号来添加各种各样的函数方法,各种各样的功能。那么在一个事件触发时候,这里可以执行所有你添加进去的方法。如我们之前提到的人物受伤,如果触发了很可能我们要调用ui、播放音乐、执行方法,播放动画,所有的内容都可以放在这里。
在这里插入图片描述

应用举例,我们把playerAnimations拖拽下去,我们找到代码中的playerHurt的函数方法,然后可以选择在何时运行它,如在游戏运行或是编辑器里时,这里我们选择只在游戏运行时执行。

在这里插入图片描述

接下来我们会到代码文件Character中,回看这行代码public UnityEvent<Transform> Ontakedamage;,**这个关于事件Ontakedamage,刚才的加号是代表我们把各种各样的方法注册到这个事件当中,接下来我们需要把这个事件启动起来,它其实有一个固定的写法。**注意新写入的代码Ontakedamage?.Invoke(attcker.transform);问号代表判断一下有没有任何方法添加进来,很可能之前的列表是空的,那我们就可能报错了,所以加上问号。**后面接点Invoke表示启动当前事件的内容(不要忘记打上括号)。**然后因为刚刚我们创建时有设置了参数,所以需要传一个transform进去,谁攻击我我就朝反方向移动,那么我们就要获得attcker它的transform了。这样,我们就实现了该函数(TakeDamage(Attack attcker))受伤数值减少、触发无敌,然后执行所以注册过来的受伤的函数方法。(目前我们只注册了受伤时播放闪烁的动画)

public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能减血{currentHp -= attcker.damage;//如果学过python,你会知道这行代码等于currentHp = currentHp - attcker.damage;//触发无敌TriggerInvincible();//执行受伤Ontakedamage?.Invoke(attcker.transform);}

运行游戏,如果人物经过野猪会有一个人物闪烁的效果,**我经过测试发现:如果把野猪的Is trigger给关掉或胶囊触发器关闭不使用,那么人物经过野猪,不管是顶着它走还是穿过它都不能能触发受伤闪烁的效果。**这样我们就学习了如何触发事件来执行一些方法。接下来我们给人物受伤切换回我们之前想要的受伤动画,然后按照我们之前给没有素材的动画添加受伤会变红闪烁的效果即可,然后这样我们就有了红色受伤的动画,那么我们还需要让人物反弹回去。
在这里插入图片描述

我们受伤被击退的事件应该在人物控制的代码中被执行,因为控制人物的方向要被打断,如果一直向前跑但是受伤后需要被弹开。所以我们在player_control里面创建新的方法,来执行一个人物反弹的效果。我们需要设置一下玩家的状态,受伤就要阻止我们其他的移动,也要反弹一段距离。所以需要创建是否受伤的布尔值类型的变量isHurt。然后反弹的时候希望有一个力把它弹开一段距离。

	public bool isHurt;public float hurtForce;
....private void FixedUpdate()//固定频率运行,即0.02秒执行一次。跟物理有关的放在这执行{if (!isHurt)//没有进入受伤状态才能走动{if (isShift && physicsCheck.isGround)Walk();elseMove();}}
.....public void GetHurt(Transform attcker){isHurt = true;//受伤了//接下来执行反弹,不过前提是先把人物的速度停下来。rb.velocity = Vector2.zero;//表示物体的xy轴速度全设置为了。//接下来计算受伤的方向,然后ta要朝反方向弹射。Vector2 dir=new Vector2((transform.position.x-attcker.position.x),0).normalized;/*这里对上行代码进行说明,dir是direction方向的简写。计算方向我们就用人物坐标减去野猪或是其他的attacker的坐标对于x轴来说,如果人物在敌人左边那么它应该是负数,所以我们根据正负数作为它的方向乘上它的反冲力hurtForce(现实加速的效果)。dir算完后,我们需要不是数值的大小,而是方向值(我们按下键盘时dir有-1和1两种数值)。如果人物离野猪很远,那么x		  的值会非常大,乘反弹力会更大,反而离得近数值会很小,所以我们要把数值归一化,即用到normalized的		  方法。         */rb.AddForce(dir*hurtForce,ForceMode2D.Impulse);//添加瞬时的力反弹人物}

保存上面写好的代码会回到unity的窗口,我们需要把我们写好的人物受伤的函数方法添加到Ontakedamage这个事件中去,然后我们给人物被攻击的力改成8,我们发现人物被弹走后停不下来,原因是isHurt一直没用变回flase。
在这里插入图片描述

我们留意到animator中,我们看到受伤动画状态的右边,即我们可以添加一个代码,在这个动画执行的过程中,做一些代码的变化,我们先添加一个叫HurtAninmation的代码。输入完名称后,按下回车键,然后它会为你创建这个新的代码,不过代码被放在了我们project下的Assets下了,和一些文件目录同级了。

在这里插入图片描述
在这里插入图片描述

双击打开代码,我们可以看到这是一个unity自动为我们写好的模板,我们可以直接拿来用。它继承了**StateMachineBehaviour,也就是状态机的行为,**在做敌人我们也会单独来写。取消方法前面的注释就可以用了。第一方法是,当进去这个状态时执行,第二方法是当在执行这个动画的过程中我执行函数方法(如果这个状态也可称为动画时间比较久那么函数一直执行),第三个是当状态退出后,我们执行某某方法。So,当我们受伤播完并退出后,我们更改我们的人物isHurt的状态为flase即可。
在这里插入图片描述

override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex){animator.GetComponent<Player_control>().isHurt = false;}

注意我们用Ontakedamage事件的这个方法,我们即播放了动画,又可以播放脚本里的函数的逻辑。最后一个我们要做的就是人物的死亡,在任何状态下我们的人物都会死亡,所以我们到动画控制器中添加死亡的动画,然后HurtLayer的动画图层我们把混合的模式改为Override覆盖。我们在Parameter中添加死亡参数进行判断isDead(布尔值)。然后给Any State连一根线到死亡动画中去,条件为isDead为true时,其他要么无要么为0。

在这里插入图片描述

注意一下,我们的人物是否会一直进入死亡状态呢?不一定,如果我们重新开始游戏,那么人物要刷新状态并退出死亡的动画(退出的条件大家应该都熟练了,isDead为flse其他要么无要么为0)。
在这里插入图片描述

接下来把死亡动画链接到函数,我们需要在Character代码中添加死亡的事件方法。因为在人物死亡时,可能也要执行很多的事情,比如跳出UI的面板,除了通知你Game Over,还要通知你很多的信息,比如通知你的敌人不要继续攻击,人物不要再移动了。但是这次我们不需要传递任何参数,就是人物只是死亡。

//#Characte.cspublic UnityEvent Ondie;//新加入,对应代码第22行
..........
public void TakeDamage(Attack attcker){if (invincible)return;//Debug.Log(attcker.damage);if (currentHp - attcker.damage > 0)//血量健康才能减血{currentHp -= attcker.damage;//如果学过python,你会知道这行代码等于currentHp = currentHp - attcker.damage;TriggerInvincible();//触发无敌//执行受伤Ontakedamage?.Invoke(attcker.transform);}else{currentHp=0;//触发死亡Ondie?.Invoke();}}

那么人物的死亡是一个布尔值,所以它不是单次执行的,没有必要单独去写,我们直接把状态连接到Animation当中即可,并通过人物控制停止我们所有的人物操作如移动。

//#Player_control.cs
public bool isDead;
...
public void PlayerDead(){isDead = true;inputControl.GamePlayer.Disable();//我们之前输入系统的人物操作相关的内容。我们只关闭人物的操作,正常的ui操作还要保留的。}

然后在PlaterAnimation中把状态连接起来。

public void SetAnimatons()//需要做很多动画的切换,我们用这个函数来执行所有的动画切换。{........anim.SetBool("isDead", playercon.isDead);}

在这里插入图片描述

然后设置人物的血量为6进行死亡测试,不过你会发现人物会反复死亡,这是因为人物的死亡动画没有设置为只播放一次。把下图人物死亡的动画的循环关去即可,让它单次执行。一般来说很多动画都需要单次播放的,如果不连接到Any State中,它都不会有这样的问题,如果你链接了Any State且只希望播放一次,一定要取消勾选Loop Time。
在这里插入图片描述

总结:

​ 添加事件的方式特别的方便,它能帮助我们添加各种函数去执行一些事件,我们虽然只做了两个动画,即人物的受伤和死亡却操作了很久说明做游戏也不是很容易的。这节可能没那么好理解,记得多多操作并理解这些步骤是为什么要这么做的,就连我自己都要反复看才能理出一点头绪。

​ 为了能记下Unity一些的特殊用法,还是一些来稍微回味一下这期的内容吧。在创建人物受伤和死亡的动画之前,我们先是创建了人物被触发后能够闪烁的动画,这样的动画我们是通过组件Sprite Renderer里面的color功能区实现的。我们创建了一个新的动画图层,修改它显示的权重并用于叠加到我们之前的动画上。触发受伤的动画是通过触发器来实现的,所以只需要单次执行,我们不会把它放入到Update函数中去,我们将在PlayerAnimations类中的函数PlayerHurt()放到Character代码中去执行,因为人物检测到血量减少后应该就执行人物受伤的动画,这很符合直觉。然后因为如果我们的人物受伤了,我们需要做很多的事情,如播放音乐、播放受伤动画等,所以我们使用了命名空间UnityEngine.Events,来给物体添加一些事件的功能,而且我们在Unity窗口的物体的组件上也能看到在对应的代码多出了添加一些注册事件的功能,然后我们需要在代码的对应位置启动某某事件固定格式为:事件名称.Invoke(参数)Ontakedamage?.Invoke(attcker.transform);

​ 运行游戏后发现触发人物的受伤动画是正常的,接下来我们需要人物在进去受伤动画时,人物不应该能执行一些操作,如果移动跑步等,并且受伤被击退的事件应该在人物控制的代码中被执行,即现在我们需要确定的事件就是,人物受伤不能操作,且要被击退,而播放动画是在人物属性的代码中执行的,因为一旦扣血我们才播放受伤动画。在人物控制的代码文件中,我们创建了新的函数方法为GetHurt(Transform attcker),然后我们创建一个布尔值变量判断受伤,和一个受伤应该能弹飞人物的力的变量。然后该事件函数(人物被弹飞,且不能操作)的调用我们放入到刚刚Character的代码中去注册到事件Ontakedamege中去,这个地方就是如果在Character代码中如果事件Ontakedamage被启动了,相应的人物动画代码中的触发的参数hurt将被激活,然后执行人物受伤的动画,再接下来就是人物控制代码中的函数GetHurt(Transform attcker)被调用了,这是直接更新人物的受伤状态isHurt为true,那么,人物进入不能操作且被击飞的状态,这个持续的时间是是无限时间,因为没有设定何时把isHurt改为flase,在人物控制的FixedUpdate()函数中isHurt还是true,达不到我们能操作的条件,所以我们在受伤动画退出的时间即受伤动画播放完后,我们通过在受伤的State中创建新的代码来在退出动画时更新我们人物受伤的状态,该代码文件的关键代码为:animator.GetComponent<Player_control>().isHurt = false;,即我们获取了人物控制的代码,在动画完全退出后我们把isHurt的状态改为flase,这样在我们人物被击飞后我们又获得了人物操作的控制权(是的,人物在受伤获得操控权后又飘了…)。然后就是注入人物死亡的动画,当人物的状态isDead为true时,我们让人物进入死亡并且所有操作都要停止,但是也只是限制人物的操作,像其他的如UI的操作我们没有停止,因为那是结算界面。我们在人物控制的代码文件中创建新的函数为PlayerDead(),人物死亡则isDead为true,而且关闭人物相关操作,并在人物动画中时时检测人物死亡因为重开游戏人物会满血达不到死亡的条件。

​ 大致的流程就是这样了,不知道我有没有说清楚?唉这个部分就是比较混乱的,多看多想吧。

未尽事宜以后可能会补充。

-------------------------结束线

相关文章:

Unity2D游戏制作入门 | 12(之人物受伤和死亡的逻辑动画)

上期链接&#xff1a;Unity2D游戏制作入门 | 11(之人物属性及伤害计算)-CSDN博客 上期我们聊到了人物的自身属性和受伤时的计算&#xff0c;我们先给人物和野猪挂上属性和攻击属性的代码&#xff0c;然后通过触发器触发受伤的事件。物体&#xff08;人物也好敌人也行&#xff…...

从河流到空气,BL340工控机助力全面环保监测网络构建

在环保监测领域&#xff0c;智能化、高效率的监测手段正逐步成为守护绿水青山的新常态。其中&#xff0c;ARMxy工业计算机BL340凭借其强大的处理能力、高度的灵活性以及广泛的兼容性&#xff0c;在水质监测站、空气质量检测、噪音污染监控等多个环保应用场景中脱颖而出&#xf…...

零拷贝技术

背景 磁盘可以说是计算机系统重最慢的硬件之一&#xff0c;读写速度相对内存10以上&#xff0c;所以针对优化磁盘的技术非常的多&#xff0c;比如&#xff1a;零拷贝、直接I/O、异步I/O等等&#xff0c;这些优化的目的就是为了提高系统的吞吐量&#xff0c;另外操作系统内核中的…...

Flutter_Android上架GooglePlay_问题

上架GooglePlay权限问题 问题描述 REQUEST_INSTALL_PACKAGES 权限问题解决方式 方式1 找到所有使用该权限的库修改删除该权限引用 方式2 打开项目 ~/andoird/app/src/main/AndroidMainfest.xml 添加文本<uses-permission android:name"android.permission.REQUES…...

【Java】解决Java报错:NumberFormatException

文章目录 引言1. 错误详解2. 常见的出错场景2.1 字符串包含非数字字符2.2 空字符串或 null 字符串2.3 数值超出范围 3. 解决方案3.1 验证字符串格式3.2 使用异常处理3.3 处理空字符串和 null 4. 预防措施4.1 数据验证4.2 编写防御性代码4.3 单元测试 结语 引言 在Java编程中&a…...

视觉大模型(VLLM)学习笔记

视觉多模态大模型&#xff08;VLLM&#xff09; InternVL 1.5 近日&#xff0c;上海人工智能实验室 OpenGVLab 团队、清华大学、商汤科技合作推出了开源多模态大语言模型项目InternVL 1.5&#xff0c;它不仅挑战了商业模型巨头例如 GPT-4V 的霸主地位&#xff0c;还让我们不禁…...

【软考的系统分析师的考题考点解析2025】

2024-2025系统分析师考试&#xff08;简称软考&#xff09;是计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试中的高级资格考试&#xff0c;主要考察考生在系统分析、系统设计、项目管理等方面的知识和技能。以下是软考系统分析师的常见考点、考题和重点&#x…...

JavaScript前端技术入门教程

引言 在前端开发的广阔天地中&#xff0c;JavaScript无疑是最耀眼的一颗明星。它赋予了网页动态交互的能力&#xff0c;让网页从静态的文本和图片展示&#xff0c;进化为可以与用户进行实时交互的丰富应用。本文将带您走进JavaScript的世界&#xff0c;为您提供一个入门级的教…...

类和对象(上续)

前言&#xff1a;本文介绍类和对象中的一些比较重要的知识点&#xff0c;为以后的继续学习打好基础。 目录 拷贝构造 拷贝构造的特征&#xff1a; 自定义类型的传值传参 自定义类型在函数中的传值返回 如果返回值时自定义的引用呢&#xff1f; 在什么情况下使用呢&#…...

【C++初阶学习】第十三弹——优先级队列及容器适配器

C语言栈&#xff1a;数据结构——栈(C语言版)-CSDN博客 C语言队列&#xff1a;数据结构——队列&#xff08;C语言版&#xff09;-CSDN博客 C栈与队列&#xff1a;【C初阶学习】第十二弹——stack和queue的介绍和使用-CSDN博客 前言&#xff1a; 在前面&#xff0c;我们已经…...

Java(十七)---ArrayList的使用

文章目录 前言1.ArrayList的简介2. ArrayList使用2.1.ArrayList的构造2.2.ArrayList的扩容机制(JDK17) 3.ArrayList的常见操作4. ArrayList的具体使用4.1.[杨辉三角](https://leetcode.cn/problems/pascals-triangle/description/)4.2.简单的洗牌游戏 5.ArrayList的问题及思考 …...

实验六、IPv4 地址的子网划分,第 2 部分《计算机网络》

你有没有发现&#xff0c;困的时候真的清醒不了。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 完成本练习之后&#xff0c;您应该能够确定给定 IP 地址和子网掩码的子网信息。 知道 IP 地址、网络掩码和子网掩码后&#xff0c;您应该能够确定有关该 IP 地…...

定个小目标之刷LeetCode热题(12)

这是一道简单题&#xff0c;使用位运算中的异或运算即可&#xff0c;异或运算有以下性质&#xff1a; 1、任何数异或 0 结果仍然是原来的数&#xff0c;即 a⊕0a 2、任何数和其自身做异或运算&#xff0c;结果是 0 所以我们只需要让数组里的所有元素进行异或运算得到的结果就…...

MYSQL内存占用查询语句

可以通过以下 SQL 语句查询相关配置参数的当前值&#xff1a; InnoDB 缓冲池大小 (innodb_buffer_pool_size)&#xff1a; SHOW VARIABLES LIKE innodb_buffer_pool_size;最大连接数 (max_connections)&#xff1a; SHOW VARIABLES LIKE max_connections;临时表大小 (tmp_table…...

HikariCP连接池初识

HikariCP的简单介绍 hikari-光&#xff0c;hikariCP取义&#xff1a;像光一样轻和快的Connetion Pool。这个几乎只用java写的中间件连接池&#xff0c;极其轻量并注重性能&#xff0c;HikariCP目前已是SpringBoot默认的连接池&#xff0c;伴随着SpringBoot和微服务的普及&…...

LeetCode136只出现一次的数字

题目描述 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 解析 需要想到异或运算&#…...

html5实现端午节网站源码

文章目录 1.设计来源1.1 端午首页页面1.2 端午由来页面1.3 端午图集页面1.4 端午活动页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/139524377 ht…...

echarts组件x轴坐标显示不全解决方法

1.旋转: 修改前: option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [120, 200, 150, 80, 70, 110, 130,120, 200, 150, 80, 70, 1…...

JS实现移动端的轮播图滑动事件

在移动端实现轮播图滑动事件&#xff0c;我们通常使用 touchstart、touchmove 和 touchend 这三个事件。下面是一个基本的示例&#xff0c;展示了如何使用原生JavaScript来创建一个简单的移动端轮播图滑动效果&#xff1a; HTML结构&#xff1a; <div id"carousel&qu…...

2024.6.10学习记录

1、代码随想录二刷 2、项目难点 review 3、计组复习...

RapidJSON

要在项目中使用 RapidJSON 库&#xff0c;需要首先下载并包含该库的头文件。以下是详细的步骤&#xff0c;包括如何下载、引用和使用 RapidJSON&#xff1a; 使用 CMake 引用 RapidJSON 如果你的项目使用 CMake 构建系统&#xff0c;可以按照以下步骤引用 RapidJSON&#xff…...

二叉树的创建

目录 一、二叉树的定义 二、代码定义 三、遍历二叉树 1、前序遍历 2、中序遍历 3、后序遍历 四、方法的使用 一、二叉树的定义 二叉树&#xff08;binary tree&#xff09;是指树中节点的度不大于2的有序树&#xff0c;它是一种最简单且最重要的树。二叉树的递归定义为&a…...

adb shell进入设备后的命令

目录 一、查看删除手机 /data/local/tmp/下的文件 二、设置权限 三、查看手机设备正在运行的服务 四、可能需要的adb 命令 一、查看删除手机 /data/local/tmp/下的文件 可以通过以下命令&#xff1a; adb shell # 进入设备 ls /data/local/tmp/ # 查看文件夹下的内容…...

【Android面试八股文】Java中静态内部类是什么?和非静态内部类的区别是什么?

文章目录 Java中静态内部类是什么?和非静态内部类的区别是什么?这道题想考察什么?考察的知识点考生应该如何回答什么是内部类,什么是静态内部类?静态内部类非静态内部类静态内部类和非静态内部类的区别静态内部类和普通内部类都有各自的用途和优势扩展一:使用静态内部类来…...

IDEA启动项目报java.lang.OutOfMemoryError: GC overhead limit exceeded

idea编译项目时报j ava.lang.OutOfMemoryError: GC overhead limit exceeded错误&#xff0c;教你两步搞定&#xff01; 第一步&#xff1a;打开help -> Edit Custom VM Options ,修改xms和xmx的大小&#xff0c;如下图&#xff1a; 第二步&#xff1a;File -> Settings…...

基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析

原文链接&#xff1a;基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606139&idx4&snf94ec30bfb5fa7ac0320403d49db3b66&chksmfa821e9ccdf5978a44a9ba96f6e04a121c0bbf63beea0940b385011c0b…...

【笔记2】Python编程:从入门到实践(第2版) - 埃里克·马瑟斯

第二部分 1、外星人入侵 Pygame包 2、数据可视化 Matplotlib 、Plotly 3、Web应用程序 Django 项目1&#xff1a;外星人入侵 第12章&#xff5e;第14章 使用Pygame包来开发一款2D游戏。 它在玩家每消灭一群向下移动的外星人后&#xff0c;将玩家提高一个等级。等级越高&…...

优质免费的 5 款翻译 API 接口推荐

当谈到翻译API时&#xff0c;我们通常指的是一种编程接口&#xff0c;它允许开发者将文本从一种语言翻译成另一种语言。这些API通常由专业的翻译服务提供商提供&#xff0c;如谷歌翻译 API、实时翻译API、腾讯翻译API、DeepL翻译API、Azure翻译API等。 这些API通常提供多种语言…...

雷电模拟器中控实现,直通源码

目录 前言 开发 需求 初始环境 UI搭建 功能实现 前言 本篇为易语言雷电模拟器中控项目实现操作&#xff0c;一般用于&#xff1a;脚本开发多线程模拟操作等起始模板框架&#xff0c;使用易语言原因为其前后端一体化&#xff0c;对于脚本开发而言更为方便。 开发 需求 以…...

从渲染管线到着色器Shader实践

浏览器渲染管线原理 浏览器渲染管线是浏览器将HTML、CSS和JavaScript转换为用户可见的网页的过程。这一过程涉及多个步骤,包括解析、布局、绘制和合成等。下面是浏览器渲染管线的详细原理: 解析(Parsing): HTML解析:浏览器下载HTML内容后,首先进行HTML解析,将HTML文本…...

求职网站网页模板/淘宝关键词排名优化技巧

精彩回顾如何实现H5可视化编辑器的实时预览和真机扫码预览功能在线IDE开发入门之从零实现一个在线代码编辑器基于ReactKoa实现一个h5页面可视化编辑器&#xff0d;DooringTS核心知识点总结及项目实战案例分析前言本文是基于上一篇文章介绍H5编辑器 后台管理系统实战的第二篇文章…...

网站开发达成口头协议算不算诈骗/优化设计七年级上册语文答案

Python 的对象天生拥有一些神奇的方法&#xff0c;它们总被双下划线所包围&#xff0c;它们是面向对象的 Python 的一切。它们是可以给你的类增加魔力的特殊方法&#xff0c;如果你的对象实现&#xff08;重载&#xff09;了某一个魔法方法&#xff0c;那么这个方法就会在特殊的…...

招工信息发布平台/seo网站推广杭州

先来先服务&#xff08;FCFS,First Come First Serve) FCFS算法思想主要从“公平”的角度考虑&#xff08;类似于我们生活中排队买东西的例子)算法规则按照作业/进程到达的先后顺序进行服务用于作业/进程调度用于作业调度时&#xff0c;考虑的是哪个作业先到达后备队列;用于进…...

b2c网站平台建设/我是做推广的怎么找客户

一份睡袋使用养护全攻略送给爱户外的你具体如下&#xff1a;一、如何验货&#xff1a;睡袋产品都是成品&#xff0c;仅凭外观很难辨其优劣&#xff0c;如何验货&#xff0c;教你几招&#xff1a;一看 看产品标签信息是否齐全&#xff1b;二按 将羽绒睡袋放松铺平&#xff0c;让…...

南阳手机网站推广/优化网站的软件下载

字符串的不可变性 定义一个字符串 String s "abcd";s中保存了string对象的引用。下面的箭头可以理解为“存储他的引用”。 使用变量来赋值变量 String s2 s;s2保存了相同的引用值&#xff0c;因为他们代表同一个对象。 字符串连接 s s.concat("ef"…...

有没有发布需求的网站/巨量引擎app

敏捷开发 敏捷个人我们所说的敏捷是一种病毒。 它进入组织并扰乱正常的业务过程。 例如&#xff0c;在2010年之前的早期&#xff0c;可以指望公司的抗体能够根除并消灭病毒&#xff0c;而不会造成太大的损失。 但是有时候这些反抗组织没有发挥作用。 正如古老的格言所说&#…...