[Tutorial] State machines (automata)
#1

State machines (automata)
O que й, para que serve e como usar

Introduзгo

Se vocк nunca leu a pawn lang, й quase 100% de certeza que nгo conhece state machines, ou automata. Atй hoje, nunca vi NENHUM script lanзado que utilize automata, o que й uma vergonha, jб que esse mйtodo й muito ъtil. Mas tambйm existem algumas pessoas que leram, e sabem o que sгo. Umas delas sou eu, e por isso estou fazendo este guia. PAWN nativamente suporta um sistema chamado state machines, ou automata, que basicamente permitem que vocк use mъltiplas cуpias da mesma funзгo para diferentes circunstвncias.

Antes de comerзamos, quero deixar uma coisa clara: State machines, ou automata, nгo foram feitos para serem usados como arrays, pois nгo podem possuir indexes, ou seja, vocк nгo poderб usar automata com fins de gerenciar as aзхes cada player, por exemplo.

Exemplo

Vamos usar o seguinte cуdigo como exemplo:

pawn Код:
new print;

forward PrintShit();

main()
{
    print = 0;
    SetTimer("PrintShit", 1000, 1);
}

public PrintShit()
{
    if(print == 1)
    {
        print("Estamos mostrando uma frase no console.");
    }
    else
    {
        return 1;
    }
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    if(strcmp(cmdtext, "/print", true) == 0)
    {
        if(print == 0)
        {
            print = 1;
        }
        else
        {
            print = 0;
        }
    }

    return 0;
}
Esse й o cуdigo mais simples em que consegui pensar. Como podem ver, a funзгo 'PrintShit' mostra uma frase no console se a variбvel 'print' for igual a 1, de 1 em 1 segundo. Se print for igual a 0 nada acontece. Com o comando /print podemos ligar/desligar essas mensagens. Mas podemos melhorar muito este cуdigo:

pawn Код:
#include <a_samp>

forward PrintShit();

main()
{
    state print:no;
    SetTimer("PrintShit", 1000, 1);
}

public PrintShit() <print:yes>
{
    print("Estamos mostrando uma frase no console.");
}

public PrintShit() <print:no>
{
    return 1;
}

public OnPlayerCommandText(playerid, cmdtext[]) <print:no>
{
    state (strcmp(cmdtext, "/print", true) == 0) print:yes;
   
    return 0;
}

public OnPlayerCommandText(playerid, cmdtext[]) <print:yes>
{
    state (strcmp(cmdtext, "/print", true) == 0) print:no;

    return 0;
}
Usando automata, o cуdigo fica mais limpo e tambйm mais rбpido por ser nativamente suportado pela linguagem.

Uma coisa importante a ressaltar й que a diretiva 'state' pode ter condicionais dentro da mesma. Essa linha:

pawn Код:
state (strcmp(cmdtext, "/print", true) == 0) print:yes;
Corresponde a:

pawn Код:
if(strcmp(cmdtext, "/print", true) == 0)
{
    state print:yes;
}

Vantagens

Usando automata, nгo precisamos usar variбveis globais, ou seja, nгo usamos espaзo a mais na memуria, e o cуdigo fica mais limpo e mais rбpido, como disse anteriormente, alйm de nгo precisar de enormes 'if's e 'else's ou grandes estruturas como 'switch', com automata vocк pode criar vбrios 'PrintShit's, 'OnGameCommandText's etc. Nгo hб problema nenhum em usar a mesma automata em vбrias funзхes ao mesmo tempo.


Explicaзгo

