Tutorials
Tutorials

This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this tutorial in English

Level complete - projeto de exemplo

Neste projeto de exemplo, que você pode abrir pelo editor ou baixar do GitHub, demonstramos efeitos para mostrar a contagem de pontuação que poderia ocorrer quando um nível é concluído. Uma pontuação total é contada para cima e três estrelas aparecem quando diferentes níveis de pontuação são alcançados. O exemplo também usa a funcionalidade de reload para permitir iterações rápidas ao ajustar valores.

A cena é acionada por uma mensagem do jogo. A mensagem contém a pontuação total obtida e em quais níveis de pontuação as três estrelas devem aparecer. Quando isso acontece, o texto do título (“Level completed!”) aparece gradualmente enquanto é reduzido até o tamanho regular (100%). Isso é feito em on_message() abaixo.

Depois que a animação do texto do título é concluída, a pontuação total começa a contar para cima. Cada vez que isso acontece, a pontuação atual é incrementada em um pequeno passo. Então verificamos se um dos níveis das estrelas foi cruzado; nesse caso, a animação de uma estrela começa (veja abaixo). Enquanto não alcançamos a pontuação-alvo, a pontuação total é animada com um efeito de quique. Ela também cresce em direção a uma escala máxima conforme se aproxima da pontuação total. Da mesma forma, sua cor muda gradualmente de branco para verde. Isso é feito em inc_score().

Cada vez que uma estrela aparece, ela surge gradualmente e encolhe até o tamanho regular. Isso é feito em animate_star().

Quando a estrela termina de animar, estrelas menores são criadas em um círculo ao redor da estrela maior. Isso é feito em spawn_small_stars().

Depois, elas são animadas para disparar aleatoriamente a partir da estrela. Tanto a velocidade quanto a escala são randomizadas enquanto elas se expandem para fora. Em seguida, elas desaparecem e finalmente são removidas. Isso é feito em animate_small_star() e delete_small_star().

Quando a pontuação alcança a pontuação total, a marca de high-score aparece gradualmente e encolhe de volta para o lugar. Isso começa no final de inc_score() e é executado em animate_imprint().

A função setup() garante que os nodes tenham os valores iniciais corretos. Ao chamar setup() a partir de on_reload(), garantimos que tudo seja configurado corretamente sempre que o script for recarregado pelo Defold Editor.

-- file: level_complete.gui_script

-- velocidade com que a pontuacao e incrementada por segundo
local score_inc_speed = 51100
-- quanto tempo entre cada atualizacao da pontuacao
local dt = 0.03
-- escala da pontuacao no inicio da contagem
local score_start_scale = 0.7
-- escala da pontuacao quando a pontuacao-alvo foi alcancada
local score_end_scale = 1.0
-- quanto a pontuacao "quica" a cada incremento
local score_bounce_factor = 1.1
-- quantas estrelas pequenas criar para cada estrela grande
local small_star_count = 16

local function setup(self)
    -- torna a cor do titulo transparente
    local c = gui.get_color(self.heading)
    c.w = 0
    gui.set_color(self.heading, c)
    -- torna a sombra do titulo transparente
    c = gui.get_shadow(self.heading)
    c.w = 0
    gui.set_shadow(self.heading, c)
    -- define o titulo inicialmente com o dobro da escala
    local s = 2
    gui.set_scale(self.heading, vmath.vector3(s, s, s))
    -- define a pontuacao inicial (0)
    gui.set_text(self.score, "0")
    -- define a cor da pontuacao como branco opaco
    gui.set_color(self.score, vmath.vector4(1, 1, 1, 1))
    -- define a escala para que a pontuacao possa crescer durante a contagem
    gui.set_scale(self.score, vmath.vector4(score_start_scale, score_start_scale, 1, 0))

    -- torna todas as estrelas grandes transparentes
    for i=1,#self.stars do
        gui.set_color(self.stars[i], vmath.vector4(1, 1, 1, 0))
    end
    -- torna a marca transparente
    gui.set_color(self.imprint, vmath.vector4(1, 1, 1, 0))
    -- a pontuacao sendo exibida atualmente
    self.current_score = 0
    -- a pontuacao-alvo durante a contagem
    self.target_score = 0
