├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── PressStart2P-Regular.ttf ├── example.gif ├── metrics.png └── thumbnail.png ├── dtypewriter └── dtypewriter.lua └── game.project /.gitattributes: -------------------------------------------------------------------------------- 1 | # Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091) 2 | *.animationset linguist-language=JSON5 3 | *.atlas linguist-language=JSON5 4 | *.camera linguist-language=JSON5 5 | *.collection linguist-language=JSON5 6 | *.collectionfactory linguist-language=JSON5 7 | *.collectionproxy linguist-language=JSON5 8 | *.collisionobject linguist-language=JSON5 9 | *.cubemap linguist-language=JSON5 10 | *.display_profiles linguist-language=JSON5 11 | *.factory linguist-language=JSON5 12 | *.font linguist-language=JSON5 13 | *.gamepads linguist-language=JSON5 14 | *.go linguist-language=JSON5 15 | *.gui linguist-language=JSON5 16 | *.input_binding linguist-language=JSON5 17 | *.label linguist-language=JSON5 18 | *.material linguist-language=JSON5 19 | *.mesh linguist-language=JSON5 20 | *.model linguist-language=JSON5 21 | *.particlefx linguist-language=JSON5 22 | *.render linguist-language=JSON5 23 | *.sound linguist-language=JSON5 24 | *.sprite linguist-language=JSON5 25 | *.spinemodel linguist-language=JSON5 26 | *.spinescene linguist-language=JSON5 27 | *.texture_profiles linguist-language=JSON5 28 | *.tilemap linguist-language=JSON5 29 | *.tilesource linguist-language=JSON5 30 | 31 | # Defold JSON Files 32 | *.buffer linguist-language=JSON 33 | 34 | # Defold GLSL Shaders 35 | *.fp linguist-language=GLSL 36 | *.vp linguist-language=GLSL 37 | 38 | # Defold Lua Files 39 | *.editor_script linguist-language=Lua 40 | *.render_script linguist-language=Lua 41 | *.script linguist-language=Lua 42 | *.gui_script linguist-language=Lua 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.internal 2 | /build 3 | .externalToolBuilders 4 | .DS_Store 5 | Thumbs.db 6 | .lock-wscript 7 | *.pyc 8 | .project 9 | .cproject 10 | builtins 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 White Box Dev 2 | 3 | This software is provided 'as-is', without any express or implied warranty. 4 | In no event will the authors be held liable for any damages arising from the use of this software. 5 | 6 | Permission is granted to anyone to use this software for any purpose, 7 | including commercial applications, and to alter it and redistribute it freely, 8 | subject to the following restrictions: 9 | 10 | 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 11 | If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 12 | 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 14 | 15 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Defold Typewriter 2 | 3 | Defold Typewriter provides text scrolling and styling in a Defold game engine project. 4 | 5 | Please click the ☆ button on GitHub if this repository is useful or interesting. Thank you! 6 | 7 | ![alt text](https://github.com/whiteboxdev/library-defold-typewriter/blob/main/assets/thumbnail.png?raw=true) 8 | 9 | ## Installation 10 | 11 | Add the latest version to your project's dependencies: 12 | https://github.com/whiteboxdev/library-defold-typewriter/archive/main.zip 13 | 14 | ## Configuration 15 | 16 | Import the dtypewriter module into your gui script like so: 17 | 18 | ``` 19 | local dtypewriter = require "dtypewriter.dtypewriter" 20 | ``` 21 | 22 | Initialize dtypewriter with `dtypewriter.init()`. This function requires several metrics to properly align text content inside a textbox. The following image outlines what each parameter refers to: 23 | 24 | ![alt text](https://github.com/whiteboxdev/library-defold-typewriter/blob/main/assets/metrics.png?raw=true) 25 | 26 | The more interesting parameters are outlined here: 27 | 28 | 1. `container_node_id`: Each character in a textbox is created as an individual gui node. These nodes are adopted by a parent container node, which defines the origin position of each character. 29 | 2. `text_area_x`: X offset of text content. 30 | 3. `text_area_y`: Y offset of text content. 31 | 4. `text_area_width`: Total width of text content, which dictates the point of line wrap. 32 | 5. `line_count_max`: Number of lines to display in a textbox before beginning a new paragraph. 33 | 6. `line_offset`: Number of spacing pixels between each line. 34 | 35 | Text input must be parsed and loaded with `dtypewriter.load()` before being displayed with `dtypewriter.start()`. Text input should be formatted similarly to HTML elements. The following describes all element names and supported values: 36 | 37 | | Name | Description | Values | Examples | 38 | |-----------|--------------------------------------------------------|---------------------------------------|----------------------------------------------------| 39 | | line | Wrap to next line. | N/A | \ | 40 | | paragraph | Stop typing and wait, then move onto next paragraph. | N/A | \ | 41 | | color | Set color of next characters. | "default", string | \, \ | 42 | | speed | Set speed of next characters in characters per second. | "default", "instant", positive number | \, \, \ | 43 | 44 | The example animation was created by passing the following string into `dtypewriter.load()`: 45 | 46 | ``` 47 | "Just like the classic RPG dialog systems, dtypewriter is a fantastic dialog solution!It can do all kinds of neat things, like colors, speeds, and instant text display, among other things!" 48 | ``` 49 | 50 | Instead of changing the alpha of each character from 0 to 255 instantly, a smoother and more gradual fade can be enabled with `dtypewriter.set_fade_delay()`. The default fade value is 0. 51 | 52 | When a new paragraph is needed to continue displaying characters within the predefined textbox, characters will stop being typed and dtypewriter will wait until `dtypewriter.continue()` is called. 53 | 54 | The programmer will receive a message in their `on_message()` function on significant state changes, such as waiting for a new paragraph or typing a character. See the [API: Properties](https://github.com/whiteboxdev/library-defold-typewriter#dtypewritermessages) section for more information. 55 | 56 | Once the loaded text is done being typed, the programmer should call `dtypewriter.clear()` to clear internal tracking variables and free dynamically allocated resources. 57 | 58 | ## API: Properties 59 | 60 | ### dtypewriter.messages 61 | 62 | Table of messages that are passed to the `on_message()` function of your gui script. 63 | 64 | ``` 65 | dtypewriter.messages = 66 | { 67 | start = hash("start"), 68 | restart = hash("restart"), 69 | type = hash("type"), 70 | wait = hash("wait"), 71 | continue = hash("continue"), 72 | complete = hash("complete"), 73 | clear = hash("clear") 74 | } 75 | ``` 76 | 77 | 1. `start`: Loaded text is starting to be typed. 78 | 2. `restart`: Typing is restarted from the beginning. 79 | 3. `type`: An individual character is typed. 80 | 4. `wait`: No more characters can be typed within the boundaries of the textbox and a new paragraph must be started. 81 | 5. `continue`: A new paragraph is started. 82 | 6. `complete`: Loaded text is done being typed. 83 | 7. `clear`: Text is unloaded and resources are freed. 84 | 85 | ## API: Functions 86 | 87 | ### dtypewriter.init(container_node_id, font_id, text_area_x, text_area_y, text_area_width, line_count_max, line_offset, messages_url) 88 | 89 | Initialize dtypewriter. If dtypewriter was already initialized, call `dtypewriter.clear()` before reinitializing. 90 | 91 | #### Parameters 92 | 93 | 1. `container_node_id`: Container node that defines the origin position of each character node. 94 | 2. `font_id`: Hashed id of the font to use. 95 | 3. `text_area_x`: X offset of text content. 96 | 4. `text_area_y`: Y offset of text content. 97 | 5. `text_area_width`: Total width of text content. 98 | 6. `line_count_max`: Number of lines before starting a new paragraph. 99 | 7. `line_offset`: Number of spacing pixels between lines. 100 | 8. `message_url`: URL to where [dtypewriter messages](https://github.com/whiteboxdev/library-defold-typewriter#dtypewritermessages) are sent. 101 | 102 | --- 103 | 104 | ### dtypewriter.clear() 105 | 106 | Clear internal tracking variables and free dynamically allocated resources. This function should be called when text is no longer desired on screen, likely after `dtypewriter.messages.complete` is received in the `on_message()` function. 107 | 108 | --- 109 | 110 | ### dtypewriter.load(text) 111 | 112 | Load raw text to be parsed into formatted gui text nodes. Calls `dtypewriter.clear()` before performing any other tasks. 113 | 114 | #### Parameters 115 | 116 | 1. `text`: Raw text. See the [Configuration](https://github.com/whiteboxdev/library-defold-typewriter#configuration) section for information on how to insert styling elements. 117 | 118 | --- 119 | 120 | ### dtypewriter.start() 121 | 122 | Start typing characters after loading text with `dtypewriter.load()`. 123 | 124 | --- 125 | 126 | ### dtypewriter.restart() 127 | 128 | Restart typing characters after calling `dtypewriter.start()`. 129 | 130 | --- 131 | 132 | ### dtypewriter.continue() 133 | 134 | Continue onto the next paragraph after the end of a paragraph has been reached. 135 | 136 | --- 137 | 138 | ### dtypewriter.skip() 139 | 140 | Skip to the end of the current paragraph if characters are being typed. 141 | 142 | --- 143 | 144 | ### dtypewriter.add_color(name, color) 145 | 146 | Add a custom color in the `` element. If the color name already exists, it is overwritten. 147 | 148 | #### Parameters 149 | 150 | 1. `name`: Name of the color. 151 | 2. `color`: The color itself `vector4`. 152 | 153 | --- 154 | 155 | ### dtypewriter.set_default_color(color) 156 | 157 | Set a default color or in the `` element. 158 | 159 | #### Parameters 160 | 161 | 1. `color`: The color itself `vector4`. 162 | 163 | --- 164 | 165 | ### dtypewriter.clear_colors() 166 | 167 | Clear all custom colors, excluding the default color. 168 | 169 | --- 170 | 171 | ### dtypewriter.set_fade_delay(delay) 172 | 173 | Set the amount of time it takes for the alpha of an individual character to change from 0 to 255 when it is typed. The default value is 0. 174 | 175 | #### Parameters 176 | 177 | 1. `delay`: Amount of seconds for a character to become completely opaque. 178 | 179 | --- 180 | 181 | ### dtypewriter.set_default_type_speed(speed) 182 | 183 | Set the default type speed in characters per second in the `` element. 184 | 185 | #### Parameters 186 | 187 | 1. `speed`: Type speed in characters per second. 188 | 189 | --- 190 | 191 | ### dtypewriter.is_clear() 192 | 193 | Check if no text is loaded. 194 | 195 | #### Returns 196 | 197 | Returns `bool`. 198 | 199 | --- 200 | 201 | ### dtypewriter.is_loaded() 202 | 203 | Check if text is loaded with `dtypewriter.load()`. 204 | 205 | #### Returns 206 | 207 | Returns `bool`. 208 | 209 | --- 210 | 211 | ### dtypewriter.is_typing() 212 | 213 | Check if dtypewriter is actively typing. 214 | 215 | #### Returns 216 | 217 | Returns `bool`. 218 | 219 | --- 220 | 221 | ### dtypewriter.is_waiting() 222 | 223 | Check if the end of a paragraph has been reached and dtypewriter is waiting to move onto the next paragraph with `dtypewriter.continue()`. 224 | 225 | #### Returns 226 | 227 | Returns `bool`. 228 | 229 | --- 230 | 231 | ### dtypewriter.is_complete() 232 | 233 | Check if dtypewriter is done typing the loaded text, but has not yet been cleared with `dtypewriter.clear()`. 234 | 235 | #### Returns 236 | 237 | Returns `bool`. 238 | -------------------------------------------------------------------------------- /assets/PressStart2P-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/library-defold-typewriter/d5f854ae693b25c1952abc07ae675ab83a8b1f9b/assets/PressStart2P-Regular.ttf -------------------------------------------------------------------------------- /assets/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/library-defold-typewriter/d5f854ae693b25c1952abc07ae675ab83a8b1f9b/assets/example.gif -------------------------------------------------------------------------------- /assets/metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/library-defold-typewriter/d5f854ae693b25c1952abc07ae675ab83a8b1f9b/assets/metrics.png -------------------------------------------------------------------------------- /assets/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whiteboxdev/library-defold-typewriter/d5f854ae693b25c1952abc07ae675ab83a8b1f9b/assets/thumbnail.png -------------------------------------------------------------------------------- /dtypewriter/dtypewriter.lua: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- LICENSE 3 | -------------------------------------------------------------------------------- 4 | 5 | -- Copyright (c) 2024 White Box Dev 6 | 7 | -- This software is provided 'as-is', without any express or implied warranty. 8 | -- In no event will the authors be held liable for any damages arising from the use of this software. 9 | 10 | -- Permission is granted to anyone to use this software for any purpose, 11 | -- including commercial applications, and to alter it and redistribute it freely, 12 | -- subject to the following restrictions: 13 | 14 | -- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 15 | -- If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 16 | 17 | -- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 18 | 19 | -- 3. This notice may not be removed or altered from any source distribution. 20 | 21 | -------------------------------------------------------------------------------- 22 | -- INFORMATION 23 | -------------------------------------------------------------------------------- 24 | 25 | -- https://github.com/whiteboxdev/library-defold-typewriter 26 | 27 | ---------------------------------------------------------------------- 28 | -- PROPERTIES 29 | ---------------------------------------------------------------------- 30 | 31 | local dtypewriter = {} 32 | 33 | local _container_node 34 | 35 | local _font_id 36 | local _font 37 | 38 | local _text_area_x 39 | local _text_area_y 40 | local _text_area_width 41 | 42 | local _line_count_max 43 | local _line_offset 44 | 45 | local _chunks = {} 46 | 47 | local _characters = {} 48 | local _character_index 49 | local _paragraph_index 50 | 51 | local _waiting = false 52 | local _skip = false 53 | 54 | local _colors = {} 55 | local _default_color = vmath.vector4(1, 1, 1, 1) 56 | 57 | local _fade_delay = 0 58 | 59 | local _default_type_speed = 30 60 | 61 | local _messages_url 62 | 63 | local _callback_handle 64 | 65 | ---------------------------------------------------------------------- 66 | -- CONSTANTS 67 | ---------------------------------------------------------------------- 68 | 69 | dtypewriter.messages = 70 | { 71 | start = hash("start"), 72 | restart = hash("restart"), 73 | type = hash("type"), 74 | wait = hash("wait"), 75 | continue = hash("continue"), 76 | complete = hash("complete"), 77 | clear = hash("clear") 78 | } 79 | 80 | ---------------------------------------------------------------------- 81 | -- LOCAL FUNCTIONS 82 | ---------------------------------------------------------------------- 83 | 84 | local function strip_spaces(text) 85 | local remove_consecutive_spaces = string.gsub(text, "%s+", " ") 86 | local remove_front_spaces = string.gsub(remove_consecutive_spaces, "^%s+", "") 87 | local remove_back_spaces = string.gsub(remove_front_spaces, "%s+$", "") 88 | local remove_line_spaces = string.gsub(remove_back_spaces, "%s*%s*", "") 89 | return remove_line_spaces 90 | end 91 | 92 | local function add_chunk(type, data) 93 | local chunk = { type = type, data = data or {} } 94 | _chunks[#_chunks + 1] = chunk 95 | end 96 | 97 | local function add_character(chunk_index, text, color, speed) 98 | local character_data = { chunk_index = chunk_index, text = text, color = color, speed = speed } 99 | _characters[#_characters + 1] = character_data 100 | end 101 | 102 | local function set_transparent(color) 103 | return vmath.vector4(color.x, color.y, color.z, 0) 104 | end 105 | 106 | local function type_callback() 107 | msg.post(_messages_url, dtypewriter.messages.type) 108 | ::instant:: 109 | local character_data = _characters[_character_index] 110 | if _fade_delay > 0 then 111 | gui.animate(character_data.node, "color.w", 1, gui.EASING_LINEAR, _fade_delay) 112 | else 113 | gui.set_color(character_data.node, character_data.color) 114 | end 115 | _character_index = _character_index + 1 116 | local next_character_data = _characters[_character_index] 117 | if next_character_data then 118 | if character_data.paragraph < next_character_data.paragraph then 119 | msg.post(_messages_url, dtypewriter.messages.wait) 120 | _waiting = true 121 | elseif next_character_data.speed == 0 or _skip then 122 | goto instant 123 | else 124 | _callback_handle = timer.delay(1 / next_character_data.speed, false, type_callback) 125 | end 126 | else 127 | msg.post(_messages_url, dtypewriter.messages.complete) 128 | _callback_handle = nil 129 | end 130 | end 131 | 132 | ---------------------------------------------------------------------- 133 | -- MODULE FUNCTIONS 134 | ---------------------------------------------------------------------- 135 | 136 | function dtypewriter.init(container_node_id, font_id, text_area_x, text_area_y, text_area_width, line_count_max, line_offset, messages_url) 137 | _container_node = gui.get_node(container_node_id) 138 | _font_id = font_id 139 | _font = gui.get_font_resource(font_id) 140 | _text_area_x = text_area_x 141 | _text_area_y = text_area_y 142 | _text_area_width = text_area_width 143 | _line_count_max = line_count_max 144 | _line_offset = line_offset 145 | _messages_url = messages_url 146 | end 147 | 148 | function dtypewriter.clear() 149 | msg.post(_messages_url, dtypewriter.messages.clear) 150 | _text_raw = nil 151 | _chunks = {} 152 | for _, character_data in ipairs(_characters) do 153 | gui.delete_node(character_data.node) 154 | end 155 | _characters = {} 156 | _character_index = nil 157 | _paragraph_index = nil 158 | _waiting = false 159 | if _callback_handle then 160 | timer.cancel(_callback_handle) 161 | _callback_handle = nil 162 | end 163 | end 164 | 165 | function dtypewriter.load(text) 166 | dtypewriter.clear() 167 | text = strip_spaces(text) 168 | local chunk_start_index = 1 169 | local character_index = 1 170 | local character_color = _default_color 171 | local character_speed = _default_type_speed 172 | while character_index <= #text do 173 | local character = string.sub(text, character_index, character_index) 174 | if character == " " then 175 | local chunk_type = "content" 176 | local chunk_text = string.sub(text, chunk_start_index, character_index - 1) 177 | local chunk_data = { text = chunk_text, metrics = resource.get_text_metrics(_font, chunk_text) } 178 | add_chunk(chunk_type, chunk_data) 179 | chunk_type = "space" 180 | chunk_text = " " 181 | chunk_data = { text = chunk_text, metrics = resource.get_text_metrics(_font, chunk_text) } 182 | add_chunk(chunk_type, chunk_data) 183 | add_character(#_chunks, chunk_text, character_color, character_speed) 184 | chunk_start_index = character_index + 1 185 | character_index = character_index + 1 186 | elseif character == "<" then 187 | if string.sub(text, character_index, character_index + 6) == "" then 204 | local chunk_type = "content" 205 | local chunk_text = string.sub(text, chunk_start_index, character_index - 1) 206 | local chunk_data = { text = chunk_text, metrics = resource.get_text_metrics(_font, chunk_text) } 207 | add_chunk(chunk_type, chunk_data) 208 | chunk_type = "line" 209 | add_chunk(chunk_type) 210 | chunk_start_index = character_index + 6 211 | character_index = character_index + 6 212 | elseif string.sub(text, character_index, character_index + 10) == "" then 213 | local chunk_type = "content" 214 | local chunk_text = string.sub(text, chunk_start_index, character_index - 1) 215 | local chunk_data = { text = chunk_text, metrics = resource.get_text_metrics(_font, chunk_text) } 216 | add_chunk(chunk_type, chunk_data) 217 | chunk_type = "paragraph" 218 | add_chunk(chunk_type) 219 | chunk_start_index = character_index + 11 220 | character_index = character_index + 11 221 | end 222 | else 223 | add_character(#_chunks + 1, character, character_color, character_speed) 224 | if character_index == #text then 225 | local chunk_type = "content" 226 | local chunk_text = string.sub(text, chunk_start_index, character_index) 227 | local chunk_data = { text = chunk_text, metrics = resource.get_text_metrics(_font, chunk_text) } 228 | add_chunk(chunk_type, chunk_data) 229 | end 230 | character_index = character_index + 1 231 | end 232 | end 233 | local text_metrics = resource.get_text_metrics(_font, text) 234 | local paragraph = 1 235 | local line = 1 236 | local line_width_remaining = _text_area_width 237 | local character_x = _text_area_x 238 | local invalid_chunk_indices = {} 239 | for chunk_index, chunk in ipairs(_chunks) do 240 | if chunk.type == "paragraph" then 241 | line = 1 242 | line_width_remaining = _text_area_width 243 | paragraph = paragraph + 1 244 | character_x = _text_area_x 245 | elseif chunk.type == "line" or (chunk.data.text and line_width_remaining - chunk.data.metrics.width < 0) then 246 | line = line + 1 247 | line_width_remaining = _text_area_width 248 | if line > _line_count_max then 249 | line = 1 250 | paragraph = paragraph + 1 251 | end 252 | character_x = _text_area_x 253 | if chunk.type == "space" then 254 | invalid_chunk_indices[chunk_index] = true 255 | goto continue 256 | end 257 | end 258 | if chunk.data.text then 259 | for _, character_data in ipairs(_characters) do 260 | if character_data.chunk_index == chunk_index then 261 | local character_metrics = resource.get_text_metrics(_font, character_data.text) 262 | local character_position = vmath.vector3(character_x, -_text_area_y - (line - 1) * text_metrics.height + (line - 1) * _line_offset, 0) 263 | character_x = character_x + character_metrics.width + 1 264 | line_width_remaining = line_width_remaining - character_metrics.width - 1 265 | local character_node = gui.new_text_node(character_position, character_data.text) 266 | gui.set_parent(character_node, _container_node) 267 | gui.set_font(character_node, _font_id) 268 | gui.set_color(character_node, set_transparent(character_data.color)) 269 | gui.set_adjust_mode(character_node, gui.ADJUST_FIT) 270 | gui.set_pivot(character_node, gui.PIVOT_NW) 271 | character_data.node = character_node 272 | character_data.paragraph = paragraph 273 | end 274 | end 275 | end 276 | ::continue:: 277 | end 278 | for character_index = #_characters, 1, -1 do 279 | if invalid_chunk_indices[_characters[character_index].chunk_index] then 280 | table.remove(_characters, character_index) 281 | end 282 | end 283 | end 284 | 285 | function dtypewriter.start() 286 | if dtypewriter.is_loaded() then 287 | msg.post(_messages_url, dtypewriter.messages.start) 288 | _character_index = 1 289 | _paragraph_index = 1 290 | _callback_handle = timer.delay(0, false, type_callback) 291 | end 292 | end 293 | 294 | function dtypewriter.restart() 295 | if dtypewriter.is_typing() or dtypewriter.is_waiting() or dtypewriter.is_complete() then 296 | msg.post(_messages_url, dtypewriter.messages.restart) 297 | _character_index = 1 298 | _paragraph_index = 1 299 | _waiting = false 300 | if _callback_handle then 301 | timer.cancel(_callback_handle) 302 | end 303 | for character_index = 1, #_characters do 304 | local character_data = _characters[character_index] 305 | gui.set_color(character_data.node, set_transparent(character_data.color)) 306 | end 307 | _callback_handle = timer.delay(0, false, type_callback) 308 | end 309 | end 310 | 311 | function dtypewriter.continue() 312 | if _waiting then 313 | msg.post(_messages_url, dtypewriter.messages.continue) 314 | _waiting = false 315 | _paragraph_index = _paragraph_index + 1 316 | character_index = 1 317 | while character_index < _character_index do 318 | local character_data = _characters[character_index] 319 | gui.set_color(character_data.node, set_transparent(character_data.color)) 320 | character_index = character_index + 1 321 | end 322 | _callback_handle = timer.delay(0, false, type_callback) 323 | end 324 | end 325 | 326 | function dtypewriter.skip() 327 | if dtypewriter.is_typing() then 328 | if _callback_handle then 329 | timer.cancel(_callback_handle) 330 | end 331 | _skip = true 332 | type_callback() 333 | _skip = false 334 | end 335 | end 336 | 337 | function dtypewriter.add_color(name, color) 338 | _colors[name] = color 339 | end 340 | 341 | function dtypewriter.set_default_color(color) 342 | _default_color = color 343 | end 344 | 345 | function dtypewriter.clear_colors() 346 | _colors = {} 347 | end 348 | 349 | function dtypewriter.set_fade_delay(delay) 350 | _fade_delay = delay 351 | end 352 | 353 | function dtypewriter.set_default_type_speed(speed) 354 | _default_type_speed = speed 355 | end 356 | 357 | function dtypewriter.is_clear() 358 | return not _character_index and #_characters == 0 359 | end 360 | 361 | function dtypewriter.is_loaded() 362 | return not _character_index and #_characters > 0 363 | end 364 | 365 | function dtypewriter.is_typing() 366 | return _character_index and _character_index <= #_characters and not _waiting 367 | end 368 | 369 | function dtypewriter.is_waiting() 370 | return _waiting 371 | end 372 | 373 | function dtypewriter.is_complete() 374 | return _character_index and _character_index == #_characters + 1 375 | end 376 | 377 | return dtypewriter -------------------------------------------------------------------------------- /game.project: -------------------------------------------------------------------------------- 1 | [bootstrap] 2 | main_collection = /example/main.collectionc 3 | render = /rendercam/rendercam.renderc 4 | 5 | [script] 6 | shared_state = 1 7 | 8 | [display] 9 | width = 960 10 | height = 540 11 | 12 | [android] 13 | input_method = HiddenInputField 14 | 15 | [project] 16 | title = Defold Typewriter 17 | version = 1.0.0 18 | publisher = White Box Dev 19 | developer = White Box Dev 20 | dependencies#0 = https://github.com/rgrams/rendercam/archive/master.zip 21 | 22 | [graphics] 23 | default_texture_min_filter = nearest 24 | default_texture_mag_filter = nearest 25 | 26 | [library] 27 | include_dirs = dtypewriter 28 | 29 | --------------------------------------------------------------------------------