PDA

Просмотр полной версии : [Include] UICompass



m1n1vv
13.12.2017, 00:10
UICompass v0.7

http://tscars.narod.ru/p-w/new/N.png

Данный инклуд предназначен для реализации компаса с стиле PUBG. Он выводит нынешнее направление включая три предыдущих и последующих.

Все направления в шкале кратны максимальному шагу, MAX_UICOMPASS_STEP. Направление выводится с интервалом. Например при [41 - 47] выведет 45. Поддерживается только нечетное количество TD!

Реализация TD на вашей стороне.



RoundCompassDirection - округляет направление до кратного round.


RoundCompassDirection(Float:angle, round);

Float:angle - нынешнее направление игрока
round - делает число кратным указанному значению

CreateCompassString - создает строку с направлением игрока.


CreateCompassString(angle, round);

angle - направление игрока полученное из RoundCompassDirection
round - делает число кратным указанному значению

CompassHeadingNorth - определяет, в каком из TD будет выведено "N".


CompassHeadingNorth(angle);

angle - направление игрока полученное из RoundCompassDirection



ДирективыПо умолчаниюОписание
MAX_UICOMPASS_TD7Количество TD, которое будет использоваться в Вашем компасе
MIN_UICOMPASS_STEP5Минимальный шаг компаса
MAX_UICOMPASS_STEP15Максимальный шаг компаса



Применение:

Создаем коллбэк для таймера.

http://tscars.narod.ru/p-w/new/compass.png


forward UICompassTimer(playerid);
public UICompassTimer(playerid)
{
static const
step_1 = MAX_UICOMPASS_STEP * 1,
step_2 = MAX_UICOMPASS_STEP * 2,
step_3 = MAX_UICOMPASS_STEP * 3;

static
north,
result,
direction,
Float:angle;

//Узнаем направление игрока
GetPlayerFacingAngle(playerid, angle);

//Получаем максимальный шаг компаса
result = RoundCompassDirection(angle);

//Получаем минимальный шаг компаса
direction = RoundCompassDirection(angle, MIN_UICOMPASS_STEP);

//Узнаем, в каком TD будет выведено "N"
north = CompassHeadingNorth(result);

//Три предыдущих направления
PlayerTextDrawSetString(playerid, td_uicompass[playerid][0], CreateCompassString(result - step_3));
PlayerTextDrawSetString(playerid, td_uicompass[playerid][1], CreateCompassString(result - step_2));
PlayerTextDrawSetString(playerid, td_uicompass[playerid][2], CreateCompassString(result - step_1));

//Нынешнее направление
PlayerTextDrawSetString(playerid, td_uicompass[playerid][3], CreateCompassString(result));

//Три последующих направления
PlayerTextDrawSetString(playerid, td_uicompass[playerid][4], CreateCompassString(result + step_1));
PlayerTextDrawSetString(playerid, td_uicompass[playerid][5], CreateCompassString(result + step_2));
PlayerTextDrawSetString(playerid, td_uicompass[playerid][6], CreateCompassString(result + step_3));

//Выводим направление кратное минимальному шагу
PlayerTextDrawSetString(playerid, td__compass_dir[playerid], CreateCompassString(direction, MIN_UICOMPASS_STEP));

//Устанавливаем всем TD изначальный цвет (Готов выслушать предложения по упрощению)
PlayerTextDrawColor(playerid, td_uicompass[playerid][0], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][0]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][1], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][1]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][2], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][2]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][3], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][3]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][4], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][4]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][5], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][5]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][6], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][6]);

//Устанавливаем нужному TD желтый цвет, где будет выведено "N"
if (0 <= north < MAX_UICOMPASS_TD)
{
PlayerTextDrawColor(playerid, td_uicompass[playerid][north], 0xFFFF00FF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][north]);
}

return 1;
}

Автор: m1n1vv
Скачать/Репозиторий: https://github.com/m1n1vv/UICompass
Версия: v0.7

