我正在制作一款 2D 回合制游戏。当玩家动作发生时,各种 Node2D 对象会移动。
但是当他们移动时,他们会进行基于物理的检查。因为我希望前一个节点所做的移动影响后一个节点所做的移动,所以我有这样的东西:
for individual in individuals:
# We need to wait for the move to take effect so that the next
# collision calculations take it into account.
await get_tree().physics_frame
individual.do_thing_using_area2d()
这可以确保发生物理更新,以便下一次物理检查有效。 (例如,如果一个人刚刚移动到即将移动的人前面,就会发生碰撞。)
这样做的问题是 Sprite2D 附加到正在移动的节点上。因此它们会在单独的帧中重新绘制并导致闪烁。
为了使所有精灵在一帧中更新,我这样做了:
# Stop _process and draw calls, but keep physics going.
get_tree().paused = true
PhysicsServer2D.set_active(true)
然后,在所有个人都移动并更新物理对象后,我取消暂停:
await get_tree().create_timer(0.1).timeout
# Unpause to get _process and _draw going again.
get_tree().paused = false
这确实有效,但感觉有点太多了,而且可能会产生后果。有没有更干净、更传统的方法来批量Sprite2D更新?
我能想到的最接近禁用a
Node
重绘的方法是禁用a Viewport
的自动重绘。
所以我不会回答这个问题...
相反,这就是我的想法:您可以将
top_level
设置为 true
上的 Node2D
,这样它就不会随其父级移动(同时仍处于场景树中的位置),然后您必须移动它...
例如,您可以给它一个类似这样的脚本:
func _physics_process(_delta: float) -> void:
var parent := get_parent() as Node2D
if is_instance_valid(parent):
global_transform = parent.global_transform
或者像这样保存几个周期:
extends Node2D
var parent_node_2d:Node2D
func _ready() -> void:
top_level = true
parent_node_2d = get_parent() as Node2D
set_physics_process(is_instance_valid(parent_node_2d))
func _exit_tree() -> void:
parent_node_2d = null
request_ready()
func _physics_process(_delta: float) -> void:
global_transform = parent_node_2d.global_transform
这里我使用
set_physics_process
来根据父级启用或禁用 _physics_process
。让我们通过配置警告来加强它:
@tool
extends Node2D
var parent_node_2d:Node2D
func _ready() -> void:
top_level = true
parent_node_2d = get_parent() as Node2D
set_physics_process(is_instance_valid(parent_node_2d))
func _exit_tree() -> void:
parent_node_2d = null
request_ready()
func _physics_process(_delta: float) -> void:
global_transform = parent_node_2d.global_transform
func _get_configuration_warnings() -> PackedStringArray:
if not is_instance_valid(parent_node_2d):
return ["Must be a child of a Node2D"]
return []
或者您可以使用
_process
,这就是您开始编写自己的物理插值的方式。
@tool
extends Node2D
var parent_node_2d:Node2D
func _ready() -> void:
top_level = true
parent_node_2d = get_parent() as Node2D
set_process(is_instance_valid(parent_node_2d))
func _exit_tree() -> void:
parent_node_2d = null
request_ready()
func _process(delta: float) -> void:
var final_transform := parent_node_2d.global_transform
var factor := get_approach_factor(1.0 / Engine.physics_ticks_per_second, delta)
global_transform = global_transform.interpolate_with(final_transform, factor)
func _get_configuration_warnings() -> PackedStringArray:
if not is_instance_valid(parent_node_2d):
return ["Must be a child of a Node2D"]
return []
func get_approach_factor(total_time:float, delta_time:float) -> float:
# Constants
const EPSILON := 0.00001
const SCALE := 1000.0
# When the total_time is not finite, the approach factor is zero
if not is_finite(total_time):
return 0.0
# When the total_time is approximately zero, the approach factor is one
if total_time < EPSILON / SCALE:
return 1.0
# Compute the approach factor
var base := pow(EPSILON, 1.0 / (total_time * SCALE))
var approach_factor := 1.0 - pow(base, delta_time * SCALE)
return approach_factor