Does anybody have some examples of slowly appearing text?

This took me way longer than I expected to. An hour? Maybe two. I’m not very happy with it. But I haven’t seen any other examples of this.

function setup()
    local str = [[Hello! This is a test to animate the appearance of text. It is a work in progress.]]
    t = {}
    t[0]=""
    for i = 1, #str do
        t[i] = str:sub(i, i)
        print(t[i])
    end
end

-- function to slowly draw text at x,y every speedth frame
-- feed it an empty table holding a text key and a target array of text (see setup above)
-- use a table for subject because pointers
function slowText(x,y, subject, target, iter, speed)
    local i = iter.i
    local j = i+1
    if target[j] and time % speed == 0 then
        subject.text = subject.text .. table.concat(target, "", i, j)
        iter.i=iter.i+2
    end
    -- This stuff below is graphical, Codea only
    local w = textSize(subject.text)
    pushStyle()
    textWrapWidth(740)
    fontSize(20)
    fill(252)
    font("ArialMT")
    text(subject.text, x + (w/2), y)
    popStyle()
end
-- The draw function gets called once every frame
time = 0
iter = {i=0}
local str={text=""}
function draw()
    time = time + 1
    background(40, 40, 50)
    strokeWidth(5)
    slowText(28,280,str,t,iter,2)
    if time == 59 then time = 0 end
end


@xThomas Here an example. It should be made into a class to be able to display different text at different speeds at the same time.

function setup()
    textMode(CORNER)
    str ="Hello! This is a test to animate the appearance of text. It is a work in progress."
end

function draw()
    background(0)
    fill(255)
    slowText(10,300,str,20) -- change 20. Higher value mean slower display.
end

function slowText(x,y, subject,limit)
    if len==nil or cnt==nil then
        cnt=0
        len=1
    end
    if len<#str then
        if cnt<limit then
            cnt=cnt+1
        else
            len=len+1
            cnt=0
        end
    end
    text(string.sub(subject,1,len),x,y)
end

Here is a class version of the above code. More things can be added to the class.

displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    s1=slowText(50,200,20,color(255,0,0),20,"Hello! This is a test to animate the appearance of text. It is a work in progress.")
    s2=slowText(10,400,50,color(0,255,0),50,"Hello! This is a test to animate text, the end.")
end

function draw()
    background(0)
    s1:draw()
    s2:draw()
end

slowText = class()

function slowText:init(x,y,limit,col,size,str)
    self.x=x
    self.y=y
    self.col=col
    self.size=size
    self.str=str
    self.limit=limit
    self.len=1
    self.cnt=0    
end

function slowText:draw()
    pushMatrix()
    fill(self.col)
    fontSize(self.size)
    textMode(CORNER)
    if self.len<#self.str then
        if self.cnt<self.limit then
            self.cnt=self.cnt+1
        else
            self.len=self.len+1
            self.cnt=0
        end
    end
    text(string.sub(self.str,1,self.len),self.x,self.y)
    popMatrix()
end

Here’s another version where I added more to the class.

displayMode(FULLSCREEN)
supportedOrientations(LANDSCAPE_ANY)

function setup()
    s1=slowText(WIDTH/2,200,20,color(255,0,0),20,0,0,"Hello! This is a test to animate the appearance of text. It is a work in progress.")
    s2=slowText(400,HEIGHT/2,50,color(0,255,0),40,45,0,"Hello! This is a test to animate text, work in progress.")
    s3=slowText(WIDTH/2+100,HEIGHT/2,50,color(255,255,0),40,0,.1,"Hello!")
end

function draw()
    background(0)
    s1:draw()
    s2:draw()
    s3:draw()
end

slowText = class()

function slowText:init(x,y,limit,col,size,ang,inc,str)
    self.x=x
    self.y=y
    self.col=col
    self.size=size
    self.ang=ang
    self.str=str
    self.inc=inc
    self.limit=limit
    self.len=1
    self.cnt=0    
end

function slowText:draw()
    pushMatrix()
    fill(self.col)
    fontSize(self.size)
    if self.len<#self.str then
        if self.cnt<self.limit then
            self.cnt=self.cnt+1
        else
            self.len=self.len+1
            self.cnt=0
        end
    end
    translate(self.x,self.y)
    self.ang=self.ang+self.inc
    rotate(self.ang)
    text(string.sub(self.str,1,self.len),0,0)
    popMatrix()
end

this typewriter function makes it so you write text, standard alignment is left. as you make new lines it makes the old text go towards the top of the screen. note that codea will not draw text if textsize is greater than the sceeen. and this is a very minimal implementation, i made it this way by accident trying to do something else. What I actually wanted to do was different but whatever.

I think textAlign(LEFT) is bugged a bit, as when you try to draw text on only one line, it doesn’t actually do the aligning. You need at least two lines.

-- typewriter

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
end

local long = [["gagshgjhdghsjgjhfgsgfhjshjfjhgdjhfgjhdgfhjgsjhfgjhhgfhgjdhgfhjdjfhgdjhfgjhdgfjhgdjhfgjhdgfjhgdfjhgejhfgjhdgfjhgdfhjgdjhfghjdgfhjgdjhfgjhgdfjhgejhfgjhgjhrgfjhgrfhjgjhdfgjhgdfjhgjrhfghjrgfjhr\
\
ijsgkjgdjkgfhkdgjfjghdkfghkghjgjhgjhghjg^>#^%\\#^{%#^%]#{^%#{]%}^*^#[]^*^]{"]]
-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    fill(177)
    fontSize(15)
    font("Inconsolata")
    textWrapWidth(312)
    typewriter('Apple Banana Crayon Dog Eagle Falcon Greens Ohayo')
    typewriter(long, 6, 200,399)
    -- Do your drawing here
    
end

local textObject = {
    text = "\
",

}

--[[
Auxilary function for animating text one character at a time. Made for RPG games.
Tries to align text to the left so that character n is always at the same x,y position
no matter the string. For this reason please use monospaced fonts.
The first parameter is the string to animate. The optional second parameter is the 
speed to draw at in frames per second. (default is 6). Third and fourth determine where
to draw the text. Always aligns LEFT. 

todo: add align mode

Returns  String of textObject.text if called without first parameter
]]

local count = 0
local time = 0
function typewriter(characters, fps, x, y)
    if not characters then
        return textObject.text
    else
        characters = '\
'..characters   --keeps first line display correctly
        time = time + 1
        fps = fps or 6
        if time % fps == 0 then count = count + 1 end
        x = x or 0
        y = y or 0
        if textObject.text ~= characters then
            textObject.text = string.sub(characters, 1, count)
            textAlign(LEFT)
            local w,h = textSize(typewriter())
            local wrap = textWrapWidth()
            local x = x + w/2
            local y = y + h/2
            
            text(textObject.text, x, y)
        else
            textAlign(LEFT)
            local w,h = textSize(typewriter())
            local wrap = textWrapWidth()
            local x = x + w/2
            local y = y + h/2
            text(textObject.text, x, y)
        end
    end
end

function touched(touch)
    if touch then showKeyboard() end
end

function keyboard( key )
    long = keyboardBuffer()
end