PDA

Просмотр полной версии : [Function] ProxDetector - сообщение ближайшим игрокам, с цветом зависящим от расстояния



ziggi
03.08.2016, 15:52
Описание:

Функция отправляет сообщение ближайшим игрокам вычисляя цвет, интенсивность которого завит от расстояния.

Параметры:

playerid - игрок, от которого идёт сообщение
Float:max_range - максимальное расстояние, на котором будет отправлено сообщение
color - базовый цвет
string[] - сообщение
Float:max_ratio = 1.6 (необязательный) - коэффициент уменьшения интенсивности цвета


Возвращаемое значение:

Функция возвращает 0, если playerid не подключен, в остальных случаях возвращается 1.

Код:

stock ProxDetector(playerid, Float:max_range, color, const string[], Float:max_ratio = 1.6)
{
new
Float:pos_x,
Float:pos_y,
Float:pos_z,
Float:range,
Float:range_ratio,
Float:range_with_ratio,
clr_r, clr_g, clr_b,
Float:color_r, Float:color_g, Float:color_b;

if (!GetPlayerPos(playerid, pos_x, pos_y, pos_z)) {
return 0;
}

color_r = float(color >> 24 & 0xFF);
color_g = float(color >> 16 & 0xFF);
color_b = float(color >> 8 & 0xFF);
range_with_ratio = max_range * max_ratio;

#if defined foreach
foreach (new i : Player) {
#else
for (new i = GetPlayerPoolSize(); i != -1; i--) {
#endif
if (!IsPlayerStreamedIn(playerid, i)) {
continue;
}

range = GetPlayerDistanceFromPoint(i, pos_x, pos_y, pos_z);
if (range > max_range) {
continue;
}

range_ratio = (range_with_ratio - range) / range_with_ratio;
clr_r = floatround(range_ratio * color_r);
clr_g = floatround(range_ratio * color_g);
clr_b = floatround(range_ratio * color_b);

SendClientMessage(i, (color & 0xFF) | (clr_b << 8) | (clr_g << 16) | (clr_r << 24), string);
}

SendClientMessage(playerid, color, string);
return 1;
}


Примечания:

Функция поддерживает любые комбинации цветов, прозрачность переданного цвета остаётся не тронутой.

Пример использования:

CMD:say(playerid, params[])
{
ProxDetector(playerid, 20.0, 0xFFAA99FF, params);
return 1;
}


Автор: ziggi

Nexius_Tailer
03.08.2016, 20:20
Изменение яркости цвета полезно, спасибо.
Появилась тут мысль, как с её помощью реализовать 3d-тексты над пикапами с покупкой дома, как в сингле (когда при приближении к нему текст цены дома становился отчётливее)

ziggi
04.08.2016, 10:48
Изменение яркости цвета полезно, спасибо.
Появилась тут мысль, как с её помощью реализовать 3d-тексты над пикапами с покупкой дома, как в сингле (когда при приближении к нему текст цены дома становился отчётливее)

В сингле ещё размер менялся, а этого, увы, в сампе не сделать.

123
04.08.2016, 15:31
Разве GetPlayerPos вернет 0, если игрок не подключен? В вики написано, что функция ничего не возвращает.

Nexius_Tailer
04.08.2016, 15:33
Разве GetPlayerPos вернет 0, если игрок не подключен? В вики написано, что функция ничего не возвращает.
Если написано в русской вики - врёт. Её обновляют гораздо реже, так что советую сверяться с английскими копиями статей.

ziggi
04.08.2016, 16:36
Разве GetPlayerPos вернет 0, если игрок не подключен? В вики написано, что функция ничего не возвращает.

Да, проверка игрока на подключение к серверу есть во всех функциях (скорее всего во всех, но я все не проверял).

BadPawn
05.08.2016, 05:24
Блестящая работа!

ziggi, если не сложно, напиши пожалуйста, что используется в коде, дабы разобрать код.

Побитовые сдвиги вижу (или как правильно назвать :)))

ziggi
05.08.2016, 13:58
Побитовые сдвиги вижу (или как правильно назвать :)))

Изучи работу побитовых операций, в интернете масса информации на эту тему.

Profyan
05.08.2016, 15:43
Блестящая работа!

ziggi, если не сложно, напиши пожалуйста, что используется в коде, дабы разобрать код.

Побитовые сдвиги вижу (или как правильно назвать :)))

http://forum.sa-mp.com/showthread.php?t=177523 - тут расписана бинарная система и битовые операции

$continue$
05.08.2016, 16:13
Побитовые операции везде одинаковые (разве, что различие в синтаксисе и то не везде)
Можешь посмотреть:

https://www.youtube.com/watch?v=ptjccWUALZA
Сам не давно посмотрел =)

TheMallard
07.08.2016, 20:22
А gl_common'овская реализация как вам?

ziggi
07.08.2016, 21:12
А gl_common'овская реализация как вам?

Если ты про gl_message.inc и функцию TalkMessage, то она отправляет сообщение только в оттенках серого.

Nash_Brigers
07.08.2016, 21:39
Круто, Сергей. Видна рука мастера, как всегда.