end

function init(self)
    -- recupera nodes para facilitar o acesso
    self.heading = gui.get_node("heading")
    self.stars = {gui.get_node("star_left"), gui.get_node("star_mid"), gui.get_node("star_right")}
    self.score = gui.get_node("score")
    self.imprint = gui.get_node("imprint")
    -- cor inicial da pontuacao
    self.score_start_color = vmath.vector4(1, 1, 1, 1)
    -- salva a cor da pontuacao e anima em direcao a ela durante a contagem posteriormente
    self.score_end_color = gui.get_color(self.score)
    setup(self)
end

-- remove uma estrela pequena, chamado quando a estrela terminou de animar
local function delete_small_star(self, small_star)
    gui.delete_node(small_star)
end

-- anima uma estrela pequena de acordo com a posicao inicial e o angulo dados
local function animate_small_star(self, pos, angle)
    -- direcao de deslocamento da estrela pequena
    local dir = vmath.vector3(math.cos(angle), math.sin(angle), 0, 0)
    -- cria uma estrela pequena
    local small_star = gui.new_box_node(pos + dir * 20, vmath.vector3(64, 64, 0))
    -- define sua textura
    gui.set_texture(small_star, "small_star")
    -- define sua cor como branco total
    gui.set_color(small_star, vmath.vector4(1, 1, 1, 1))
    -- define escala inicial baixa
    local start_s = 0.3
    gui.set_scale(small_star, vmath.vector3(start_s, start_s, 1))
    -- variacao na escala de cada estrela pequena
    local end_s_var = 1
    -- escala final real desta estrela
    local end_s = 0.5 + math.random() * end_s_var
    gui.animate(small_star, gui.PROP_SCALE, vmath.vector4(end_s, end_s, 1, 0), gui.EASING_NONE, 0.5)
    -- variacao na distancia percorrida (essencialmente a velocidade da estrela)
    local dist_var = 300
    -- distancia real que a estrela percorrera
    local dist = 400 + math.random() * dist_var
    gui.animate(small_star, gui.PROP_POSITION, pos + dir * dist, gui.EASING_NONE, 0.5)
    gui.animate(small_star, gui.PROP_COLOR, vmath.vector4(1, 1, 1, 0), gui.EASING_OUT, 0.3, 0.2, delete_small_star)
end

-- cria varias estrelas pequenas
local function spawn_small_stars(self, star)
    -- posicao da estrela grande ao redor da qual a estrela pequena sera criada
    local p = gui.get_position(star)
    for i = 1,small_star_count do
        -- calcula o angulo da estrela pequena especifica
        local angle = 2 * math.pi * i/small_star_count
        -- assim como a posicao
        local pos = vmath.vector3(p.x, p.y, 0)
        -- cria e anima a estrela pequena
        animate_small_star(self, pos, angle)
    end
end

-- inicia a animacao de aparecimento gradual de uma estrela grande
local function animate_star(self, star)
    -- duracao do aparecimento gradual
    local fade_in = 0.2
    -- torna-a transparente
    gui.set_color(star, vmath.vector4(1, 1, 1, 0))
    -- aparece gradualmente
    gui.animate(star, gui.PROP_COLOR, vmath.vector4(1, 1, 1, 1), gui.EASING_IN, fade_in)
    -- escala inicial
    local scale = 5
    gui.set_scale(star, vmath.vector3(scale, scale, 1))
    -- encolhe de volta para o lugar
    gui.animate(star, gui.PROP_SCALE, vmath.vector4(1, 1, 1, 0), gui.EASING_IN, fade_in, 0, spawn_small_stars)
end

