Доброго времени суток, уважаемые форумчане. Решил поделится с вами вопросами, которые в своё время задавал сам, и, собственно, ответами на них, а также некоторыми полезными советами.
Итак, приступим...
1) Самая простая функция которая возвращает случайное натуральное число от Min до Max-1.
Пример использования:PHP код:
stock minrandom(min, max) return random(max-min)+min;
PHP код:
if(minrandom(1, 11) == 10) SendClientMessage(playerid, -1, "Да ты везунчик просто!");
2) Если вы хотите создать таймер с повтором, лучше всего сделать этот самый повтор вручную, не через SetTimer/SetTimerEx.
Объясняю: создаётся таймер, и параметр repeating равен false, а в конце таймерной функции делается очередной запуск (перезапуск) таймера (repeating остаётся равным false).
Почему именно так, спросите вы? Ответ очень прост. Представьте, что у вас стоит таймер на 300 миллисекунд, а в самой функции куча операторов и функций, которые не успевают выполнится за это время. Тогда уж сервер зависнет и перестанет вызвать таймеры. Вот почему стоит делать повторяющиеся таймеры вручную, ибо это даёт 100% гарантии, что такое никогда не случится.
Пример использования (односекундный таймер):
PHP код:
//Перед этим SetTimer("SecondTimer", 1000, true); заменяется на SetTimer("SecondTimer", 1000, false);
public SecondTimer()
{
//тут куча кода
SetTimer("SecondTimer", 1000, false);
}
3) Как пропустить необязательный параметр?
В Pawn есть возможность создания функций с необязательными параметрами, у которых уже есть значения, задаваемые по умолчанию.
Подробнее про такие функции: http://forum.sa-mp.com/showthread.php?t=321465
Итак, существуют 2 способа пропустить такие параметры:
- Если параметр(ы) последний(ие) то просто не будем их указывать. Это самый простой способ пропуска.
Например, нам нужно узнать только час когда мы запустили мод. Для этого мы будем использовать функцию gettime.
Параметры функции:
http://breedpmnr.ru/i/fa549ae22d7061b6591d09731e76.jpg
В большинство чудо модах обычно вот так:
А остальные 2 переменные создаются просто так, дабы "удовлетворить" функцию.PHP код:
new hours, minutes, seconds;
gettime(hours, minutes, seconds);
SetWorldTime(hours);
Вместо этого можно просто создать одну переменную вместо трёх, и не утруждать память.
PHP код:
new hours;
gettime(hours);
SetWorldTime(hours);
- А что если нам нужно узнать только секунды, или минуты? Первые параметры так просто не пропустишь...
Тогда вместо параметра, который нужно пропустить, просто указываем символ подчёркивания _.
Пример:
PHP код:
new minutes;
gettime(_, minutes); //или же gettime(_, minutes, _);
printf("Мод запущен на %i минуте.", minutes);
4) Как можно поделить значения одной переменной целочисленного типа на несколько ровных частей без всяких проверок?
Для этого используется простая функция деления. Допустим нам нужно разделить время нахождения игрока на сервере на 3 части... Конечно, звучит легко и просто:
А что, если нам нужно не 3 части, а целых 10?PHP код:
//До этого создаётся массив TimePart[MAX_PLAYERS];
//В функции успешного логина
new minute;
gettime(_, minute, _);
switch(minute){
case 0 .. 20: TimePart[playerid] = 1;
case 21 .. 40: TimePart[playerid] = 2;
case 41 .. 60: TimePart[playerid] = 3;
}
Решение:
Простая математика и меньше головной боли.PHP код:
new minute;
gettime(_, minute, _);
TimePart[playerid] = minute/20 + 1; //Мы можем легко изменить 20 на 10, при этом мы увеличим части с 3 до 6... и так далее
Если перевести код выше на естественный язык языке то получим что-то вроде: Берём целую часть значения и делим на (кол-во частей плюс 1).
5) Для форматирования строк (и других строковых операций) лучше использовать локальные массивы, чем глобальные.
При небрежном использовании одного и того же массива можно просто всё спутать, к тому же локальные переменные очищаются из памяти после окончаний функций в которой они используются.
6) Эффективный перебор игроков.
Хоть плагин vectoralpawn в некоторых случаях и быстрее стандартного перебора игроков с IsPlayerConnected, он всё же уступает по эффективности другим методам, таким как foreach.inc от Y_Less'а и перебор игроков методом Tracker1, поэтому его использование в цикле перебора игроков является неоптимальным выбором.
Если же выбрать между методом Tracker1 и foreach.inc, foreach может быть быстрее быстрее, но при использовании плагина JIT (подробнее: КЛАЦ) метод Tracker1 вырывается вперёд. Выбор за вами.
Подробнее про переборы игроков:
foreach (Y_Less): http://forum.sa-mp.com/showthread.php?t=92679
Перебор игроков Tracker1: http://pro-pawn.ru/showthread.php?5747
7) Форматируя сроку, можно указывать не только ширину поля, которое будет дополняться пробелами*, но и нулями, добавляя между % и число указывающее размер поля - 0.
Часто встречаемый пример:PHP код:
printf("Value: %02d", 9); //Выводит на экран "Value: 09"
Вместо этого можно сделать так:PHP код:
// Говнокод для вывода минут в двухсимвольном виде - ищите в любом RLS.
gettime(hours, minuites, seconds);
if (minuite < 10)
format(string, sizeof(string), "~y~%d %s~n~~g~|~w~%d:0%d~g~|", day, mtext, hours, minuites);
else
format(string, sizeof(string), "~y~%d %s~n~~g~|~w~%d:%d~g~|", day, mtext, hours, minuites);
*При форматировании строк можно указывать максимальную длину поля между символом % и символом спецификатора. Подробнее: КЛАЦPHP код:
gettime(hours, minuites, second);
// Между "%" и "d" мы добавили "02", чтобы минуты отображались в
// двухсимвольном формате с пустыми ячейками поля, заменяющимися на нули.
format(string, sizeof(string), "~y~%d %s~n~~g~|~w~%d:%02d~g~|", day, mtext, hours, minuites);
8) Функции, названия которых начинаются с символа "@", автоматически получают атрибут public.
Такие функции можно использовать в таймерах, CallLocalFunction и т.п.
*Символ "@" обязательно должен быть первым, а какие символы будут дальше - разницы нет.
Пример:
PHP код:
@TimerFunc();
@TimerFunc()
{
print("Прошла 1 секунда с момента запуска мода");
}
public OnGameModeInit()
{
SetTimer("@TimerFunc", 1000, false);
}
9) Оформление кода никак не влияет на скомпилированный код (.amx).
Чего не скажешь про его читабельность и восприятие автором или другими программистами.
Отличные рекомендации по написанию кода можете найти здесь: http://pro-pawn.ru/showthread.php?8347
10) "Переключаемые" многострочные комментарии.
Думаю, все знакомы с многострочными комментариями в Pawn:
Но что, если вам вдруг нужно раскомментировать этот участок кода?Код:/*
SendClientMessage(playerid, -1, "Some text");
*/
Правильно, кроме стирания первых "/*" придётся выискивать и завершающие комментарий символы "*/".
Это может оказаться проблемой, если приходится часто комментировать/раскомментировать длинный участок кода (например, при тестировании).
На этот случай можно сделать комментарий "переключаемым":
Теперь добавим перед "/*" один слэш ("/"):Код:/*
SendClientMessage(playerid, -1, "Some text");
// */
В итоге мы "нейтрализовали" многострочный комментарий.Код://*
SendClientMessage(playerid, -1, "Some text");
// */
Чтобы включить его обратно, достаточно лишь убрать первый слэш.
Обратите внимание: между последними двумя слэшами и закрытием многострочного комментария ("//" и "*/") стоит пробел.
Они разделены пробелом, чтобы компилятор обрабатывал их именно как "//" и "*/", а не "/", "/*" и "/" - в этом случае компилятор подумает, что это вложенный комментарий, и выдаст варнинг.
11) Пропуск инициализации ячеек массива нулями.
При объявлении локальных массивов внутри функций компилятор не только резервирует место в стеке под массив, но и инициализирует все его ячейки нулями, чтобы в них не было мусорных значений.
Сделано это из-за быдлокодеров, которые, пользуются переменными, забывая их инициализировать.
Тем не менее, инициализация занимает некоторое время, да и польза от этого сомнительная, если вы способны отдавать отчёт своим действиям.
К счастью, есть способ избежать потерь во времени, пропустив инициализацию:
Почему пропуск инициализации повышает производительность кода?PHP код:
SomeFunction()
{
// перед объявлением массива перейдём на метку skip_array_init
goto skip_array_init;
// объявляем массив
new arr[256];
skip_array_init:
// в этом месте массив arr будет существовать, но он не будет инициализирован:
// код инициализации существует, но он находится _до_ метки skip_array_init,
// т.е. мы обошли этот код
// дальше - код с использованием массива
}
Также для удобства можно использовать следующий макрос:
Пример использования:PHP код:
#define noinit:%0[%1]; goto _noinit_%0;new %0[%1];_noinit_%0:
PHP код:
public OnGameModeInit()
{
// Объявляем массив test и пропускаем обычную инициализацию его ячеек.
noinit:test[120];
// Инициализируем ячейки массива вручную случайными числами.
for (new i = 0; i < sizeof(test); i++)
test[i] = random(sizeof(test));
// ...
}
12) strcat или format?
Какая из этих функций наиболее эффективна для соединения строк?
Согласно тесту скорости (по алгоритму профилирования Daniel_Cortez), strcat выполняется намного быстрее чем format при конкатенации 2 строк.
Но если нужно соединить 3 или более строк, рано или поздно format вырвется вперёд, т.к. львиная доля времени уходит на вызов нативных функций. Чем больше строк нужно соединить, тем больше раз нужно вызвать функцию strcat. В то же время, функция format может одним вызовом соединить практически неограниченное количество строк - отсюда и выгода.
Опытным путём удалось выяснить, что strcat выгодно использовать при соединении от 2 до 7 строк.
При соединении 8 строк format уже начинает обгонять strcat. Как и предполагалось, при достаточном количестве строк выгода strcat сошла на нет.
Также strcat автоматически распаковывает строку, если попытаться прицепить упакованную строку к неупакованной, и наоборот, упаковывает, если первая строка тоже была упакована.
Так или иначе, в отличие от format, при помощи функции strcat нельзя одним вызовом объединить две строки, записав результат в отдельный массив, или одновременно объединить больше чем две строки - нужно сначала отдельным действием записать в массив для хранения результата одну строку, а потом с помощью strcat добавить другую.
Автор темы: ^_^.
Авторы ответов: 1, 2, 3, 5, 6 - Tracker1; 4, 6, 8, 9, 10, 11 - Daniel_Cortez; 8 - DeimoS; 3,4 - ^_^
Если у вас появился интересный ответ или хороший совет, строго касающегося языка pawn или частных проблем sa-mp, прошу оставить его в комментариях (он будет добавлен в саму тему). Заранее спасибо.
Тема будет дополняться.