7 dicas para melhorar o desempenho dos seus jogos

Ver o tópico anterior Ver o tópico seguinte Ir em baixo

7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Gonçalves em Dom 10 Ago 2014, 02:15

5 dicas para melhorar o desempenho dos seus jogos de GM

1. Use o profiling do GMS

Uma função nova do debug que irá abrir seus olhos, o Profiling system. Como ele funciona? Ele, enquanto seu jogo é executado, retorna o número de vezes que uma função foi executada, e o tempo de execução. Ou seja, com o auxílio dessa ferramenta, você poderá saber quais as funções mais pesadas, e poderá assim otimizar a forma de fazer sistemas de jogos. Para usá-lo é simples, primeiramente execute seu projeto no modo Debug (F6):


Feche as janelas que estão abertas no debugger, clique com o botão direito e selecione Profile:


Ao iniciar o profiling (clicando no círculo cinza), podemos ver algumas informações:


Vemos nesse exemplo que as funções draw são as mais pesadas, e que devem ser evitadas ao máximo. Perceba que desenhar uma sprite (draw_self) é muito mais leve que um texto... E por aí vai, assim você vai conhecendo o "peso" das funções. Outro erro que cometemos é usar distance_to_object sem necessidade, podendo usar point_distance, que é 2x mais rápida.

2. Salvar valores de funções para evitar usar mais vezes do que o necessário

Algo que eu fazia muito, por exemplo:

Código:
if distance_to_object(ObPlayer)<200 && distance_to_object(ObPlayer)>500
{
     //Ação...
}

Veja que usamos uma mesma função, com os mesmos argumentos, duas vezes, podemos simplificar fazendo:

Código:
var PlayerDistance=distance_to_object(ObPlayer)

if PlayerDistance<200 && PlayerDistance>500
{
     //Ação...
}

Assim usamos a função apenas uma vez. Pode parecer pouco, mas quanto mais leve o jogo, em mais máquinas vai rodar, e isso é ótimo!

3. Evitar checagens desnecessárias a cada step

Outra coisa que fazemos que, além de pesado e desnecessário, é irrealista. Normalmente, em nossos jogos, checamos o inimigo mais próximo ou a decisão a ser tomada a cada step, o que não faz muito sentido. Nenhuma pessoa consegue tomar decisão 60x por segundo, muito menos perceber quem tá mais perto, haha. Como eu faço para impedir isso de acontecer?

Simples. No objeto controle dos meus jogos, eu crio uma variável (pode-se usar alarms, mas odeio eles, rs) que começa em 0 e vai até certo número, quando atinge esse número, zera, e refaz o processo. Nos objetos do meu jogo, para certas ações, eu checo se essa tal variável atingiu seu limite, e só assim, executá-las. Exemplo:

Create (Controle):
Código:
globalvar UpdateAI
UpdateAI=0

End Step (Controle):
Código:
if UpdateAI>=60
UpdateAI=0
else
UpdateAI++

Já nos objetos normais, eu uso, por exemplo:

Código:
if UpdateAI>=60
{
     Near=instance_nearest(x,y,Inimigo)
     ....
}

Lembrando que toda variável definida com globalvar será reconhecida como global sem necessidade de 'global.' em qualquer objeto (isso no GMS, claro)...

Assim ele redefine o inimigo mais próximo de 1 em 1 segundo, o que ainda é bem rápido, e 60x mais leve, haha. Uso também esses intervalos para atualizar surface de fog-of-war, entre outras coisas. Melhora bastante o FPS.

4. Evite ao máximo as funções Draw

Como pudemos ver no profile, as funções draw são extremamente pesadas, então evite-as sempre que possível. Se não puder desativar uma instância fora da view porquê comprometeria o funcionamento do jogo, sem problema, desativar as funções draw dela já faz metade do serviço.

Outro exemplo é o caso do draw_text. Normalmente, para desenhar listas, usamos um for e jogamos dentro um draw_text, que se repetirá de acordo com o número de loops. O que podemos fazer nesses casos? Tem uma solução que acho bem interessante... Ao invés de usar o for para chamar draw_text várias vezes, podemos usá-lo para somar a uma string os valores dessa lista, assim só usaremos um draw.

