【Godot4自学手册】第十八节主人公的血量显示

2024-03-01 08:12

本文主要是介绍【Godot4自学手册】第十八节主人公的血量显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天,我主要学习主人公的血量显示,在屏幕的左上角,会显示主人公的头像,后面会显示血量进度条,当主人公受到伤害时,血量会实时变动,显示绿色血条减少,后是红色血量逐渐减少到正确位置,效果如下:
请添加图片描述

一、修改BUG

再开始今天的学习之前,修改以前的一些Bug,在敌人攻击和受伤,主人公的攻击和受伤学习中又许多Bug,主要是因为我把需要执行一次的状态代码和需要执行一段时间的代码全都写到_physics_process函数的原因,所以我将需要执行一次的代码加到state状态的set(v):函数内执行一次;把需要多次执行的代码加到了_physics_process函数内。

1.Player代码修改如下:
extends CharacterBody2D
@onready var anima_tree=$AnimationTree
@onready var animation_player = $AnimationPlayer
@onready var stats = $Stats
@onready var direcion = Vector2.ZERO
enum {IDLE,WALK,SWORD,HURT
}
var state = IDLE:set(v):state=vmatch  state:IDLE:idle_state()WALK:walk_state()SWORD:sword_state()HURT:hurt_state()const SPEED = 120.0
var enemyPositon
var knockback=200func _ready():Globals.last_Player = positionfunc _physics_process(delta):	direcion = Vector2.ZEROdirecion.x = Input.get_axis("left", "right")direcion.y = Input.get_axis("up", "down")if state!=SWORD and state!=HURT:if direcion:anima_tree.set("parameters/Idle/blend_position",direcion)anima_tree.set("parameters/Walk/blend_position",direcion)anima_tree.set("parameters/Sword/blend_position",direcion)anima_tree.set("parameters/Hurt/blend_position",Vector2(direcion.x*-1,direcion.y))state = WALKelse:velocity=Vector2.ZEROstate=IDLEif Input.is_action_just_pressed("sword"):velocity= Vector2.ZEROstate = SWORDGlobals.last_Player = positionmove_and_slide()	func idle_state():#待机状态anima_tree["parameters/playback"].travel("Idle")
func walk_state():#行走状态anima_tree["parameters/playback"].travel("Walk")velocity = direcion * SPEED	func sword_state():#进攻状态anima_tree["parameters/playback"].travel("Sword")await anima_tree.animation_finished	state=IDLEfunc hurt_state():#受伤状态var dir = enemyPositon.direction_to(global_position).normalized()anima_tree["parameters/playback"].travel("Hurt")if dir.x>0:velocity.x +=knockbackelse :velocity.x -=knockbackawait anima_tree.animation_finishedstats.health -=10	state=WALKfunc _on_hurt_box_area_entered(area):enemyPositon = area.owner.global_positionstate=HURT	
2.Enemy代码修改如下:
extends CharacterBody2D
enum {IDLE,CHASE,ATTACK,HURT,DEATH
}
const SPEED = 1.0
var hitCount=2
@onready var anima_s = $AnimaS
@onready var anima_p = $AnimaP
@onready var hit_box = $CheckBox/HitBox
@onready var trace_collsion = $CheckBox/TraceArea/Trace_Collsionvar knockback=300
var hurtdirecionvar state = IDLE:set(v):state = vmatch state:IDLE:idle_state()CHASE:chase_state()ATTACK:attack_state()HURT:hurt_state()DEATH:death_state()func _physics_process(delta):	var direction =  Globals.last_Player-global_positionif direction.x<0:anima_s.flip_h=truehit_box.scale.x =-1else:anima_s.flip_h = falsehit_box.scale.x=1if state==CHASE:		global_position = global_position.move_toward(Globals.last_Player,SPEED)move_and_slide()func idle_state():#待机状态anima_p.play("Idle")func chase_state():#跟踪状态anima_p.play("Run")func attack_state():#攻击状态anima_p.play("Attack")	await  anima_p.animation_finishedstate = CHASEfunc hurt_state():	#受伤状态var dir = hurtdirecion.direction_to(global_position).normalized()if abs(dir.x)>abs(dir.y):if dir.x<0:velocity.x =-knockbackelse :velocity.x =knockbackelse:if dir.y<0:velocity.y =-knockbackelse :velocity.y =knockbackanima_p.play("TakeHit")await  anima_p.animation_finished	velocity = Vector2.ZEROstate=CHASEfunc death_state():	passfunc _on_trace_area_body_entered(body):if body.name=="Player" and state!=HURT and state!=ATTACK:state = CHASEfunc _on_trace_area_body_exited(body):	if body.name=="Player" and state!=HURT and state!=ATTACK:state = IDLEfunc _on_hit_area_body_entered(body):#进入攻击范围if body.name=="Player" :state = ATTACKfunc _on_hurt_box_area_entered(area):	#进入受伤范围hurtdirecion = area.owner.global_positionstate = HURT

二、新建血量显示场景

1.新建场景。

