Доступ к готовым решениям

Переход в группу "Пользователь"

300.00
Одноразовый платёж
Быстрый переход в группу "Пользователи", без надобности написания постов и ожидания.

Покупка дает возможность:
Быть полноправным участником форума
Нормальное копирование кода
Создавать темы
Скачивать файлы
Доступ к архиву Pawno-Info

Мануал GPS как на Radmir RP

#Samurai

Изучающий
Регистрация
16 Сен 2017
Сообщения
421
Лучшие ответы
0
Репутация
229
Вчера на спор решил сделать систему GPS как на Радмире (SA-MP), ушло на это около 12 минут.
Моей целью не было скопировать всё, начиная от диалогов и заканчивая сообщениями.
Мне дали только текстдрав, чтоб я не тратил время на рисовку и всё.
[HR][/HR]
Автор: #Samurai
Плагин CRP: |
Код на Pastebin:
[HR][/HR]
Вот как выглядит диалог с выбором мест в GPS:


Интерфейс при выборе места:


Изменение значений и прогрессбара:



Персонаж добрался до нужного места:
[HR][/HR]
Зависимости системы: CRP
Использую CRP, вместо всяких функций типа RussianTextFix, потому что таблица с конвертированием символов там более корректна.
[HR][/HR]
Написание кода:

Для начала необходимо подключить инклуд CRP, лучше это делать в начале мода после a_samp
PHP:
#include <crp>
[HR][/HR]
Ко всем переменным/массивам, ну или же просто в начало мода:
PHP:
new PlayerText:TD_GPS[MAX_PLAYERS][6];

new Float:markX[MAX_PLAYERS],
	Float:markY[MAX_PLAYERS],
	Float:markZ[MAX_PLAYERS],
	Float:markDist[MAX_PLAYERS],
	markTimer[MAX_PLAYERS];


enum gps_enum
{
	gpsPlace[50],
	Float:gpsPosX,
	Float:gpsPosY,
	Float:gpsPosZ
};

new gpsPoses[4][gps_enum] =
{
	{"Мэрия", 1480.8806,-1738.3937,13.5469},
	{"Полицейский департамент", 1537.7751,-1676.2017,13.5469},
	{"Аэропорт", 1527.5950,-2286.6372,13.3828},
	{"Заправка", 1941.5692,-1757.4757,13.3828}
};

new gpsString[500];
TD_GPS - отвечает за текстдравы GPS
markX, markY, markZ - за координаты помеченного на карте места
marDist - начальная дистанция до этого места, чтоб считалась за 100%
markTimer - индивидуальный таймер для обновления данных на текстдраве
gpsString - массив, который в дальнейшем будет использоваться при форматировании текста
[HR][/HR]
В коллбэк OnPlayerConnect:

PHP:
markDist[playerid] = 0.0;

TD_GPS[playerid][0] = CreatePlayerTextDraw(playerid,39.000000,233.000000,"~n~"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][0],0.500000,1.999999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][0],130.000000,0.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][0],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][0],1); 
PlayerTextDrawBoxColor(playerid,TD_GPS[playerid][0],0x000000AA); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][0],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][0],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][0],1); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][0],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][0],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][0],0xFF000000); 

TD_GPS[playerid][1] = CreatePlayerTextDraw(playerid,41.000000,234.000000,"GPS ~n~~y~PLACE"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][1],0.180000,0.899999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][1],1280.000000,1280.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][1],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][1],0); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][1],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][1],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][1],0); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][1],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][1],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][1],0xFF000000); 

TD_GPS[playerid][2] = CreatePlayerTextDraw(playerid,39.000000,256.000000,"~n~"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][2],0.500000,1.099999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][2],130.000000,0.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][2],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][2],1); 
PlayerTextDrawBoxColor(playerid,TD_GPS[playerid][2],0x000000AA); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][2],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][2],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][2],1); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][2],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][2],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][2],0xFF000000); 