Passaríamos disso:

Código:
//Create
Text[0]="My car"
Text[1]="My boat"
Text[2]="My truck"
Text[3]="My plane"
Text[4]="My train"

//Draw
for(i=0;i<5;i++)
     draw_text(0,30*i,Text)

Para isso:

Código:
//Create
Text[0]="My car"
Text[1]="My boat"
Text[2]="My truck"
Text[3]="My plane"
Text[4]="My train"

//Draw
var List="",i;

for(i=0;i<5;i++)
     List+=Text[i]+"#"

draw_text(0,0,List)

Que é mais rápido.

5. Arrays sempre que possível

Fazendo um teste com dois objetos, um com 10 variáveis comuns, e outro com uma array de 10 indíces, temos o seguinte no profile:


Os objetos não tem nada além da declaração das variáveis, e uma soma simples no step (se tiver nada não aparece no profiling). Quanto mais variáveis, maior esse tempo de execução, mesmo que não estejam sendo usadas.

6. Vars temporárias sempre que possível

As variáveis temporárias também são mais leves, e mesmo que, no próximo step você venha a definir seu valor novamente (e parecer não haver necessidade de deletá-las), elas se mostram bem mais leves:


Então, se for usar variáveis que não serão usadas em outros steps (ou serão redefinidas) nem em outros objetos, use as temporárias. Outro caso que esquecemos também é antes dos for, aquele i não é temporária por natureza, precisamos fazer isso manualmente:

Código:
var i;

for(i=0;i<5;i++)
{
     ....
}

7. Se uma variável global for referenciada muitas vezes num script, salve seu valor numa local

Isso:

Código:
repeat(1000)
     a+=global.Variable

É bem mais lento que isso:

Código:
var Global=global.Variable;

repeat(1000)
     a+=Global

Bom, é isso. Não se esqueça de sempre fazer testes de perfomance, assim saberá onde aprimorar seus scripts.

Dicas Bônus:
1. Script para checar mouse dentro de um retângulo

Geralmente fazemos nossos scripts com esse tipo de checagem assim:

Código:
return
   mouse_x>=(min(argument0,argument2))
&& mouse_y>=(min(argument1,argument3))
&& mouse_x<=(max(argument0,argument2))
&& mouse_y<=(max(argument1,argument3))

Porém podemos, nas versões mais novas do GM:S, fazer assim que é bem mais rápido:

Código:
///MouseCheck(X1,Y1,X2,Y2)
return point_in_rectangle(mouse_x,mouse_y,min(argument0,argument2),
min(argument1,argument3),
max(argument0,argument2),
max(argument1,argument3))

2. Evite o uso de string(), é bem pesado

Uma função que é bem pesada e costumamos usar loucamente no Draw para transformar nossos valores reais em string. Ela é bem pesada, então recomendo evitá-la ao máximo. Um caso do meu jogo, onde eu mostrava o fps na tela:

Código:
if Update>=60 //Daquele esqueminha mostrado acima
    FPS=fps_real //Pegar o valor do FPS de 1 em 1 segundo

draw_text(0,0,string(ceil(FPS))) //Assim, quando eu desenhá-lo na tela, não atualiza 60x por segundo e eu conseguir ler alguma coisa :D

Veja que eu, de 60 em 60 steps pego o valor do fps, e passo pra string e arredondo toda vez a cada step. Agora eu faço dessa maneira:

Código:
if Update>=60 //De 60 em 60 steps
    FPS=string(ceil(fps_real)) //Pegar a string do valor arredondado (pra baixo) do FPS de 1 em 1 segundo

draw_text(0,0,FPS)

Assim eu deixaria de usar esse função, desnecessariamente, a cada step e só usarei 1 vez por segundo quando realmente houver a necessidade.

Existem diversas outras partes dos códigos que podemos otimizar de forma a deixar mais rápido e ter o mesmo resultado ainda. Fique atento a isso e sempre debugue!