Daniel_Cortez
13.12.2017, 22:45
Взглянул на код, вот проблемы, которые сразу бросились в глаза:
Неудачно названные функции. К примеру, в английском языке первым в предложении ставится дополнительное существительное, а после него основное, поэтому корректным названием будет не "GetDirectionCompass", а "GetCompassDirection".
Настоятельно рекомендую заглянуть сюда (http://pro-pawn.ru/showthread.php?8347), здесь больше примеров в пунктах 14 и 15.

Функция названа CompassSetString, но на вход принимает не строку, а число. Это идёт вразрез с логикой, по которой именуются стандартные функции TextDrawSetString и PlayerTextDrawSetString (а на неё ориентируются авторы многих других хорошо выполненных инклудов, так что это не просто пара функций).

Магические числа.


uic__N = 24 - uic__N + uic__min_N;

Пришлось портатить несколько минут, чтобы понять, что "24" здесь означает "360 / 15". Можно было бы вынести это в отдельную константу ("MAX_UICOMPASS_DIRECTIONS", например).

Путаница со сравнением целочисленных и логических значений с 0/false.


if (!angle)

Обычно таким образом проверяют логические переменные (или выражения) на равенство false. Из-за этого возникает впечатление, что angle - переменная логического типа, и приходится перемещаться в самый верх инклуда, к объявлению этой переменной, чтобы убедиться в обратном.
Та же самая проблема, но с проверкой на ненулевое значение:


if (uic__diff)

Не ленитесь дописать "== 0" или "!= 0" - это отнимет полсекунды вашего времени, но зато будет понятно, что производится сравнение именно с 0, а не с true/false.

Этот отрывок


if (angle > 360)
angle -= 360;
else if (angle < 0)
angle += 360;

можно заменить на


angle %= 360;


Что помешало объявить это как константу?


static
getN;

getN = (UICOMPASS_MAX_TD + 1) / 2;


Табы вперемешку с пробелами. На GitHub это особенно заметно, т.к. там один таб равносилен не 4, а 8 пробелам.
Бросайте pawno, возьмите нормальный текстовый редактор, который не подсовывает пробелы вместо табов - на форуме есть мануалы по адаптации (1 (http://pro-pawn.ru/showthread.php?1543), 2 (http://pro-pawn.ru/showthread.php?14620)).

В коде нет лицензии. Отсутствие лицензии означает отсутствие разрешения на использование кода, т.е. использование сего инклуда по сути незаконно (по крайней мере, такой принцип действует в юрисдикциях США и стран Европы, на счёт кривого российского законодательства не уверен).
Устранить эту проблему довольно просто: добавьте в начало файла копирайт и текст лицензии (к примеру, я обычно выкладываю свой код под лицензией zlib (https://github.com/Daniel-Cortez/samp-plugin-template/blob/5d1ad80a495544539929a675a94ba9dba9f039b7/pluginutils.h#L1-L21) - она довольно простая и накладывает минимум обязательств на пользователя, но вы вправе выбрать любую другую лицензию).


Задумка в целом хорошая, но реализация немного хромает. Хотя, справедливости ради стоит отметить объявление локальных переменных с атрибутом static - для одиночных переменных это выгоднее, чем создание переменных в стеке с ключевым словом new, и позволяет немного снизить требования к используемой памяти, но немногие знают об этом приёме.

m1n1vv
14.12.2017, 00:03
А если CreateCompassString и RoundCompassDirection?

Я уже который год использую сублайм.

Fallen A.
14.12.2017, 13:09
//Устанавливаем всем TD изначальный цвет (Готов выслушать предложения по упрощению)
PlayerTextDrawColor(playerid, td_uicompass[playerid][0], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][0]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][1], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][1]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][2], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][2]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][3], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][3]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][4], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][4]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][5], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][5]);
PlayerTextDrawColor(playerid, td_uicompass[playerid][6], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][6]);



Не?



for(new i; i < 7; i++)
{
PlayerTextDrawColor(playerid, td_uicompass[playerid][i], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][i]);
}