单击新建场景按钮,选择其它节点,在创建Node对话框中,选择HBoxContainer节点,单击创建按钮,创建新的场景,如下:
请添加图片描述

将新场景保存到Scenes文件夹下,命名为:StatusUI。
将根节点重新命名为StatusPanel,检查器中将Transform->Size重置为0,0。

2.添加节点

首先为根节点添加PanelContainer子节点,再为PanelContainer添加TextureRect子节点,显示头像。为根节点添加TextureProgressBar子节点,显示血量,最终效果如下:
请添加图片描述

最后将PanelContainer命名为HeadBox;将TextureRect命名为Head;将TextureProgressBar命名为HeadthBar。

3.设置人物头像背景框

将HeadBox检查器中Theme Overrides->style->Panel属性设置为StyleBoxTextture。并将我们事先做好的背景边框图片结合托人到Texture内。
请添加图片描述

单击Sub-Region属性,展开界面选择编辑区域,在区域编辑框中选择像素吸附,画出图像背景框,然后选择关闭按钮,如下:
请添加图片描述

检查器中Custom Minimum Size属性设置为23,23,表示图像框的大小为23.如下:
请添加图片描述

检查器中Theme Overrides->Styles->Content Margins中,Left,Top,Right,Bottom均设置为3,表示填充边框为3,如下:
请添加图片描述

4.设置头像

切换到Head节点,在检查器中Texture选择AtlasTexture图集纹理,将主人公的Player.png图片拖入到Atlas属性,如下:
请添加图片描述

在检查器中选择Region,单击下面的编辑区域按钮,在弹出的区域编辑框中选择像素吸附,选取主人公正面头像,然后关闭。
请添加图片描述

head检查器中Stretch Mode属性选择 Keep Aspect Centered,表示图像保持比例缩放,居中。如下:
请添加图片描述

最后的头像效果如下:
请添加图片描述

5.设置血量显示条

切换到HealthBar节点,在检查器中Textures展开属性,在Progress选择AtlasTexture,将HUD.png拖入到Atlas中,如下:
请添加图片描述

在Region属性下单击编辑按钮,在区域编辑框中选择自动剪裁,然后选择绿色图片,最后单击关闭。
请添加图片描述

然后突出Progress属性,在HealthBar检查器中Range属性中Max Value设置为1,step设置为0,Value设置为1,如下所示:
请添加图片描述

同样方法设置Texture下的Over,图片选择黑色背景边框,然后设置Progress Offset设置为1,1,这样保证绿色图片在黑色背景边框中间,设置如下所示:
请添加图片描述

在HealthBar的检查器中Control->Layout->Container Sizing->Vertical属性选择居中收缩。如下:
请添加图片描述

最后显示效果如下:
请添加图片描述

6.设置红色血量显示调

复制HealthBar命名为HealthBarRead,并将其设为HealthBar的子节点,如下所示:
请添加图片描述

在其检查器中Textures属性重置Over属性,Progress属性选择唯一化,然后从新编辑区域,选择红色血条,效果如下:
请添加图片描述

然后在编辑器上方控制节点锚点和偏移值的预设中选择整个矩形,这样红色血量和绿色血量最终重合,如下:
请添加图片描述

然后在检查器中找到Visibility->Show Behind Parent并启用,这样绿色血量将会在红色血量的上方。
请添加图片描述

通过以上步骤所有节点都已布置完成,先忙开始编写代码。

三、编写代码

1.抽象状态类。

无论是敌人还是主人公都有一些相同状态,如血量,我把这些相同的状态定义成一个类,需要的时候继承就好了。首先切换到脚本,单击文件新建脚本,新建Class文件夹,将新建的脚步保存到Class文件夹内,命名为Status。编写如下脚本:

class_name Stats
extends Node
signal  health_changed@export var max_health: int = 100
@onready var health: int = max_health:set(v):v = clampi(v, 0, max_health)if health == v:returnhealth = vhealth_changed.emit()  #发出信号

第一行代码主要把该脚本命名为Stats类,这样的目的是,把所有跟敌人或者主人公有关状态的量抽象一个类,复用。
第二行代码说明该类继承了Node节点,Node节点的方法和属性都可以使用。
第三行定义了一个信号,表示当血量发生变化时,出现该信号。
第四行定义了最大血量,默认是100,@export表示该变量可以在编辑器中看到和修改。
第五行定义了当前血量,@onready表示该变量会在Node节点就绪状态时赋值,默认赋值为最大血量。
第六行表示当给health变量赋值时,发生。
第七行表示给health复制时,取值范围为0到max_health,当超过这个范围会自动变换到这个范围。
第八行、第九行表示如果复完值就跳出该方法。
第十行表示把用户输入的值付给health。
第十一行表示复完值后发出血量变化信号。

2.StatusUI场景代码

切换到StatusUI场景,选择根节点,单击创建脚本按钮,将代码保存到Scripts文件夹内,命名为StatusUI。如下:
请添加图片描述

编写如下代码:

