PDA

Просмотр полной версии : [Вопрос] Сетка из 360тыс элементов



LINKINPARK
19.05.2021, 07:13
добрый день товарищи. Ума не приложу как правильно назвать тему. Суть такая - Есть идеи как поделить карту СА на 360тыс мелких квадратов размером 10х10? и более того как узнать в каком из квадратов находится игрок!?

DeimoS
19.05.2021, 08:09
Можно хоть так - *click* (https://pro-pawn.ru/showthread.php?17282-%D0%9A%D0%B0%D0%BA-%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE-%D0%B7%D0%B0%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D1%8C-%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D1%83%D1%8E-%D0%B7%D0%BE%D0%BD%D1%83-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0%D0%BC%D0%B8&p=97765&viewfull=1#post97765)
Хоть какую-то более мудрёную формулу применить.

Узнать можно обычным циклом. Помимо тех 360-и тысяч квадратов, делишь карту так же на более крупные квадраты, а после уже делаешь проверки начиная с самых больших квадратов и по ним отфильтровывая сразу основную.
То бишь, определяешься с минимальными и максимальными координатами для области, которую будут покрывать твои 360 тысяч квадратов и сначала её делишь на 4 больших. Далее каждый из 4-ёх квадратов делишь ещё на 4 квадрата. И так можно повторить ещё пару раз (чтоб, в итоге, у тебя за один заход проверялось штук по 100 мелких квадратов всего). В итоге ты сможешь сначала проверить то, в каком из первых 4-ёх больших квадратов находится игрок и, тем самым, отфильтровать сразу большое количество ненужных тебе мелких квадратов.

Так же, если тебе нужно именно постоянно отслеживать в каком квадрате находится игрок, а не при вводе команды, например, то можно запариться и сделать систему, которая будет запоминать в каком квадрате игрок заспавнился/в какой квадрат телепортировался, и уже после этого проверять только текущий квадрат + если игрок не в текущем квадрате - ближайшие к текущему.

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

LINKINPARK
19.05.2021, 08:28
Можно хоть так - *click* (https://pro-pawn.ru/showthread.php?17282-%D0%9A%D0%B0%D0%BA-%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D0%BD%D0%BE-%D0%B7%D0%B0%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D1%8C-%D0%BF%D1%80%D1%8F%D0%BC%D0%BE%D1%83%D0%B3%D0%BE%D0%BB%D1%8C%D0%BD%D1%83%D1%8E-%D0%B7%D0%BE%D0%BD%D1%83-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0%D0%BC%D0%B8&p=97765&viewfull=1#post97765)
Хоть какую-то более мудрёную формулу применить.

Узнать можно обычным циклом. Помимо тех 360-и тысяч квадратов, делишь карту так же на более крупные квадраты, а после уже делаешь проверки начиная с самых больших квадратов и по ним отфильтровывая сразу основную.
То бишь, определяешься с минимальными и максимальными координатами для области, которую будут покрывать твои 360 тысяч квадратов и сначала её делишь на 4 больших. Далее каждый из 4-ёх квадратов делишь ещё на 4 квадрата. И так можно повторить ещё пару раз (чтоб, в итоге, у тебя за один заход проверялось штук по 100 мелких квадратов всего). В итоге ты сможешь сначала проверить то, в каком из первых 4-ёх больших квадратов находится игрок и, тем самым, отфильтровать сразу большое количество ненужных тебе мелких квадратов.

Так же, если тебе нужно именно постоянно отслеживать в каком квадрате находится игрок, а не при вводе команды, например, то можно запариться и сделать систему, которая будет запоминать в каком квадрате игрок заспавнился/в какой квадрат телепортировался, и уже после этого проверять только текущий квадрат + если игрок не в текущем квадрате - ближайшие к текущему.

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

Да мне постоянно нужно отслеживать в каком квадрате сейчас игрок.
Цикл - слишком затратно, хотя в паре с твоей идеей делить квадрат на подквадраты вполне может быть работоспособной.
Думал о динам зонах стримера - бред.
Вариант деления квадрата на подквадраты идея не плохая, мне кажется, я придумал как это реализовать менее затратно и по скорости и ресурсам.
Еще мне нужно знать центр квадрата, а так же мин/мах Х, У, что бы в нужный момент отмечать квадрат гангзоной.

DeimoS
19.05.2021, 08:41
Да мне постоянно нужно отслеживать в каком квадрате сейчас игрок.

Ну тогда делаешь вообще всё, о чём я писал в предыдущем сообщении. За счёт деления областей быстро находишь тот квадрат, в котором заспавнился игрок, а далее уже проверяешь ближайшие квадраты таймером. В итоге у тебя таймер будет проверять 9 квадратов всего из 360-и тысяч.


Еще мне нужно знать центр квадрата, а так же мин/мах Х, У, что бы в нужный момент отмечать квадрат гангзоной.

"мин/мах Х, У" тебе и так будут известны (если ещё не понял, то через тот код, который по ссылке был, нужно координаты для квадратов заранее приготовить и записать в массивы, а не генерировать каждый старт сервера), а центр легко находится по формуле "(min_x+max_x)/2.0" (то же самое и для Y-оси)

LINKINPARK
19.05.2021, 08:58
Решение.
Набросал код на коленке, возможно где-то перепутал плюсы/минусы, возможны и прочие ошибки.
это код может разделить карту на квадраты от 4-х(если SQUARE_STEP = 3000,0) до 36 000 000 если (если SQUARE_STEP = 1,0)
так же очень быстро определяет по координатам № квадрата, его центр.


#include <a_samp>

#define SQUARE_STEP 10.0
#define SQUARE_SIZE 3000.0

main()
{
new
Float: X = 2690.0,
Float: Y = -1547.0,
player_square
;
player_square = GetNumberSquare (X, Y);
if (player_square != -1)
{
printf ("Игрок в квадрате № %i", player_square+1);
}
else
{
print ("Игрок за пределами квадрта");
}

}
GetNumberSquare (Float:x, Float:y)
{
if (x >= SQUARE_SIZE || x <= -SQUARE_SIZE || y >= SQUARE_SIZE || y <= -SQUARE_SIZE)
{
return -1;//за границей квадрата
}

new
number_square = floatround ((SQUARE_SIZE*2)/SQUARE_STEP); //макс кол-во квадратов от -3000 до 3000

new
newX = floatround ((SQUARE_SIZE+x)/SQUARE_STEP, floatround_floor); //номер квадрата по оси Х
new
newY = number_square*floatround ((SQUARE_SIZE-y)/SQUARE_STEP, floatround_floor); //номер квадрата по оси Y
/*
printf ("X %f, Y %f", //центр квадрата
((float (newX)*SQUARE_STEP)+(SQUARE_STEP/2))-SQUARE_SIZE, // X

SQUARE_SIZE-((float (newY/number_square)*SQUARE_STEP))-(SQUARE_STEP/2)); // Y

printf ("MAX X %f MAX Y %f, MIN X %f MIN Y %f",

(float (newX)*SQUARE_STEP)-SQUARE_SIZE, // MAX X

SQUARE_SIZE-(float (newY/number_square)*SQUARE_STEP), //MAX Y

((float (newX)*SQUARE_STEP)+SQUARE_STEP)-SQUARE_SIZE, // MIN X

SQUARE_SIZE-((float (newY/number_square)*SQUARE_STEP))-SQUARE_STEP); // MIN Y
*/
return newX + newY;//возвращаем номер квадрата
}
p/s Это очень хороший аналог для постарения ганг-зон с настройками

#define SQUARE_STEP 300.0
#define SQUARE_SIZE 3000.0
400 ганг-зон размером 300х300, с моментальным поиском ида гангзоны :)

DeimoS спасибо, подтолкнул в нужном направлении

LINKINPARK
19.05.2021, 10:12
и вновь я в тупике.. Не понимаю как к каждому квадрату привязать определенное действие.
например

GetPlayerPos (playerid, x, y, z);

if (GetNumberSquare (x, y) == 50000)
{
действие;
}
не прописывать же это 360тыс раз)
EDD:
Например есть 2е машины, стоят они в квадрате 50 и 151, есть массив с этими машинами

