Введение
Приветствую всех! Сегодня мы с вами рассмотрим небольшой способ создания команды для слежки за игроком. Преимущества данного варианта, в достаточно практичном автоматическом обновлении режима слежки в необходимых случаях (смена интерьера, смена виртуального мира, посадка в транспорт).
Не буду лгать что идея возникла в моей голове внезапно. Я всего-лишь наткнулся на заморский топик, после чего решил перенести это в наше комьюнити.
Поехали...
Для начала, создадим необходимую нам переменную, которая будет отвечать за ID того игрока, за которым мы наблюдаем:
PHP код:
new spectating[MAX_PLAYERS];
Использовать эту переменную мы будем следующим образом:
PHP код:
spectating[playerid] = - 1; // данное значение переменной, означает что мы игрок не за кем не наблюдает
spectating[playerid] = playerid; // любое значение, отличающееся от -1, будет значить, что игрок за кем-то наблюдает
Создавать мы будем, следующие команды:
Код:
/spectate - для того чтобы начать слежку за определенным игроком.
/offspec - для того чтобы закончить слежку за определенным игроком.
Мы также введем новый колбэк в мод, это облегчит процесс обновления режима слежки за определенным игроком.
Перейдем непосредственно к коду...
PHP код:
// Я приведу пример на целом колбэке OnPlayerCommandText
// Для определения ID игрока после команды (как параметр к команде), я буду использовать sscanf.
// Подробнее как использовать OnPlayerCommandText и sscanf, можно узнать перейдя по ссылке в конце мануала
public OnPlayerCommandText(playerid, cmdtext[])
{
new cmd[32],params[128];
sscanf(cmdtext, "s[32]s[128]", cmd, params);
if(strcmp(cmd, "/spectate"))
{
new player_id;
if(sscanf(params, "d", player_id)) return SendClientMessage(playerid, 0xFFFFFF, "/spectate [ID]");
if(IsPlayerConnected(player_id))
{
//Получаем виртуальный мир игрока за которым следим и устанавливаем такой-же игроку который следит, аналогично с интерьером
SetPlayerVirtualWorld(playerid,GetPlayerVirtualWorld(player_id));
SetPlayerInterior(playerid,GetPlayerInterior(player_id));
//Сейчас мы установим значение нашей переменной следящему игроку.
spectating[playerid] = player_id;
//Теперь, переведем следящего в режим наблюдения за игроком
TogglePlayerSpectating(playerid, 1);
//Разберёмся, находидтся ли игрок за которым следим в машине или нет. Установим соответствующий тип слежки.
if(IsPlayerInAnyVehicle(player_id)) PlayerSpectateVehicle(playerid, GetPlayerVehicleID(player_id), SPECTATE_MODE_NORMAL);
else PlayerSpectatePlayer(playerid, player_id, SPECTATE_MODE_NORMAL);
}
else return SendClientMessage(playerid, -1, "Игрок не найден!");
return 1;
}
if(strcmp(cmd, "/offspec", true) == 0)
{
if(IsPlayerConnected(playerid))
{
//Устанавливаем следящему виртуальный мир, который используется при spawn, аналогично с интерьером
SetPlayerVirtualWorld(playerid,0);
SetPlayerInterior(playerid,0);
//Очищаем переменную
spectating[playerid] = -1;
//Отключаем режим наблюдения у следящего
TogglePlayerSpectating(playerid, 0);
}
return 1;
}
return 0;
}
Теперь обновим режим слежки за игроком, в необходимых случаях.
PHP код:
public OnPlayerStreamOut(playerid, forplayerid)
{
//Данный паблик вызовется когда игрок за которым следим, пропадет из вида следящего (смена интерьера, виртуального мира)
if(IsPlayerConnected(forplayerid))
{
if(spectating[forplayerid] == playerid)//Проверяем действительно ли следит следящий игрок именно за этим игроком (см. примечание 1)
{
//Колбэк указанный ниже, поможет нам быстро обновить режим слежки
UpdateSpectatingStatus(forplayerid, playerid);
}
}
return 1;
}
public OnPlayerStateChange(playerid, newstate, oldstate)
{
//Если игрок за которым следим, меняет свой статус относительно нас (садится в машину)
for(new i = 0; i != MAX_PLAYERS; i++)
{
if(IsPlayerConnected(i))
{
if(spectating[i] == playerid)//Проверяем действительно ли следит следящий игрок именно за этим игроком
{
//Колбэк указанный ниже, поможет нам быстро обновить режим слежки
UpdateSpectatingStatus(i, playerid);
}
}
}
return 1;
}
Ну и наконец, добавим в любую точку мода, нашу функцию обновления режима слежки:
PHP код:
stock UpdateSpectatingStatus(spectatorid, spectedid)
{
//Еще раз проверяем, совпадает ли значение в переменной следящего игрока с ID игрока за которым следят
if(spectating[spectatorid] == spectedid)
{
//Приведенные ниже строчки-оповещения, вы можете не использовать
if(GetPlayerState(spectedid) == PLAYER_STATE_WASTED) return GameTextForPlayer(spectatorid, "~r~Target wasted!", 5000, 3); // игрок убит
if(GetPlayerState(spectedid) == PLAYER_STATE_SPECTATING) return GameTextForPlayer(spectatorid, "~r~Target in spectating mode!", 5000, 3); // игрок перешел в режим слежки
if(!IsPlayerConnected(spectedid)) return GameTextForPlayer(spectatorid, "~r~Target disconnected!", 5000, 3); // игрок отключился
//Снова устанавливаем виртуальный мир следящему, то же самое, проделываем с интерьером
SetPlayerVirtualWorld(spectatorid,GetPlayerVirtualWorld(spectedid));
SetPlayerInterior(spectatorid,GetPlayerInterior(spectedid));
//Отправляем следящего снова в режим слежки
TogglePlayerSpectating(spectatorid, 1);
if(IsPlayerInAnyVehicle(spectedid)) PlayerSpectateVehicle(spectatorid, GetPlayerVehicleID(spectedid), SPECTATE_MODE_NORMAL);
else PlayerSpectatePlayer(spectatorid, spectedid, SPECTATE_MODE_NORMAL);
}
return 1;
}
Дополнение
Мне предложили отличное дополнение к режиму наблюдение - это переключение между игрокам за которыми следим, при помощи клавиш. Я выбрал клавиши NUM 4, NUM6. Итак, для этого нам потребуется задействовать паблик OnPlayerKeyStateChange:
PHP код:
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
if(newkeys & KEY_ANALOG_LEFT) // проверяем нажатие клавиши NUM 4
{
if(spectating[playerid] != -1) // проверяем наблюдает ли за кем-либо игрок
{
if(spectating[playerid] <= 0) spectating[playerid] = GetMaxPlayers(); // если игрок наблюдает за минимальным ID, то перекидываем его на максимальный
else spectating[playerid]--; // или убавляем -1 от ID игрока за кем следящий наблюдал ранее
UpdateSpectatingStatus(playerid, spectating[playerid]); // обновляем режим слежки
}
}
if(newkeys & KEY_ANALOG_RIGHT) // проверяем нажатие клавиши NUM 6
{
if(spectating[playerid] != -1) // проверяем наблюдает ли за кем-либо игрок
{
if(spectating[playerid] >= GetMaxPlayers()) spectating[playerid] = 0; // если игрок наблюдает за максимальным ID, перекидываем его на минимальный
else spectating[playerid]++; // или добавляем +1 к ID игрока за кем следящий наблюдал ранее
UpdateSpectatingStatus(playerid, spectating[playerid]); // обновляем режим слежки
}
}
return 1;
// Не спорю, удобнее будет из цикла вытаскивать ID самого большого подключившегося игрока
// Но, я не думаю что это будет мелочью в плане быстродействия кода.
// Можно также завести переменную и записывать в нёё самый последний ID подключившегося игрока (см. примечание 2)
}
Заключение
Важно помнить и учитывать следующие факторы:
- В коде не используются, как может оказаться по вашему мнению, наиболее быстрые функции (исключение sscanf).
- Изменять код приведенный в примере, вы можете как душе угодно, я помогу вам разобраться с получившимися багами.
На этом всё...
Ах да!
Примечание 1 Примечание 1
OnPlayerStreamOut - вызывается для каждого игрока, который теряет из виду любого игрока сервера, именно поэтому нам необходима проверка на совпадение ID.
Примечание 2 Примечание 2
Как же нам определить самый большой ID среди игроков? Попробуем так:
PHP код:
new last_id; // создаем переменную для записи самого большого ID игрока
public OnPlayerConnect(playerid)
{
if(playerid > last_id) // проверяем, больше ли ID подключившегося игрока, чем предыдущее значении перменной
{
last_id = playerid; // если так, то обновляем значение
}
return 1;
}
// Теперь в дополнении, при переключении кнопок, вместо GetMaxPlayers, можно использовать значение данной переменной
// Единственный минус, в том, что если игрок отключится от сервера, максимальный ID - не обновится
// Но я думаю мне предложат варианты как исправить данный минус
Использование OnPlayerCommandText + sscanf
Автор мануала: wAx