-- inicia a animacao de aparecimento gradual da marca
local function animate_imprint(self)
    -- espera um pouco antes de a marca aparecer
    local delay = 0.8
    -- duracao do aparecimento gradual
    local fade_in = 0.2
    -- escala inicial
    local scale = 4
    gui.set_scale(self.imprint, vmath.vector4(scale, scale, 1, 0))
    -- encolhe de volta para o lugar
    gui.animate(self.imprint, gui.PROP_SCALE, vmath.vector4(1, 1, 1, 0), gui.EASING_IN, fade_in, delay)
    -- tambem aparece gradualmente
    gui.animate(self.imprint, gui.PROP_COLOR, vmath.vector4(1, 1, 1, 1), gui.EASING_IN, fade_in, delay)
end

-- incrementa a pontuacao em um passo em direcao ao alvo
local function inc_score(self, node)
    -- quanto a pontuacao e incrementada neste passo
    local score_inc = score_inc_speed * dt
    -- nova pontuacao apos o incremento
    local new_score = self.current_score + score_inc
    for i = 1,#self.stars do
        -- inicia a animacao de uma estrela grande se cruzarmos o nivel de pontuacao para ela aparecer
        if self.current_score < self.star_levels[i] and new_score >= self.star_levels[i] then
            animate_star(self, self.stars[i])
        end
    end
    -- atualiza a pontuacao, mas limita ao alvo
    self.current_score = math.min(new_score, self.target_score)
    -- atualiza a pontuacao na tela
    gui.set_text(self.score, tostring(self.current_score))
    -- se ainda nao terminamos, continua animando e incrementando
    if self.current_score < self.target_score then
        -- quao perto estamos do alvo
        local f = self.current_score / self.target_score
        -- mistura a cor para obter um desaparecimento lento
        local c = vmath.lerp(f, self.score_start_color, self.score_end_color)
        gui.animate(self.score, gui.PROP_COLOR, c, gui.EASING_NONE, dt, 0, inc_score)
        -- nova escala para este passo
        local s = vmath.lerp(f, score_start_scale, score_end_scale)
        -- aumenta a escala pelo fator de quique
        local sp = s * score_bounce_factor
        -- anima da escala de quique de volta para a escala apropriada
        gui.set_scale(self.score, vmath.vector4(sp, sp, 1, 0))
        gui.animate(self.score, gui.PROP_SCALE, vmath.vector4(s, s, 1, 0), gui.EASING_NONE, dt)
    else
        -- terminamos, faz a marca aparecer gradualmente
        -- OBSERVACAO! em um caso real, isso deveria ser verificado contra o high score realmente armazenado
        animate_imprint(self)
    end
end

function on_message(self, message_id, message, sender)
    -- alguem nos informa que devemos exibir a cena de nivel concluido
    if message_id == hash("level_completed") then
        -- recupera a pontuacao obtida e em quais niveis de pontuacao as estrelas devem ser exibidas
        self.target_score = message.score
        self.star_levels = message.star_levels
        -- faz o titulo aparecer gradualmente ("level completed")
        local c = gui.get_color(self.heading)
        c.w = 1
        gui.animate(self.heading, gui.PROP_COLOR, c, gui.EASING_IN, dt, 0.0, inc_score)
        c = gui.get_shadow(self.heading)
        c.w = 1
        gui.animate(self.heading, gui.PROP_SHADOW, c, gui.EASING_IN, dt, 0.0)
        -- encolhe para o lugar
        gui.animate(self.heading, gui.PROP_SCALE, vmath.vector4(1, 1, 1, 0), gui.EASING_IN, 0.2, 0.0)
    end
end

-- esta funcao e chamada quando o script e recarregado
-- ao configurar a cena e simular level complete, obtemos um fluxo de trabalho muito rapido para ajustes
function on_reload(self)
    -- garante que quaisquer alteracoes de configuracao sejam consideradas
    setup(self)
    -- simula que o nivel foi concluido
    msg.post("#gui", "level_completed", {score = 102000, star_levels = {40000, 70000, 100000}})
end