Launch different dialogues [Defold + Arcweave + DefArc] (solved)

Hello all :grinning:

I’m new to Defold, Arcweave, and DefArc. Please bare with me; I’m learning every day a bit more :slight_smile:

I hope someone can advise me on creating the basic code structure for a 2D dialogue game I started developing.

I followed a video tutorial from Unfolding Defold on making basic interactive dialogs in Defold. And I was wondering what the best way is to create the following:

I want to create stand-alone Arcweave boards per character and export them to JSON. (every character has its JSON file) And I want to start a character dialogue randomly or based on something that happened in the game.

Two questions:

  1. How to not display the dialogue anymore after the player finishes it?

I was thinking about writing a function that removes the dialogue from the screen instead of hiding it. Is this better for in-game memory usage?

  1. How do you launch a new dialogue after the first is finished? Let’s say after 30 seconds.

Maybe someone can share a simple timer.delay() code snippet with me that launch a new JSON file?

At the moment I have the following code:

local defarc = require "defarc.defarc"

local small_node = vmath.vector3(0.9)
local normal_node = vmath.vector3(1)
local options = {}

function show_text_and_options()
	-- Get and set text:
	local text = defarc.get_text()
	local node = gui.get_node("game")
	gui.set_text(node, text)

	-- Get and set options:
	options = defarc.get_options_table()

	for i = 1,4 do
		local option_text = options[i] and options[i].label or ""
		local option_node = gui.get_node("option"..i)
		gui.set_text(option_node, option_text)
		gui.get_blend_mode(node)
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	defarc.load("/assets/character-1.json")

	local starting_element = defarc.get_starting_element_id()
	
	defarc.select_element(starting_element)

	show_text_and_options()
end

-- hide hide_dialogue function
local function hide_dialogue()
	
	print("close dialogue")
end

function on_input(self, action_id, action)
	for i = 1,4 do
		local current_option_node = gui.get_node("option"..i)

		if gui.pick_node(current_option_node, action.x, action.y) then
			
			if action.pressed then
				gui.set_scale(current_option_node, small_node)
			elseif action.released then
				gui.set_scale(current_option_node, normal_node)

				defarc.select_element(options[i].target_id) -- select el

				show_text_and_options()

				-- hide the dialogue
				print("need to close dialogue")

				hide_dialogue()
			end
		end
	end 
end

Always happy to learn more, and thanks in advance :blush:

*Excuse any spelling mistakes; I’m dyslexic.

1 Like

@Pawel should be able to give advise on this!

2 Likes

Sure! Glad you started a journey with Defold and Arcweave :wink: I will try to answer and prepare some code example and tips tommorow, I will have some free time after work! :blush:

1 Like

Ok, so there are two approaches - you can either handle such logic in Lua script in Defold or try to use as much of Arcweave as possible:

1. Defold + Lua approach

You can for example create a table with data for each NPC - holding some flags, like conversation_x_happened or reached_y_node or more descriptive bob_insulted_mark_in_tavern. Then, before showing any text from DefArc - check those flags. Format of such table might be however you want - you can include here information about which node in Arcweave JSON it regards or which title in Node it regards. This actually might be easier, because you then describe the nodes in Arcweave with the same names as in Lua table, for example: Fiend starts or Fiend Attacks! and in Arcweave:

You can also utilize here components for checking events (Like I do above, where you notice the icons for events)

For randomness - perhaps you could name some of the starting nodes start_node_x and x would be a number, so in Defold you can generate this random in runtime, when you start a conversation with given NPC. Implementation is here written directly by you and you have full control over it and you only utilize DefArc, for getting text (and options) for elements you choose.

Notice DefArc allows you to choose elements not only by id, but also by a title of an element!
Take a look at API for e.g. get_text():


2. Arcweave approach

I think doing as much of the logic as possible in Arcweave is better, because you can then test it in Arcweave too - using directly the Play button there! Especially for your use cases.

DefArc comes with the example utilizing directly Sample Project from Arcweave. In this project there is a usage of variables shown - take a look at this node with an ArcScript:

This ArcScript is automatically parsed by DefArc in get_text() function - it will create such variable inside DefArc and if there will be any ArcScript detected later on and it will be parsing such variable - it will have this variable’s value already saved and will compare it then to give you a proper result.

In the SampleProject, when reaching node The small house - Examine the painting - the variable paintingExamined is created inside DefArc table and it’s value is stored there (in this case true). So after this node you will have a table in defarc.global_variables:

DEBUG:SCRIPT: 
{ --[[0x7f0580153330]]
  paintingExamined = true
}

(I added pprint(M.global_variables) inside DefArc’s M.save_variable_function())
Check out how it is happening automatically:


Later on, in the Arcweave’s Sample Project you see the Condition:

It is also automatically checked in defarc.get_options_table()
If condition in the ArcScript is not met, the option that is linked to it, will not be in the options_table. Otherwise, it will be there! :wink:

You can check out the conversation with the Knight, before examining the picture and after it (when new option will be available [You remember the name on the painting] ):

DefArc currently have 2 crucial parsers for ArcScript (check out the source code for those functions:)

local function arcscript_if_parser(splitted, start_at) - for parsing ArcScript if else conditions

local function arcscript_assingment_parser(splitted, start_at) - for assigning values to variables

There is a function in ArcScript for generating random value - but sadly, it is not yet implemented in the DefArc :frowning: If you would like it, you can modify the function:

function M.arcscript_code_parser(splitted, start_at)
    local next = splitted[start_at + 1]
    local next_len = string_len(next)

    if string_find(next, "elseif") then
	    next = string_sub(next, 7, next_len)

    elseif string_find(next, "endif") then
	    splitted[start_at] = ""			-- remove code opening tag
	    splitted[start_at + 1] = ""		-- remove endif tag
	    splitted[start_at + 2] = ""		-- remove code closing tag

    elseif string_find(next, "if") then	arcscript_if_parser(splitted, start_at)
    elseif string_find(next, "= ") then	arcscript_assingment_parser(splitted, start_at)
        -- Add here :
        -- elseif string_find(next, "random") then arcscript_random_parser(splitted, start_at)
    end
end

And write a function arcscript_random_parser analogically to other parsers, that will assign a random value (for example using Defold’s math.random())

More about ArcScript:
https://arcweave.com/docs/1.0/arcscript


A hint for the future:

I use Defold Printer by @Insality to print the text in my game instead of just putting the text using gui.set_text() (so in the first image you can notice Printer’s specific tags {strong} Text here {/} :wink:

9 Likes

@Pawel Thank you very much for your tips and explanation! :slight_smile: I’m going to look into it and work on it.

1 Like

@Pawel After reading a lot and looking at both suggested options, I Googled, YouTubed, and opened sample projects. I hope you can help me with a follow-up question.

In test_arcweave.gui_script, I saw an interesting code line. Is it possible to name an element in Arcweave “Exit” and, when this element is loaded, the dialogue will stop being displayed? So there will be no more dialogue going on the screen.

I was also trying some things with this line: msg.post(“dialogue”, “disable”), but not sure if this is the best thing to use.

test_arcweave.gui_script:

function on_input(self, action_id, action)
	for i = 1,3 do
		local current_option_node = gui.get_node("Option_"..i)

		if gui.pick_node(current_option_node, action.x, action.y) then	-- handle clicking on option nodes
			if action.pressed then
				gui.set_scale(current_option_node, vmath.vector4(0.9))	-- scale clicked options a little
			elseif action.released then
				gui.set_scale(current_option_node, vmath.vector4(1))	-- scale it back when released

				local jumper = defarc.get_jumper(options[i].target_id)
				if jumper then											-- if the target id is a jumper
					defarc.select_element(defarc.get_jumper_element_id(jumper))
				else
					defarc.select_element(options[i].target_id)			-- select next element
				end

				if defarc.get_element_title() == "Exit" then			-- if one of elements have title "Exit"
				defarc.select_element(defarc.get_starting_element())-- we will just start over (or we can quit the conversation here)
				
				end

				show_current_text_and_options()							-- display next text and options
			end
			return true
		end

	end
end

I will continue to research/try things out about the variables. Thank you for the tips. I also checkout Defold Printer, which looks like an excellent module to use in the project.

1 Like

Exactly, I use Exit as a title of the node in all my Arcweave projects - and like in this code, I end the conversations when such node is reached :blush:

It depends how you show dialogs - I do it in a separate gui which is a pop up in game - so when it ends - I hide this pop up. If you would like something like this, I can also recommend Monarch or Defold Svlcreen Manager - for screen management and showing pop ups like this :wink:

In the code above, instead of finishing the dialogue - it is started from beginning again :wink:

2 Likes

Hi @Pawel

Thank you so much for helping me start my project!

I look at Monarch, and it’s the perfect module for the game. I have already implemented it and now working on learning more about it.

Could you maybe help me a bit more with the Exit element function? What do you exactly mean by beginning?

I tried to test the function with a print-to console on different places in the code, but I probably have the code in the wrong place, or do I need to write it differently?

local defarc = require("defarc.defarc")
local monarch = require "monarch.monarch"

local small_node = vmath.vector3(0.9)
local normal_node = vmath.vector3(1)
local options = {}

function show_text_and_options()
	
	local text = defarc.get_text()
	local node = gui.get_node("game")
	gui.set_text(node, text)
	
	option = defarc.get_options_table()

	for i = 1,4 do
		local option_text = option[i] and option[i].label or ""
		local option_node = gui.get_node("option"..i)
		gui.set_text(option_node, option_text) 
		gui.get_blend_mode(node)
		
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	defarc.load("/assets/game.json")

	local starting_element = defarc.get_starting_element_id()
	defarc.select_element(starting_element)
	
	show_text_and_options()
end

-- function exit() -- testing function
-- if defarc.get_element_title() == "Exit" then		
-- 	defarc.select_element(defarc.get_element())
-- 	print("exit")
-- 	end
-- end

function on_input(self, action_id, action)
	
	if action_id == hash("touch") and action.pressed then
		if gui.pick_node(gui.get_node("dialogue_button"), action.x, action.y) then
			monarch.back()
		end
	end

	for i = 1,4 do
		local current_option_node = gui.get_node("option"..i)

		if defarc.get_element_title() == "Exit" then		
			defarc.select_element(defarc.get_element())
			print("exit")
		end
	
		if gui.pick_node(current_option_node, action.x, action.y) then
		
			if action.pressed then
				gui.set_scale(current_option_node, small_node)
			
			elseif action.released then
				gui.set_scale(current_option_node, normal_node)
				defarc.select_element(option[i].target_id)
			end
				show_text_and_options()
			end
		end
end

@Pawel It’s working now :slight_smile: I had something wrong in my JSON file :slight_smile:

Thank you for your tips :+1: :grinning:

2 Likes

Glad you managed! Let us know about the results anytime! :wink:

@Pawel I will do :slight_smile: I’m working on building the basic game system first. And after that, I will create a topic to show some progress on the game :smiley:

2 Likes