Система динамических чекпоинтов -
anybox - 17.01.2013
Всем привет. Допустим, что по некоторым причинам вас не удовлетворяют средства проверки, что игрок находится в какой-либо точке, например с помощью пикапов или проверок IsPlayerInRangeOfPoint. Или же вы просто хотите сделать чекпоинты как дополнение к уже существующим пикапам(в том смысле, чтобы чекпоинт появлялся, когда подходишь к какому-либо пикапу). Я расскажу, как сделать систему динамических чекпоинтов, а вы уже определите, как будете использовать её в своих проектах.
1 шаг. Создание основы. Структуры и функции.
Во-первых, нам нужна структура, которая будет содержать информацию о чекпоинте: позиция, радиус чекпоинта и дистанция, начиная с которой чекпоинт будет отображаться.
pawn Code:
enum CHECKPOINTINFO {
Float: e_cpX, // позиция чекпоинта по X
Float: e_cpY, // позиция чекпоинта по Y
Float: e_cpZ, // по Z
e_cpRad, // радиус(размер) чекпоинта
e_cpDist // дистанция, начиная с которой чекпоинт будет отображаться
}
Далее нужно будет объявить массив чекпоинтов. Давайте сделаем
два чекпоинта. Так, просто для теста.
pawn Code:
new dynamicCp[][CHECKPOINTINFO] = {
{0.0, 0.0, 1.0, 3, 5},
{2.0, 0.0, 1.0, 3, 5}
};
Мы сразу заполняем массив чекпоинтов dynamicCp нужной информацией(если вас не устраивает такой способ заполнения массива, вы можете сделать считывание основных параметров из файла). Давайте разберём строку {0.0, 0.0, 1.0, 3, 5}. Первые три цифры - это позиция чекпоинта, далее радиус и последнее - дистанция. По сути, эта строка указывает, что чекпоинт размера 3 будет создан в центре карты (0.0, 0.0, 1.0) и покажется игроку, только если расстояние между ними окажется меньше 5.
Объявите новый массив pDynCp[MAX_PLAYERS].
Назначение его в том, чтобы хранить индекс того чекпоинта, который в данный момент виден игроку. Мы будем использовать значения этого массива, чтобы определять в OnPlayerEnterCheckpoint, на какой чекпоинт зашёл игрок. Всё, что нужно сделать с данным массивом, это "обнулить" одну из его ячеек, когда какой-либо игрок присоединиться. (фактически, мы не обнуляем, а присваиваем -1, потому что индекс чекпоинта может быть и нулевым)
pawn Code:
public OnPlayerConnect(playerid)
{
// какой-то ваш код
pDynCp[playerid] = -1;
return 1;
}
Далее. Создайте паблик, пока пустой.
pawn Code:
forward checkDynCp();
public checkDynCp()
{
return 1;
}
Отлично, паблик создан. Последним на данном, подготовительном этапе шагом будет создание таймера. В OnGameModeInit перед return 1; поместите данный ниже код:
pawn Code:
SetTimer("checkDynCp", 1000, true);
Мы объявили таймер, суть которого будет объяснена ниже.
Поздравляю, вы закончили первый этап, давайте перейдём ко второму.
2. Непосредственно обработка чекпоинтов.
Не самый сложный код, но в данном мануале, пожалуй, самый основной.
Вернёмся к нашему паблику checkDynCp. Пропишите в нём следующее:
pawn Code:
forward checkDynCp();
public checkDynCp()
{
static k, Float: x, Float: y, Float: z, dist, id;
for (new j = 0; j < MAX_PLAYERS; j++) {
if (!IsPlayerConnected(j)) continue;
id = pDynCp[j];
if (id != -1) {
dist = dynamicCp[id][e_cpDist];
if (!IsPlayerInRangeOfPoint(j, dist, dynamicCp[id][e_cpX], dynamicCp[id][e_cpY], dynamicCp[id][e_cpZ])) {
pDynCp[j] = -1;
DisablePlayerCheckpoint(j);
}
} else
for (k = 0; k < sizeof(dynamicCp); k++) {
dist = dynamicCp[k][e_cpDist];
x = dynamicCp[k][e_cpX];
y = dynamicCp[k][e_cpY];
z = dynamicCp[k][e_cpZ];
if (IsPlayerInRangeOfPoint(j, dist, x, y, z)) {
pDynCp[j] = k;
SetPlayerCheckpoint(j, x, y, z, dynamicCp[k][e_cpRad]);
break;
}
}
}
}
Время разобраться, что же собственно говоря происходит в данном паблике.
В начале мы объявляем вспомогательные переменные, делаем их статическими (созданы они будут один раз и доступны только в пределах данного паблика).
Далее запускаем цикл по всем игрокам (если вы используете свои "оптимизированные" циклы только по подключенным игрокам, то можете изменить эту строку). Первая проверка - подключен ли игрок. Если нет, переходим к следующему игроку. Далее узнаём позицию игрока GetPlayerPos(j,x,y,z); В переменную ID заносим значение индекса чекпоинта, который виден в данный момент игроку. Далее проверяем, если индекс НЕ равен -1 (то есть игроку виден какой-либо чекпоинт в данный момент), то будем проверять, отошёл ли игрок от чекпоинта на достаточное расстояние(e_cpDist), чтобы скрыть чекпоинт. Если не отошёл, то чекпоинт так и будет виден, и нам не надо проверять другие чекпоинты (помните, что в GTA SAMP в один момент времени может существовать только ОДИН чекпоинт). Если же у нас id равен -1 (то есть игроку ещё не виден никакой чекпоинт), то мы проверим, какой чекпоинт ближе всего к игроку. Для этого пройдёмся по всем чекпоинтам и расчитаем расстояние от чекпоинта до игрока. Если расстояние меньше чем e_cpDist, то в массив pDynCp[playerid] заносим индекс найденного чекпоинта, устанавливаем на карте чекпоинт и прерываем цикл через break;.
Отлично! Мы написали основной код, перейдём теперь к следующему этапу.
3. Делаем что-либо, в зависимости от того, на каком чекпоинте игрок.
pawn Code:
public OnPlayerEnterCheckpoint(playerid)
{
switch (pDynCp[playerid]) {
case 0: SendClientMessage(playerid, 0xFFFFFFFF, "Вы на первом чекпоинте");
case 1: SendClientMessage(playerid, 0xFFFFFFFF, "Вы на втором чекпоинте");
}
return 1;
}
Как видите, проверки очень просты. Если сейчас игроку виден 0 чекпоинт, то соответственно он может на него встать, а когда встанет ему появится сообщение "Вы на первом чекпоинте". То же самое для второго. Вместо этих действий вы вправе прописать любой свод код, например показать игроку какое-нибудь меню, либо телепортировать его в другое место.
Помните, что всегда могут возникнуть ситуации, когда ваша система идёт вразрез с этой, поэтому тщательно переделывайте любой свой код связанный с чекпоинтами, если вы будете использовать эту систему. (проблемным будет импортировать данный код в gf-based моды)
Re: Система динамических чекпоинтов -
White_116 - 17.01.2013
Для определения расстояния используй лучше
GetPlayerDistanceFromPoint(), быстрее будет.
Re: Система динамических чекпоинтов -
anybox - 17.01.2013
Хорошо, спасибо.
Re: Система динамических чекпоинтов -
Stepashka - 17.01.2013
- избавляемся от #define MAX_CHECKPOINTS 2
- во всех циклах ломимся в sizeof(dynamicCp)
- сам массив объявляем так new dynamicCp[][CHECKPOINTINFO] = {...};, компилятор сам определит его размер
Преимущество: нам теперь не нужно держать в голове информацию о том что необходимо ещё и где-то константу менять, просто добавляем новый чекпоинт в массив и компилируем скрипт.
Недостаток: при загрузке массива из стороннего источника, нам все равно придется жестко указать размер данного массива, но опять же только в одном месте.
Quote:
Originally Posted by White_116
Для определения расстояния используй лучше GetPlayerDistanceFromPoint(), быстрее будет.
|
А ещё быстрее будет использовать
IsPlayerInRangeOfPoint
pawn Code:
if (GetPlayerDistanceFromPoint(j, x0, y0, z0) <= dist) {
if (IsPlayerInRangeOfPoint(j, dist, x0, y0, z0)) {
pawn Code:
if (GetPlayerDistanceFromPoint(j, dynamicCp[id][e_cpX], dynamicCp[id][e_cpY], dynamicCp[id][e_cpZ]) > dist) {
if (!IsPlayerInRangeOfPoint(j, dist, dynamicCp[id][e_cpX], dynamicCp[id][e_cpY], dynamicCp[id][e_cpZ])) {
Re: Система динамических чекпоинтов -
OKStyle - 17.01.2013
Помню, [LTD]Luxury делал что-то подобное. Естественно, без этих модных функций расстояния =)
Re: Система динамических чекпоинтов -
anybox - 18.01.2013
Подправил. Вопрос в том, почему быстрей будет использовать эти функции? И почему среди этих функций IsPlayerInRangeOfPoint будет работать пошустрей, чем GetPlayerDistanceFromPoint? Это было выявлено на тестах или дело в чём-то ином?
Re: Система динамических чекпоинтов -
Stepashka - 18.01.2013
Quote:
Originally Posted by anybox
Подправил. Вопрос в том, почему быстрей будет использовать эти функции? И почему среди этих функций IsPlayerInRangeOfPoint будет работать пошустрей, чем GetPlayerDistanceFromPoint? Это было выявлено на тестах или дело в чём-то ином?
|
Все сразу.
IsPlayerInRangeOfPoint изначально была создана для проверок, она возвращает булево значение.
GetPlayerDistanceFromPoint была создана для получения расстояния от игрока до точки и она возвращает значение с плавающей запятой, а в виду того что архитектура всех десктопных процессоров такова что они основаны на работе с целочисленными переменными, работа с плавающей запятой занимает больше времени.
Re: Система динамических чекпоинтов -
Richard_Gere - 18.01.2013
И чем это лучше CreateDynamicCP, который дан в стримере от Инкогнито ?
Re: Система динамических чекпоинтов -
AirKite - 18.01.2013
Quote:
Originally Posted by Richard_Gere
И чем это лучше CreateDynamicCP, который дан в стримере от Инкогнито ?
|
Ничем. Это Tutorial