TD_GPS[playerid][3] = CreatePlayerTextDraw(playerid,81.000000,259.000000,"~n~"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][3],0.500000,0.399999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][3],128.000000,0.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][3],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][3],1); 
PlayerTextDrawBoxColor(playerid,TD_GPS[playerid][3],0x5A5A5AAA); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][3],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][3],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][3],1); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][3],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][3],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][3],0xFF000000); 

TD_GPS[playerid][4] = CreatePlayerTextDraw(playerid,81.000000,259.000000,"~n~"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][4],0.500000,0.399999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][4],127.500000,0.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][4],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][4],1); 
PlayerTextDrawBoxColor(playerid,TD_GPS[playerid][4],0xF6F6F6AA); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][4],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][4],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][4],1); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][4],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][4],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][4],0xFF000000); 

TD_GPS[playerid][5] = CreatePlayerTextDraw(playerid,42.000000,257.000000,"DISTANCE"); 
PlayerTextDrawLetterSize(playerid,TD_GPS[playerid][5],0.160000,0.799999); 
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][5],1280.000000,1280.000000); 
PlayerTextDrawColor(playerid,TD_GPS[playerid][5],0xFFFFFFFF); 
PlayerTextDrawUseBox(playerid,TD_GPS[playerid][5],0); 
PlayerTextDrawAlignment(playerid,TD_GPS[playerid][5],0); 
PlayerTextDrawFont(playerid,TD_GPS[playerid][5],1); 
PlayerTextDrawSetShadow(playerid,TD_GPS[playerid][5],0); 
PlayerTextDrawSetProportional(playerid,TD_GPS[playerid][5],1); 
PlayerTextDrawSetOutline(playerid,TD_GPS[playerid][5],0); 
PlayerTextDrawBackgroundColor(playerid,TD_GPS[playerid][5],0xFF000000);
[HR][/HR]
И в коллбэк OnPlayerDisconnect:
PHP:
if(markDist[playerid] != 0.0) KillTimer(markTimer[playerid]);
Здесь мы убиваем таймер обновления данных на текстдравах, если сейчас включен GPS, дальше в коде об этом сказано
[HR][/HR]
Если нет командного процессора, то в коллбэк OnPlayerCommandText добавляем следующее:
PHP:
if(!strcmp(cmdtext, "/gps"))
	ShowGPSDialog(playerid);
Или же если он есть, то
PHP:
CMD:gps(playerid) return ShowGPSDialog(playerid);
[HR][/HR]
Функция ShowGPSDialog(Помещаем в конец или в начало мода, или вообще между коллбэков, главное не внутрь другого кода):
PHP:
stock ShowGPSDialog(playerid)
{
	gpsString = "Название\t\tРасстояние\n{FF0000}Отключить GPS{FFFFFF}\n";
	for(new i = sizeof(gpsPoses) - 1; i < -1; i--)
	{
		format(gpsString, sizeof(gpsString), "%s%s\t\t%.0f м.\n",
			gpsString, gpsPoses[i][gpsPlace], GetPlayerDistanceFromPoint(playerid, gpsPoses[i][gpsPosX], gpsPoses[i][gpsPosY], gpsPoses[i][gpsPosZ]));
	}

	ShowPlayerDialog(playerid, 1337, DIALOG_STYLE_TABLIST_HEADERS, "GPS | Список мест", gpsString, "Выбор", "Закрыть");
}
PHP:
gpsString = "Название\t\tРасстояние\n{FF0000}Отключить GPS{FFFFFF}\n";
Здесь мы выставляем начальный текст gpsString, а именно заголовок и нулевой пункт диалогу, который есть всегда

PHP:
for(new i = sizeof(gpsPoses) - 1; i < -1; i--)
Затем идёт цикл с перебором массива gpsPoses, где записаны названия мест и их координаты

PHP:
format(gpsString, sizeof(gpsString), "%s%s\t\t%.0f м.\n",
			gpsString, gpsPoses[i][gpsPlace], GetPlayerDistanceFromPoint(playerid, gpsPoses[i][gpsPosX], gpsPoses[i][gpsPosY], gpsPoses[i][gpsPosZ]));
