设计模式和介绍
由于玩家脚本中代码冗余较大(接近150行即将成为屎山代码),所以将玩家死亡设计成一个新的场景,并在玩家死亡后将这个死亡场景添加到玩家身上并删除玩家,从而简化项目的逻辑,减少代码的耦合。
具体步骤
创建一个新的场景 PlayerDeath使用结点 KinematicBody2D,并将原来场景中的 CollisionShape2d 合并进新场景,同时添加子节点 AnimationPlayer 和 Sprite。我们只用使用一张图片(精灵图片使用默认图像即可)并在 AnimationPlayer 中自己制作一个简单的死亡动画即可。
AnimationPlaeyr 中的动画,数值可以根据自己的想法进行设计
右边的线性差值使用 三次方,rotation_degrees, position, scale 为左上角添加轨道中的 属性轨道。
为脚本添加代码:
extends KinematicBody2D
var velocity = Vector2.ZERO
func _process(delta):
velocity = move_and_slide(velocity, Vector2.UP) # 第二个参数告诉移动函数地面法向量向上
if (is_on_floor()):
velocity.x = lerp(0, velocity.x, pow(2, -10 * delta)) # 通过线性插值让速度变化更加平滑
到这里就制作好了单独的尸体以及对应的动画,作为一个新的实例。但是还有一些问题没有修改,如:玩家死亡之后相机会立即生成一个新的玩家,所以相机会立即随玩家回到出生点。以及尸体僵硬不会消失,接下来进行修改。
延迟玩家的重生
在玩家脚本中预加载场景 PlayerDeath,
var playerDeathScene = preload("res://scenes/PlayerDeath.tscn")
创建玩家死亡以及生成尸体在玩家身上的脚本 kill():
func kill():
var playerDeathInstance = playerDeathScene.instance()
get_parent().add_child_below_node(self, playerDeathInstance)
playerDeathInstance.global_position = global_position
playerDeathInstance.velocity = velocity
emit_signal("died")
在判断玩家死亡的脚本 func on_hazard_area_entered(area2d) 中进行延时回调:
func on_hazard_area_entered(area2d):
$"/root/Helpers".apply_camera_shake(.75)
call_deferred("kill")
到这里如果运行一下就会发现玩家死亡后相机是静止的,并且调试中会给出如下错误:
func create_player():
var playerInstance = playerScene.instance()
add_child_below_node(currentPlayerNode, playerInstance) # 创建新的玩家实例,并将放到场景树原先应有的位置上
playerInstance.global_position = spawnPosition
register_player(playerInstance) # 注册新的玩家实例作为当前的玩家实例
具体原因就是之前脚本中生成尸体是生成在玩家结点的下方的,玩家结点如果被删除就会导致报错。
我们可以在基础场景中添加一个统一管理所有玩家的父节点 PlayerRoot:
这样就算生成新的玩家也能进行准确的定位(不依赖于玩家结点,而是生成一个新的结点作为依赖)。
然后运行,一个初级的玩家死亡动画就制成了,但是仍然有一个小问题,那就是玩家的尸体依旧不会被删除并且很僵硬(死亡后不会继续移动)。
我将在下面两个part中提到如何添加粒子效果来掩盖玩家的死亡消失,并且增加一些细节。