|
Multiple TextBox Pages Displaying 1-7 of 7 total.
1
lynerd
|
Hello there everyone. First of all I would really like to thank Rpgking and Interface22 for having very nice and neat code that makes it much easier for a new person like myself to understand.
I want to have multiple pages to a text conversation and not just display the entire TextWrap array at one time. So it might display 2 of the lines and pop up a waiting arrow, the player hits enter and then the next 2 lines are shown, and etc.
Rpgking's DQ_WIP does exactly what I want, but his code is way too complicated at this point for me to understand. Though, I promise I will be looking over it again even after I post this.
My guess is I have to do something in the while loop, but everything I have tried has failed pretty badly. I have included my TextBox() code and a few of the variable declarations to make understanding it easier. I hope my comments in the code are helpful.
#define TEXT_BOX_FONT_WIDTH 8
#define TEXT_BOX_FONT_HEIGHT 8
#define TEXT_BOX_MAX_WRAP_LINES 4 //sentences visable at one time
#define TEXT_BOX_MAX_SPEECH 20 //max number of sentences in a speech
#define TEXT_BOX_MAX_LINE_LENGTH 296
#define TEXT_BOX_WAIT 2 //wait time till next char is printed
#define TEXT_BOX_VERT_SPACE 2 //space between printed lines
string TextWrap[TEXT_BOX_MAX_SPEECH]; //used to store the cut up lines of a text box
IMAGE TextBoxBG;
IMAGE TextBoxCursor;
FONT TextBoxFont;
//-------------------------------------------------------
//output the text box
void TextBox(string TextBoxString) {
int TextX, TextY, LineLength, NumberLines, CurPos, TotalLines, TextBoxX, TextBoxY, PlayerPos;
LineLength = TEXT_BOX_MAX_LINE_LENGTH;
PlayerPos = 1;
SetEntitiesPaused(TRUE); // Pause all entities while the text box is active
//is the player in the top half of the screen or the bottom half. call PlayerPos(); funct
if(PlayerPos) {
TextBoxX = TEXT_BOX_BG_TOP_X;
TextBoxY = TEXT_BOX_BG_TOP_Y;
}
else {
TextBoxX = TEXT_BOX_BG_BOTTOM_X;
TextBoxY = TEXT_BOX_BG_BOTTOM_Y;
}
//text position = text box position + text offset
TextX = TextBoxX + TEXT_BOX_TEXT_OFFSET_X;
TextY = TextBoxY + TEXT_BOX_TEXT_OFFSET_Y;
//We decrease by 1 since we're using it to handle the array textwrap[], which starts at 0, not 1.
NumberLines = WrapTextLines(TextBoxFont, TextBoxString) - 1; // Grab the number of lines to print.
TotalLines = NumberLines;
DrawTextBoxBG(TextBoxX, TextBoxY);
// Blit the text, letter by letter:
while (NumberLines >= 0) {
for (CurPos = 1; CurPos <= len(TextWrap[TotalLines - NumberLines]); CurPos++) {
PrintString(TextX, TextY, screen, TextBoxFont, left( TextWrap[TotalLines - NumberLines], CurPos));
ShowPage();
SkipWait(TEXT_BOX_WAIT);
}
NumberLines--;
TextY = TextY + (TEXT_BOX_FONT_HEIGHT + TEXT_BOX_VERT_SPACE);
}
Unpress(0); //clear the enter press, so the player doesn't skip the text box
WaitForEnter(); //pause to give the player time to read
ClearTextBoxVariables(); //clear out text arrary for next time
SetEntitiesPaused(FALSE); // Unpause all entities
}
Posted on 2007-05-01 10:48:18
|
Overkill
|
This is textbox code I wrote a while ago and often use in various things, with text wrapping and overflow detection.
#define TEXTBOX_ACCEPT_OVERFLOW 0
#define TEXTBOX_MINIMUM_LINES 0
#define TEXTBOX_PRINT_DELAY 5
#define TEXTBOX_FONT_HANDLE font_main
int default_textbox_x = 5;
int default_textbox_y = 5;
int default_textbox_width = ImageWidth(screen) - 10;
int default_textbox_maxlines = 2;
int textbox_x, textbox_y, textbox_width, textbox_maxlines, textbox_active;
void AlterTextBox(int tb_x1, int tb_y1, int tb_width, int tb_maxlines)
{
textbox_x = tb_x1;
textbox_y = tb_y1;
textbox_width = tb_width;
textbox_maxlines = tb_maxlines;
}
void DefaultTextBox()
{
AlterTextBox(default_textbox_x,
default_textbox_y,
default_textbox_width,
default_textbox_maxlines);
}
void TextBox(string tb_text)
{
int tb_font = TEXTBOX_FONT_HANDLE;
string tb_cur_text;
// Find the width and subract some. Because there is padding on all sides.
tb_text = WrapText(tb_font, tb_text, textbox_width - 16);
tb_cur_text = tb_text;
if (TEXTBOX_ACCEPT_OVERFLOW)
{
while (TokenCount(tb_text, chr('\n')) > 0)
{
if (TokenCount(tb_text, chr('\n')) + 1 > textbox_maxlines)
{
tb_cur_text = TokenLeft(tb_text, chr('\n'), textbox_maxlines);
//tb_cur_text = right(tb_cur_text, len(tb_cur_text) - 1);
tb_text = TokenRight(tb_text, chr('\n'), textbox_maxlines);
if (!len(tb_cur_text))
{
tb_cur_text = tb_text;
tb_text = "";
}
}
else
{
tb_cur_text = tb_text;
tb_text = "";
}
TextBoxHandler(tb_font, textbox_x, textbox_y, textbox_width, tb_cur_text, 1);
}
}
else
{
TextBoxHandler(tb_font, textbox_x, textbox_y, textbox_width, tb_cur_text, 1);
}
}
void TextBoxHandler(int tb_font, int tb_x1, int tb_y1, int tb_width, string tb_text, int tb_more)
// Pass: The font to use, the coordinates of the textbox, the
// prewrapped string to display, whether or not to draw a bobbing
// arrow at the bottom.
// Return: void
// Assumes: The font is valid
{
int done;
int box_time;
int mid_offset, line_offset, line_count;
string mid_text, line_text;
textbox_active = 1;
line_count = max(TokenCount(tb_text, chr(10)), TEXTBOX_MINIMUM_LINES);
Unpress(1);
box_time = systemtime + (len(tb_text) * TEXTBOX_PRINT_DELAY);
while (!done)
{
RectFill(0, 0, ImageWidth(screen), ImageHeight(screen), RGB(255, 0, 0), screen);
Render();
// Draw our textbox window.
DrawWindow(tb_x1, tb_y1, tb_x1 + tb_width, tb_y1 + 16 + (line_count * FontHeight(tb_font)), screen);
// Draw the "More text" arrow.
/*
if (tb_more)
{
TBlit(tb_x1 + tb_width - 16,
tb_y1 + (sin(systemtime * 2) * 4 >> 16) + 6 + (line_count * FontHeight(tb_font)),
img_arrow_down, screen);
}
*/
// Blit the lines of text.
PrintString(tb_x1 + 8, tb_y1 + 8, screen, tb_font, mid_text);
ShowPage();
// Increment the length our text midsection.
if (mid_offset < len(tb_text))
{
mid_offset = len(tb_text) - ((box_time - systemtime) / TEXTBOX_PRINT_DELAY);
if (mid_offset > len(tb_text)) mid_offset = len(tb_text);
}
mid_text = left(tb_text, mid_offset);
// Hitting B1 causes all text to appear.
if (b1 && mid_offset < len(tb_text))
{
Unpress(1);
mid_offset = len(tb_text);
}
// Hitting B1 can also cause us to exit this textbox loop.
else if (b1 && mid_offset == len(tb_text))
{
Unpress(1);
done = 1;
}
}
textbox_active = 0;
}
It makes reference to a builtin function called WrapText(), TokenLeft() and TokenRight(), and an updated PrintString which accepts line breaks, which can be found in the SVN build. (Username: anonymous, Password: anonymous) Also, replace DrawWindow with your own window drawing routine. This might be a little more than you need, so maybe just use it as a reference or tweak it to your requirements.
Also, this code was copypasta from a larger source file of mine, I hope all the requirements are there. Oh yeah, and call DefaultTextbox() in your Autoexec().
Posted on 2007-05-02 00:01:37 (last edited on 2007-05-02 21:20:23)
|
lynerd
|
The way yours works is really impressive and easy to understand when I go through it. Breaking off the sentences with tokens and then slowly displaying the whole line of text.
I had to do a little playing with the code to figure out that it was just slowly showing the entire sentence as opposed to printing it out letter by letter. (if that makes any sense)
I am still not 100% clear on what this piece of code is doing though.
if (mid_offset < len(tb_text))
{
mid_offset = len(tb_text) - ((box_time - systemtime) / TEXTBOX_PRINT_DELAY);
if (mid_offset > len(tb_text)) mid_offset = len(tb_text);
}
Posted on 2007-05-02 18:56:41 (last edited on 2007-05-02 20:11:23)
|
Overkill
|
Basically, it checks to see if the scrolling text has reached the end, and, if it hasn't reached the end yet, it uses a timestamp and divides that by the delay for each letter.
When the TextboxHandler is called initially, box_time is set to the current systemtime plus the time that each letter in the text will take to print. To get how much time has passed since the textbox started and have it be consistent across machines, (box_time - systemtime) is used, which will count up automatically as the engine loops along.
If you don't use timestamps, the only other good way to get timing to be the same on every machine is to use frame limiting. But that's a bit trickier, and little unnecessary if you only need it for the textbox, especially if you don't care about the frames in between you potentially miss. I suppose there's also HookTimer(), but that means a lot of ugly setup in advance, and once again does unnecessary extra work between drawn frames. Anyway, Verge's timing functionality is useful and important stuff.
Posted on 2007-05-02 21:15:51
|
lynerd
|
I notice you had commented out your cursor showing code for more text. I figured out how to make it appear at the end of the scrolling of the text and only if there would be more text after. I hope this is of help in some way.
if (TokenCount(tb_text, chr(NEWLINECHAR)) + 1 > textbox_maxlines)
{
tb_cur_text = TokenLeft(tb_text, chr(NEWLINECHAR), textbox_maxlines);
tb_text = TokenRight(tb_text, chr(NEWLINECHAR), textbox_maxlines);
if (!len(tb_cur_text))
{
tb_cur_text = tb_text;
tb_text = "";
}
TextBoxHandler(textbox_x, textbox_y, textbox_width, tb_cur_text, 1);
}
else
{
tb_cur_text = tb_text;
tb_text = "";
TextBoxHandler(textbox_x, textbox_y, textbox_width, tb_cur_text, 0);
}
Put this after your DrawWindow() function.
if(tb_more && ( len(mid_text) == len(tb_text) ) )
DrawTextBoxCursor(textbox_cursor_x, textbox_cursor_y);
Something I haven't figured out yet, is how you would make parts of your speech show up in a different color text. Like if a character said a clue or item name, have that in blue instead of the normal black and white text.
Posted on 2007-05-02 22:35:02
|
Overkill
|
Yeah, er, drawing stuff with font subsets would be a pain at the moment.
Posted on 2007-05-02 22:42:34
|
lynerd
|
I see it has been awhile since you have updated your tutorials, Overkill. Any chance that it will be worked on anymore? Your code is very easy to read and the tutorials have helped me quite a bit.
Posted on 2007-05-03 17:55:32
|
Displaying 1-7 of 7 total.
1
|
|