Agora que jб vemos alguns exemplos e sabemos como funciona vamos olhar mais detalhadamente no cуdigo:
  • state

    pawn Код:
    state a:s;
    Isso coloca a automata 'a' dentro do estado 's' (tambйm existem estados indeclarados, para mais informaзхes leia a pбgina 37 da pawn lang). Diferentemente de variбveis, automatas nгo precisam ser declaradas globalmente, pois o prуprio compilador lhe poupa desse trabalho, do contrбrio nгo seria possнvel usar automatas em qualquer funзгo do teu script, mas й preciso declarar a automata em alguma funзгo, no caso a fiz em main().

    Como falei anteriormente, vocк pode usar condicionais dentro da diretiva 'state':

    pawn Код:
    state (c == 1) a:s;
    Isso equivale a:

    pawn Код:
    if(c == 1) state a:s;
    Naturalmente vocк pode escolher qual mйtodo usar.

  • Funзхes

    Uma funзгo pode ter vбrias cуpias delas mesma para serem usadas em vбrias circunstвncias, afinal esse й o principal 'recurso' da automata. Vocк pode orientar uma funзгo para nгo ter estados, ter apenas um, vбrios, ou ser chamada se todos os outros estados nгo forem vбlidos.

    • Nenhum estado

      pawn Код:
      stock Math()
      {
          new x = 2;
          new y = 4;
         
          printf("%i", y-x);
      }
      Essa funзгo й sempre chamada independentemente do estado de qualquer automata.

    • Um estado

      pawn Код:
      stock Math() <calcs:on>
      {
          new x = 2;
          new y = 4;
         
          printf("%i", y-x);
      }
      Essa funзгo й chamada se a automata 'calcs' estiver no estado 'on'.

    • Estados mъltiplos

      pawn Код:
      stock Math() <calcs:on, calcs:always>
      {
          new x = 2;
          new y = 4;

          printf("%i", y-x);
      }
      Essa funзгo й chamada se a automata 'calcs' estiver no estado 'on' ou 'always'.

      Quando se usa nъmeros como estados, precisa-se adicionar um underline ('_') antes do nъmero, pois sнmbolos nгo podem comeзar com nъmeros, como no exemplo:

      pawn Код:
      stock Math() <calcs:_1, calcs:_2>
      {
          new x = 2;
          new y = 4;

          printf("%i", y-x);
      }
    • Outros estados


      pawn Код:
      stock Math() <>
      {
          new x = 2;
          new y = 4;

          printf("%i", y-x);
      }
      Essa funзгo й chamada quando o estado da automata 'calcs' nгo corresponde a nenhum outro estado explнcito no script.

  • entry

    Й uma funзгo especial que funciona como uma callback. A callback OnPlayerCommandText nгo й chamada quando o jogador envia um comando? A 'entry' й chamada quando se muda o estado de uma automata.

    O cуdigo:

    pawn Код:
    main()
    {
        print("Hello");
        state printstring:sure;
        print("World");
    }

    entry() <printstring:sure>
    {
        print("Fuckin'");
    }
    Iria fazer mostrar no console:

    Код:
    Hello
    Fuckin'
    World
    Pois quando se alterou o estado da automata 'printstring', a funзгo 'entry' correspondente foi chamada e executou a funзгo que estava contida dentro da mesma.
Conclusгo

Espero que todos tenham entendido. Qualquer dъvida, nгo hesite em perguntar. Para mais informaзхes, leia a pawn lang a partir da pбgina 37.
Reply
#2

Gostei do tuto Parabйns hehe
Reply
#3

Bom tutorial. ; )
Acho que poucos sabem da existкncias dessas estruturas
Reply
#4

Estб ai uma coisa que eu nгo sabia, vou passar a utilizar esse meio, que alйm de facilitar, deixa o script pequeno e й rбpido.

a бrea portuguesa precisa de tutoriais assim, e nгo tutoriais que ensinam a editar GF!

Muito bom.
Reply
#5

aff. Eu nгo sabia disso D:
Reply
#6

Se eu nгo me engano, jб vi um tutorial sobre este mesmo assunto feito pelo ******.

De qualquer forma, parabйns pelo belo tutorial =D
Reply
#7

awesome #nensabiasquessasporraexistia D:
Reply
#8

Quote:
Originally Posted by Luнs Miki
Посмотреть сообщение
aff. Eu nгo sabia disso D:
Muito menos eu ._.
Reply
#9

Jб sabia, porйm acho inъtil elas.
bom tutor
Reply
#10

Obrigado a quem gostou, й meu primeiro tutorial.

@Ricop: Nгo ache isso! Sу sгo inъteis pra quem nгo sabe utilizб-las. Leia a seзгo 'Vantagens' e verб que sгo muito boas. Obrigado por achar bom meu tutorial.

@GPenner: Tambйm penso assim, cada dia que venho aqui nгo vejo um tutorial sobre coisas realmente importantes, sу tutoriais de como criar 'org's, como criar npc, como criar infoorg, como criar isso e aquilo. Nгo que eu tenha algo contra quem cria tutoriais sobre isso, sу acho que deveriam postar mais coisas que realmente importam quando o assunto й PAWN.

@Shadow: Sim, ****** tambйm fez um tutorial assim. Como й meu primeiro tutorial, eu fiz o nome das seзхes baseado no dele, apesar de ter conhecimento sobre o que eu estava escrevendo e os cуdigos serem completamente diferentes. Nгo й e nem deve ser considerado uma traduзгo nem uma cуpia.

Ah, pra quem quiser saber, sim, jб li a pawn lang e tenho ela impressa como livro.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)