new
car [2];
как узнать если я стою в 50 квадрате то это 0 ячейка массива car, а если в 151 то это соответственно 1 ячейка массива.
массив может иметь более 1000 ячеек

создать массив такого типа
car [2][2];
где car [0] [0] = например модель машины
car [0] [1] = 151 номер ячейки в которой она находится
и далее циклом сверять? car [0] [1] == GetNumberSquare (x, y) ??

LINKINPARK
19.05.2021, 10:56
Блин я сам уже запутался чего хочу:)
Представим такую ситуацию:

Игрок выбросил АК-47 в квадрате № 666, через некоторое время другой игрок находясь в квадрате 666 этот самый АК-47 забирает себе.
В одном квадрате может быть несколько вещей, по команде формируется список вещей которые в нем находятся. Ну и естественно в массиве нужно как-то обнулять эти вещи когда их забирают и добавлять когда бросают.

Массив имеем такой

new
array [2000] [20];
//где
array [0] [1] = 0; //пусто
array [0] [1] = 1;// АК-47
каким образом срастить 2000 и 3600000:)
конечно было бы проще обьявить так array [360000] [20]; и использовать array [GetNumberSquare (x, y) [ .. ] = 1/0 но это очень не очень

DeimoS
19.05.2021, 12:39
Для чего ты вообще хочешь всё это разделение делать? Ибо всё то, что ты написал, не требует каких-либо разделений карты на квадраты.

Касаемо транспорта и оружия - по их координатам и проверяй. В чём проблема?
Тем более, что для всего, созданного через стример, есть замечательная функция Streamer_GetNearbyItems, которая сама вернёт список нужных вещей в радиусе, отсортируя их, при этом, по расстоянию.

LINKINPARK
19.05.2021, 13:13
Для чего ты вообще хочешь всё это разделение делать? Ибо всё то, что ты написал, не требует каких-либо разделений карты на квадраты.

Касаемо транспорта и оружия - по их координатам и проверяй. В чём проблема?
Тем более, что для всего, созданного через стример, есть замечательная функция Streamer_GetNearbyItems, которая сама вернёт список нужных вещей в радиусе, отсортируя их, при этом, по расстоянию.

Да хрен знает зачем я это делаю, 2ва года не писал ничего, решил тряхнуть стариной:)
изначальная идея была сделать альтернативу долгим циклам в нахождении определенной зоны.
Вот исправленный код для быстрого нахождения идов 400 зон (для какой нибудь системы банд)
при его помощи можно легко заполнить карту гангзонами и быстро получать номер гангзоны в которой находится игрок

