Hello everyone. I'm working on an interactive book game and I'm having a couple issues with crossfading from one page to another. For each page, I have a Control node ("Page_000", for example) with a TextureRect for the artwork with Buttons to navigate from page to page. These pages are contained in another Control node ("Pages") that has a script attached to handle the Button signals and perform the transition via a Tween ("Transition Tween"). I have a NinePatchRect ("WindowFrame") overlaying the pages as a or additional controls like a tile bar and progress meters.

The Scene Tree:

The Game Screen:

I've got the crossfading working but I'm having a bit of trouble with getting a couple things: I want to hide the page when it's faded out at the end of the tween, to prevent interaction with it. The WindowFrame's Mouse Filter is working when I change it to STOP, but not changing back to PASS.

I've only been working with GDScript for a couple of weeks so far, so any advice will be most welcome!

Here is the code so far:

extends Control

# Node variables

onready var transition_tween := get_node("../TransitionTween")
onready var window_frame := get_node("../WindowFrame")

# Variable to track the current page

onready var current_page = "Page_000"

func navigate_to(page: String) -> void:

	print("Navigate from " + current_page)

	# Change the Mouse Filter on the WindowFrame node to prevent clicking buttons during the transition between pages.
	window_frame.mouse_filter = Control.MOUSE_FILTER_STOP
	
	# Tween to fade the currently visible page to transparent.
	transition_tween.interpolate_property(get_node(current_page), "modulate:a", 1.0, 0.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
	
	# Make sure the current_page is hidden
	transition_tween.interpolate_callback(get_node(current_page), 0.5, "hide")
	
	# Change the Mouse Filter on the WindowFrame node to allow clicking buttons after the transition between pages.
	transition_tween.interpolate_callback(self, 0.5, "enable_buttons")

	# Update the current page.
	current_page = page
	
	# Make sure the current_page is visible.
	get_node(current_page).show()
	
	# Tween to fade the next page from transparent.
	transition_tween.interpolate_property(get_node(current_page), "modulate:a", 0.0, 1.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
	transition_tween.start()
	
func enable_buttons() ->void:
	print(window_frame.mouse_filter)
	window_frame.mouse_filter == Control.MOUSE_FILTER_PASS
	print(window_frame.mouse_filter)
  • ThinKing_2005 replied to this.
  • After a bit of tinkering, and thanks to ALBATI_2005's advice, I was able to go back in and solve the problems I was having. Below is the revised code (with some extra comments to point out the changes). (Spoiler alert: STOP/PASS not working on the Window Frame was due to incorrect targeting.)

    In the Pages node (where the original attempt resided):

    extends Control
    
    # Node variables
    
    onready var transition_tween := get_node("../TransitionTween")
    onready var window_frame := get_node("../WindowFrame")
    
    # Variable to track the current page
    
    onready var current_page = "Page_000"
    
    func navigate_to(next_page: String) -> void:
    
    	# Change the Mouse Filter on the WindowFrame node to prevent clicking buttons during the transition between pages.
             ### I MOVED THE FUNCTION TO TOGGLE THE WindowFrame TO A SCRIPT ATTACHED TO THE WindowFrame NODE ITSELF ###
    	window_frame.toggle_interaction()
    	
    	# Tween to fade the currently visible page to transparent.
    	transition_tween.interpolate_property(get_node(current_page), "modulate:a", 1.0, 0.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
    	
    	# Make sure the current_page is hidden
    	transition_tween.interpolate_callback(get_node(current_page), 0.5, "hide")
    	
    	# Show the next page
             ### I HAD TRIED USING .show() ORIGINALLY, BUT MESSED UP ON MY TARGETING. I FIXED THAT AND GOT RID OF THE enable_butons() FUNCTION ALTOGETHER ###
    	transition_tween.interpolate_callback(get_node(next_page), 0.5, "show")
    	transition_tween.interpolate_callback(window_frame, 0.5, "toggle_interaction")
    
    	# Make sure the current_page is visible.
    	get_node(current_page).show()
    	
    	# Tween to fade the next page from transparent.
    	transition_tween.interpolate_property(get_node(next_page), "modulate:a", 0.0, 1.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
    	transition_tween.start()
    
             # Update the current page.
             ### I MOVED THIS LINE BECAUSE TRYING TO UPDATE current_page PRIOR TO THE ABOVE "FADE IN" WAS CONFUSING THE TWEENS ###
    	current_page = next_page

    And in the WindowFrameNode:

    extends NinePatchRect
    
    func toggle_interaction() ->void:
    	# Toggle the mouse_filter to STOP or PASS events through the window_frame
    	if self.mouse_filter == Control.MOUSE_FILTER_STOP:
    		self.mouse_filter = Control.MOUSE_FILTER_PASS
    	elif self.mouse_filter == Control.MOUSE_FILTER_PASS:
    		self.mouse_filter = Control.MOUSE_FILTER_STOP

    erobertwald I've got the crossfading working but I'm having a bit of trouble with getting a couple things: I want to hide the page when it's faded out at the end of the tween, to prevent interaction with it.

    Instead of changing the value of mouse_filter, you could simply change the visible property of each page (control node). Just so you know, when a control node is invisible, it no longer responds to mouse clicks. I think the purpose of mouse_filter is when the control node is still visible. Just use the following code:
    window_frame.set("visible", false) #becomes invisible
    window_frame.set("visible", true) #becomes visible

    P.S. modulate.a == 0, does NOT mean visible == false. Each is a different value, and mouse clicks do not respond ONLY when visible == false.

    Edit: You can of course use mouse_filter, but I believe you're not using it correctly. Below is a quote from https://docs.godotengine.org/en/stable/classes/class_control.html#class-control-property-mouse-filter.

    #QUOTE START
    "enum MouseFilter:

    MOUSE_FILTER_STOP = 0 --- The control will receive mouse button input events through _gui_input if clicked on. And the control will receive the mouse_entered and mouse_exited signals. These events are automatically marked as handled, and they will not propagate further to other controls. This also results in blocking signals in other controls.

    MOUSE_FILTER_PASS = 1 --- The control will receive mouse button input events through _gui_input if clicked on. And the control will receive the mouse_entered and mouse_exited signals. If this control does not handle the event, the parent control (if any) will be considered, and so on until there is no more parent control to potentially handle it. This also allows signals to fire in other controls. Even if no control handled it at all, the event will still be handled automatically, so unhandled input will not be fired.

    MOUSE_FILTER_IGNORE = 2 --- The control will not receive mouse button input events through _gui_input. The control will also not receive the mouse_entered nor mouse_exited signals. This will not block other controls from receiving these events or firing the signals. Ignored events will not be handled automatically."
    #QUOTE END

      ThinKing_2005 Thanks for the quick response. The trick is the window_frame remains visible at all times while the Page_XXX nodes in Pages are what are actually fading. That being said, your advice did force me to look at my code from a slightly different angle and I got things working properly 🙂
      Forum etiquette question: Should I post my revised code as an edit to the original post, or as a new answer and mark as best answer?

        erobertwald I guess you should make it as a new answer and make it as best answer. I mean, I'm no expert in this forum, but it's better so that those who have a similar problem can see the answer. If you edit the original post, nobody would be able to make use of the answer.

        Also, for the window_frame thing, I guess I wrote my answer on a rush. I meant that the pages should disappear. Anyway, glad that I could help.

        After a bit of tinkering, and thanks to ALBATI_2005's advice, I was able to go back in and solve the problems I was having. Below is the revised code (with some extra comments to point out the changes). (Spoiler alert: STOP/PASS not working on the Window Frame was due to incorrect targeting.)

        In the Pages node (where the original attempt resided):

        extends Control
        
        # Node variables
        
        onready var transition_tween := get_node("../TransitionTween")
        onready var window_frame := get_node("../WindowFrame")
        
        # Variable to track the current page
        
        onready var current_page = "Page_000"
        
        func navigate_to(next_page: String) -> void:
        
        	# Change the Mouse Filter on the WindowFrame node to prevent clicking buttons during the transition between pages.
                 ### I MOVED THE FUNCTION TO TOGGLE THE WindowFrame TO A SCRIPT ATTACHED TO THE WindowFrame NODE ITSELF ###
        	window_frame.toggle_interaction()
        	
        	# Tween to fade the currently visible page to transparent.
        	transition_tween.interpolate_property(get_node(current_page), "modulate:a", 1.0, 0.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
        	
        	# Make sure the current_page is hidden
        	transition_tween.interpolate_callback(get_node(current_page), 0.5, "hide")
        	
        	# Show the next page
                 ### I HAD TRIED USING .show() ORIGINALLY, BUT MESSED UP ON MY TARGETING. I FIXED THAT AND GOT RID OF THE enable_butons() FUNCTION ALTOGETHER ###
        	transition_tween.interpolate_callback(get_node(next_page), 0.5, "show")
        	transition_tween.interpolate_callback(window_frame, 0.5, "toggle_interaction")
        
        	# Make sure the current_page is visible.
        	get_node(current_page).show()
        	
        	# Tween to fade the next page from transparent.
        	transition_tween.interpolate_property(get_node(next_page), "modulate:a", 0.0, 1.0, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT)
        	transition_tween.start()
        
                 # Update the current page.
                 ### I MOVED THIS LINE BECAUSE TRYING TO UPDATE current_page PRIOR TO THE ABOVE "FADE IN" WAS CONFUSING THE TWEENS ###
        	current_page = next_page

        And in the WindowFrameNode:

        extends NinePatchRect
        
        func toggle_interaction() ->void:
        	# Toggle the mouse_filter to STOP or PASS events through the window_frame
        	if self.mouse_filter == Control.MOUSE_FILTER_STOP:
        		self.mouse_filter = Control.MOUSE_FILTER_PASS
        	elif self.mouse_filter == Control.MOUSE_FILTER_PASS:
        		self.mouse_filter = Control.MOUSE_FILTER_STOP