Giter Site home page Giter Site logo

textboxy's Introduction

textboxy


Twitter: @glitchroy

textboxy is using scribble by @JujuAdams. If you are looking for the old version, please see the textboxy-legacy repo.

In short, textboxy is a message box management system for GameMaker Studio 2.3 and up. The goal of textboxy is to provide a simple system for RPG-styled message boxes, either as a classic "textbox" (think Dragon Quest or Final Fantasy) or a "speech bubble" (something like the Mario & Luigi series). The messages should use a "typing" effect with sound.

Commands are defined in a simple queue, examples are pausing, setting and jumping to labels, changing message box properties and, of course, showing message boxes. Advanced features like flow control using conditionals are also implemented.

Features:

  • Drop-in solution for RPG styled textbox systems, either as standalone message boxes or "speech bubbles"
  • Powerful text system with a lot of built-in effects and control codes, courtesy of scribble by @JujuAdams
  • Easy to understand queue system, modeling the flow of the conversation
  • Management of line breaks and distribution of message boxes - you only need to focus on writing the content
  • Automatic linking of speech bubbles and speaker objects
  • Options to hook into the queue itself via callbacks
  • Global config script to manage defaults and input options
  • You can define your messages directly in GML, with support for external files planned

Due to the new GMS 2.3 update, the syntax is once again a work in progress, too. This is an example of how it looks currently:

var c = new TbyChain([
	new TbyChunk().add.box("This will show a message box!"),
	new TbyChunk().add.label("label1"),
	new TbyChunk().add.bubble("This will show a speech bubble above obj_talker!", instance_find(obj_talker, 0)),
	new TbyChunk().add.execute(show_message, "This executes a built-in script!"),
	new TbyChunk().add.branch(function() { return mouse_x < room_width/2 },
    [
      new TbyChunk().add.box("This executes if your mouse cursor is on the left side of the screen!"),
    ],
    [
      new TbyChunk().add.box("This would execute if the mouse cursor is on the right.")
    ]
	),
  new TbyChunk().add.box("Either way, you will resume the chain right here!"),
  new TbyChunk().add.pause(1),
  new TbyChunk().add.config("instance", instance_find(obj_talker, 0)),
  new TbyChunk().add.bubble("Now I don't need to specify a speaker anymore, since I set the chains' config!"),
  new TbyChunk().add.box("Let's start from the beginning...", "middle"),
  new TbyChunk().add.goto("label1")
]);

c.run();

If you have feedback regarding the syntax, you can open an issue or message me. Please excuse the lack of documentation or release builds. I'm trying to get to a working release as fast as possible!

textboxy's People

Contributors

glitchroy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

textboxy's Issues

Rename TbyBranch

In the ever so difficult pursuit of naming things correctly, I think there has to be a better alternative to TbyBranch.

  • TbySequence
  • TbyChain
  • TbyGroup
  • TbyTree

Sort out box dimensions

Use scribble internal systems to fix the mess that is "box size with padding" and "box size without padding". Ideally, TbyDim provides dimensions and padding and the rest is handled by scribble. Only the "outer box" would remain, while the text is automatically padded in.

Overview: Responsibilites of textboxy

In this doc, I will try to outline what responsibilites the textboxy project should have and how it is structured. Probably just for internal use and as an overview.

Different parts of textboxy

  1. textboxy is a dialogue management system. That means you should be able to create branching dialogue trees (of limited complexity) with effects such as pauses directly in-code. This dialogue tree should be indepentent from the actual representation of the dialogue.
    • Includes defining text and control codes, the flow of different dialogue passages, conditional branching and labels.
  2. textboxy is a textbox management system. That means it should take dialogue trees as code and display them in-game.
    • Includes performant drawing of the textbox and the text itself as well as special effects, drawing and positioning the textbox in relation to the game world or camera and taking and processing inputs from the player.

That means textboxy is split into a logical part that should handle defining the flow and content of the dialogue itself, and a displaying part, handling the drawing of text and textboxes.
How should these two responsiblities interact? Ideally, the logical part of textboxy is decoupled in such a way that in can be input from any source, e.g. the in-engine code or an external file. The displaying part should not care where the code is defined, as long as it is well-structured.

textboxy-drawer?

Should the two parts be split into two projects? Having a lightweight textboxy-drawer (or interpreter) as a add-on of sorts for scribble would allow game devs to only include that if they provide external dialogue trees.

What would a dedicated drawer have to include?

  1. Code for drawing and displaying text and textboxes
    • Scribble
    • Textbox drawing
    • Textbox sizing / positioning
  2. Code for handling the structure of the dialogue tree (input)
    • TbyBranch lifecycle logic
    • Data structure handling

