-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dialoger and FontEngine task distribution. #60
Comments
I'm going to put this here as well as that forum post. Basically I'm thinking we take the base dialog text and shove it into the parser to get back the following, and then shove that into the renderer to show it on screen.
|
Pre-existing FormatRange object: extra would hold, e.g. the colour to use if the type was colour. |
[QUOTE=Mme Sparklecakes XVII;6676646]What's wrong with the current FormatRange object, as far as styles go? More generalized, and you can add/ignore them whenever.[/QUOTE] Basically what I'm seeing as the problem is that they are broken apart when at any time you just want to know what font you should be applying to the text. You have to look at each range to decide what style to apply to the current letter. With my method adding a letter looks like. var curFormat = 0;
for (var curLetter = 0;curLetter<text.chars.length;curLetter++)
{
if (formats.length>curFormat+1&&formats[curFormat+1].index<=curLetter)
curFormat++;
addLetter(text.chars[curLetter],formats[curFormat]);
} While yours is slightly more complicated since you have to loop through the entire formatting array to find all possible applicable formats on each letter. Then you need to pull up your current formatting, and make changes. My way replaces all formatting only when something changes which is somewhat quicker. var curFormat = new Object();
for (var curLetter = 0;curLetter<text.chars.length;curLetter++)
{
for(var i = 0;formats.length>=i;++;)
{
if (curLetter>=formats[i].minIndex&&curLetter<=formats[i].maxIndex)
curFormat[formats[i].type]=formats[i].extra;
}
addLetter(text.chars[curLetter],curFormat);
} |
My way should be done as follows: As a bonus, you don't have to walk through every character and ask "okay, now?", you just have to look at the heads of the two queues and ask "when does my current style change?", and just jump to that. That means I can also render large blocks of text at once (generally a whole visual line, if there's no formatting on it), instead of character by character. I don't even need to consider characters which have no unique style. I'm doubtful this is how I actually implemented it, because I rushed it. Also no maintenance of an extra array the size of the the string (though you could replace your array with a map, honestly). |
Hmm yeah. I guess they would be about the same then. Honestly for the most part I just didn't see it way down there at the bottom until I had already gutted the rendering parts. For lines that only contain a single type of formatting my array would only have a single entry. If you weren't in the "typing" style of placement you would just grab the substring from the current format entry until the next one, plop them in a span, and set the span's style to whatever the format was. I guess the only major thing that makes me prefer my method is the fact that since I would be rendering with html something like "_Underline\0xaaaaaa\ColorChange_NotUnderlinedButStillColorChanged\0x" could mess up tag nesting. I'm probably over thinking it really. |
My syntax explicitly supports unbalanced tags. |
A compromise would be to return objects that specify the complete formatting at a point in the text, but only for the characters where the formatting actually changes. This way, the fact that my syntax supports unbalanced tags is obfuscated away, but it still supports my ability to just ask "when will it change next". Also no need to maintain two priority queues and a stack of active effects. All you need to do is ask "when will the style change next and to what", and render all the text up until that point with the current styles, without doing anything extra. |
This is exactly what my thing does. Whenever the formatting changes it stores the current formatting, and the index the change occurs at.
Not sure what you are saying here, but it is time for me to head to work so I'll look at it again in the morning. |
I got the impression from your description that you stored it for every character. The second half I was discussing there was that my method is just heavy on datastructures. |
So is the plan to split the Dialogger up into different parts now? If so it might be worthwhile to create an issue for each part so multiple people can work on them simultaneously without stepping on toes. |
That would seem to be the plan, but we're trying to settle how much each part should do, and how they should communicate. |
2 parts for all of text handing. One parts loads from the file and generates a completely generic object to be passed to the other part for doing whatever it takes to display it. |
Right, but does the parsing object handle parsing conversations into |
I think 'windows' should be handled by the parsing. After all, I think the goal would be that, for whatever language you use, you should get the same thing rendered regardless of if you use XML or CrazyAndrewFormat. (If we allow multiple rendering engines, than at least consistency when switching languages on the same renderer). |
By "windows" do you mean the automatic splitting of huge lines? If so the Dialoger should handle that, as windows may not be consistent in size or wrap method, resulting in different presentation. I think ideally the parser just gives you the lines, and the renderer figures out how it has to break it up and apply the styling. Changing the renderer will change how it looks in more ways then the internals. Changing the parser shouldn't matter. |
Right so Dialoger needs to be broken up as well too, then. And the parser |
By "windows" I mean the @'s delimiting a new sprite/window. |
I'm probably the most qualified to know what the hell it's supposed to be |
Oh, then yes the parser makes the "windows", parses the styling, etc etc. The renderer has to figure out what to do if the text is too long, figure out how to take the (now generic) style information and make the text actually styled (or ignore it if it doesn't know how). The idea is that there should be no need for any communication between parser and renderer other than "Hey here are the lines", and that any parser can work with any renderer. |
Maybe I'll make FontEngine be a third class that wraps FontParser and |
Why not take all the text and UI elements, and just put them in a div floating over the canvas? None of them update fast enough or do anything fancy enough to justify manually redrawing them every frame. I guess I'm kind of starting to sound like a broken record on this issue, but just hear me out. We have an xml file call it uiElements.xml or something. <sburb>
<ui>
<elements>
<element name="sound" position="5,5,50,50" command="toggleVolume" background="volumeControl"/>
<element name="leftActor" position="whatever"/>
<element name="rightActor" position="whatever"/>
<element name="chat" position="whatever"/>
<element name="hashtags" position="whatever"/>
<element name="endConversation" position="whatever" command="skipDialog">
> End Conversation.
</element>
<element name="data" position="whatever"/ "command="showSaveLoad"/>
<element name="pauseScreen" position="0,0,100%,100%" command="resumePlaying">
<center>
PUASED<br/>CLICK MOUSE TO RESUME<br/>FROM BELOW
</center>
</element>
<element name="chooser" position="whatever">
<select id="chooserSelectBox" size=5>
<option>The options will be replaced when the chooser is shown.</option>
</select>
</element>
</elements>
<states>
<state name="walkaround" show="canvas,sound,data,controls" setfocus="canvas"/>
<state name="dialog" show="sound,leftActor,rightActor,chat,endConversation" setfocus="chat"/>
<state name="pause" show="pauseScreen"/>
<state name="choose" show="chooser" setfocus="chooser"/>
</states>
</ui>
</sburb> So we have that right? Okay now for each of those elements we create a div which is nested inside the main SBURBgameDiv. We transform the internal stuff like having command="toggleVolume" in the sound control thing into javascript event declarations like onclick="Sburb.performAction('toggleVolume')" or whatever it would be. The rest of the attributes will be passed on to the div so you can set CSS stuff here or later in code. Only the elements listed in the show section of the current state will have their div shown. The "canvas" is exempt from being actually hidden, but it stops responding to events when it isn't shown in the current state. The setfocus thing determines what segment recieves keypress events. Every div should have a getfocus event so if they aren't currently supposed to be visible they will just put focus back to the current setfocus target of the state they are in after firing whatever their command is if they have one. As for the dialogs. <action class='meenahTalk1' sprite='latula' command='talk' name='Talk to Meenah.'><args>
@latula_happytalk LATULA: yo yo, p4ystubz my grrrl!
@meenah_idle MEENAH: shit tules
@meenah_talk:#passin-out-names-like-cheap-cuttlefish MEENAH: i forgot how many rad nicknames you like to cycle through
@meenah_fish MEENAH: you know i always thought paycheck was kind of dope why dont you just stick with that
@latula_happier:#WOO LATULA: r1ght on! 1 l1k3 th4t on3 too, p4ych3ck 1t 1z. H1GH F1V3 GRL!!!
@meenah_angry:#OOW MEENAH: no lets not OWWWWWW
@! -SNIP-
<!-- -->
</args></action> I think this is a good setup for a dialog data format. function dialog(text)
{
this.lines = new Array();
text = text.split("\n");
for (var i = 0;i<text.length;i++)
{
var line = text[i].match(/(@[^:\s]+)(:[^\s]*)?\s([^\n]*)/);
alert(text[i] + line);
if (!line)break;
var metadata = line[1].match(/([@_~%][^@_~%]+)/g);
if (line[2])metadata.push(line[2]);
//Metadata types can be determined by the first character
// @ = actor
// _ = sprite
// ~ = textbox image
// % = background image
// : = extra info/hashtags (must be last)
// We might want to add a metadata type for not parsing for formatting
// so people don't have to do a lot of underscore escaping
this.lines.push({meta: metadata, text: line[3], formatting = null});
}
}
function parseFormatting(dialog)
{
for (var i = 0;i<dialog.lines.length;i++)
{
var formattinginfo = new Array();
//Parse dialog.lines[i].text to extract the formatting into formattinginfo
//Strip out formatting codes from dialog.lines[i].text, and remove escape characters
//Set dialog.lines[i].text to the unformatted text
dialog.lines[i].formatting = formattinginfo;
}
}
//Example usage
var text = "@latula_happytalk LATULA: yo yo, p4ystubz my grrrl!\n @meenah_idle MEENAH: shit tules\n @meenah_talk:#passin-out-names-like-cheap-cuttlefish MEENAH: i forgot how many rad nicknames you like to cycle through\n @meenah_fish MEENAH: you know i always thought paycheck was kind of dope why dont you just stick with that\n @latula_happier:#WOO LATULA: r1ght on! 1 l1k3 th4t on3 too, p4ych3ck 1t 1z. H1GH F1V3 GRL!!!";
var latMeeDia = new dialog(text);
parseFormatting(latMeeDia); So much typing. Nearly bedtime. Hands sore. |
Because I'm burnt out on trying to render text with someone else's Also, pulling things out of the canvas makes shit waaaay more complicated. The HUD elements are already completely replaceable in SburbML. Everything Swapping out the text rendering engine is NOT a standard use case. Neither Also it seems all of us either have school or jobs to deal with. So we |
But hey, if you find a way to make a living off of this let me know. |
I'm actually sustained by yelling on the internet. |
I may have a tendency to get really fucking excited about whatever I start to do for the first few days. Possibly. Could be. I get you on the fork issue. Think I'll do that for a bit. You might want to look up where I edited in that wall of text and code to the last section. It actually has nothing to do with divs whatsoever. Just drop in the formatting decoder of your choice, and it is good to go. By the way the wiki is kind of screwed up because it still is pointing to Gankro\Jterniaborn links. I fixed the home page. All I had to do was open it and save it, and it was fine. |
I have submitted a tentative specification in #70 |
Specification is over here now: https://github.com/Gankro/Sburb/blob/text-engine/TextEngine.js I do not recommend integrating this work into master until there is working code to substitute the current structure. I will also not be doing further work on this effort as it simply does not interest me. The current system, while sloppy, is adequate for my purposes at this juncture in time. |
The only reason I want this change is so that the editor can spit out XML instead of the current dialog format. I think it would be easier to export that way. Still extremely low priority. |
I wouldn't really see the editor as the ideal place to write the dialog |
Have you looked into using an svg editor like inkscape? Import the sprite, put it where you want, open the object properties, set the id to the name, set the label to the class, and put whatever goes inside it into the description. Then you can just write an xslt to turn it into whatever you want. I'll keep plodding along with the text engine. I'm about 70% done with the parser. I'm thinking of moving all batching into the renderer because the parser has no need to worry itself about how shit fits on screen. If you don't mind too much I want to shift around a little about how the data is stowed and passed internally, and maybe in the markup. By preference it would be something like <dialog>
<box name='talk' background='dialogBox'>
<style name='speakerLeft' position='90,120' textDimensions='150,30,350,220' spritePos='-300,450;100,450'/>
<style name='speakerRight' position='20,120' textDimensions='30,30,350,220' spritePos='950,450;550,450'/>
<style name='hidden' position='-1000,120'/>
<style name='alert' position='56,120' textDimensions="30,30,450,220"/>
</box>
<actor name='meenah' frameInterval='6' x='-180' y='-524' font="color: #77003c;" actortags="meenah;">
<sprites>
<animation name='_idle' sheet='meenah_idle'/>
<animation name='_talk' sheet='meenah_talk' length='2'/>
<animation name='_angry' sheet='meenah_angry'/>
</sprites>
</actor>
<actor name='ariada' frameInterval='6' x='-245' y='-504' font='color: #a10000;' actortags='ariada;aa;'>
<animation name='_happy' sheet='aradia_happy' />
<animation name='_happytalk' sheet='aradia_happytalk' length='2' />
</actor>
</dialog> Right now I'm testing it with an html page which is working it's way up to be a basic dialog editor in it's own right. |
Oh while we are talking about workflows. What javascript ide are you guys using. I just started using aptana, but it is kind of clunky, and doesn't seem to want to push to git. Huge improvement over wordpad and notepad though. |
GEdit and command line git are all you need. Well, all you need if you are too lame to write with a magnetized needle. Also, breaking XML back-compatibility seems like a really, really bad idea... |
Nah the markup is fine as it is. Leave it be for now. Also the renderer already handles the vast majority of batching. All format parsing must be in the parser, or you're just writing FontEngine again. The parser already has no notion of how things "fit". It just specifies "I definitely want the text broken up AT LEAST here, but if you want more break points than go nuts". |
So what are you calling batching? Is non-batched
While batched would be
??? |
Non batched is just straight up text. e.g. "Blha blah blah" as opposed to "@what_huh blha blha blah" Chooser would use non-batched. Actually might just use no-format. |
But if we are parsing why would we ever return the @_~: tags? I strip all that off, and shove it in the various data orifices in TextParser or what have you. actors[]backgrounds[] ect Not sure where to get boxes[] from I need to stop working on it, but internet dude is still wireing everything so can't sleep yet. If I keep coding my incoherence will be come unreadable code. |
none mode: Do not interpret any syntax. Return the string verbatim with Given: |
Minor corrections, no_batch should have had all the underscores parsed out. |
boxes[] is the set of custom boxes to use on specific batches. If the default is to be used jut put null at that index. That stuff's described in the wiki page on dialogs. Dialoger did a lot of stuff. |
Pretty sure it isn't. Unless are boxes the ~tags? |
Right in there: |
Okay yeah my bad. Got that now. https://github.com/ikkonoishi/Sburb/tree/textengine I need to do more work on the renderer, and then I will start digging into the dialoger to get it working with the rest of the framework. |
The idea has come up of creating a generic API so that:
(a) The way conversations are displayed
(b) The way text formatting is parsed
(c) The way text is rendered
Are split up into three separate replaceable modules. Don't like how we render text? Swap it out. Don't like our syntax? Swap it out. Want conversations to just be alerts? Swap it out.
As it stands, (a) is handled by the Dialoger class for the most part. However it performs some of the roles of (b). For example it parses the text into "batches" (the @ delimiters).
(b) and (c) are handled by FontEngine, however for the most part, FontEngine is already broken up into essentially two parts, the parser and the renderer, via the parser handing the rendering code FormatRange objects, that describe what to render. However it ultimately is one object and shares a bunch of stuff.
The questions would then be:
Is it worth it?
Should the batch parsing be moved out of Dialoger, and/or Dialoger split into two objects (batch parser, and batch renderer)?
Should FontEngine be broken into two classes, FontParser and FontRenderer?
Also how would this be architected?
With not much thought it would make sense to me to do it something like:
DialogParser has a DialogRenderer has a FontParser has a FontRenderer, and the core engine basically just dumps the text to DialogParser and calls it a day. Similarly the command prompts just go straight to FontParser to handle themselves, I guess.
The text was updated successfully, but these errors were encountered: