You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GODOT如何实现对话框激活时禁用玩家移动、关闭后恢复移动

问题根因

  • NPC的diaplay函数仅在按下E键触发对话时执行1次,后续对话结束修改done状态后不会再次触发该函数,因此玩家的can_move属性不会被更新为true
  • 对话框脚本的load_dialog逻辑错误:当前只要dialog_index ≥ 0就会把NPC的done设为true,对话刚启动时index初始值就是0,相当于对话刚打开就标记为结束,状态完全错乱
  • 对话框的对话结束判断逻辑写反,没有在所有对话播放完成后再执行销毁和状态更新操作

修复方案

1. 修正NPC脚本

extends Area2D
var done = true

func _ready(): 
    Global.npc1 = self
func _exit_tree():
    Global.npc1 = null

var can_interact = false
const DIALOG = preload("res://dialoguebox.tscn")

func _physics_process(delta):
    $AnimatedSprite.play()
    # 把状态判断放到每帧执行,保证done变化时即时更新玩家移动权限
    check_dialog_state()

# 修正原函数拼写错误
func check_dialog_state():
    if done == false:
        Global.player.can_move = false
        print("test")
    if done == true:
        print("test2")
        Global.player.can_move = true

func _on_Area2D_body_entered(body):
    if body.name == "player":
        $Label.visible = true
        can_interact = true

func _on_Area2D_body_exited(body):
    if body.name == "player":
        $Label.visible = false
        can_interact = false

func _input(event):
    if Input.is_key_pressed(KEY_E) and can_interact == true:
        done = false
        $Label.visible = false
        var dialog = DIALOG.instance()
        get_parent().add_child(dialog)
        dialog.position = $Position2D.global_position

2. 修正对话框脚本

done=true的正确放置位置是所有对话播放完成、即将销毁对话框的节点下,修正后完整代码如下:

extends Control
var dialog = [
    'sampletext',
    'sampletext2',
]
var dialog_index = 0
var finished = false

func _ready():
    load_dialog() 
    Global.DialogBox = self
    
func _exit_tree():
    Global.DialogBox = null

func _physics_process(delta):
    $"Ind".visible = finished
    if Input.is_action_just_pressed("ui_accept"):
        # 优化交互:文字还在逐字播放时按确认直接显示完整内容,不跳下一步
        if not finished:
            $Tween.stop_all()
            $RichTextLabel.percent_visible = 1
            finished = true
        else:
            load_dialog()

func load_dialog():
    if dialog_index < dialog.size():
        finished = false
        $RichTextLabel.bbcode_text = dialog[dialog_index]
        $RichTextLabel.percent_visible = 0
        $Tween.interpolate_property(
            $RichTextLabel, "percent_visible",  0, 1, 1,
            Tween.TRANS_LINEAR, Tween.EASE_IN_OUT
        )
        $Tween.start()
        dialog_index += 1
    else:
        # 所有对话播放完成再更新NPC状态、销毁对话框
        Global.npc1.done = true
        queue_free()
    
func _on_Tween_tween_completed(object, key):
    finished = true

内容的提问来源于stack exchange,提问作者Ajajajaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 19:54:08