Can point 2 be somehow included in the actual dialogue tree data, cutting the theoretical size of textboxy-drawer down to the actual drawing only?

Dialogue tree markup: textboxy-gen

How should the data that textboxy-drawer takes as input be structured? Let's call the in-code editor that works with TbyBranches textboxy-gen.

What would textboxy-gen need to include?

  • Exporting the content, logic, flow and branching of the dialogue tree into data.
  • Clear, understandable syntax for the end user that fits into GMS syntax.
  • Should not need any GMS objects or scribble dependency

Re-implement profiles

The legacy textboxy version had the concept of profiles, where a different configuration of options could be stored and applied on the fly. Otherwise, a lot of different options have to be set every time a character speaks. Possible profile options could be

  • Message sound
  • Text speed
  • Speaking instance
  • Textbox skin
  • Default color

In fact, every TbyOption could potentially be usuful in a profile sense (see the wiki).

A profile could be applied in a branch, maybe using a new script next to add and set, like tby_branch_profile(profile:Array). Profiles could be declared with tby_profile_create().
Profiles would have to be stored by the user in a variable.
Should profiles be a simple array, or contain identifying information such as the tby_list type?


/// @param tby_list
var tby_list = argument0;
if (ds_exists(tby_list, ds_type_list)) {
var meta = tby_list[| 0];
return (meta[TbyListMeta.IdentifierString] == "TBY_LIST")
}

Update to new GMEdit features

A new version of GMEdit released on 2019-10-02. Especially the #mfunc feature provides a new way for short functions to compile to macros. See if code can be shortened using this.

TbyType.Choice and handling more than two choices

In theory, TbyType.Choice should handle more than two answer options fine. Currently, it is created with a fixed 3 line height.

var position/*:TbyPos*/ = tby_normal_get_placement_from_enum(tbPlacement, 3);

The line amount would need to be dynamically calculated, based on the height of the previous text line and the amount of choices.

This also raises the question about handling TbyType.Choices in general -- what should be an upper limit to choices? A big enough textbox could obscure the entire screen. Should choices be in the same window at all, or in a different one? This topic is open for discussion.

TbyType.GoTo only works on labels that have been created prior in the branch

Currently, when a TbyType.Label is created, the pointer to the current branch entry is simply added to tby_current_labels_map. This means that a GoTo type that occurs before the label is "registered" fails to find the label.

case TbyType.Label:
//1: label name
global.tby_current_labels_map[? tbData[1]] = tby_list_get_pointer(tby_branch_get_active_id());
tby_branch_next_entry();
break;

There needs to be some sort of forward scan, recording all the Label types, either when the branch is first ran, or when the first GoTo type is found.

Plugin system

A system for users to register and use plugins would be a good idea. Maybe even re-write everything but the most basic features of the engine as plugins, so users can disable them if they want.

In the new GMS 2.3 version, tby_src_runtime() holds a big switch statement for every command. Since a plugin would most likely add on to this, maybe somehow split this into different files - a potential plugin would then just register this file and a signature for calling the command in TbyChunk.

Define instance properties in state scripts

For readability, explicitly define the instance properties like scribble_element in the tby_state_instance_* scripts as local variables.
Performance implications for primitives? Arrays should be passed by reference anyway.

top left of textbox not in the correct location

using the following code for example, you can see that the textbox does not correctly move the top left location when changing to the next queued item.

tbyAddAction(TbyAction.SetSpeaker, objPlayer);

tbyAddAction(TbyAction.ShowString, "This is the first line.");

tbyAddAction(TbyAction.ShowString, "What [c/red]crazy[r] and [c/orange]unique[r] adventures await?");

tbyAddAction(TbyAction.ShowString, "What the heck is going on here?\nWhy are you in my garden?\nGet out of here!");

tbyStart();

if the speaker moves once the textbox has been created, it will move to the correct location, otherwise the additional lines will cause the bottom of the textbox to overlap the speakers location.

Implement new scribble v5.0.0 version

Scribble v5.0.0 has been released and brings a whole lot of new stuff.

To-Do

  • Replace scripts
  • Adjust config file
  • Adjust init script
  • Adjust script calls in textbox object
  • Implement cache-system on a per-branch level

Tracked in /feature/scribble-5.0.0 branch.

Find better way to chain textbox creation

Currently, the Finished state calls the objTby to handle the next element in the branch. For this to work, objTby has to hold a reference to the current running branch. This is not as clean as I would like it.

Important things to consider:

  • Instances of objTbyInstance should not hold a reference to the entire branch. Instead, they should just be responsible for drawing their own box state
  • This means that either there has to be some global reference to the current state, or each objTbyInstance instance somehow holds a reference to the next element in the branch
  • objTbyInstance could also announce that it is finished and this could somehow trigger calling the next element, although this is not much different from the current implementation

