Letter by letter text function - SOLVED

Started by Kinoko, Wed 16/06/2004 15:59:16

Previous topic - Next topic

Kinoko

I'd like to know if someone could give me an idea of how to create a feature in an RPG I'm hoping to make with AGS. Basically, I'd like to be able to call a function with certain pieces of text that makes the text appear letter by letter until it has written the whole string out.

If anyone knows a program called 'ika', it uses a code based on a language called Python, which I'm very, very new to. I'll just show you a section in their tutorials that talks about how this program deals with this particular function.


QuoteScrolling
Looking at the pages isn't very interesting when it instantly all appears.. what we would like is for the text to scroll by character by character. Again, this isn't hard to do. We'll have a list to store the scroll positions of each line, and a variable to store which line is currently scrolling. Add this in between the two while loops:

Ã,  Ã,  Ã,  Ã, scroll = [0, 0, 0, 0]
Ã,  Ã,  Ã,  Ã, curline = 0

We put it here because we want these values to reset every time we reach a new page. Next, we need the part that actually does the work, which we add at the top of the for loop, before we Print:

Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã, if curline == i:
Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  scroll[curline] += 1
Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  if scroll[curline] == len(line): curline += 1

This says if we're looking at the currently scrolling line, increment its scroll position, and look at the next line once it's reached the end of the current one. Pretty simple. :)

Finally, a simple modification so that we print just the part of the line that we want:

Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã, font.Print(15, ika.Video.yres-70+15*i, line[:scroll])

The line[:scroll] part returns the string from the beginning of the line, to the current scroll position. As you can see, slicing is really coming in handy here. :)

Now if you run it, depending on your machine, it will either run way too fast, or too slow, or maybe just right depending on your framerate. This isn't good - we want it to scroll the same speed no matter what the framerate is.

Fortunately, it's again easy to modify. Insert this line just after curline = 0:

Ã,  Ã,  Ã,  Ã, time = ika.GetTime()

This will store the time when we started the loop. Now, inside the for loop, we want this:

Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã, if curline == i and ika.GetTime() - time >= 2:
Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  Ã,  time = ika.GetTime()

We added a part to the for loop that ensures at least 2 ticks go by before it scrolls to the next character. You can play with the number a little bit if you think it's too fast or too slow, although because ika only uses 100 ticks per second, the accuracy isn't as great as it could be.

The entire article can be found here: http://ika.sourceforge.net/articles.php?view=10


Obviously a lot of things in there are very specific to this particular code but I just put it there in case it gave anyone any ideas. I've had a bit of a think myself but I'm just -not- at the scripting level where I can do this without help.

Privateer Puddin'


Kinoko

#2
*groan* Why do these things always escape me? Thanks for that ^_^

I have to go to bed now before my head melts off but I'll try this in the morning. I suspect I'll have to do a bit of customisation in order to make this a function I can use often and not just for credits.

EDIT: OK, I've had a look at the script, and inserted it into a game but I get an error message that 'line1' is an undefined token.
EDIT2: Nope, fixed that with some 'int' lines. Though now I'm getting 'undefined symbol' for TypeLine.

Scorpiorus

Try putting the following line into the script header:

import function TypeLine(string line, int vspacing);

How is it going?

Kinoko

This time I got "Unresolved import" for TypeLine when I tried to test the game.

Scorpiorus

#5
Then make sure you have....

function TypeLine(string line, int vspacing, int xpos, int font, int colour, int width) {
Ã, 
//declare local vars
Ã,  int length=0;
Ã,  int i = 0;
Ã,  string displayedline;
Ã,  int textid = 0;
//initialise vars , overdoing it a bit ;-)
Ã,  length = 0;Ã, 
Ã,  i=0;
Ã,  StrCopy(displayedline," ");
Ã,  textid = CreateTextOverlay(xpos,50,400,font,colour,displayedline);

Ã,  Ã,  Ã,  Ã,  Ã,  //get string length, to know how long the loop must run
Ã,  length=StrLen(line); //set string length
Ã,  Ã,  Ã,  Ã,  Ã, //start loop
Ã,  while(i<length){
Ã,  Ã,  Ã,  Ã,  Ã, // pick character at position "i"and stick it at the end of string "displayed line"
Ã,  Ã,  StrFormat(displayedline, "%s%c", displayedline, StrGetCharAt(line,i));
Ã,  Ã,  Ã,  Ã,  Ã, //set textoverlay as displayedline
Ã,  Ã,  SetTextOverlay(textid, xpos,vspacing,width, font, colour, displayedline);

Ã,  Ã,  Ã,  Ã,  Ã, // if a space is added to the string do not play a sound, else play a 'tick'
Ã,  Ã,  if (StrGetCharAt(line,i) == ' '){
Ã,  Ã,  Ã,  Ã,  Ã, Wait(10);
Ã,  Ã, }
Ã,  Ã, else{
Ã,  Ã,  Ã,  Ã,  PlaySound(1);
Ã,  Ã,  Ã,  Ã,  Wait(5);
Ã,  Ã,  }
Ã,  Ã,  Ã,  Ã,  Ã,  Ã, //increase the loop counter
Ã,  Ã,  i++;
Ã,  }
Ã,  return textid;
}

