O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

Evitando lag

Iniciado por Valentine, 20/03/2017 às 07:52

Está aí o monstro dos desenvolvedores. O lag. Ele deve ser evitado a todos os custos. Um jogo perfeito em conteúdo, cheio de beleza, cheio de opções, com animações maravilhosas, não será nada divertido se tiver lag. Pode ser o projeto que use os melhores sistemas do mundo, mas se for lento, ninguém joga.

É para evitar problemas com o lag que irei dar dicas e macetes para evitar este terrível vilão.

[box class=catbg]
Inicilaize as Variáveis
[/box]

Sempre inicialize as suas variáveis. Exemplo:
#Ao invés disso:
y = x + 1 # Retorno: 1
 
#Use isso:
x = 0
y = 0
y = x + 1 # Retorno: 1


Motivo: Performance. O ganho pode ser verificado com o seguinte código RUBY:
require "benchmark"
include Benchmark
 
n = 1000000
bm(12) do |test|
 
  test.report("Normal:") do
    n.times do |x|
      y = x + 1
    end
  end
 
  test.report("Inicializando:") do
    x = y = 0
    n.times do |x|
      y = x + 1
    end
  end
 
end


O retorno deste teste (do código acima) é o seguinte:
                  user     system      total        real
Normal:        0.920000   0.000000   0.920000 (  0.978238)
Inicializando: 0.720000   0.000000   0.720000 (  0.761112)


Ou seja... Inicializando é mais rápido.

[box class=catbg]
Complexidade do código nas repetições
[/box]

Como determinar a complexidade de uma rotina? Antes de responder esta pergunta vamos ver alguns exemplos:

Exemplo 1:
p s

if s = nil
  s = Sprite.new
end

c = d + 1

s.x = c


Achou complexo? Vamos ver outro exemplo.

Exemplo 2:
n = 100
for i in 0...n
  f + = self.uma_string_qualquer(i)
end


Pareceu ser menos complexo? Ou ficou mais complexo? Antes da resposta vamos ver outro exemplo.

Exemplo 3:
n = 100

for i in 0...n

  for j in 0...n

    for k in 0...n
      self.faz_alguma_coisa(i,j,k)
    end

  end

end


E agora? Mais ou menos complexo?

Se considerarmos que a complexidade depende do número de repetições executadas, então o mais complexo é o exemplo 3. Observe que se n for igual a 2, serão executadas 8 repetições. Se n=3 , serão 27 repetições. Com n=4 serão 64 repetições. Com n=100 será um milhão de repetições.

Ao criar qualquer rotina é necessário lembrar deste detalhe para evitar repetições desnecessárias.

Mais um exemplo:
nIdSkill = 1

#Lento
for actor in $game_party.actors
  actor.hp -= calcular_dano_da_habilidade(nIdSkill)
end

#Rápido
nDano = calcular_dano_da_habilidade(nIdSkill)
for actor in $game_party.actors
  actor.hp -= nDano
end


[box class=catbg]
Gráficos e Imagens
[/box]

Se tem alguma coisa que pode causar lag são as imagens. A chamada de um simples método como o set_pixel, gera uma reação em cadeia. O módulo Graphics gerencia a tela no RGSS. Alterar um pixel usando o método set_pixel irá alterar dados da classe instanciada (window/sprite), que por sua vez irá manipular o bitmap contents. Este por sua vez, avisa ao Graphics que a janela/sprite precisa de um update para redesenhar as alterações. Por isso o Graphics.update é chamado. Por isso, cada janela aberta causa lag. O Graphics.update irá tentar atualizar todas elas.

Sabendo o que causa o lag, podemos evitar. No RGSS, o lag é causado por janelas abertas/invisíveis ou muitos eventos no mapa. Cada evento possui um sprite associado. Cada sprite cria lag através do procedimento acima.

É por isso que a maioria dos scripts anti-lag são na verdade scripts Event-Anti-Lag. Eles simplesmente evitam a atualização dos sprites dos eventos que não estão na tela.

É possível ir além do que procurar um script anti-lag para usar em nossos projetos. Lembre-se de usar o dispose em todas as janelas e sprites que não vai usar. Se depois precisar da janela/sprite, é melhor recriar ele. O código pode ficar um pouco maior ou complexo, mas o lag será reduzido bastante.