Flw! elephant


Última edição por Gonçalves em Sab 16 Ago 2014, 02:13, editado 7 vez(es)

Gonçalves

Ranking : Nota B
Número de Mensagens : 1013
Data de inscrição : 29/10/2010
Notas recebidas : B + A + C
Reputação : 79
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 2
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Funbit Games em Dom 10 Ago 2014, 02:52

Boas dicas, vão ajudar muita gente e a mim  

Funbit Games

Número de Mensagens : 21
Idade : 20
Data de inscrição : 18/08/2012
Reputação : 0
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por PedroX em Dom 10 Ago 2014, 07:55

Gostei bastante. Com as imagens, ficou perfeito.

PedroX

Ranking : Nota C
Número de Mensagens : 6034
Idade : 21
Data de inscrição : 26/07/2008
Notas recebidas : C+B
Reputação : 286
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   :
   :
   :

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Alex FC em Dom 10 Ago 2014, 11:30

Dicas rápidas e bem explicadas, muito bom Gonçalves. Creio que ajudará principalmente quem está desenvolvendo pra mobile e quer que o jogo rode em dispositivos mais modestos.

FLWS!

Alex FC

Ranking : Nota A
Número de Mensagens : 2503
Idade : 23
Data de inscrição : 20/12/2008
Notas recebidas : B A
Reputação : 174
Insignia 1 x 1 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 2
   : 1
   : 1

http://redscreensoft.blogspot.com

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Tanker GT em Dom 10 Ago 2014, 12:01

Nossa cara, esta ótimo me ajudou muito. Só trocando as funções draw_text por draw_sprite onde era possível eu reduzi em quase metade o tempo de execução total. Eu nunca imaginaria que a coisa mais pesada no jogo inteiro era o draw_line rsrs.

Tanker GT

Ranking : Nota C
Número de Mensagens : 106
Idade : 20
Data de inscrição : 08/10/2011
Notas recebidas : C
Reputação : 11
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Gonçalves em Seg 11 Ago 2014, 06:23

Valeu galere! Smile Bom eu disse lá em cima e esqueci de explicar a diferença entre point_distance e distance_to_object. É simples: a primeira vai exatamente de um ponto (x1,x2) a um (x2,y2) usando a fórmula de Pitágoras. A segunda, leva em consideração a máscara dos objetos, e o método que eles usam nem sei qual é, mas é mais pesada, já que o código tem que encontrar a 'ponta' de cada máscara. E geralmente nem precisamos de toda essa 'precisão' oferecida pelo distance_to_object...

Flw! elephant

Gonçalves

Ranking : Nota B
Número de Mensagens : 1013
Data de inscrição : 29/10/2010
Notas recebidas : B + A + C
Reputação : 79
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 2
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por matheusco em Qui 14 Ago 2014, 01:33

Ótimo tutorial Smile Obrigado pelas dicas. Vou colocar um "manual de boas práticas" no meu blog e elas vão pra lá, com os devidos créditos.

matheusco

Número de Mensagens : 395
Idade : 24
Data de inscrição : 10/08/2014
Reputação : 51
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 0

http://www.tutoriaisgamemaker.com.br

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Lighter em Qui 14 Ago 2014, 15:41

Não quero atualizar meu gm:s visto as incompatibilidades que encontraram na ultima versão.  Se possível poderia ver qual função é a mais pesada entre draw_line_color e drw_sprite? E ainda encontrei outro recurso que esta deixando muito pesado meu jogo a função é a collision_line, tem outra que possua a mesma característica e é mais leve? Pois essa gera um lag absurdo no meu pc, e olha que ele até que é bom;

Lighter

Ranking : Sem avaliações
Número de Mensagens : 307
Idade : 18
Data de inscrição : 16/01/2014
Reputação : 29
Insignia 1 x 0 Insignia 2 x 1 Insignia 3 x 0
Prêmios
   : 0
   : 1
   : 0

http://google.com

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Gonçalves em Sex 15 Ago 2014, 01:47

