Godot游戏引擎学习 第七课
今天是圣诞节,朋友圈里热热闹闹的让我感觉全世界都再过圣诞节,回家的一路上也格外冷清,相比都去购物中心或者吃喝玩乐一条街过圣诞节去了把。
今天继续学习Godot,UP今天讲的是实现很多动作游戏中的残影效果
,对这个印象最深刻的是以前看黑客帝国时候,史密斯的那个躲子弹的残影太帅了,应该算是名场面了吧!好了,废话不多说,开干。
给角色添加残影
其实我之前看Carotaa666的直播的时候看到他说过这个思路,大概是通过计时器按一定的周期绘制一个精灵,然后再销毁掉。
这里UP主的思路也是一样的,先新建一个场景名为Trail
再里面添加一个Sprite节点,和一个AnimationPlayer
,利用我们以前的学的,添加一个名为fadeout
的渐隐动画,并让动画在一定时间后自我销毁,然后设置从清晰到模糊的渐变。
然后给Player
场景添加一个计时器,然后就是代码部分了。这里说到一个以后可能会经常用的函数preload
,具体看代码,我都写了 注释了。
# 连接计时器的Timerout信号
func _on_TrailTimer_timeout():
# 如果角色没有移动,则不绘制影子
if velocity.x == 0:
return
# 用preload预加载我们做的那个影子场景,并实例化
var trail = preload("res://src/effects/Trail.tscn").instance()
# 把它添加进父场景
get_parent().add_child(trail)
# 改变它在场景树中的位置到player下方
get_parent().move_child(trail, get_index())
# 下面这些属性是要从角色上读取出来复制给影子的
var properties = [
"hframes",
"vframes",
"frame",
"texture",
"global_position",
"flip_h"
]
# 从角色身上遍历,并给与影子
for name in properties:
trail.set(name, sprite.get(name))
第一次了解Shader
这里还说了shader,什么是shader?我也是第一次接触,以前玩绝地求生的为了改变画质用过一次,不过完全不知道是什么东西;
着色器(Shader)是用来实现图像渲染的,用来替代固定渲染管线的可编辑程序。其中Vertex Shader主要负责顶点的几何关系等的运算,Pixel Shader主要负责片源颜色等的计算。
着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编辑性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。
应该就是可以通过编程方式改变画面展现出来的效果,比如图片原本是彩色的,你可以通过shader改变运行后展示出来的颜色为灰色。shader我看过一些godot的实现效果,只能说很强大,在实现一些特殊画面特效时非常有用,我还得多看看相关资料学习一下。
我们可以在Sprite
上找到Material,然后新建一个ShaderMaterial > Shader
,然后就可以编写着色器代码了。
具体代码如下:
# 定义shader类型,这个时固定的好像
shader_type canvas_item;
# 定义shader的外部参数,方便调试什么的,指定它的类型为hint_color,外部在设置的时候可以调用系统的取色板
uniform vec4 tint_color: hint_color = vec4(1.0);
# 这个是主入口函数,里面的内容就是在对每一个像素点的处理方式。
void fragment()
{
# 在一个图片里每一个像素都有自己的坐标,这里是获取当前图片的颜色坐标
vec4 col = texture(TEXTURE, UV);
# 通过算法讲每个像素换算成灰色
float grey = (col.r + col.g + col.b) / 3.0;
# 这个UP说是色阶的处理,从多少过渡到多少(大概)
grey = smoothstep(0.3, 0.6, grey) * 0.4 + 0.6;
# 把计算出来的颜色给与贴图
COLOR = vec4(grey * tint_color.rgb, col.a);
}
最后效果就是这样,还挺帅的。
增加飞行敌人
这里UP果然将Slime上一些共有属性提取到Enmey上去了。苍蝇作为怪物自然也要继承自Enmey脚本,并且也更改了移动方式。并通过一个Area2D
检测敌人的范围。
但是和Slime不一样的是,这个飞行怪物是会飞的,所以移动逻辑和地形i行走的完全不一样。也不会受y轴的重力影响,所以这里代码部分改了很多。而且还有警戒区域.
这里有一些代码有点一知半解
extends "res://src/enemies/Enemy.gd"
var target_posistion = null
onready var player_sensor = $PlayerSensor
func _process(delta):
if is_dead:
# 死后不在移动
velocity.x = 0
# 且增加增加重力影响
velocity.y += gravity * delta
else:
# 计算并更新目标位置
target_posistion = _calc_target_position()
if target_posistion == null:
# 如果没有新的目标位置就只移动到目标位置去
velocity = velocity.move_toward(Vector2.ZERO, acceleration * delta)
else:
# 获取自身到目标位置的向量
var direction = global_position.direction_to(target_posistion)
# 根据目标向量进行移动
velocity = velocity.move_toward(direction * max_speed, acceleration * delta)
# 转身
sprite.flip_h = direction.x > 0
func _physics_process(_delta):
# 移动
velocity = move_and_slide(velocity)
func _calc_target_position():
# 获得所有碰撞区内的对象数组,因为只有有些角色能和他碰撞,所以只要有数据就是游戏角色
var bodies = player_sensor.get_overlapping_bodies()
#如果有的话就更新目标位置
if not bodies.empty():
# 返回新的目标位置
return bodies[0].global_position + Vector2(0, 50)
# 这里大概意思如果离目标距离太远也不追踪了,不过不知道为什么要设置成25
if target_posistion != null and global_position.distance_squared_to(target_posistion) < 25:
print(global_position.distance_squared_to(target_posistion))
return null
return target_posistion
好了,大概效果如下
加入评论