[box class=catbg]
set_pixel    VS    fill_rect
[/box]

Agora que têmos uma idéia do lag que o set_pixel pode causar, vamos evitá-lo na prática. Observe os dois exemplos de barras gradientes a seguir:
class bitmap
  def gradient_bar_1(x, y, w, h, fill_rate, c1, c2)
    fill_rect(x, y, , w, h, Color.new(0, 0, 0))
    for i in 0...(w * fill_rate).to_i
      r = c1.red + (c2.red - c1.red) * i / w
      g = c1.green + (c2.green - c1.green) * i / w
      b = c1.blue + (c2.blue - c1.blue) * i / w
      fill_rect( x+i, y, 1, h, Color.new( r, g, b ) )
    end
  end

  def gradient_bar_2(x, y, w, h, fill_rate, c1, c2)
    fill_rect(x, y, , w, h, Color.new(0, 0, 0))
    for i in 0...(w * fill_rate).to_i
      for j in 0...h
        r = (c1.red + (c2.red - c1.red) * i / w) * j  / h
        g = (c1.green + (c2.green - c1.green) * i / w) * j  / h
        b = (c1.blue + (c2.blue - c1.blue) * i / w) * j  / h
        set_pixel( x+i, y+j, Color.new( r, g, b ) )
      end
    end
  end
end


Agora observe o resultado das duas barras, nas imagens abaixo:

Barra 1

Barra 2

Qual seria a melhor? A primeira ou a segunda? Muitos pode achar o efeito da segunda, visualmente melhor. Afinal é um efeito mais bonito, mas o lag da segunda barra é muito maior que da primeira. A diferença de tempo de execução chega a superar 40%.

A beleza é realmente necessária? Se não for, é melhor usar a barra 1 (ao invés da barra 2), pois assim evita-se bastante lag.

[box class=catbg]
Aspas Simples ou Aspas Duplas?
[/box]

No RGSS existem comandos lentos e comandos rápidos. De posse desta informação podemos deixar nosso código mais rápido e com menos lag. A primeira coisa a se ter em mente é o uso das aspas. Observe o exemplo abaixo:
bitmap.draw_text(0, 0, 600, 32,
                 'Esta primeira string é processada mais rapidamente' +
                 " do que esta segunda string.\n")


Mais exemplos:
#Lento
bitmap.draw_text(0, 0, 100, 32, "#{$game_party.gold}" )
bitmap.draw_text(0, 0, 100, 32, "#{$game_party.gold}".to_s )

#Rápido
bitmap.draw_text(0, 0, 100, 32, $game_party.gold.to_s )


Evite usar as aspas duplas. Em grande parte do código podemos usar somente as simples, mas as vezes esquecemos isso. Outras vezes fazemos o famoso CTRL+C CTRL+V e lá vem as aspas duplas. Troque sempre que puder para as asplas simples.

Mas antes de sair mudando todo o código vamos ver mais um exemplo:
#Exemplo 1
nums = [0, 1, 2, 3]
cTexto = "#{nums[0]} #{nums[1]} #{nums[2]} #{nums[3]}"

#Exemplo 2
nums = [0, 1, 2, 3]
cTexto = nums[0].to_s + nums[1].to_s + nums[2].to_s + nums[3].to_s


E agora? No exemplo anterior, o mais rápido é o exemplo 1 ou o exemplo 2?

Inicialmente, parece ser o exemplo 2, mas a chamada de to_s 4 vezes e a concatenação destes 4 valores com o operador + também irá gastar tempo. Neste caso pode-se usar qualquer um dos dois. O maior problema é quando se usa os dois ao mesmo tempo. Sempre evite usar os dois ao mesmo tempo.

Créditos:
Marcelo Cavaco

Tópico original:
http://www.rgss.com.br/dicas_lag.html

Show de bola, a primeira dica de declará as váriaveis antes foi bem legal, mas não consegui abrir o site do tópico original.

Citação de: Crixus online 20/03/2017 às 15:49
Show de bola, a primeira dica de declará as váriaveis antes foi bem legal, mas não consegui abrir o site do tópico original.
Infelizmente, o site está fora do ar.