Text rendering displays text on the Scratch Stage with more flexibility than the usual use of the Say block, but does require more work. There are two main approaches:

  1. Rapid repeated use of the Say block, which produces a teletype style in a speech bubble.
  2. Using a set of sprite costumes to display images of letters.

Text Rendering with Say Block

This is a simple process, requiring two variables: "character number" and "text". The user also needs to define a Custom block, like this:

render text [] :: custom

The block's argument is the text or numbers to be rendered.


Defining the Custom Block

This is the defining script for the custom block:

define render text [string]
Set [character number v] to [1]
Set [text v] to []
Repeat ( length of (string))
  Set [text v] to (join (text)(letter (character number) of (string))
  Say (text)
  Change [character number v] by (1)
End

This custom block has been tested.[1]

It is imperative not to check the "run without screen refresh" checkbox when defining the Custom block. If it is checked, no text will be displayed. Note also that if the project is run in Turbo Mode, the teletype effect will be undetectable unless a Wait block or other delay is included in the Repeat block.

Text Rendering with a Sprite

The examples in this section use the Stamp block. It is possible to achieve the same visual effect by creating clones: Simply replace each Stamp block with a Create Clone of (myself) block. However, the use of clones has two disadvantages:

  1. The project will be more prone to lag.
  2. The Scratch maximum limit[2] of 300 clones limits the number of characters which could be displayed simultaneously.

Attempts at text rendering with sprites can produce unwanted results if the input string contains unanticipated characters.


Without Case Sensitivity

Firstly, obtain or create 26 costumes, one for each letter from a to z. Make sure each costume has the same lowercase name as the letter it represents. It is usually a good idea to have a costume to use as a space character. It is not possible to upload an image file named only with a space, but it is safe to rename it to a single space once it has been uploaded to Scratch. If other characters need to be used (e.g. punctuation and numbers) each will require a costume whose name is the same as the character.

A Custom block (see below) processes the provided text, rendering one letter at a time. It takes three parameters: The text to be rendered, the x position where it will be rendered, and the y position where it will be rendered. It is safe and usually desirable to set this Custom block to run without screen refresh.

define render text(text) at x:(text x) y:(text y)
set [old x v] to (x position) //remember original sprite position
set [old y v] to (y position)
go to x: (text x) y: (text y) //move to text start position
set [letter v] to [1]
repeat (length of (text))
switch costume to (letter (letter) of (text))
stamp//leave an image of this letter
change x by (letter width) //move to next letter position
change [letter v] by (1)
end
go to x: (old x) y: (old y) //return to original position

This Custom block has been tested.[3]

If all of the characters have the same width, it is safe to stop here. If not, see "Varying Letter Widths" below.


With Case Sensitivity

For case sensitivity, follow the Case Sensing tutorial before following this tutorial. The costumes in the Case Sensing tutorial are required. If any letters/characters outside of a to z need to be used, they will each require a costume whose name is the same as the character. Some characters that would be useful to add include: punctuation, numbers, and more.

The first step is to create a Custom block and to go through each letter of the message to be rendered. This Custom block will take three parameters. The text to be rented, the x position where it will be rendered, and the y position where it will be rendered. It should also run without screen refresh.

The variable letter will be used to remember which letter is being looked.

define render text [text] at x: (x pos) y: (y pos)
go to x: (x pos) y: (y pos)
set [letter v] to [1]
repeat (length of (text))
  change [letter v] by (1)
end

Next, switch to the appropriate case sensitive costume. Check the Case Sensing tutorial for how this is done. After one letter has been processed, move onto the next letter by increasing the x position.

define render text [text] at x: (x pos) y: (y pos)
go to x: (x pos) y: (y pos)
set [letter v] to [1]
repeat (length of (text))
  switch costume to (letter (letter) of (text)) //if the character is lowercase, it will stay on "null"
  if <(costume #) = (1)> then //if the sprite never changed costumes due to the letter being lowercase
    switch costume to (join (character) [t]) //all lowercase costumes end in "t" or a lettered choice (refer to pattern above)
  end
  if <(costume #) = (1)> then//if the sprite still has not changed costumes
    ... //there is a space, a character without a costume, or a costume with an incorrect name
    ... //assume it is a space
  else
    stamp
  end
  change x by (10)//change this number for more space between letters
  change [letter v] by (1)
end

If all characters have the same width, it is safe to stop here. If not, see Varying Letter Widths below.


Varying Letter Widths

This section builds on the tutorials Without Case Sensitivity and With Case Sensitivity above.

Because each letter (and character) can have a different width, it is sometimes necessary to take this into account to avoid large gaps between letters and overlapping letters.

To accomplish this, create a list named "Letter Widths". For each costume, enter its width (plus a pixel or two) into the list. Make sure that the costume number corresponds with the list number!

If there is a "null" costume, it also requires a number in the "Letter Widths" list. Because the "null" costume is assumed to be a space, make sure the corresponding list number is the width of a space.

In the text rendering script, replace:

change x by (10)

With:

change x by (item (costume #) of [Letter Widths v])

To test that all of the letter widths are correct, it can be helpful to print out every letter and character supported.


Making a Console

Sometimes, a list might need to be converted into an on-screen console. This is useful for games such as text adventures or RPGs. To do this, first create a list for the rendering script to read off of (call it "console"). So the above script needs to be slightly modified to make this work:

refresh screen

define refresh screen
repeat until <(length of [console v]) < [21]>
  delete (1 v) of [console v]
end
set [list item v] to [0]
repeat (length of [console v])
  change [list item v] by (1)
  render text (item (list item) of [console v]) at y: (((0) - ((list item) * (15))) + (175))

define render text [text] at y: (y pos)
go to x: (-230) y: (y pos)
set [letter v] to [1]
repeat (length of (text))
  switch costume to (letter (letter) of (text))
  if <(costume #) = (1)> then
    switch costume to (join (character) [t])
  end
  if <(costume #) = (1)> then
    change x by (5)
  else
    stamp
  end
  change x by (item(costume #) of [Letter Widths v])
  change [letter v] by (1)
end

This script will delete any excess items in "console" so that the text can fit on the screen. Make sure that the render script is on "run without screen refresh", or else it will take a really long time to refresh the screen.

To add an item to the console, simply use the "add [] to [console v]" block and the "refresh" block to update the console.

Note Note: The above script needs constant updating. One can also make a script that detects changes in the "console" list, then refreshes the screen.

See Also


References

  1. https://scratch.mit.edu/projects/139541622/
  2. https://wiki.scratch.mit.edu/wiki/Clone
  3. https://scratch.mit.edu/projects/139471922/