Hello. I'm making a platform game where the character gets inside an elevator, and when he interacts with it, a question box is shown at the screen where the right answer will make the elevator lift up. However, when the character gets inside the elevator, I can't switch between options and the cursor gets locked at the option where I put the grab_focus() option. How can I solve that?

  • change the contents of the area entered signal from:

    func _on_Area2D_player_entered(_player: KinematicBody2D) -> void:
    	question_box.question_change(level_at)
    	using = true
    	pass # Replace with function body.

    to:

    func _on_Area2D_player_entered(_player: KinematicBody2D) -> void:
    	_player.get_parent().question_change(level_at)
    	using = true

    Since the node/script that holds the function is on the level node which is the parent of the player that enters the area. That should fix your immediate issue. I have a sneaking suspicion your next problem will be determining what level it is so the correct box gets shown.

    Also the pass keyword is unnecessary if the function is no longer empty.

Erich_L Sure!
The screen capture shows the stage structure. The player has child nodes called 'QuestionBox' that will showed to the player at the moment he enters the elevator showed at the screen capture. The box is working outside the elevator. However, when I hide the box and interact with the elevator to show it (that's the main purpose), the cursor doesn't move. Why is it happening? The elevator script:




And the stage code:

The commented lines are my tests that went wrong.

    21 days later

    Have you tried removing that

    if !using:
        return

    ?

    At a quick glance I'd think the player_entered variable should be enough..? In fact it would seem the area_entered signal would currently only set using to true but not player_entered

    And for future reference, rather than posting screenshots of your code you can copy-paste it here then encapsulate with either ~~~ or ```

      Megalomaniak True, the using variable was redundant, so I just used player_entered. Still, same thing happens. The question menu doesn't change options.

      When I enter the elevator, I can't change options by keyboard, but when I'm outside the elevator I can change them successfully.

      Another problem is that when I choose the right answer (using grab_focus( ) function) I can only choose with 'Enter' key, not with 'E' key, the interact key. It's very strange because the elevator lifts up when I press 'Enter', and 'E' later.

      I will use the commands you said to show the code. Thanks for the tip.

        7 days later

        Megalomaniak I verified the neighbours settings and it seems they're ok.
        Another thing: I don't know if it is related, but the question box scenes are children nodes from player, and again the change option problem only occurs when the player is inside the elevator.

        In the neighbors list in inspector, under focus heading. Make sure to also assign Next & Previous. In fact you should always assign at least those and the other neighbors are perhaps actually less important.

          LuanSantos95 Would be nice for keyboard users I guess. Standard would be for tab to move focus to next element and shift+tab to previous.


          LuanSantos95 And the stage code:

          Right, so you probably don't want to do this inside of process. At least the grab focus shouldn't. The process function is part of the main loop which gets reevaluated or in other words runs on every frame. So each frame you are grabbing focus of that node again.

            14 days later

            Megalomaniak Okay, with some help I made some progress: I made a function that makes the question box change and the input problem is ok, but the problem with the cursor persists. The script is right there:

            func _process(delta):
            	if get_node("Elevator").player_entered:
            		$Player.motion.y = $Elevator.move.y
            		question_change(get_node("Elevator").level_at)
            	pass
            
            func question_change(level):
            	if level == 0:
            		$Player/QuestionBox/VBoxContainer/VBoxContainer/Option1.grab_focus()
            		$Player/QuestionBox.show()
            		if $Player/QuestionBox.chosen_option:
            			get_node("Elevator").right_answer = true
            			$Player/QuestionBox.hide()
            	elif level == 1:
            		$Player/QuestionBox2/VBoxContainer/VBoxContainer/Option3.grab_focus()
            		$Player/QuestionBox2.show()
            		if $Player/QuestionBox2.chosen_option3:
            			get_node("Elevator").right_answer = true
            			$Player/QuestionBox2.hide()
            	elif level == 2:
            		$Player/QuestionBox3/VBoxContainer/VBoxContainer/Option3.grab_focus()
            		$Player/QuestionBox3.show()
            		if $Player/QuestionBox3.chosen_option3:
            			get_node("Elevator").right_answer = true
            			$Player/QuestionBox3.hide()
            	elif level == 3:
            		$Player/QuestionBox4/VBoxContainer/VBoxContainer/Option1.grab_focus()
            		$Player/QuestionBox4.show()
            		if $Player/QuestionBox4.chosen_option:
            			get_node("Elevator").right_answer = true
            			$Player/QuestionBox4.hide()
            	elif level == 4:
            		$Player/QuestionBox5/VBoxContainer/VBoxContainer/Option1.grab_focus()
            		$Player/QuestionBox5.show()
            		if $Player/QuestionBox5.chosen_option:
            			get_node("Elevator").right_answer = true
            			$Player/QuestionBox5.hide()

            What can I do now?

            Your elevator has an area, yes? If so, rather than calling this question_change() from process do it via an area_entered() signal.

              Megalomaniak but how will I pass question_change(), a function at the level script, into the elevator script? I need to implement it there too?

                I tried that way below and gave an error.

                var question_box = load("res://Source/Scenes/Level-4-1.gd").new()
                
                func _on_Area2D_player_entered(_player: KinematicBody2D) -> void:
                	question_box.question_change(level_at)
                	using = true
                	pass # Replace with function body.
                
                
                func _on_Area2D_player_exited(_player: KinematicBody2D) -> void:
                	player_entered = false
                	using = false
                	pass # Replace with function body.

                The error:

                LuanSantos95 but how will I pass question_change(), a function at the level script, into the elevator script? I need to implement it there too?

                You can connect signals across nodes.

                edit: share the project? It'll probably easier to help out if we get access to the project. zip it up and if it's too big maybe host it on dropbox or google drive or such.

                  Megalomaniak Sure! I don't know if it's possible, but maybe a direct meeting or something like that would help too.

                  PS: It's the level 4-1.

                  Before I download it, what version of godot are you running? The project is named Python Educational Game so I presume some custom Python build of the engine?

                    Megalomaniak I'm running Godot 3.2.3, and no, The "Python" at the name is about the metaphores that I'm using for teaching Python at the stages

                      LuanSantos95 Godot 3.2.3

                      OK, good to know, and worth mentioning that 3.2.3 is rather old and outdated. No longer supported so worth considering a update.