m1n1vv
14.12.2017, 13:42
Не?



for(new i; i < 7; i++)
{
PlayerTextDrawColor(playerid, td_uicompass[playerid][i], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][i]);
}


Потеря скорости

Fallen A.
14.12.2017, 13:47
Потеря скорости

В таком случае использовать форич.

m1n1vv
14.12.2017, 13:52
В таком случае использовать форич.

Любой цикл приведет к потере скорости. Я хотел бы услышать предложение о функции, которая заменит цвет у предыдущего и последующего TD. +-1 здесь не поможет.

Что-то вроде такого:


stock ReturnColorCompass(&previous, &next)
{
static const
max_limit = MAX_UICOMPASS_TD - 1;

previous = uic__N - 1;
next = uic__N + 1;

previous = (previous > max_limit) ? (0) : ((previous < 0) ? (max_limit) : (previous));
next = (next > max_limit) ? (0) : ((next < 0) ? (max_limit) : (next));

return 1;
}

Не проверял. Сделал на быструю руку.


UICompass V0.4


Изменены названия двух функций:

GetDirectionCompass > RoundCompassDirection;
CompassSetString > CreateCompassString.



Внесены небольшие изменения в работу инклуда.



UICompass V0.5


Добавлена возможность изменения минимального шага. По умолчанию было 15.
За это отвечает директива: UICOMPASS_STEP.

m1n1vv
15.12.2017, 06:07
DEL

Daniel_Cortez
15.12.2017, 12:21
А если CreateCompassString
Советую вдуматься в смысл слова "Create" и для примера посмотреть, в каких функциях SA-MP это слово используется.



и RoundCompassDirection?
Либо "ToCompassDirection", ведь функция по сути осуществляет конверсию угла.



Не?



for(new i; i < 7; i++)
{
PlayerTextDrawColor(playerid, td_uicompass[playerid][i], 0xFFFFFFFF);
PlayerTextDrawShow(playerid, td_uicompass[playerid][i]);
}


Потеря скорости
Куда больше времени уйдёт, к примеру, на вызов нативной функции (т.е. на сохранение состояния виртуальной машины, переход на нативный код и восстановление ВМ, не считая времени выполнения самой функции).
Но ведь лучше же засорять свой код, чтобы (может быть) сэкономить пару пикосекунд в коде, который выполняется 2-3 раза в секунду, правда?

m1n1vv
15.12.2017, 13:15
Значит лучше взять в цикл?

Если грамотно реализовать ту функцию, то функций изменения цвета будет в 4 раза меньше. Правда это скорей всего не возможно (при условии резкой смены угла). И для корректной работы компаса нужен таймер на 100-200 мс.

А как тут будет лучше?


stock CompassHeadingNorth(angle)
{
uic__N = angle / UICOMPASS_STEP;

if (uic__N >= uic__max_N)
uic__N = uic__max_directions - uic__N + uic__min_N;
else
{
uic__N -= uic__min_N;
uic__N = ~uic__N + 1;
}

return uic__N;
}


stock CompassHeadingNorth(angle)
{
angle /= UICOMPASS_STEP;

return (angle >= uic__max_N) ? (uic__max_directions - angle + uic__min_N) : (~(angle - uic__min_N) + 1);
}