Add TbyCmd.Script

There is a [script] message control code, no reason not to have a script callable on a branch level.
Is TbyConfig.Callback still needed now?

Restructure object instances

Restructure objTbyTextbox to not have full control over the branch and only show the information passed along.
Tracked in branch feature/new-object.

Higher textbox writing speeds are slower

A text speed is given using [ev|speed|<number>] message control code (see the wiki). The speed is used to check if the current step should forward the text counter. This is implemented using mod, meaning that a higher speed number leads to fewer forwarding steps, and thus, to a lower speed.

if (stateVar[0] mod textSpeed == 0) {

This seems counter intuitive from a usability standpoint, where one would think that a higher number corresponds to a higher speed. The implementation for this could be more difficult, however.

Font swapping on a per-message basis

This could be implemented as a TbyOption, e.g. TbyOption.SetFont, with a scribble declared font name.

//Start up Scribble and load some fonts
scribble_init_start( tby_texture_page_size );
scribble_init_add_spritefont("sprTbyFontMain",
SCRIBBLE_DEFAULT_SPRITEFONT_MAPSTRING + "«»",
-2);
scribble_init_add_spritefont("sprTbyFontSmall",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,-;:_+-*/|#[]",
-2);
scribble_init_end();

The default font is already defined as a scribble declared font name, in tby_default_font, but currently, the default is used for every message box.

textScribble = scribble_create(textRaw, pos[TbyPos.width], tby_default_font, fa_left, tby_default_color);

Add debug toggle to tby_config()

Whenever I create a new textbox it has above it in small letters "6 | state:" and then whatever state it's in, whether its Writing or Finished. Is there any way to disable this? I'm assuming it's some sort of debug setting but I don't see anything about it in TbyOptions.

Reference branches directly and not by id

Currently, the branch system uses ids (branch_names) to reference each other in the global global.tby_branches map. These ids get passed around and and referenced on the fly when needed.

I'm wondering if it would be cleaner to just pass the branch objects (arrays) around directly, since arrays do get passed by reference in GMS, thus no extra copies would be needed.

Rename "normal" textbox

"Normal" is just not a good name, especially considering the "bubble" type.
A simple tby_branch_box() could be fine.

Ensure proper destruction of data structures

With the new GMS 2.3 update, a garbage collector is implemented. Textboxy should make sure that everything that is not garbage collected (data structures) is destroyed correctly.
A TbyChain should have no expensive data structures associated, ideally. Global data structures shouldn't be a problem, since textboxy is running for the whole duration of the game.

Replace Conditional command type with Select

It would be more versatile to replace TbyCmd.Conditional with something that can branch in multiple paths, e.g. something like TbyCmd.Select (since "Branch" as a keyword is already taken, see #40 ).

This would work similar to the conditional, but instead of evaluating a condition, the variable is tested against each case, similar to a case/switch statement.

Data structure with index does not exist

Error thrown when using this code in my cutscene scripts. The box displays, but none of the content does. not sure if its a conflict with other code i'm using.

tbyAddAction(TbyAction.SetSpeaker, speaker);
tbyAddAction(TbyAction.ShowString, text);
tbyStart();


############################################################################################
ERROR in
action number 1
of Alarm Event for alarm 0
for object tbyText:

Data structure with index does not exist.
at gml_Object_tbyText_Alarm_0 (line 6) - var w = ccGrid[# tc, TbyCode.Wait];
############################################################################################

stack frame is
gml_Object_tbyText_Alarm_0 (line 6)

Alignement problem

I have used this text box system and i saw a problem using this settings:

SkinD
Calibri font 12 of size, bold
Using the text between man and old man in the documentation you can see the problem attached here:
textbox

Consolidate textbox instances to single instance

Currently, each textbox type has a seperate object. It would be beneficial and reduce shared code to use a single "textbox" instance for handling each type.

The instances mostly differ in the draw event. Since they already use a state machine for step events, maybe a modification could allow "draw states".

Shorthand script tby() for adding to the branch

The legacy textboxy had a tby(), I think it could be nice to implement this again, just as an easy access to tby_branch_add() (since the wait and options command already have a shorthand, too).

Text alignment on a per-message basis

This could be implemented as a TbyOption, e.g. TbyOption.SetAlignment, with left, center and right as options.
An alignment constant can be given to the scribble_create() script, which handles the correct drawing.

textScribble = scribble_create(textRaw, pos[TbyPos.width], tby_default_font, fa_left, tby_default_color);

The default would be fa_left, but this could very easily be a config option, e.g. tby_default_alignment.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.