Добавлен , опубликован
Способ реализации:
Версия Warcraft:

Rectange

Что это?

По давней традиции в играх используются прямоугольники ориентированные по осям. Это упрощает математику и не заставляет хорошо учиться в школе. Но что если вы не такой как все вам нужен прямоугольник со свободным углом вращения?

Как пользоваться?

Это структура. Поэтому достаточно её создать. Так же, можно воспользоваться особенностью структур и сразу вызывать её методы без смс и регистрации.
Rectangle r = Rectangle.new(centerX, centerY, width, height, radians).translatePolar(200, radians);
Для запуска требуется JNGP или Reforged.

В чём соль?

Затевалась вся эта затея ради функции distanceSquaredXY которая возвращает квадрат расстояния от заданной точки до ближайшей точки прямоугольника. Что позволяет проверить наличие юнита в прямоугольнике с учётом коллизии.
Rectangle r = Rectangle.new(centerX, centerY, width, height, radians);

GroupClear(g);
GroupEnumUnitsInRange(g, r.cx, r.cy, r.diagonal * .5 + 200, null);
ForGroup(g, function(){
    target = GetEnumUnit();
    
	if (!UnitAlive(target)) return;
    if (IsUnitOwnedByPlayer(target, GetOwningPlayer(caster))) return;
    
	targetX = GetUnitX(target);
    targetY = GetUnitY(target);
    
	distance = r.distanceXY(targetX, targetY);
    if (distance < 0 && !IsUnitInRangeXY(target, targetX, targetY + SquareRoot(-distance), 0)) return;

    SetUnitExploded(target, true);
    KillUnit(target);
});

Методы

method setData(real cx, real cy, real width, real height, real radians) -> Rectangle
method setCenter(real cx, real cy, real radians) -> Rectangle
method setSize(real width, real height, real radians) -> Rectangle
method setRadians(real radians) -> Rectangle
method translateOffset(real dx, real dy) -> Rectangle
method translatePolar(real distance, real radians) -> Rectangle
method rotate(real ox, real oy, real radians) -> Rectangle
rotate поворачивает прямоугольник на заданный угол вокруг заданной точки.
method distanceXY(real x, real y) -> real
distanceXY возвращает квадрат расстояния между точкой [x, y] и ближайшей точкой на стороне прямоугольника. Для точки лежащей вне прямоугольника возвращает отрицательное значение расстояния.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Этот комментарий удален
25
Вы делали проверку нахождения юнита в прямоугольнике, учитывая его физический размер полностью? То есть чтобы весь "круг физического размера" вошел в прямоугольник, иначе он не полностью внутри.

Я так понимаю с помощью этой системы можно такое закодить.
30
konvan5, если по простому, детектится наложение круга на прямоугольник. Визуализацию можно в WebDemo глянуть.
Иначе узкий квадрат не будет задевать жирных юнитов. Но математика там не сложная, если нужно могу дописать.
Классно, а теперь в 3д с поверхностями)
Когда завезут нативку по получению центра модели юнита, тогда сделаю 👽
30
konvan5, добавил distanceSquaredInnerXY, которая возвращает положительное значение если точка внутри прямоугольника и отрицательное если снаружи. Теперь через тот же IsUnitInRangeXY можно легко посчитать, находится ли юнит полностью в прямоугольнике.
30
Вышла новая версия! Прокрутить к ресурсу
Изменения синтаксиса, оставил только одну функцию distanceXY чтоб не плодить лишний код.
20
Патч почти добрался до выхода в свет. И я наконец-то добрался до этой либы. Еще раз спасибо, поделюсь своим API
	public function GroupEnumUnitsInRactangleCollision(group whichGroup, real centerX, real centerY, real width, real height, real radians, boolexpr filter) -> boolean {
		Rectangle r = Rectangle.new(centerX, centerY, width, height, radians);
		unit enumUnit = null;
		real targetX, targetY;

		GroupEnumUnitsInRange(whichGroup, r.cx, r.cy, r.diagonal * .5 + 200, filter);
		ForGroup(g, function(){
			enumUnit = GetEnumUnit();
			
			targetX = GetUnitX(enumUnit);
			targetY = GetUnitY(enumUnit);
			
			distance = r.distanceXY(targetX, targetY);
			if (distance < 0 && !IsUnitInRangeXY(enumUnit, targetX, targetY + SquareRoot(-distance), 0)) 
				GroupRemoveUnit(whichGroup, enumUnit);
		});
		enumUnit = null;
		r.destroy();
	}
я не проверял, но должно работать.
Ответы (6)
30
я не проверял, но должно работать.
В Зинке нет замыканий, как ты локалки собрался в анонимку пропихивать?
30
KaneThaumaturge, distanceXY кстати возвращает квадрат расстояния. Так что тяжёлый корень ты зря считаешь.
20
nazarpunk, это ты считаешь, а не я) Ща проверю
	//API
	integer This;
	real TargetX, TargetY, Distance;
	unit EnumUnit;
	group WhichGroup;

	public function GroupEnumUnitsInRactangleCollision(group whichGroup, real centerX, real centerY, real width, real height, real radians, boolexpr filter) {
		Rectangle this = Rectangle.new(centerX, centerY, width, height, radians);

		GroupEnumUnitsInRange(whichGroup, this.cx, this.cy, this.diagonal * .5 + 200, filter);

		This = this;
		WhichGroup = whichGroup;
		ForGroup(whichGroup, function() {
			Rectangle this = This;
			EnumUnit = GetEnumUnit();
			
			TargetX = GetUnitX(EnumUnit);
			TargetY = GetUnitY(EnumUnit);
			
			Distance = this.distanceXY(TargetX, TargetY);
			if (Distance < 0 && !IsUnitInRangeXY(EnumUnit, TargetX, TargetY + SquareRoot(-Distance), 0)) 
				GroupRemoveUnit(WhichGroup, EnumUnit);
		});
		this.destroy();
	}
30
KaneThaumaturge, rActangle это сильно, да и в коде меня что-то смущает.
library MyRect {
    Rectangle MyRect = Rectangle.new(0, 0, 0, 0, 0);
    real TargetX, TargetY, Distance;
    unit EnumUnit;
    group WhichGroup;

    public function GroupEnumUnitsInRectangleCollision(group whichGroup, real centerX, real centerY, real width, real height, real radians, boolexpr filter) {
        MyRect.setData(centerX, centerY, width, height, radians);

        GroupEnumUnitsInRange(whichGroup, MyRect.cx, MyRect.cy, MyRect.diagonal * .5 + 200, filter);

        WhichGroup = whichGroup;

        ForGroup(whichGroup, function() {
            EnumUnit = GetEnumUnit();
            TargetX = GetUnitX(EnumUnit);
            TargetY = GetUnitY(EnumUnit);

            Distance = this.distanceXY(TargetX, TargetY);
            if (Distance < 0 && !IsUnitInRangeXY(EnumUnit, TargetX, TargetY + SquareRoot(-Distance), 0))
                GroupRemoveUnit(WhichGroup, EnumUnit);
        });
    }
}
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.