... in the main global script.


EDIT: colour parameter was added
EDIT2: font and xpos were added
EDIT3: fixed xpos is't used
EDIT4: width was added

Kinoko

Now, I get undefined symbol, 'colour'

Scorpiorus

#7
Ah yeah, seems like originally it was a global variable. Just add one more paramter to the TypeLine(string line, int vspacing) function (see previous post). Also change the script header accordingly:

EDIT: the same with font and xpos variables:

import function TypeLine(string line, int vspacing,  int xpos, int font, int colour);

Kinoko

It was looking good there for a second. The game started up, and printed correctly, "first line". Then it all crashed and I got a fatal error:

An exception 0xC0000005 occured in ACWIN.EXE at EIP=0x0042270B;
program pointer is +6, ACI version 2.60.693, gtags (1,25)

It referred to this line:

  StrCopy(displayedline," ");

Scorpiorus

What's the code where you are trying to display a message?

Kinoko

Ah, it's okay. There were a couple of parameters missing from the TypeLine lines (though it only -now- gave me that error message) and there was a line break missing in one place. It works fine now, AND it seems to have solved my next task on it's own which was to get this kind of text inside a text window.

Thanks again, Scorpiorus ^_^ You're a champion.

Scorpiorus

No problem, you're welcome :)

Good luck with the game - it would be interesting to see an RPG made with AGS.

Kinoko

Something glaringly obvious I just noticed.

The text 'types' out alright, but only line 1, and then line 2, and then line 3, all appearing on screen (at the same spot) seperately. Line 1 will disappear as soon as line 2 starts, and so on. I honestly didn't really notice that it was doing this before and it's not what the code is supposed to do. To me, it seems like xpos is having no effect and that would back up my earlier thoughts about exactly how xpos was working (because I just for the life of me couldn't figure out from the global script how it was coded). I'm not sure why each line disappears disappears though, but then again I don't understand that much of the script anyway.

Just thought I should mention this before it gets thrown into the archives when there's still something wrong with it.

Scorpiorus

Hmm, I can't see why the line would disappear unless you remove it manualy with the RemoveOverlay function, for instance:

TypeLine ("line 1", 50, ...);
TypeLine ("line 2", 60, ...);
TypeLine ("line 3", 70, ...);

should display three lines.


but...

int id;

id = TypeLine ("line 1", 50, ...);
RemoveOverlay(id);

id = TypeLine ("line 2", 60, ...);
RemoveOverlay(id);

id = TypeLine ("line 3", 70, ...);
RemoveOverlay(id);

will remove a previous line before displayed the next one.


QuoteTo me, it seems like xpos is having no effect
Heh, yep I looked through the script and noticed that xpos is used only on initializing. We can modify it, though, to make it work as expected:

locate the line:
...
SetTextOverlay(textid, 10,vspacing,400, font, colour, displayedline);
...

and change it to:

SetTextOverlay(textid, xpos,vspacing,400, font, colour, displayedline);

Kinoko

Quote
//type lines and play sound of ticking machine
int line1;
line1 = TypeLine(" First Line", 5, 50, 1, 3);
Wait(60);
int line2;
line2 = TypeLine(" Second Line", 5, 75, 1, 3);
Wait(60);
int line3;
line3 = TypeLine(" 3rd Line.", 5, 150, 1, 3);
Wait(60);

//after a pause the text is removed again
RemoveOverlay(line1);
RemoveOverlay(line2);
RemoveOverlay(line3);

This is the code I was using in my room script. Taking away the "lineX =" lines and in lines now stops them from disappearing, so I guess that mystery is solved. (It does look stupid though, having text windows overlapping like that)

Scorpiorus

Yeah, that's because vspacing parameter is set to 5 for each function call, try:

TypeLine(" First Line", 5, 50, 1, 3);
TypeLine(" Second Line", 10, 75, 1, 3);
TypeLine(" 3rd Line.", 15, 150, 1, 3);

Kinoko

Yep, that offsets them, thanks.

Is there some glaringly obvious reason as to why the textboxes stretch horizontally off the right side of the screen?

Scorpiorus

Well, they are text overlays and thus go off the screen if displayed near its right edge.

Kinoko

These aren't displayed near the right edge. The text box is stretching far longer than the width of the text and basically goes across the whole top of the screen.

Scorpiorus

I'm not sure but if you want to adjust a text width then you can add one more parameter:

TypeLine(string line, int vspacing,  int xpos, int font, int colour, int width);

and replace:

SetTextOverlay(textid, xpos,vspacing,400, font, colour, displayedline);

with:

SetTextOverlay(textid, xpos,vspacing,width, font, colour, displayedline);

If it's not that then maybe you could post a screenshot to demonstrate the problem?

SMF spam blocked by CleanTalk