Text which appears gradually

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
xNick1
Party member
Posts: 267
Joined: Wed Jun 15, 2016 8:27 am
Location: Rome, Italy

Text which appears gradually

Post by xNick1 »

I can't figure out how to make a text which appears gradually.
Do you have any idea about how to that? o.O
User avatar
xNick1
Party member
Posts: 267
Joined: Wed Jun 15, 2016 8:27 am
Location: Rome, Italy

Re: Text which appears gradually

Post by xNick1 »

My idea doesn't seem to work:

Code: Select all

string = "This lame example is twice as big."

for i = 1, #string do
        local c = string:sub(i, i)
        love.graphics.print(c, i * i, 90)      
        -- pause for half a sec  
end

User avatar
Sir_Silver
Party member
Posts: 286
Joined: Mon Aug 22, 2016 2:25 pm
Contact:

Re: Text which appears gradually

Post by Sir_Silver »

Code: Select all

local str = "This lame example is twice as big."
local time_per_letter = 0.5
local time_passed = 0
local current_letter = 0

function love.update(dt)
	time_passed = time_passed + dt
	
	if time_passed >= time_per_letter then
		time_passed = 0
		current_letter = current_letter + 1
	end
end

function love.draw()
	local chars = str:sub(1, current_letter)
	love.graphics.print(chars, 50, 50)      
end
I wrote this example up really hastily, so forgive me if it's buggy - it's definitely not good, - but I think it's accomplishing what you want, which I think it having text appear gradually from left to right. Use what I wrote, if it is what you want, to try to understand how it works and not just to copy it please. :P

Also, I don't recommended naming your strings "string" unless you don't care about using any functions from the string library.
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Text which appears gradually

Post by Positive07 »

So I wrote this fiddle
The math one is interesting... but I guess it's adhoc, I used a method similar to Sir_Silver's one, also I made one that changes the opacity since the post doesn't state that what he wants is a marquesina effect... he may just need a fade in effect so I wrote one too
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Text which appears gradually

Post by s-ol »

Here's how I did it in a recent moonscript project:

Code: Select all

  print: (lines, x, y, width, height, align, hover) =>
    if align == "right"
      x -= width - @limit

    height = 7

    chars = @chars
    for text in *lines
      if chars
        if chars < 1
          text = ""
        else
          start = text\sub 1, (utf8.offset(text, math.floor chars + 1) or math.floor chars + 1) - 1
          chars -= utf8.len text
          text = start\gsub "%%", ""

      lg.setColor 255, 255, 255, 255
      lg.printf text, x, y, width
      y += 7

  update: (dt) =>
    @chars = math.min @maxchars, @chars + dt * @speed if @chars and @maxchars
I don't have time to explain or translate it right now, but it could give you an idea

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
Positive07
Party member
Posts: 1014
Joined: Sun Aug 12, 2012 4:34 pm
Location: Argentina

Re: Text which appears gradually

Post by Positive07 »

xNick1 wrote:My idea doesn't seem to work:
This doesn't work for a few reasons, let's me explain so you can learn something from your own code too:

First problem, you are redefining [manual]string[/manual] (which is a Lua library) and that is not a good idea, you may need that elsewhere.
Use local variables and other variable names and you'll be fine

Code: Select all

local text = "This lame example is twice as big."

for i = 1, #text do
   local c = text:sub(i, i)
   love.graphics.print(c, i * i, 90)      
   -- pause for half a sec  
end
Second, you are drawing a single character
This is no good, because [wiki]love.draw[/wiki] actually erases the screen when it's called. This is easily fixed, instead of passing i twice to [manual]string.sub[/manual], we pass a 1 followed by the i, this gives us the characters from the first to the i th one

Code: Select all

local text = "This lame example is twice as big."

for i = 1, #text do
   local c = text:sub(1, i)
   love.graphics.print(c, 10, 90)      
   -- pause for half a sec  
end
Now, you can't pause for half a second, LÖVE runs in a loop, if you pause the loop then you'll get an unresponsive screen
Instead we use [wiki]love.update[/wiki], this function is called every frame, with a number that tell's us how much time passed since the last frame... if we add this up we get how much time has passed!
I also moved the print to a function called [wiki]love.draw[/wiki]

Code: Select all

local text = "This lame example is twice as big."
local timer = 0
local i = 0

love.update = function (dt)
   timer = timer + dt
   print(start) --You'll get an increasing number here, the number of seconds since the first frame
end

love.draw = function ()
   local c = text:sub(1, i)
   love.graphics.print(c, 10, 90)      
end
So now we need to check if our timer is bigger than half a second, when it is, we increase i by one and reset the timer

Code: Select all

local text = "This lame example is twice as big."
local timer = 0
local i = 0

love.update = function (dt)
   timer = timer + dt
   if timer > 0.5 then --Bigger than half a second
      i = i + 1
      timer = 0
   end
end

love.draw = function ()
   local c = text:sub(1, i)
   love.graphics.print(c, 10, 90)      
end
Great this already should give the expected effect, now there is ultra-small problem... If the window hangs and dt for some reason is a big number like 3 seconds, you'll still get a single character drawn instead of the expected 6
The solution is to use a loop like this:

Code: Select all

local text = "This lame example is twice as big."
local timer = 0
local i = 0

love.update = function (dt)
   timer = timer + dt
   while timer > 0.5 then
      i = i + 1
      timer = timer - 0.5
   end
end

love.draw = function ()
   local c = text:sub(1, i)
   love.graphics.print(c, 10, 90)      
end
This last step is not mandatory but will give you a better result.