Daniel_Cortez
17.12.2017, 22:17
Значит лучше взять в цикл?
Всяко лучше, чем плодить китайский код (http://lurkmore.to/%D0%98%D0%BD%D0%B4%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9_%D0%BA%D0%BE%D0%B4#K.D0.B8.D1.82.D0.B0.D0.B9.D1.81.D0.BA.D0.B8.D0.B9_.D0.BA.D0.BE.D0.B4).



А как тут будет лучше?


stock CompassHeadingNorth(angle)
{
uic__N = angle / UICOMPASS_STEP;

if (uic__N >= uic__max_N)
uic__N = uic__max_directions - uic__N + uic__min_N;
else
{
uic__N -= uic__min_N;
uic__N = ~uic__N + 1;
}

return uic__N;
}


stock CompassHeadingNorth(angle)
{
angle /= UICOMPASS_STEP;

return (angle >= uic__max_N) ? (uic__max_directions - angle + uic__min_N) : (~(angle - uic__min_N) + 1);
}
Тернарные выражения лучше не использовать, если можно обойтись ветвлением if. Кстати, в первом примере фигурные скобки только в одной из веток if выглядят нелепо (да и зачем вообще нужно было разбивать выражение в той ветке на два?). Обычно скобки ставят либо на обеих ветках if, либо ни на одной.



Что помешало объявить это как константу?


static
getN;

getN = (UICOMPASS_MAX_TD + 1) / 2;





static const
getN = (MAX_UICOMPASS_TD + 1) / 2;


Это не константа -_-


P.S.: Также до сих пор не видно никаких улучшений в плане именования функций и лицензии на код. Если что-то непонятно, не бойтесь спросить.

m1n1vv
17.12.2017, 22:48
Всяко лучше, чем плодить китайский код (http://lurkmore.to/%D0%98%D0%BD%D0%B4%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9_%D0%BA%D0%BE%D0%B4#K.D0.B8.D1.82.D0.B0.D0.B9.D1.81.D0.BA.D0.B8.D0.B9_.D0.BA.D0.BE.D0.B4).



Тернарные выражения лучше не использовать, если можно обойтись ветвлением if. Кстати, в первом примере фигурные скобки только в одной из веток if выглядят нелепо (да и зачем вообще нужно было разбивать выражение в той ветке на два?). Обычно скобки ставят либо на обеих ветках if, либо ни на одной.




Это не константа -_-


P.S.: Также до сих пор не видно никаких улучшений в плане именования функций и лицензии на код. Если что-то непонятно, не бойтесь спросить.

Немного поправил CompassHeadingNorth:


stock CompassHeadingNorth(angle)
{
angle /= UICOMPASS_STEP;

if (angle >= uic__max_N)
angle = uic__max_directions - angle + uic__min_N;
else
angle = ~(angle - uic__min_N) + 1;

return angle;
}

Лицензию добавлю скорей всего со следующей версии. В смысле не константа? Просто писать const?

Geebrox
17.12.2017, 22:59
В смысле не константа? Просто писать const?

const (constant) - переводится как "постоянная", то есть зачение который хранится в константе постоянный и его нельзя изменить (можно изменить только переобъявив константу)

Можно объявить:

const CONST_NAME = const_value;

или же


#define CONST_NAME some_value

Обычно объявляется в начале кода, чтобы иметь доступ в любом месте.

Nexius_Tailer
17.12.2017, 23:45
Да проще уже было бы как дефайн её объявить и не париться.

m1n1vv
18.12.2017, 03:54
Почему-то у меня lдикое желание добавить GetDirectionOfAircraft в инклуд...

m1n1vv
24.12.2017, 22:33
v0.7


Добавлена поддержка вывода минимального шага. Который кратный 5;
У RoundCompassDirection и CreateCompassString появился новый параметр: round;
Новые макросы: MIN_UICOMPASS_STEP, MAX_UICOMPASS_STEP.

m1n1vv
25.12.2017, 21:00
Вот что умудрился сделать


http://www.youtube.com/watch?v=BCsdpoDG4Xg

Fallen A.
25.12.2017, 21:57
Вот что умудрился сделать


http://www.youtube.com/watch?v=BCsdpoDG4Xg

А с остальными городами что?

m1n1vv
25.12.2017, 22:49
А с остальными городами что?

Место действий только в одном городе. Другие пока будут закрыты.

Daniel_Cortez
15.03.2018, 21:11
Один из зарубежных пользователей жалуется на то, что текстдравы компаса криво размещены:

https://i.imgur.com/KkuHCDI.png
look? numbers disorder (red)
- i want as green

sorrry my english again :)
Оригинальная тема с обсуждением: http://pro-pawn.ru/showthread.php?16052