extends HBoxContainer
@export var stats:Stats
@onready var health_bar = $HealthBar
@onready var health_bar_red = $HealthBar/HealthBarREDfunc _ready():stats.health_changed.connect(update_health)  #血量变化信号连接到血量更新UIupdate_health()func update_health()->void:var percentage :=stats.health/ float(stats.max_health)health_bar.value = percentagecreate_tween().tween_property(health_bar_red,"value",percentage,.3)

这段代码中第二行定义了一个状态变量,继承Stats。
第三至四行代码表示获取绿色血量和红色血量节点。
_ready函数中的stats.health_changed.connect(update_health)代码表示血量变化信号发生后会调用update_health函数。
update_health自定义函数表示血量发生变化后血量显示进度条适时变化。该函数前两行代码对绿色血量进行调整,后一行代码表示红色血量变化会在0.3秒内完成,并显示间补动画,就是红色血量有个减少过程,绿色血量直接发生变化。
这里面有个引擎自带函数tween_propert方法解释一下。create_tween()表示创建一个间补动画,tween_property方法第一个参数表示要发生变化的对象,第二个参数表示该对象的哪个属性发生变化,第三个参数表示该属性到达的最后状态,第四个参数表示达到最后状态需要的持续时间。

四、给主人公添加血量显示

1.添加状态类

切换到Player场景,选择根节点,然后点击添加节点按钮,选择Stats,我们自己编写的类,如下:
请添加图片描述

单击Stats节点,在其检查器中,我们会看到我们编写该类时,暴漏的max_health的变量,我们可以在检查器中进行修改。
请添加图片描述

2.添加StatusUI场景到Player场景

切换到Player场景,选择根节点,单击实例化子场景按钮,在实例化子场景中选择StatusUI点击打开,就把StatusUI场景加入到Player场景内了,重名为PlayerStatus,然后适当调整位置。
请添加图片描述

在PlayerStatus节点单击右键选择重设父节点为新节点,在对话框中选择CanvasLayer节点,这样的目的是把主人公的血条显示固定在一个位置。操作如下:
请添加图片描述

调整PlayerStatus节点位置到屏幕的左上角,如下:
请添加图片描述

在检查器中将Stats选择Stats,操作如下:
请添加图片描述

ok,这样就应该好了,看一下最终效果:
请添加图片描述

注意观看左上角的血量变化。今天就到这,下节见,同学们。

这篇关于【Godot4自学手册】第十八节主人公的血量显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/761779

相关文章

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

lvgl8.3.6 控件垂直布局 label控件在image控件的下方显示

在使用 LVGL 8.3.6 创建一个垂直布局,其中 label 控件位于 image 控件下方,你可以使用 lv_obj_set_flex_flow 来设置布局为垂直,并确保 label 控件在 image 控件后添加。这里是如何步骤性地实现它的一个基本示例: 创建父容器:首先创建一个容器对象,该对象将作为布局的基础。设置容器为垂直布局:使用 lv_obj_set_flex_flow 设置容器

C# dateTimePicker 显示年月日,时分秒

dateTimePicker默认只显示日期,如果需要显示年月日,时分秒,只需要以下两步: 1.dateTimePicker1.Format = DateTimePickerFormat.Time 2.dateTimePicker1.CustomFormat = yyyy-MM-dd HH:mm:ss Tips:  a. dateTimePicker1.ShowUpDown = t

小程序button控件上下边框的显示和隐藏

问题 想使用button自带的loading图标功能,但又不需要button显示边框线 button控件有一条淡灰色的边框,在控件上了样式 border:none; 无法让button边框隐藏 代码如下: <button class="btn">.btn{border:none; /*一般使用这个就是可以去掉边框了*/} 解决方案 发现button控件有一个伪元素(::after

MFC中Spin Control控件使用,同时数据在Edit Control中显示

实现mfc spin control 上下滚动,只需捕捉spin control 的 UDN_DELTAPOD 消息,如下:  OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult) {  LPNMUPDOWN pNMUpDown = reinterpret_cast(pNMHDR);  // TODO: 在此添加控件通知处理程序代码    if

linux dlopen手册翻译

名称 dlclose, dlopen, dlmopen 打开和关闭一个共享对象 简介 #include <dlfcn.h>void *dlopen(const char*filename, int flags);int dlclose(void *handle);#define _GNU_SOURCE#include <dlfcn.h>void *dlmoopen(Lmid_t lm

微信小程序uniappvue3版本-控制tabbar某一个的显示与隐藏

1. 首先在pages.json中配置tabbar信息 2. 在代码根目录下添加 tabBar 代码文件 直接把微信小程序文档里面的四个文件复制到自己项目中就可以了   3. 根据自己的需求更改index.js文件 首先我这里需要判断什么时候隐藏某一个元素,需要引入接口 然后在切换tabbar时,改变tabbar当前点击的元素 import getList from '../

gazebo 已加载模型但无法显示

目录 写在前面的话问题一:robot_state_publisher 发布机器人信息失败报错一 Error: Error document empty.报错二 .xcaro 文件中有多行注释成功启动 问题二:通过 ros2 启动 gazebo 失败成功启动 问题三:gazebo 崩溃和无法显示模型问题四: 缺少 robot_description 等话题正确的输出 写在前面的话