#define SQUARE_STEP 300.0
#define SQUARE_SIZE 3000.0

GetNumberSquare (Float:x, Float:y)
{
if (x >= SQUARE_SIZE || x <= -SQUARE_SIZE || y >= SQUARE_SIZE || y <= -SQUARE_SIZE)
{
return -1;//за границей квадрата
}
new
number_square = floatround ((SQUARE_SIZE*2)/SQUARE_STEP); //макс кол-во квадратов от -3000 до 3000 по оси Х
new
newY = floatround ((SQUARE_SIZE-y)/SQUARE_STEP, floatround_floor);//номер квадрата по оси Х
new
newX = number_square*floatround ((SQUARE_SIZE+x)/SQUARE_STEP, floatround_floor);//номер квадрата по оси Y
new
Float: maxX = ((float (newY)*SQUARE_STEP)+(SQUARE_STEP/2))-SQUARE_SIZE,
Float: maxY = SQUARE_SIZE-((float (newX/number_square)*SQUARE_STEP))-(SQUARE_STEP/2);
printf ("X %f, Y %f", maxX, maxY); //центр квадрата

printf ("minx %f miny %f, maxx %f maxy %f",
maxX-(SQUARE_STEP/2), // minx
maxY-(SQUARE_STEP/2), //minx
maxX+(SQUARE_STEP/2), //maxx
maxY+(SQUARE_STEP/2)); //maxy

return newX + newY;//возвращаем номер квадрата
}
А то что я писал в предыдущих постах, это не более чем попытки придумать где и как еще можно использовать эту сетку с миллионами ячеек. Одна голова хорошо, а две лучше. Может как раз вторая голова и придумает применение к этому коду.
Может быть и я додумаю где и как еще применять это:).