Is there any way to support gui node based dialog in defold?

I am trying to make a game that sprites render as foreground and gui node as background. I just change the render script to make gui ndoe as background in the game. However, I can’t make a gui node based dialog under this render situation. Unlike sprite, you can’t set gui node texture’s material to change the render order in render script. Will defold support gui node material in the future or any other work round way to make it?

Defold does have material support for gui. You can create a second gui predicate and have that one render after the sprites. To set a material, open a gui collection and under “Script” in the properties you will find Material option. You can make another material with a tag for a second predicate and set it there.

4 Likes

How can I load another gui in main collection if I build another dialog gui and want to show it sometime then dismiss it? How to make it in code?

You can have lots of gui if you like. You can enable/disable components with a message:

1 Like

Set gui node material still doesn’t work. I am using the gui node as dialog background, the text in dialog disappeared and it can’t intercept the touch event distribute to the button behind the dialog background neither.

I’m struggling to understand what you’re trying to achieve, but I strongly suspect you’re overcomplicating it. Rather than switching materials, I think you’ll be much better off having two GUI components - one that is set to render behind sprites, and one that is rendered above as normal.

If you insist that that is not what you want, then I think you’ll need to explain in much greater detail exactly what you want to achieve (for me to get it, anyway).

What I did is exactly what you said. I add two GUI components, one that is set to render behind sprites, and the dialog one that is rendered above as normal . The weird thing is that the text in dialog gui disappeared but box texture were there. The dialog bg can’t intercept touch event behind neither. I don’t know why.

Ok, you’ll need to post some scripts or a minimal repro version of your project.

1 Like

For this feature, it is not something related to gui.script. I can post the render script.

function init(self)
	self.tile_pred = render.predicate({"tile"})
	self.gui_pred = render.predicate({"gui"})
	self.text_pred = render.predicate({"text"})
	self.hold_text_pred = render.predicate({"hold_text"})
	self.particle_pred = render.predicate({"particle"})
	self.fruits_pred = render.predicate({"fruits"})
	self.dialog_pred = render.predicate({"dialog"})

	self.clear_color = vmath.vector4(0, 0, 0, 0)
	self.clear_color.x = sys.get_config("render.clear_color_red", 0)
	self.clear_color.y = sys.get_config("render.clear_color_green", 0)
	self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
	self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)

	self.view = vmath.matrix4()

	-- default is stretch projection. copy from builtins and change for different projection
	-- or send a message to the render script to change projection:
	-- msg.post("@render:", "use_stretch_projection", { near = -1, far = 1 })
	-- msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 2 })
	-- msg.post("@render:", "use_fixed_fit_projection", { near = -1, far = 1 })
	self.near = -1
	self.far = 1
	self.projection_fn = stretch_projection

	local color_params = { format = render.FORMAT_RGBA,
			width = render.get_width(),
			height = render.get_height() } -- <1>
	local target_params = {[render.BUFFER_COLOR_BIT] = color_params }

	self.target = render.render_target("original", target_params) -- <2>
end

function update(self)
	render.set_depth_mask(true)
	render.set_stencil_mask(0xff)
	render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})

	render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())

	render.set_depth_mask(false)
	render.disable_state(render.STATE_DEPTH_TEST)
	render.disable_state(render.STATE_STENCIL_TEST)
	render.enable_state(render.STATE_BLEND)
	render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
	render.disable_state(render.STATE_CULL_FACE)

	-- render GUI
	--
	render.set_view(vmath.matrix4())
	render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))

	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.gui_pred)
	render.draw(self.text_pred)
	render.disable_state(render.STATE_STENCIL_TEST)

	render.set_view(self.view)
	render.set_projection(get_projection(self))

	render.draw(self.tile_pred)
	render.draw(self.fruits_pred)
	render.draw(self.particle_pred)
	render.draw_debug3d()

	render.set_view(vmath.matrix4())
	render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))

	render.enable_state(render.STATE_STENCIL_TEST)
	render.draw(self.hold_text_pred)
	render.draw(self.dialog_pred)
	render.disable_state(render.STATE_STENCIL_TEST)
end

Here is the gui script code I try to implement to prevent input event pass down, but the input event pass to gui behind the dialog gui.

function on_input(self, action_id, action)
	-- Add input-handling code here. The game object this script is attached to
	-- must have acquired input focus:
	--
	msg.post(".", "acquire_input_focus")
	if action_id == hash("touch") and action.pressed then
		if gui.pick_node(self.ok_btn, action.x, action.y) then
			gui.animate(self.ok_btn, gui.PROP_SCALE, vmath.vector3(1.1, 1.1, 1.1), gui.EASING_LINEAR, 0.3, 0, nil, gui.PLAYBACK_ONCE_PINGPONG)
			-- msg.post(".", "release_input_focus")
		end
	end
	--
	-- All mapped input bindings will be received. Mouse and touch input will
	-- be received regardless of where on the screen it happened.
	-- Learn more: https://defold.com/manuals/input/
	-- Remove this function if not needed
	return true
end

It doesn’t make sense to have this line in the on_input() function. If the on_input() function is called then you are already receiving input, and so this message is redundant.

Not sure what the issue is here. Are the ‘tags’ in your custom material correct? What is the tag for your text material? The default font material tag is ‘gui’ - so that would render underneath sprites in your render script. Perhaps you need to change the material tags for your fonts too.

1 Like

I don’t have much experience working with the input stack but this is the documentation.

It suggests that returning true in an on_input() function consumes all of the input (for all components with focus in the stack). So, if you are not getting input where you expect it, it probably means that input is consumed before it reaches the input function you expect. You therefore need to be mindful about how your stack is ordered.

I haven’t tested this, but it might be the case that constantly reacquiring focus in on_input() means that this component ends up always being on top of the stack. Since it returns true no matter what, it will consume the input for all other components.

1 Like

I already solve it in this way. Now I need to handle input event in input stack.