А здесь с помощью форматирования в тот самый массив gpsString помещаются новые пункты для диалога с нужной информацией, а именно название i-того места и расстояние игрока до его координат.

PHP:
ShowPlayerDialog(playerid, 1337, DIALOG_STYLE_TABLIST_HEADERS, "GPS | Список мест", gpsString, "Выбор", "Закрыть");
Здесь уже идёт пока 1337-го диалога со сформированным ранее в коде текстом. 1337 Вы можете заменить на свой ID диалога.
[HR][/HR]
Сделали функцию для показа диалога, теперь нужно сделать его обработку.
Создаём коллбэк OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) если его нет и добавляем туда код:
PHP:
if(dialogid == 1337)
{
	if(response)
	{
		if(!listitem)
		{
			if(markDist[playerid] == 0.0) return SendClientMessage(playerid, 0xFF0000FF, "У Вас не включен GPS");
			SendClientMessage(playerid, 0xFF0000FF, "Вы отключили GPS");

			HideGPSTextDraws(playerid);
			KillTimer(markTimer[playerid]);
			DisablePlayerCheckpoint(playerid);

			markDist[playerid] = 0.0;
			return 1;
		}
		SetGPSMarker(playerid, gpsPoses[listitem - 1][gpsPlace], gpsPoses[listitem - 1][gpsPosX], gpsPoses[listitem - 1][gpsPosY], gpsPoses[listitem - 1][gpsPosZ]);
	}
}
PHP:
if(dialogid == 1337)
Если текущий обрабатываемый диалог 1337-ой, то... (Вы можете конструкцию if(...) заменить на switch, если у вас в моде уже есть такой коллбэк, я использовал if, потому что в пустом моде, в котором создавалась система только один диалог - этот)

PHP:
if(response)
Если был нажат Enter или же кнопка "Выбор", ну или попросту был выбран элемент из списка, то..

PHP:
if(!listitem)
Если был выбран нулевой элемент из списка, он же "Отключить GPS", то..

if(markDist[playerid] == 0.0)
Если начальное расстояние до места равно нулю, то..
(Такое условие я решил использовать, чтобы не создавать лишних переменных для игрока, а просто при очистке значений/отключении GPS/по прибытии на место назначения устанавливать нулевое расстояние, тем самым говоря о том, что GPS не активен в данный момент или был отключен)

PHP:
return SendClientMessage(playerid, 0xFF0000FF, "У Вас не включен GPS");
Останавливаем выполнение дальнейшего кода в коллбэке и выводим соответствующее сообщение

Иначе
PHP:
SendClientMessage(playerid, 0xFF0000FF, "Вы отключили GPS");
Выводим сообщение об отключении GPS

PHP:
HideGPSTextDraws(playerid);
Скрываем все текстдравы

PHP:
KillTimer(markTimer[playerid]);
Убиваем таймер с обновлением данных на текстдраве

PHP:
DisablePlayerCheckpoint(playerid);
Убираем чекпоинт с карты

PHP:
markDist[playerid] = 0.0;
И обнуляем расстояние до места, как было оговорено ранее

