На правах рерайтинга
Вступление
Я никогда не использовал переключатели, за это мне стыдно. Они очень полезны. Павн с роду умеет использовать переключатели(так же известные как automata) которые позволяют подстраивать функции под нужные требования, которые могут менятся
На словах все трудно. Перейдем к делу
Пример №1
Что бы продемонстрировать суть переключателей, я написал очень простой мод(*да да, именно мод)
Используя стандартные способы, так что люди смогут понять что делает этот код:
#include <a_samp>
forward change();
enum
{
end = 0,
gmx
}
new
gExitType;
main()
{
gExitType = end;
SetTimer("change", 10000, 0);
}
public OnGameModeExit()
{
switch (gExitType)
{
case end:
printf("This mode was ended by the server");
case gmx:
printf("This mode was ended by the timer");
}
}
public change()
{
gExitType = gmx;
GameModeExit();
}А теперь тоже самое но на переключателях:
#include <a_samp>
forward change();
main()
{
state exitType:end;
SetTimer("change", 10000, 0);
}
public OnGameModeExit() <exitType>
{
printf("This mode was ended by the server");
}
public OnGameModeExit() <exitType>
{
printf("This mode was ended by the timer");
}
public change()
{
state exitType:gmx;
GameModeExit();
}Преимущества[
Какие же преимущества от этого способа? Ну, как вы можете заметить код МЕНЬШЕ; к тому же, я добавил enum к первой версии, чтобы коды выглядели как можно более похоже, но OnGameModeExit функция определенно меньше. Так же, оно намного полезнее - вам не нужны большие switch проверки в функции чтобы определить что же происходит.
Пример №2
Другой пример, в этот раз используем комманду /debug, чтобы быстро переключать вывод сообщении
#include <a_samp>
dprint(message[]) <printState>
{
// Показываем сообщение
print(message);
}
dprint(message[]) <printState>
{
//Ничего не делаем
#pragma unused message
}
forward output();
main()
{
state printState:off;
// Включаем таймер
SetTimer("output", 1000, 1);
}
public OnPlayerCommandText(playerid, cmdtext[]) <printState>
{
state (!strcmp(cmdtext, "/debug")) printState:off;
}
public OnPlayerCommandText(playerid, cmdtext[]) <printState>
{
state (!strcmp(cmdtext, "/debug")) printState:on;
}
public output()
{
static
sCount = 0;
if (++sCount == 5)
{
OnPlayerCommandText(0, "/debug");
sCount = 0;
}
// Статично выводим сообщение дял примера
dprint("Hello World");
}Разбор полетов
Некоторые вещи которые необходимо учесть здесь:
Во-первых dprint не public функция, это обычная функция, но переключатели нормально работают с ней.
Во-вторых в переключателях могут быть условия. Как в этой строке
state (!strcmp(cmdtext, "/debug")) printState:on;[/php]
тоже самое что и
if (!strcmp(cmdtext, "/debug"))
{
state printState:on;
}В-третьих здесь 2 функции которые зависят от одного переключателя (OnPlayerCommandText and dprint). Это не проблема.
Разьяснения
Теперь, когда мы взглянули на примеры, вы наверно интересуетесь, что же происходит (конечно если вы не читали pawn-lang.pdf). Давайте, в таком случае, взглянем на код ближе
state:
state a:b
Это устанавливает переключатель a в положение b. Вам не надо обьявлять переключатели, по сравнению с переменными.
Как уже упоминалось в переключателях может быть условие
state (c == 1) a:b;
Это устанавливает переключатель а в положение б если с равно 1.
Функции:
Вы можете создавать множество копий одной и той же функции, которая должна будет вызываться в разных ситуациях, без проверок до вызова или в самой функции. Функция может содержать: 0 переключателей, 1 переключатель, множество переключателей, другие переключатели(*заметка от переводчика: взгляните на пример прежде чем понимать это)
Например:
Без переключателей
dprint(message[])
{
print(message);
}Эта функция вызывается всегда, неважно в каком положении любой переключатель находится
Один переключатель
dprint(message[]) <debugState>
{
print(message);
}Эта функция будет вызываться когда debugstate в положении on
Несколько переключателей
dprint(message[]) <debugLevel>
{
print(message);
}Функция будет вызываться если debuglevel в положении _1 или _2 (переменные не могут иметь в названии лишь цифры или начинаться с них)
Другие переключатели
dprint(message[]) <>
{
print(message);
}Эта функция будет вызываться тогда когда другие функции dprint не вызвались, из-за того что переключатели не совпали
entry()
Это спец функция (похожая на main) которая вызывается в тех случаях, когда вы переключаете переключатель(sic). К сожалению работает лишь для одного переключателя
main ()
{
printf("hello");
state myState:moo;
printf("world");
}
entry() <myState>
{
printf("change");
}Выведет в консоль
hello change world
Пример №3
CancelRace()
{
state raceState:none; // Выключает гонку
gEntrants = 0;
}
public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
// Вызывается когда ниодной гонки не запущено
SendClientMessage(playerid, 0xFF0000AA, "Sorry, there's no race on at this time");
}
public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
// Вызывается когда кто-то из игроков входит в последний чекпоинт
if (AtLastCheckpoint(playerid))
{
// Этот игрок вошел в последнюю точку первым
SendClientMessage(playerid, 0xFF0000AA, "Congratulations, you won the race");
DisablePlayerRaceCheckpoint(playerid);
state raceState:won;
--gEntrants;
}
else
{
// И тот который нет
SetNextCheckpoint(playerid);
}
}
public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
// Вызывается когда кто-то уже выйграл, а другие нет
if (AtLastCheckpoint(playerid))
{
// Доехал до конца, но не выйграл
SendClientMessage(playerid, 0xFF0000AA, "Sorry, somebody already won");
DisablePlayerRaceCheckpoint(playerid);
state (--gEntrants == 0) raceState:none;
}
else
{
// Еще не доехал
SetNextCheckpoint(playerid);
}
}
public OnPlayerEnterRaceCheckpoint(playerid) <>
{
// Вызывается во время гонки, просто переставляем чекпоинты
SetNextCheckpoint(playerid);
if (AtLastCheckpoint(playerid))
{
// Кто-то доехал до финиша
state raceState:finish;
}
}Автор: Y_Less Перевод: [A]Le[X]and[R]