介绍
我们知道,Godot中的Camera2d结点有Position和Offset属性,其中Position是位置属性,我们使它附着在玩家上。Offset表示偏移量,可以使相机产生一定的偏移。
简单的讲,我们需要实现的相机抖动效果就是在相机移动时,为相机增加了一个随机的Offset偏移。这个偏移会逐渐减小,最后相机静止。
本文中介绍的相机抖动实现效果,主要着重讨论平滑相机效果的实现。需要实现平滑的相机抖动,就不能使用粗糙的直接生成的随机值,需要借助噪声来生成平滑的随机值。
OpenSimplexNoise
OpenSimplexNoise 是一个基于Open Simplex 算法的噪声生成器。
属性
- seed:用于生成随机值的种子,不同的种子会产生不同的噪声模式。
- octaves:OpenSimplex 噪声层数,影响噪声的细节和生成时间。最大值为 9。
- period:基础八度的周期,影响噪声的频率。
- persistence:不同八度的贡献因子,影响噪声的衰减率。
- lacunarity:八度之间的周期差异,影响噪声的粗糙度。
上述属性了解即可,不太会用到。
本文中介绍的相机抖动主要利用了该类的OpenSimplexNoise.get_noise_2d()方法来生成一个2d的噪声。
代码主要实现:
- 利用分组获取到玩家结点 -> 获取玩家的全局位置 -> 存储在targetPosition中
- 通过噪声位置来生成x和y上的平滑噪声值
- 根据噪声值来生成抖动
- 削弱抖动使相机停止
extends Camera2D
var targetPosition = Vector2.ZERO
var sourcePosition
export(Color, RGB) var backgroundColor
export(OpenSimplexNoise) var shakeNoise
var xNoiseSampleVector = Vector2.RIGHT # 获取样本的方向
var yNoiseSampleVector = Vector2.DOWN
var xNoiseSamplePosition = Vector2.ZERO
var yNoiseSamplePosition = Vector2.ZERO
var noiseSampleTravelRate = 500 # 当前抖动的delta速率
var maxShakeOffset = 6 # 当前抖动的最大偏移量
var currentShakePercentage = 0 # 当前抖动百分比
var shakeDecay = 4 # 抖动衰减
func _ready():
VisualServer.set_default_clear_color(backgroundColor)
apply_shake(1) # 初始化currentShakePercentage为一个正常的随机百分比
func _process(delta):
acquire_target_position() # 获取玩家的目标位置
global_position = lerp(targetPosition, global_position, pow(2, -15 * delta)) # 将相机平滑地移动到玩家的位置上
# ------------------- 相机抖动效果 -------------------
if (currentShakePercentage > 0): # 如果当前的抖动百分比大于零(正常来说一定是大于零的)
xNoiseSamplePosition += xNoiseSampleVector * noiseSampleTravelRate * delta
yNoiseSamplePosition += yNoiseSampleVector * noiseSampleTravelRate * delta
# 获取x方向上的噪声位置和y上的噪声位置 (都是平面向量) = 对应方向的单位向量乘上抖动的速度*delta
var xSample = shakeNoise.get_noise_2d(xNoiseSamplePosition.x, xNoiseSamplePosition.y)
var ySample = shakeNoise.get_noise_2d(yNoiseSamplePosition.x, yNoiseSamplePosition.y)
# 获取噪声位置的采样值
var calculatedOffset = Vector2(xSample, ySample) * maxShakeOffset * pow(currentShakePercentage, 2)
# 根据噪声采样值来进行偏移实现抖动效果
# 用乘上抖动百分比来削减当前的相机偏移量
offset = calculatedOffset
currentShakePercentage = clamp(currentShakePercentage - shakeDecay * delta, 0, 1)
# 不断削弱抖动直至相机停止运动
# ---------------------------------------------------------
func apply_shake(percentage):
currentShakePercentage = clamp(currentShakePercentage + percentage, 0, 1)
# 将当前的抖动百分比+1,但是限制在(0, 1)的范围内
# 本质上其实就是生成了一个(1% ~ 100%)范围内的正常百分比而已
func acquire_target_position():
# 明确目标位置
var players = get_tree().get_nodes_in_group("player")
# 如果玩家组中只有一个玩家,应该是为了以防万一。就固定位置到玩家的位置上去。
if (players.size() > 0):
var player = players[0]
targetPosition = player.global_position