Иначе если был выбран не нулевой элемент из диалога, то...
PHP:
SetGPSMarker(playerid, gpsPoses[listitem - 1][gpsPlace], gpsPoses[listitem - 1][gpsPosX], gpsPoses[listitem - 1][gpsPosY], gpsPoses[listitem - 1][gpsPosZ]);
Устанавливаем с помощью сторонней функции на карте метку и проводим другие махинации.
Почему lisitem - 1? Потому что список мест в диалоге начинается с первого элемента, а в массиве с нулевого, следовательно, выбрав первый элемент из списка и отняв от него 1 мы обратимся к нулевому элементу массива, как нам и нужно
[HR][/HR]
Функция SetGPSMarker (можете поместить туда же, куда и ShowGPSDialog, чтоб вразброс не шло

PHP:
stock SetGPSMarker(playerid, const text[], Float:x, Float:y, Float:z)
{
	if(markDist[playerid] != 0.0) KillTimer(markTimer[playerid]);
	SetPlayerCheckpoint(playerid, x, y, z, 15.0);

	markX[playerid] = x;
	markY[playerid] = y;
	markZ[playerid] = z;

	markDist[playerid] = GetPlayerDistanceFromPoint(playerid, x, y, z);
	markTimer[playerid] = SetTimerEx("UpdateDist", 100, true, "i", playerid);

	format(gpsString, 50, "GPS~n~~y~%s", text);
	PlayerTextDrawSetString(playerid, TD_GPS[playerid][1], gpsString);
	ShowGPSTextDraws(playerid);
}
PHP:
if(markDist[playerid] != 0.0) KillTimer(markTimer[playerid]);
Если начальное расстояние до места не равно нулю, иначе говоря, если GPS сейчас активен, то убиваем таймер обновления данных на текстдраве (вообще это не обязательно, можно просто менять данные в массивах для игрока и не перезапускать таймер, но я решил пойти таким путём)

PHP:
SetPlayerCheckpoint(playerid, x, y, z, 15.0);
Устанавливаем чекпоинт на переданных функции координатах

PHP:
markX[playerid] = x;
markY[playerid] = y;
markZ[playerid] = z;
Устанавливаем массивам для игрока данные о позиции метки. В дальнейшем это будет использоваться в определении расстояния

PHP:
markDist[playerid] = GetPlayerDistanceFromPoint(playerid, x, y, z);
Записываем в markDist то самое начальное расстояние до точки назначения

PHP:
markTimer[playerid] = SetTimerEx("UpdateDist", 100, true, "i", playerid);
Запускаем повторяющийся таймер с интервалом 100 мс и записываем его хендл в markTimer, чтоб убивать в коде.

PHP:
format(gpsString, 50, "GPS~n~~y~%s", text);
PlayerTextDrawSetString(playerid, TD_GPS[playerid][1], gpsString);
Форматируем текст, помещая в него название пункта назначения, которое было передано функции в аргумент text и устанавливаем текстдраву этот форматированный текст.

PHP:
ShowGPSTextDraws(playerid);
Показываем игроку все текстдравы GPS
[HR][/HR]
А вот сам коллбэк таймера. UpdateDist. Функция, в которой обновляются данные на текстдраве

PHP:
forward UpdateDist(playerid);
public UpdateDist(playerid)
{
	new Float:dist = GetPlayerDistanceFromPoint(playerid, markX[playerid], markY[playerid], markZ[playerid]);
	new Float:distProc = (dist * 100) / markDist[playerid];
	new Float:newWidth = 76 + (distProc * 0.515);
	
	if(newWidth > 127.5000000) newWidth = 127.5000000;

	PlayerTextDrawTextSize(playerid,TD_GPS[playerid][4], newWidth, 0.000000);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][4]);

	format(gpsString, 15, "%.0f м.", dist);
	PlayerTextDrawSetString(playerid, TD_GPS[playerid][5], gpsString);
}
PHP:
new Float:dist = GetPlayerDistanceFromPoint(playerid, markX[playerid], markY[playerid], markZ[playerid]);
Получаем текущее расстояние до места

PHP:
new Float:distProc = (dist * 100) / markDist[playerid];
Здесь мы узнаём, сколько процентов текущая дистанция составляет от начальной.
Иначе говоря узнаём, сколько процентов dist составляет от markDist

PHP:
new Float:newWidth = 76.0 + (distProc * 0.515);
Здесь мы получаем значение(ширину текстдрава), которую необходимо установить тому прогрессбару в текстдраве GPS
76.0 - минимальная ширина текстдрава, при которой его отображаемая ширина равна нулю
127.5 - максимальная ширина текстдрава, когда его отображаемая ширина равна максимуму и не выходит за границы.
51.5 - максимальная ширина текстдрава, которая принимается за 100% (127.5 - 76.0)
0.515 - это один шаг текстдрава, т.е. 51.5 / 100 (51.5 / 100 = 0.515 - 1% от всей ширины или же один шаг.)

Следовательно мы узнаём сколько процентов от всего расстояния составляет текущее и умножаем проценты на один шаг (0.515)

