PDA

Просмотр полной версии : [Вопрос] Поиск близжайших "предметов"



somebodies
19.07.2017, 22:30
Всем привет! В общем, работаю над survival-модом.
Столкнулся со следующей проблемой. Есть функция, определяющая ID ближайшего "лута".


stock GetIDLoot(playerid)
{
for(new i=0; i<MAX_LOOT; i++)
{
if(IsPlayerInRangeOfPoint(playerid,1.1, LootInfo[i][xLoot],LootInfo[i][yLoot],LootInfo[i][zLoot]))
{
return i;
}
}
return 0;
}

Она определяет [!] только 1 ближайший ID лута. Идем далее.
Функция подбора лута


if(newkeys & KEY_NO)
{
if(!IsPlayerInAnyVehicle(playerid))
{
if(IsPlayerInRangeOfPoint(playerid,1.1,LootInfo[GetIDLoot(playerid)][xLoot],LootInfo[GetIDLoot(playerid)][yLoot],LootInfo[GetIDLoot(playerid)][zLoot]))
{
DisplayLootDialogForPlayer(playerid);
}
}
}

Само форматирование диалога


public DisplayLootDialogForPlayer(playerid)
{
new fmt[MAX_LOOT_NAME];
format(fmt,sizeof(fmt),"1\t%s",LootInfo[GetIDLoot(playerid)][nameLoot]);
ShowPlayerDialog(playerid,DIALOG_LOOT,DIALOG_STYLE_LIST,"Подбор предмета",fmt,"Взять","Не взять");
return 1;
}


Ну и вот в чем суть. Среди кучи айтемов (20+) довольно сложно угадать координаты нужного лута и встать к нему близко. Я решил сделать подбор всего лежащего поблизости лута (т.е чтобы в диалоге форматировались и отображались все близлежайшие предметы). Я решил немного поменять логику функций (лучше бы свою логику как-то можно было поменять). Создав переменную, отвечающую за хранение ИДа предыдущего лута, я проверял , совпадает ли этот ид с полученным в рез-тате работы функции (знаю,что быдлокод и можно лучше, но мне нужен был хоть какой-нибудь результат для того чтобы получить возможность переписать функцию)
if(lootid[playerid] == i) continue; и пропускал итерацию в случае этого. Это дало возможность просмотреть 2 близлежаших лута, но не больше. Т.к функция просто переходила к прошлому айдишнику , т.к он не равен записанному в переменную. И таким образом, содержание списка просто дублировалось по типу: Аптечка М4 Аптечка М4 Аптечка М4.
Уже попробовал все различные способы. Прошу помочь в решении проблемы. Надеюсь, все ясно объяснил

DeimoS
19.07.2017, 23:10
Код и правда не оч. Особенно глупо то, что ты во втором цикле кучу раз прописываешь GetIDLoot, из-за чего у тебя каждое нажатие на кнопку N запускает 3 цикла, которые возвращают одну и ту же информацию.


Принцип у скрипта должен быть какой-то такой

new first_item_id = -1,
second_item_id = -1,
Float:max_item_distance = 99999.0,
Float:current_distance;

for(new i; i < MAX_LOOT; i++)
{
current_distance = GetPlayerDistanceFromPoint(playerid, LootInfo[i][xLoot], LootInfo[i][yLoot], LootInfo[i][zLoot]);
if(current_distance <= max_item_distance)// Если записанная ранее дистанция больше или ровна той, что получилась в данный момент (то бишь, предмет ближе)
{
max_item_distance = current_distance;// Обновляем записанную дистанцию
second_item_id = first_item_id;// Предыдущий найденный объект записываем в переменную для второго объекта
first_item_id = i;// Текущий объект записываем в переменную первого объекта
}
}
И далее уже проверяй, не равны ли first_item_id и second_item_id значению "-1" и если не равны - работай с ними (в них будет ID ячеек для объектов)

В теории должно работать. На практике не проверял

somebodies
20.07.2017, 02:10
По поводу "второго цикла" - спасибо, переделал.
По поводу кода - не работает. Попросту не записывает в first_item_id и second_item_id ИДы лута. В чем может быть проблема? пробовал менять код даже, но ничего не срабатывало.

DeimoS
20.07.2017, 04:03
const
Float:default_distance = 9999.0;

new Float:max_item_distance = default_distance,
Float:current_distance,
first_item_id = -1,
second_item_id = -1;

for(new i = 0; i < MAX_LOOT; i++)
{
current_distance = GetPlayerDistanceFromPoint(playerid, LootInfo[i][xLoot], LootInfo[i][yLoot], LootInfo[i][zLoot]);
if(current_distance <= max_item_distance)
{
max_item_distance = current_distance;
first_item_id = i;
}
}

if(first_item_id != -1)
{
max_item_distance = default_distance;
for(new i = 0; i < MAX_LOOT; i++)
{
if(first_item_id == i)
continue;
current_distance = GetPlayerDistanceFromPoint(playerid, LootInfo[i][xLoot], LootInfo[i][yLoot], LootInfo[i][zLoot]);
if(current_distance <= max_item_distance)
{
max_item_distance = current_distance;
second_item_id = i;
}
}
}

somebodies
20.07.2017, 06:10
Огромное спасибо, теперь все иды корректно записываются, и можно форматировать диалог близлежащими предметами.
Но есть еще вопросик. Можно ли как-то "автоматизировать" записывание идов в переменные? Допустим, под игроком будет лежать 10 предметов. Получается, мне в функции нужно будет делать 10 (и то не факт, что 10, предметов может быть больше) различных проверок на расстояние и использованные иды предметов.Что-то вроде:


if(third_item_id != -1)
{...}
if(fourth_item_id != -1)
{...}
if(fifth_item_id != -1)
{...}


Что, вроде бы, быдлокод не очень. К тому же, каждый раз будет действовать 10 проверок, даже когда возле игрока есть только один предмет :negative:
Есть ли какие-либо способы?

DeimoS
20.07.2017, 12:42
Ну так тебе нужно отобразить все предметы, которые есть вокруг или как? Если исключительно 10/20/30/etc самых ближайших - без проверок не обойтись, ибо иначе эти самые ближайшие не найти. А если просто определённое количество в радиусе - уже проще.
В любом случае ты собираешься сделать механизм, который отсеивает среди кучи объектов лишь нужные. Естественно он будет более сложно реализован, включая в себя дополнительные проверки. Хочешь по простому - просто делай подбор первого найденного в цикле ближайшего объекта и всё.

somebodies
20.07.2017, 19:17
Спасибо тебе огромное за помощь=)
можно закрывать