O draw_sprite é mais leve que desenhar qualquer outro primitivo (principalmente com _color). O caso do collision_line é aquele, você tem que criar um intervalo a cada checagem senão fica inviável mesmo.

Edit: Bom, quanto à dica #3, encontrei uma forma melhor, mais simples e rápida:

Código:
//Create
Update=0

//Step
if Update mod 5==0
{
     //Isso acontece a cada 5 steps
}

if Update mod 20==0
{
     //Isso acontece a cada 20 steps
}

if Update mod 60==0
{
     //Isso acontece a cada 60 steps
}

Update++

Assim você usa apenas uma variável para a atualização, e não precisa se preocupar com o fato de às vezes o código não acontecer (quando por exemplo essa checagem está no End Step de um objeto, que daí pode acontecer do update voltar pra 0 antes da tal checagem, logo nunca aconteceria).

Gonçalves

Ranking : Nota B
Número de Mensagens : 1013
Data de inscrição : 29/10/2010
Notas recebidas : B + A + C
Reputação : 79
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 2
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Kapoty em Sex 15 Ago 2014, 10:23

Gonçalves escreveu:
Código:
//Create
Update=0

//Step
if Update mod 5==0
{
     //Isso acontece a cada 5 steps
}

if Update mod 20==0
{
     //Isso acontece a cada 20 steps
}

if Update mod 60==0
{
     //Isso acontece a cada 60 steps
}

Update++
Considerando uma room da 60 FPS com o jogo aberto por 5 horas seguidas, o valor da variavel Update seria 1080000, ou seja, quanto mais tempo com o jogo aberto, mais lento o mod ficaria, acho que a solução seria:

Código:
if Update mod 60==0
{
     Update=0;
     //Isso acontece a cada 60 steps
}

Não tenho certeza de nada, é só uma teoria.

Kapoty

Ranking : Nota B
Número de Mensagens : 635
Data de inscrição : 05/11/2011
Notas recebidas : E + D + C + B + D +B + A
Reputação : 22
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 1
   : 0
   : 1

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Gonçalves em Sex 15 Ago 2014, 12:07

Bom eu fiz um teste aqui e: http://prntscr.com/4d2qps

Não ficou tão mais pesado mesmo com um número bem alto. Mas se preferir você pode deixar no seu código algo como if Update>10000 Update=0 e no caso seu código dá no mesmo que if Update==60 porquê ele vai zerar de qualquer forma. XD

Edit: Se for checar posição do mouse, isso:

Código:
///MouseCheck(X1,Y1,X2,Y2)
return point_in_rectangle(mouse_x,mouse_y,min(argument0,argument2),
min(argument1,argument3),
max(argument0,argument2),
max(argument1,argument3))

É bem mais rápido que isso:

Código:
return
   mouse_x>=(min(argument0,argument2))
&& mouse_y>=(min(argument1,argument3))
&& mouse_x<=(max(argument0,argument2))
&& mouse_y<=(max(argument1,argument3))

EDIT: Uma forma de evitar diversas variáveis ou até mesmo usar diversas arrays quando poderia usar apenas uma, é o uso de constantes. Antigamente eu costumava fazer isso nos meus jogos (em um objeto de várias instâncias):

Código:
Atk=8//ataque do mob
Def=6//defesa do mob
Spd=5//velocidade do mob

Criamos 3 variáveis. Poderiamos reduzir usando arrays, como já explicado:

Código:
Mob[0]=8//ataque do mob
Mob[1]=6//defesa do mob
Mob[2]=5//velocidade do mob

Porém, por números, ficaria dificil lembrar em qual indice está cada atributos, então podemos fazer uso das constantes. Constantes são parecidos com as variáveis , tirando o fato de serem imutáveis dentro do jogo e serem identificadas como keywords (vermelho). Podemos criar nossas constantes assim:

Spoiler:

Clicando em Default, daí adicionamos novas constantes ao clicar em Add. Veja que o GM identifica as constantes, no caso do código Game[Stop] é o mesmo que Game[0] e Game[NPC] o mesmo que Game[2].