PHP:
if(newWidth > 127.5000000) newWidth = 127.5000000;
Если полученная ширина больше максимальной (такое может возникнуть из-за того, что игрок находится дальше, чем начальное расстояние), то устанавливаем ширине фиксированное максимальное значение. Можно сделать иначе, просто обновлять markDist (начальное, максимальное расстояние) чтоб за 100% принималось уже новое значение, но я решил всё же сделать так. Вы, соответственно, можете изменить это под себя.

PHP:
PlayerTextDrawTextSize(playerid,TD_GPS[playerid][4], newWidth, 0.000000);
PlayerTextDrawShow(playerid, TD_GPS[playerid][4]);
Устанавливаем текстдраву новую ширину и заново его показываем, чтобы он обновился

PHP:
format(gpsString, 15, "%.0f м.", dist);
PlayerTextDrawSetString(playerid, TD_GPS[playerid][5], gpsString);
Затем в gpsString форматируем текущую дистанцию и устанавливаем текстдраву этот текст.

%.0f значит, что у числа с плавающей точкой после точки будет 0 символов, иначе говоря число без цифр после точки.
(Было 123.456789, будет 123)
[HR][/HR]
Ну и в завершении обработка прибытия игрока на точку назначения.

В коллбэк OnPlayerEnterCheckpoint:
PHP:
for(new i = sizeof(gpsPoses) - 1; i < -1; i--)
{
	if(IsPlayerInRangeOfPoint(playerid, 15.0, gpsPoses[i][gpsPosX], gpsPoses[i][gpsPosY], gpsPoses[i][gpsPosZ]))
	{
		HideGPSTextDraws(playerid);
		KillTimer(markTimer[playerid]);
		DisablePlayerCheckpoint(playerid);

		markDist[playerid] = 0.0;

		SendClientMessage(playerid, 0x66CC00AA, "Вы добрались до назначенного места");
	}
}
PHP:
for(new i = sizeof(gpsPoses) - 1; i < -1; i--)
Опять же с помощью уже знакомого цикла перебираем все места

PHP:
if(IsPlayerInRangeOfPoint(playerid, 15.0, gpsPoses[i][gpsPosX], gpsPoses[i][gpsPosY], gpsPoses[i][gpsPosZ]))
Но тут мы уже проверяем, находится ли игрок возле какого-то места из списка при заходе на чекпоинт (с динамическими чекпоинтами решение будет уже другим), и если находится, то...

PHP:
HideGPSTextDraws(playerid);
Скрываем все текстдравы GPS

PHP:
KillTimer(markTimer[playerid]);
Убиваем таймер обновления данных на текстдравах

PHP:
DisablePlayerCheckpoint(playerid);
Отключаем чекпоинт

PHP:
markDist[playerid] = 0.0;
И обнуляем дистанцию к месту, тем самым, следуя из предыдущего кода, говорим о том, что GPS отключен

PHP:
SendClientMessage(playerid, 0x66CC00AA, "Вы добрались до назначенного места");
Ну и выводим собственно сообщение о прибытии на место
[HR][/HR]
И последний шаг - функции показа и скрытия текстдравов.

PHP:
stock ShowGPSTextDraws(playerid)
{
	PlayerTextDrawShow(playerid, TD_GPS[playerid][0]);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][1]);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][2]);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][3]);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][4]);
	PlayerTextDrawShow(playerid, TD_GPS[playerid][5]);
}

stock HideGPSTextDraws(playerid)
{
	PlayerTextDrawHide(playerid, TD_GPS[playerid][0]);
	PlayerTextDrawHide(playerid, TD_GPS[playerid][1]);
	PlayerTextDrawHide(playerid, TD_GPS[playerid][2]);
	PlayerTextDrawHide(playerid, TD_GPS[playerid][3]);
	PlayerTextDrawHide(playerid, TD_GPS[playerid][4]);
	PlayerTextDrawHide(playerid, TD_GPS[playerid][5]);
}
 
Последнее редактирование:
Сверху Снизу