Daniel_Cortez
01.10.2018, 15:35
Исправлена проблема с const-корректностью в заголовке функции (приводило к выдаче варнингов на версии компилятора 3.10.9).

punkochel
29.05.2020, 23:41
Описание:

Функция отправляет сообщение ближайшим игрокам вычисляя цвет, интенсивность которого завит от расстояния.

Параметры:

playerid - игрок, от которого идёт сообщение
Float:max_range - максимальное расстояние, на котором будет отправлено сообщение
color - базовый цвет
string[] - сообщение
Float:max_ratio = 1.6 (не обязательный) - коэффициент уменьшения интенсивности цвета


Возвращаемое значение:

Функция возвращает 0, если playerid не подключен, в остальных случаях возвращается 1.

Код:

stock ProxDetector(playerid, Float:max_range, color, const string[], Float:max_ratio = 1.6)
{
new
Float:pos_x,
Float:pos_y,
Float:pos_z,
Float:range,
Float:range_ratio,
Float:range_with_ratio,
clr_r, clr_g, clr_b,
Float:color_r, Float:color_g, Float:color_b;

if (!GetPlayerPos(playerid, pos_x, pos_y, pos_z)) {
return 0;
}

color_r = float(color >> 24 & 0xFF);
color_g = float(color >> 16 & 0xFF);
color_b = float(color >> 8 & 0xFF);
range_with_ratio = max_range * max_ratio;

#if defined foreach
foreach (new i : Player) {
#else
for (new i = GetPlayerPoolSize(); i != -1; i--) {
#endif
if (!IsPlayerStreamedIn(playerid, i)) {
continue;
}

range = GetPlayerDistanceFromPoint(i, pos_x, pos_y, pos_z);
if (range > max_range) {
continue;
}

range_ratio = (range_with_ratio - range) / range_with_ratio;
clr_r = floatround(range_ratio * color_r);
clr_g = floatround(range_ratio * color_g);
clr_b = floatround(range_ratio * color_b);

SendClientMessage(i, (color & 0xFF) | (clr_b << 8) | (clr_g << 16) | (clr_r << 24), string);
}

SendClientMessage(playerid, color, string);
return 1;
}


Примечания:

Функция поддерживает любые комбинации цветов, прозрачность переданного цвета остаётся не тронутой.

Пример использования:

CMD:say(playerid, params[])
{
ProxDetector(playerid, 20.0, 0xFFAA99FF, params);
return 1;
}


Автор: ziggi

Решение отличное, но есть способ который на чуть чуть быстрее работает, но приходится вписывать цвета самому.

Код функции:
stock ProxDetector(Float:radi, playerid, const string[], color1, color2, color3, color4, color5)
{
if(IsPlayerConnected(playerid))
{
static Float:posx, Float:posy, Float:posz, Float:oldposx, Float:oldposy, Float:oldposz, Float:tempposx, Float:tempposy, Float:tempposz;
GetPlayerPos(playerid, oldposx, oldposy, oldposz);
foreach(new i: Player)
{
if(IsPlayerConnected(i))
{
if(GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
{
GetPlayerPos(i, posx, posy, posz);
tempposx = (oldposx -posx);
tempposy = (oldposy -posy);
tempposz = (oldposz -posz);
if(((tempposx < radi/16) && (tempposx > -radi/16)) && ((tempposy < radi/16) && (tempposy > -radi/16)) && ((tempposz < radi/16) && (tempposz > -radi/16))) {
SendClientMessage(i, color1, string);
}
else if(((tempposx < radi/8) && (tempposx > -radi/8)) && ((tempposy < radi/8) && (tempposy > -radi/8)) && ((tempposz < radi/8) && (tempposz > -radi/8))) {
SendClientMessage(i, color2, string);
}
else if(((tempposx < radi/4) && (tempposx > -radi/4)) && ((tempposy < radi/4) && (tempposy > -radi/4)) && ((tempposz < radi/4) && (tempposz > -radi/4))) {
SendClientMessage(i, color3, string);
}
else if(((tempposx < radi/2) && (tempposx > -radi/2)) && ((tempposy < radi/2) && (tempposy > -radi/2)) && ((tempposz < radi/2) && (tempposz > -radi/2))) {
SendClientMessage(i, color4, string);
}
else if(((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi))) {
SendClientMessage(i, color5, string);
}
}
}
}
}
return 1;
}

Пример использования:
CMD:shout(playerid, params[])
{
if(sscanf(params, "s[137]", params[0])) return SCM(playerid, COLOR_WHITE, "Введите: /s(hout) [текст]");
new string[19+(-2+MAX_PLAYER_NAME)+(-2+3)+(-2+96)+1];
format(string, sizeof(string), "Крик: %s!", params[0]);
ProxDetector(60.0, playerid, string, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xE6E6E6E6, 0xC8C8C8C8);
return 1;
}

Тесты скорости.

Код сравнения:
// Кол-во итераций в циклах.
const PROFILER_ITERATIONS_MAJOR = 10_000;
const PROFILER_ITERATIONS_MINOR = 1_000;

// Названия отрывков кода.
new const code_snippets_names[2][] =
{
{"ProxDetector by ziggy"},
{"ProxDetector"}
};

// Здесь вы можете объявить переменные, используемые в профилируемых отрывках кода
// и выполнить некоторые действия непосредственно перед профилированием.
#define Prerequisites();\
/*
Собственно, сами отрывки кода, которые нужно тестировать.
Если код состоит из нескольких строк, переносите их обратным слэшем.
Пример:
#define CodeSnippet1();\
DoSomething();\
DoSomethingElse();
*/

#include <a_samp>
#include "../sources/include/foreach.inc"

#define COLOR_WHITE 0xFFFFFFFF

#define CodeSnippet0();\
ProxDetector(0, 20.0, COLOR_WHITE, "params");

#define CodeSnippet1();\
ProxDetector_2(60.0, 0, "string", COLOR_WHITE,COLOR_WHITE,COLOR_WHITE,COLOR_WHITE,COLOR_WHITE);

stock ProxDetector(playerid, Float:max_range, color, const string[], Float:max_ratio = 1.6)
{
new Float:pos_x, Float:pos_y, Float:pos_z, Float:range, Float:range_ratio, Float:range_with_ratio,
clr_r, clr_g, clr_b, Float:color_r, Float:color_g, Float:color_b;

if (!GetPlayerPos(playerid, pos_x, pos_y, pos_z)) {
return 0;
}

color_r = float(color >> 24 & 0xFF);
color_g = float(color >> 16 & 0xFF);
color_b = float(color >> 8 & 0xFF);
range_with_ratio = max_range * max_ratio;

foreach (new i:Player) {
if (!IsPlayerStreamedIn(playerid, i)) {
continue;
}

range = GetPlayerDistanceFromPoint(i, pos_x, pos_y, pos_z);
if (range > max_range) {
continue;
}

range_ratio = (range_with_ratio - range) / range_with_ratio;
clr_r = floatround(range_ratio * color_r);
clr_g = floatround(range_ratio * color_g);
clr_b = floatround(range_ratio * color_b);

SendClientMessage(i, (color & 0xFF) | (clr_b << 8) | (clr_g << 16) | (clr_r << 24), string);
}

SendClientMessage(playerid, color, string);
return 1;
}

stock ProxDetector_2(Float:radi, playerid, const string[], color1, color2, color3, color4, color5)
{
if(IsPlayerConnected(playerid))
{
static Float:posx, Float:posy, Float:posz, Float:oldposx, Float:oldposy, Float:oldposz, Float:tempposx, Float:tempposy, Float:tempposz;
GetPlayerPos(playerid, oldposx, oldposy, oldposz);
foreach(new i: Player)
{
if(IsPlayerConnected(i))
{
if(GetPlayerVirtualWorld(playerid) == GetPlayerVirtualWorld(i))
{
GetPlayerPos(i, posx, posy, posz);
tempposx = (oldposx -posx);
tempposy = (oldposy -posy);
tempposz = (oldposz -posz);
if(((tempposx < radi/16) && (tempposx > -radi/16)) && ((tempposy < radi/16) && (tempposy > -radi/16)) && ((tempposz < radi/16) && (tempposz > -radi/16))) SendClientMessage(i, color1, string);
else if(((tempposx < radi/8) && (tempposx > -radi/8)) && ((tempposy < radi/8) && (tempposy > -radi/8)) && ((tempposz < radi/8) && (tempposz > -radi/8))) SendClientMessage(i, color2, string);
else if(((tempposx < radi/4) && (tempposx > -radi/4)) && ((tempposy < radi/4) && (tempposy > -radi/4)) && ((tempposz < radi/4) && (tempposz > -radi/4))) SendClientMessage(i, color3, string);
else if(((tempposx < radi/2) && (tempposx > -radi/2)) && ((tempposy < radi/2) && (tempposy > -radi/2)) && ((tempposz < radi/2) && (tempposz > -radi/2))) SendClientMessage(i, color4, string);
else if(((tempposx < radi) && (tempposx > -radi)) && ((tempposy < radi) && (tempposy > -radi)) && ((tempposz < radi) && (tempposz > -radi))) SendClientMessage(i, color5, string);
}
}
}
}
return 1;
}

Результат теста:

Тестирование: <ProxDetector by ziggy> vs <ProxDetector>
Режим: интерпретируемый, 10000x1000 итераций.
ProxDetector by ziggy: 4755
ProxDetector: 3313



Автор функции: неизвестен

Kovshevoy
30.05.2020, 10:37
Решение отличное, но есть способ который на чуть чуть быстрее работает, но приходится вписывать цвета самому.

Зато читабельность кода хромает.

Daniel_Cortez
30.05.2020, 10:58
Решение отличное, но есть способ который на чуть чуть быстрее работает, но приходится вписывать цвета самому.

Зато читабельность кода хромает.
Исполнение тоже такое себе. Очень сомневаюсь, что такой код может быть производительнее варианта из 1-го поста. Каким образом проводилось тестирование? Сколько игроков/ботов было подключено? В каком радиусе они были от контрольного игрока, на котором тестировалась функция?