Hope this helps!
for i, person in ipairs(everybody) do
[tab]if not person.obey then person:setObey(true) end
end
love.system.openURL(github.com/pablomayobre)
User avatar
xNick1
Party member
Posts: 267
Joined: Wed Jun 15, 2016 8:27 am
Location: Rome, Italy

Re: Text which appears gradually

Post by xNick1 »

Sir_Silver wrote:

Code: Select all

local str = "This lame example is twice as big."
local time_per_letter = 0.5
local time_passed = 0
local current_letter = 0

function love.update(dt)
	time_passed = time_passed + dt
	
	if time_passed >= time_per_letter then
		time_passed = 0
		current_letter = current_letter + 1
	end
end

function love.draw()
	local chars = str:sub(1, current_letter)
	love.graphics.print(chars, 50, 50)      
end
I wrote this example up really hastily, so forgive me if it's buggy - it's definitely not good, - but I think it's accomplishing what you want, which I think it having text appear gradually from left to right. Use what I wrote, if it is what you want, to try to understand how it works and not just to copy it please. :P

Also, I don't recommended naming your strings "string" unless you don't care about using any functions from the string library.
Thank you so much.
I like it written that way!
I'll try to readapt it to fit my needs.

And thank you so much Positive07, you're the man.
I didn't know the draw function erased everything,
so yeah, drawing everything with one more character every time makes sense!
Thank you for the explanation =)
zingo
Prole
Posts: 42
Joined: Mon Jan 16, 2023 7:34 am

Re: Text which appears gradually

Post by zingo »

I know this thread is kind of old, but I didn't want to start a new one being as this is more or less what I was already looking for, except one additional feature: I want to have different parts of the text being printed one letter at a time, in different colors. I was able to achieve this using multiple texts, and some hard-coded timing, but was hoping someone could help me achieve the same result in a more optimized way (if possible, for example, just having one text, etc.)

Code: Select all

--text one letter at a time, multicolored

--colors
local red = {1,0,0,1}
local green = {0,1,0,1}
local blue = {0,0,1,1}
local white = {1,1,1,1}
local black = {0,0,0,1}
local yellow = {1,1,0,1}
--

--texts
local textA = "This text is"
local textB = " red "
local textC = "and then white."

local a = "" --substitute with textA
local b = "" --substitute with textB
local c = "" --substitute with textC
--

--variables
local textLength = 32 --number of letters in the string
local timer = 0 --starting time
local delay = 0.05 --text delay, higher number = slower text
local i = 0 --current letter
--

function love.update (dt)
    
 if i < textLength then
   timer = timer + dt --deltatime
   while timer>0 do
      i = i+1
      timer = timer-delay
   end
 end
   
end

function love.draw (dt)
    
   if i<13 then 
    a = textA:sub(1,i) --current textA
   end    
    
   if i>12 then 
    b = textB:sub(1,i-12) --current textB
   end
   
   if i>17 then 
    c = textC:sub(1,i-17) --current textC
   end
   
   --print multicolor text
   love.graphics.print ({white,a,red,b,white,c},10,0)
   
   --print information
   love.graphics.print ('i='..i..'\nstring length = '..textLength,10,40)
   
end
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Text which appears gradually

Post by pgimeno »

zingo wrote: Fri Jul 07, 2023 4:41 am I know this thread is kind of old, but I didn't want to start a new one being as this is more or less what I was already looking for, except one additional feature: I want to have different parts of the text being printed one letter at a time, in different colors. I was able to achieve this using multiple texts, and some hard-coded timing, but was hoping someone could help me achieve the same result in a more optimized way (if possible, for example, just having one text, etc.)
An obvious answer is to have the texts in a single array with their colours. You'd have an index to the array and a pointer to the current character in the current index; when you complete one text, you advance the current index. Meanwhile you build another table with the contents that will go into love.graphics.printf (or print).

And if you plan to make it generic, i.e. translatable to other languages, don't forget to add support for Unicode.
zingo
Prole
Posts: 42
Joined: Mon Jan 16, 2023 7:34 am

Re: Text which appears gradually

Post by zingo »

I didn't quit understand all that, however I sort of got an idea of what you mean. Here's the updated code, where all the text is in just one table

Code: Select all

--text one letter at a time, multicolored

--colors
local red = {1,0,0,1}
local green = {0,1,0,1}
local blue = {0,0,1,1}
local white = {1,1,1,1}
local black = {0,0,0,1}
local yellow = {1,1,0,1}
--

--text
local text = {'This text is',' red ','and then white.',"","",""}
--

--variables
local textLength = 32 --number of letters in the string
local timer = 0 --starting time
local delay = 0.05 --text delay, higher number = slower text
local i = 0 --current letter (iteration)
--

function love.update (dt)
    
 if i < textLength then
   timer = timer + dt --deltatime
   while timer>0 do
      i = i+1
      timer = timer-delay
   end
 end
   
end

function love.draw (dt)
    
   if i<13 then 
    text[4] = text[1]:sub(1,i) --current text[4]
   end    
    
   if i>12 then 
    text[5] = text[2]:sub(1,i-12) --current text[5]
   end
   
   if i>17 then 
    text[6] = text[3]:sub(1,i-17) --current text[6]
   end
   
   --print multicolor text
   love.graphics.print ({white,text[4],red,text[5],white,text[6]},10,0)
   
   --print information
   love.graphics.print ('current letter = '..i..'\nstring length = '..textLength,10,40)
   
end
This is better, but I'm still having a bit of difficulty figuring out how to do the iteration without a bunch of "if/then" statements. Thank you for taking the time to reply, and for your patience.
Post Reply

Who is online

Users browsing this forum: No registered users and 77 guests