No caso acima, se criamos as constantes Atk com valor 0, Def com valor 1, Spd com valor 2, teríamos:

Código:
Mob[Atk]=8//ataque do mob
Mob[Def]=6//defesa do mob
Mob[Spd]=5//velocidade do mob

Que seria mais fácil de ler. O mesmo caso eu fiz no meu jogo, que tinha como variáveis de texto:

Spoiler:

Uma array pra cada 'área' de texto. Agora uso dessa maneira:

Spoiler:

Que me reduz esse número de arrays a 1, o que ainda evita conflitos com outros varíaveis (toda hora eu botava uma variável com nome igual dessas :p). O mesmo para as base de dados:

Spoiler:

Cada construção representa um número na base de dados, e também seus atributos, facilita bastante na hora de manipular.

---------

Tenha em mente que o Step% do profile significa quando do step ele cada estrutura toma, se atingir 100% no total, significa L.A.G! No meu jogo, tenho no step% cerca de 50%, que considero bom num pc fraco como o meu: http://prntscr.com/4emktg

Gonçalves

Ranking : Nota B
Número de Mensagens : 1013
Data de inscrição : 29/10/2010
Notas recebidas : B + A + C
Reputação : 79
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 2
   : 0
   : 0

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Kabeção em Sex 22 Ago 2014, 15:27

Esse profiling é muito útil em projetos mais complexos e ainda é fácil e rápido de se usar.
Foi uma ótima ideia adicionar isso ao debugger.

Esse exemplo da função draw_text não ilustra o principal problema que causa perda de performance na hora de desenhar.
Desenhar algo 5 vezes é mais lento do que desenhar 5 coisas ao mesmo tempo mais isso é algo geral e se aplicada a muitas outras situações.
Por exemplo, escrever 5 linhas em um arquivo de texto usando 5 funções file_write é mais lento do que juntar as 5 linhas e usar um file_write.

Especificamente no caso das funções draw, o que causa perda de performance é a troca entre texture pages.
Por exemplo, você tem dois backgrounds sendo desenhados, cada background esta em uma texture page diferente.
O processo que a engine deve fazer para desenhar o primeiro background e logo depois o outro e muito mais lento do que desenhar os dois background da mesma texture page.
Por isso é melhor organizar isso manualmente e evitar que, por exemplo, gráficos da fase 1 fiquem juntos com gráficos da fase 7 e alternar entre desenhar um botão e depois um texto quando se pode desenhar todos os botões e depois todo texto.

Código:
// Considerando que os botões e a fonte estão em texture pages diferentes

// Isso é muito mais rápido
draw_sprite(sprB0...);
draw_sprite(sprB1...);
draw_sprite(sprB2...);

draw_text(...,'Botão 0');
draw_text(...,'Botão 1');
draw_text(...,'Botão 2');

// do que isso
draw_sprite(sprB0...);
draw_text(...,'Botão 0');

draw_sprite(sprB1...);
draw_text(...,'Botão 1');

draw_sprite(sprB2...);
draw_text(...,'Botão 2');

Isso é ainda mais evidente em projetos para mobile.

Vocês já tentaram usar buffers?
Também é muito mais rápido em diversas situações (em troca é claro da complexidade).

Kabeção

Ranking : Sem avaliações
Número de Mensagens : 2314
Data de inscrição : 08/06/2008
Reputação : 100
Insignia 1 x 0 Insignia 2 x 0 Insignia 3 x 0
Prêmios
   : 3
   : 0
   : 1

http://blackcapapps.blogspot.com.br/

Voltar ao Topo Ir em baixo

Re: 7 dicas para melhorar o desempenho dos seus jogos

Mensagem por Conteúdo patrocinado Hoje à(s) 14:35


Conteúdo patrocinado


Voltar ao Topo Ir em baixo

Ver o tópico anterior Ver o tópico seguinte Voltar ao Topo

- Tópicos similares

 
Permissão deste fórum:
Você não pode responder aos tópicos neste fórum