Дано:
  1. Существует карта с игровой зоной (А).
  2. Внутри существует красная область спавна юнитов (В), которые периодически (в определенные моменты) массово спавнятся триггерами в рандомной позиции этой области (затем они идут в географический центр карты).
  3. Существует голубая (С) внутри красной области (В).
Задача: организовать по команде спавн юнитов в красной области (В), ИСКЛЮЧАЯ голубую зону (С). Благодарю откликнувшихся и надеюсь на подсказки.

СерафимКречет, ух, ну тогда держи простую, тупую гуишную систему, где втупую рандомим точку. Если находится внутри среднего региона - рандомим еще раз.
Инициализация координат регионов
Рандомизация точки и спавн юнита в этой точке
Результат
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
32
Епттить проверять координаты чтобы они были больше макс х коррдинаты области C или меньше минимальной координаты x, аналогично для координаты y.
В целом, можно наделать много точек спавна и занести их в массив, и выбирать случайную.
22
Один подход, можно поделить красную зону на 4 или 8 зон (вне синей) и сперва рандомить одну из них.
Второй подход: сперва рандомим координату ширины, если она вне пределов ширины голубой зоны, то просто рандомим высоту. А если внутри, то тогда выбираем выше или ниже (рандомом), затем рандомим высоту выше или ниже голубой зоны, между ее пределом и соответствующим пределом красной.
7
Если площадь области спавна слишком мала, по отношению к забанненым областям, может оборваться поток. Но при штатом пользовании должно работать нормально.
Код

function GetSpawnPoint takes rect spawnRect returns location 
	local real x
	local real y
	local boolean pass
	loop
		set pass = true
		set x = GetRandomReal(GetRectMinX(spawnRect),GetRectMaxX(spawnRect))
		set y = GetRandomReal(GetRectMinY(spawnRect),GetRectMaxY(spawnRect))
		if RectContainsCoords(gg_rct_rectC,x,y) then  		// проверяем лежит ли случайная точка в запрещенной области
			set pass = false					
		endif
		/*
		if RectContainsCoords(gg_rct_rectD,x,y) then  			// можно добавить несколько забаненых областей
			set pass = false							
		endif
		*/
		exitwhen pass
	endloop
	return Location(x,y)				// незабываем удалять локацию после использвания 
endfunction 

..
local location loc = GetSpawnPoint(gg_rct_rectB)
call CreateUnitAtLoc(p,id,loc,GetRandomReal(0.,360))
call RemoveLocation(loc)
set loc = null 
..
Ответы (4)
26
Zeix, зачем так цикл раздувать? сразу пиши в закрывашку
loop
	set x = GetRandomReal(GetRectMinX(spawnRect),GetRectMaxX(spawnRect))
	set y = GetRandomReal(GetRectMinY(spawnRect),GetRectMaxY(spawnRect))
	exitwhen RectContainsCoords(gg_rct_rectC,x,y)
endloop
7
В комментах написано, что бы автор вопроса мог проще добавить другие забаненные зоны. Такой код легче читается и редактируется новичками. Можно еще сократить, и не использовать координаты, а сразу создавать и двигать локацаю, это еще сократит код еще на две строки, но зачем?
26
Zeix, все остальные области я бы просто добавил в exitwhen через and )) ну ладно, я думал про новичков тут уже давно не думают...
30
Zeix, если думаешь про новичков, то лучше откажись от location и пиши координаты в глобалки.
28
ему нужна формула поиска случайной точки в многоугольнике, а не ваши костыли
Ответы (3)
7
rsfghd, в вопросе буквально нет ни слова, ни намека на многоугольники, четко и ясно написано Области(которые являются прямоугольниками). Если в варике понадобилось использовать многоугольники, то что-то в дизайне пошло явно не так.
28
Если в варике понадобилось использовать многоугольники, то что-то в дизайне пошло явно не так.
Это явно было лишним
30
Zeix, не просто прямоугольники, а ориентированные по осям многоугольники.
28
Может я тупой, но единственный вариант к которому я додумался, это разбить многоугольник на треугольники, выбирать среди них случайный и там уже искать рандомную точку, однако таким треугольникам нужно задавать определенный "вес", зависящий от их площади для определенного шанса, то есть чем больше треугольник, тем больше шанс его выбора. Но учитывая, что тебе доступен вариант попроще (разбитие на прямоугольники), лучше пользоваться им
26
rsfghd, можно просто рандомить координаты и при этом, если X выпадает в ненужный промежуток - рандомить Y немного иначе, вот и всё.

