【Godot4自学手册】第二十节增加游戏的打击感,镜头震颤、冻结帧和死亡特效

news/2024/5/18 16:36:49 标签: 游戏, godot, 游戏引擎, Godot4, 游戏程序

这节我主要学习增加游戏的打击感。我们通过镜头震颤、冻结帧、增加攻击点特效,增加死亡。开始了。

一、添加攻击点特效

增加攻击点特效就是,在攻击敌人时,会在敌人受击点显示一个受击动画。

1.添加动画。

第一步先做个受击点动画。切换到Enemy场景,给根节点添加AnimatedSprite2D节点,命名为HiteffectAnima。在其检查器Animation->Sprite Frames 属性选择新建SpriteFrames。过程如下:
请添加图片描述

在动画帧面板中选择从精灵表中添加按钮,在弹出的对话框中选择我们提前做好的图片素材HitParticle.png,然后在选择帧面板中水平设置4,垂直设置为1,然后单击全选,最后单击添加4帧按钮。
请添加图片描述

然后在动画帧面板中将动画命名为“Default”,动画速度设置10FPS,取消动画循环。
请添加图片描述

这样我们的动画就做好了。

2.编写代码

首先需要获取动画结点,代码如下:

@onready var hiteffect_anima = $HiteffectAnima

然后编写hitHide函数,代码如下:

func hitHide():
	hiteffect_anima.hide()

编写hitPlay函数,代码如下:

func hitPlay():
	var ran = RandomNumberGenerator.new()
	var jiaodu = ran.randi_range(1,30) #产生个1到30随机数
	hiteffect_anima.rotation=TAU/jiaodu 
	#TAU示一个弧度值,改行代码表示该动画随机旋转一个角度
	hiteffect_anima.show()  #动画显示
	hiteffect_anima.play("Default")  #播放Default动画

敌人刚开始载入时需要隐藏受击点动画的,所以_ready函数调用hitPlay()函数,代码如下:

func _ready():
	hitHide()

敌人受击时,要调用hitPlay()函数,现在我们敌人受击代码已经很丰富了,如下:

func hurt_state():	#受伤状态
	stats.health -=10  #受伤一次减去10点血量
	var dir = hurtdirecion.direction_to(global_position).normalized()
	if abs(dir.x)>abs(dir.y):
		if dir.x<0:
			velocity.x =-knockback
		else :
			velocity.x =knockback
	else:
		if dir.y<0:
			velocity.y =-knockback
		else :
			velocity.y =knockback
	anima_p.play("TakeHit")
	hitPlay()  #播放受击点动画
	await  anima_p.animation_finished	
	if stats.health<=0:#血量小于等于零时,敌人进入死亡状态
		state=DEATH
	else:
		velocity = Vector2.ZERO
		state=CHASE

选择HiteffectAnima结点,在结点面板双击nimation_finished(),在弹出的对话框中选择enemy结点,然后单击链接按钮。
请添加图片描述

在代码中添加如下代码,表示动画播放完成后隐藏

func _on_hiteffect_animation_finished():
	hitHide()

二、添加死亡动画

1.添加动画。

新建Node2D场景,命名为animations,保存到Scenes目录下。给animations结点添加AnimatedSprite2D结点,命名为anima。添加动画过程与第一点中的添加动画大同小异。只需要添加我们事先准备好的动画精灵,最后动画帧面板如下:
请添加图片描述

2.添加代码

为该场景根节点添加animations代码,并保存到Scripts文件夹下,具体代码如下:

extends Node2D
# Called when the node enters the scene tree for the first time.
func _ready():
	self.hide() #隐藏动画
	pass # Replace with function body.

'''
options.box 动画父类
options.ani_name 动画名称
options.position 动画生成坐标
opions.scale 动画缩放
'''
func run_animation(options):
	var ani_temp = self.duplicate() #复制本身动画
	options.box.add_child(ani_temp) #作为options.box的子节点
	ani_temp.show()  #显示动画
	ani_temp.scale= options.scale if options.has("scale") else Vector2(1,1) 
	#三项条件,当参数有scale属性的时候,动画设置为scale没有的时候设置为不缩放
	ani_temp.position = options.position#设置动画位置
	ani_temp.get_node("anima").play("Dealth")#播放Dealth动画
	pass


func _on_anima_animation_finished():#动画播放完毕
	self.queue_free() #释放该节点
	pass 
3.全局变量

切换到全局变量globals,添加如下代码

extends Node
var last_Player
var animation_scene = preload("res://Scenes/animations.tscn")#预加载动画
var animation_scene_obj=null #场景对象
var duplicate_node = null

func _ready():
	animation_scene_obj = animation_scene.instantiate() #实例化animation_scene动画场景
	add_child(animation_scene_obj) #添加到场景中	
	var node2d = Node2D.new() #新建Node2D结点
	node2d.name ="anima_node"#结点名称为duplicate_node
	get_window().add_child.call_deferred(node2d)#将node2d结点添加到主场景的最后位置
	duplicate_node=node2d #将该节点复制给duplicate_node
	pass
4.添加死亡代码

切换到敌人代码中,对死亡代码进行修改如下:

func death_state():		
	Globals.animation_scene_obj.run_animation({
		"box":Globals.duplicate_node,
		"ani_name":"Dealth",
		"position":self.global_position,
		"scale":Vector2(1,1)
	})
	self.queue_free()

这样就完成了敌人的死亡动画调用。

三、添加镜头震颤和冻结帧

1.给相机添加代码

切换到Player场景,给Camera2D添加代码,存在Scriptes目录下命名为HitEffect.gd,具体代码如下:

extends Camera2D
	
func _hit(_scale,_offset):#震颤效果
	var tween= create_tween()
	tween.tween_property(self,"offset",Vector2.ZERO,0.12).from(_offset)
	#偏移量从_offset到ector2.ZERO,需要0.12秒
	tween.parallel().tween_property(self,"zoom",Vector2(2.00,2.00),0.12).from(_scale)
	#缩放从_scale到Vector2(2.00,2.00),需要0.12秒,这里面为啥是2不是1,是因为我本身就给主人公放大二倍显示
func frameFreeze(time_scale,duration):#冻结帧
	Engine.time_scale = time_scale 
	#控制游戏中的时钟与现实生活中的时钟的快慢。默认值为 1.0。值为 2.0 意味着游戏的移动速度是现实生活的两倍,
	#而值为 0.5 意味着游戏的移动速度是常规速度的一半
	await get_tree().create_timer(duration*time_scale).timeout
	Engine.time_scale=1
2.给Player代码中添加函数

切换到Player代码,添加hit_effect函数

func hit_effect():
	$Camera2D._hit(Vector2(1.99,1.99),Vector2(7,-9))
	$Camera2D.frameFreeze(0.1,0.09)
3.敌人受伤时调用

切换到Enemy场景,选择HurtBox节点,在其结点信号面板中双击area_enterd(area:Area2D)信号,在弹出框选择Enemy结点,并在脚本中添加如下代码:

func _on_hurt_box_area_entered(area):	#进入受伤范围
	hurtdirecion = area.owner.global_position
	area.owner.hit_effect()
	state = HURT

这样我们这节就OK了,需要源代码的同学请在顶端下载下载。


http://www.niftyadmin.cn/n/5409308.html

相关文章

【Git】merge时报错:refusing to merge unrelated histories

文章目录 一、问题二、解决办法1、将feature分支的东西追加到master分支中2、将feature里的东西直接覆盖到master分支中 一、问题 今天将feature分支合并到master时报错&#xff1a;refusing to merge unrelated histories&#xff08;拒绝合并无关历史&#xff09; 报错原因&…

vue3 (四)动态组件Vs异步组件

1.动态组件 点击toggle切换2个组件&#xff0c;配合<keep-alive>使用防止切换后数据丢失 <keep-alive><component :is"currentItem"></component> </keep-alive> 2.异步组件 定义方法&#xff1a;app.component(组件名,Vue.defineAs…

【论文阅读】Mamba:选择状态空间模型的线性时间序列建模(二)

文章目录 3.4 一个简化的SSM结构3.5 选择机制的性质3.5.1 和门控机制的联系3.5.2 选择机制的解释 3.6 额外的模型细节A 讨论&#xff1a;选择机制C 选择SSM的机制 Mamba论文 第一部分 Mamba:选择状态空间模型的线性时间序列建模(一) 3.4 一个简化的SSM结构 如同结构SSM&#…

C语言数据结构与算法——深度、广度优先搜索(DFS、BFS)

目录 一、深度优先搜索&#xff08;Depth-First-Search 简称&#xff1a;DFS&#xff09; 无向图的深度优先搜索 有向图的深度优先搜索 二、广度优先搜索&#xff08;Breadth-First-Search 简称&#xff1a;BFS&#xff09; 无向图的广度优先搜索 有向图的广度优先搜索 深…

uniapp实现---单选题按钮

目录 一、实现思路 二、实现步骤 ①view部分展示 ②JavaScript 内容 ③css中样式展示 三、效果展示 一、实现思路 使用样式布局控制单选框的位置&#xff0c;这里使用的是原生态uniapp&#xff0c;并没有使用组件。 二、实现步骤 ①view部分展示 <template><view …

72. 编辑距离【leetcode】/动态规划难

72. 编辑距离 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符删除一个字符替换一个字符 示例 1&#xff1a; 输入&#xff1a;word1 “horse”, word2 “ros”…

lua与C++粘合层框架

lua调用C++ 在lua中是以函数指针的形式调用函数, 并且所有的函数指针都必须满足如下此种类型: typedef int (*lua_CFunction) (lua_State *L);   也就是说, 偶们在C++中定义函数时必须以lua_State为参数, 以int为返回值才能被Lua所调用. 但是不要忘记了, 偶们的lua_State是支…

DataGrip 连接 Centos MySql失败

首先检查Mysql是否运行&#xff1a; systemctl status mysqld &#xff0c; 如果显示没有启动则需要启动mysql 检查防火墙是否打开&#xff0c;是否打开3306的端口 sudo firewall-cmd --list-all 如果下面3306没有打开则打开3306端口 publictarget: defaulticmp-block-inver…