Такой вариант, с примером:
Допустим область B имеет размер 6000x6000, а область C в её центре имеет размер 2000x2000. Ищем случайный X для B - это случайное число от 0 до 6000, т.е. мин/макс. координата X для B.
Если случайно полученная координата X выпадает на область C (т.е. между 2000 и 4000), то нужно указать для следующих расчётов что мы будем мнимо сдвигать диапазон в меньшую сторону, поэтому запишем set Y0 = 2000 (иначе оно должно быть равно 0, т.к. проще всегда считать его, но с разным результатом).
Теперь мы ищем координату Y, которая будет равна случайному числу от 0 до 6000 - Y0, т.е. для случаев когда нет наложения - это от 0 до 6000, а когда есть наложение - от 0 до 4000.
Далее, если наше случайно найденное значение для Y удовлетворяет условие Y > 2000 то можно докинуть к нему Y0 (т.е. обратно увеличить на мнимый сдвиг set Y = Y + Y0), который будет равен 0 или 2000 (в случае если диапазон был уменьшен).
На выходе мы получим Y от 0 до 6000 при Y0 = 0 без сдвига.
А со сдвигом - от 0 до 4000 при Y0 = 2000, что даст нам от 0 до 2000 если Y меньше 2000, или от 2000+2000 до 4000+2000 со сдвигом (т.е. от 4000 до 6000).
примерно такой набросочек, может что запамятовал...
	rect B = ... // зона спавна
	rect C = ... // чистая зона
	
	local real xC_min = GetRectMinX(C)
	local real xC_max = GetRectMaxX(C)
	local real xR = GetRandomReal(GetRectMinX(B),GetRectMaxX(B))
	local real yR 
	local real y0 = 0.
	
	if xR > xC_min and xR < xC_max then
		set y0 = xC_max - xC_min
	endif
	
	set yR = GetRandomReal(GetRectMinY(B),GetRectMaxY(B)-y0)
	
	if yR < GetRectMinX then
		set yR = yR + y0
	endif
Ответы (7)
28
Extremator, а если фигура будет посложнее статических прямоугольников? Как зарандомить в этой фигуре точку?
26
rsfghd, для решения своего вопроса можешь создать отдельный топик и указать там все исходные.
25
rsfghd, когда решаешь несуществуюшие задачи :D
(Идеальные универсальные решения мало кому нужны на практике хех)
26
konvan5:
Идеальные универсальные решения мало кому нужны на практике
vJass пытался быть универсальным... и где он теперь?)
23
rsfghd, если будет, то пусть автор создаёт на эту тему вопрос))) но он не задал, значит, ему это не надо)
18
Тут конечного уже ответили, но такого типа вопросы рили у того же ChatGPT задавать можно.
Оно тупо по времени быстрее выйдет.
23
Создаешь и привязываешь к голубой области регион через call Region Add Rect
Затем генерируешь случайные координаты в красной области ( в гуи есть это, только с точкой, потребуется просто переделать bj функцию на координаты)
Если not Is point in region ( регион голубой области, координаты x, y )
То создаешь юнита в координатах и отправляешь в
центр голубой области
Есть варианты и с точками, тогда проверять надо будет через is location in region, ну и удалять новые точки)
Также, если голубая область нужна любой формы, то нужно будет сделать несколько областей и привязать их к региону
Также, если нужно, чтобы и красная область была любой формы, то можно по границам красной области распихать областей и привязать их к этому же региону, у региона не обязательно области должны быть рядом, их можно хоть по концам карты расставить)
Собственно всё)
30
Разбиваешь прямоугольник на несколько, выбираешь из них случайный основываясь на площади и в нём уже авчисляешь случайную точку. Вот код от гпт:
function randomPointExcludingB(A, B) {
    const [xA, yA, wA, hA] = A;
    const [xB, yB, wB, hB] = B;

    // Площади зон
    const leftArea = (xB - xA) * hA;
    const rightArea = (xA + wA - (xB + wB)) * hA;
    const topArea = wB * (yB - yA);
    const bottomArea = wB * (yA + hA - (yB + hB));

    // Зоны и их площади
    const zones = [
        { name: "left", area: leftArea },
        { name: "right", area: rightArea },
        { name: "top", area: topArea },
        { name: "bottom", area: bottomArea }
    ];

    const totalArea = zones.reduce((sum, zone) => sum + zone.area, 0);

    // Выбор зоны пропорционально площади
    let r = Math.random() * totalArea;
    let selectedZone = null;
    for (const zone of zones) {
        if (r <= zone.area) {
            selectedZone = zone.name;
            break;
        }
        r -= zone.area;
    }

    // Генерация случайной точки в выбранной зоне
    let x, y;
    switch (selectedZone) {
        case "left":
            x = Math.random() * (xB - xA) + xA;
            y = Math.random() * hA + yA;
            break;
        case "right":
            x = Math.random() * (xA + wA - (xB + wB)) + (xB + wB);
            y = Math.random() * hA + yA;
            break;
        case "top":
            x = Math.random() * wB + xB;
            y = Math.random() * (yB - yA) + yA;
            break;
        case "bottom":
            x = Math.random() * wB + xB;
            y = Math.random() * (yA + hA - (yB + hB)) + (yB + hB);
            break;
    }

    return [x, y];
}

// Пример использования
const A = [0, 0, 10, 10]; // Прямоугольник A
const B = [3, 3, 4, 4];   // Прямоугольник B
console.log(randomPointExcludingB(A, B));
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.