Inhaltsverzeichnis

IsInSectorRange

Hinweis: Normalerweise reicht es völlig, wenn man die Funktion IsNear() verwendet! Diese Funktion hier macht nur in ganz speziellen Fällen Sinn und soll auch eigentlich nur das Prinzip der Entfernungsberechnung zwischen 2 Punkten verdeutlichen!

Mit Hilfe dieser kleinen Funktion kann man feststellen, ob ein bestimmter Punkt 2 innerhalb eines angegebenen Radius (Range) und in einem bestimmten Sektor (Viertel- oder Halbkreis) zu einem Punkt 1 liegt, und wie groß die Entfernung (gerade Linie) in Siedlerzentimetern zwischen den zwei Punkten ist.

Die Funktion liefert vier Werte zurück:

  1. Boolscher Wert (true/false) für Punkt 2 liegt innerhalb des Radius und des Sektors (wenn angegeben) oder nicht
  2. Distanz zwischen Punkt 1 und 2 (in Siedlerzentimetern)
  3. Winkel in Grad (Ganzzahl zwischen 0 und 360) zwischen Punkt 1 und Punkt 2
  4. Den Sektor in dem sich Punkt 2 befindet (Zahlenwert, Werte siehe Abb. unten)
    Wenn der zurückgelieferte Sektorwert 0 ist, dann sind Punkt 1 und 2 identisch (gleiche Koordinaten). Wenn Punkt 2 genau auf einer der Achsen (X, Y) von Punkt 1 liegt, wird als Sektorenwert der jeweilige Zahlenwert für die Halbkreisangabe zurückgeliefert.

Die beiden Punkte 1 und 2 können jeweils angegeben werden als

Der Aufruf der Funktion erfolgt dann bspw. so:

function xy()
	local isInRange, distance, angle, isInSector = IsPointInRange("Punkt_1",77399,1500,9)
	if isInRange then
		Message("Der Punkt liegt innerhalb des Radius in einer Entfernung von "..distance.." in Sektor "..isInSector.." in einem Winkel von "..angle.." Grad")
	else
		Message("Der Punkt liegt ausserhalb des Radius oder Sektors in einer Entfernung von "..distance)
	end
end

oder so (wenn die Sektorangabe weggelassen wird, oder gleich 0 ist, dann wird wie bei IsNear() der Vollkreis genommen):

function xy()
	local isInRange, distance, angle, isInSector = IsPointInRange({X=6400,Y=12800},"Punkt_2",1500)
	if isInRange then
		Message("Der Punkt liegt innerhalb des Radius in einer Entfernung von "..distance.." in Sektor "..isInSector.." in einem Winkel von "..angle.." Grad")
	else
		Message("Der Punkt liegt ausserhalb des Radius in einer Entfernung von "..distance)
	end
end

oder so wenn man die Entfernung, den Winkel und den Sektor (zur Weiterverarbeitung) nicht braucht:

function xy()
	if IsInSectorRange("Punkt_1",77399,1500,9) then
		Message("Der Punkt liegt innerhalb des Radius und Sektors")
	else
		Message("Der Punkt liegt ausserhalb des Radius oder Sektors")
	end
end

Aus der Abbildung kann man die entsprechenden Sektorenwerte für die Viertel-, bzw. Halbkreise entnehmen:
Anmerkung: Die Werte für die Halbkreise ergeben sich aus der Addition der jeweiligen Viertelkreiswerte.

Code

irgendwo an eine freie Stelle (nicht innerhalb anderer Funktionen!) ins Script kopieren:

function IsInSectorRange(_pos1,_pos2,_range,_sector)
	local pos = {_pos1,_pos2}
	local sector = _sector or 0
	local sectorTemp = sector
	assert(type(_range) == "number", "Der Radius muss ein Zahlenwert sein")
	assert(type(sector) == "number", "Die Sektorangabe muss ein Zahlenwert sein")
	assert(sector >= 0 and sector <=12 and sector ~= 5 and sector ~= 7 and sector ~= 10 and sector ~= 11, "Der Sektorwert muss: 0, 1, 2, 3, 4, 6, 8, 9, oder 12 betragen")
	for i=1,2 do
		if type (pos[i]) == "string" or type (pos[i]) == "number" then
	        pos[i] = GetPosition(GetEntityId(pos[i] ));
	    end
	end
	if (sector == 3) then sector = 1 sectorTemp = 2
	elseif (sector == 6) then sector = 2 sectorTemp = 4
	elseif (sector == 9) then sector = 8 sectorTemp = 1
	elseif (sector == 12) then sector = 4 sectorTemp = 8
	end
	local a = 0
	local angle = 0
	local inSector = 0
	local distance = 0
	local inRange = false
	local diff_X = (pos[1].X - pos[2].X)
	local diff_Y = (pos[1].Y - pos[2].Y)
	if (diff_X == 0 or diff_Y == 0) then
		if ((diff_X == 0) and (diff_Y == 0)) then inSector = 0 distance = 0 angle = 0
		elseif (diff_X == 0 and diff_Y > 0) then inSector = 9 distance = math.abs(diff_Y) angle = 90
		elseif (diff_X == 0 and diff_Y < 0) then inSector = 6 distance = math.abs(diff_Y) angle = 270
		elseif (diff_X > 0 and diff_Y == 0) then inSector = 3 distance = math.abs(diff_X) angle = 0
		elseif (diff_X < 0 and diff_Y == 0) then inSector = 12 distance =math.abs(diff_X) angle = 180
		end
	else
		if ((diff_X > 0) and (diff_Y > 0)) then inSector = 1 a = diff_Y
		elseif ((diff_X > 0) and (diff_Y < 0)) then inSector = 2 a = diff_X angle = 270
		elseif ((diff_X < 0) and (diff_Y < 0)) then inSector = 4 a = math.abs(diff_Y) angle = 180
		elseif ((diff_X < 0) and (diff_Y > 0)) then inSector = 8 a = math.abs(diff_X) angle = 90
		end
		distance = math.sqrt((pos[1].X - pos[2].X)^2 + (pos[1].Y - pos[2].Y)^2)
		angle = angle + math.floor(math.deg(math.asin(a/distance)) + 0.5)
	end
	if distance <= _range then
		inRange = true
	end
	if (sector ~= 0 and inSector ~= 0 and inRange) then
		if (inSector ~= sector and inSector ~= sectorTemp) then
			inRange = false
		end
	end
	return inRange, distance, angle, inSector
end

Entfernung/ Distanz

Wer einfach nur die Entfernung zwischen 2 Punkten (Entities) wissen will, der kommt hiermit aus:

-- Hiermit kann man sich einfach nur die Enfernung von zwei Entities zurückgeben lassen
function GetDistance(_entity1, _entity2)
    local _pos1, _pos2 = GetPosition(_entity1), GetPosition(_entity2)
    return math.sqrt((_pos1.X - _pos2.X)^2 + (_pos1.Y - _pos2.Y)^2)
end

Pythagoras

(Mathe-)Hinweis: Die Formel zur Berechnung ist nichts anderes, als der Satz des Pythagoras!

a^2 + b^2 = c^2

Unsere beiden Punkte (Punkt 1 und Punkt 2) bilden die Punkte A und B eines rechtwinkligen Dreiecks. Ihre Entfernung entspricht also der Länge der Strecke AB ( = Seitenlänge c).

Somit ergibt sich c aus der Quadratwurzel (math.sqrt) von (a^2 + b^2).
Die Seiten a und b ergeben sich aus der Differenz der jeweiligen X- und Y-Koordinaten der Punkte 1 und 2 (und aufgrund des Quadrierens spielt das Vorzeichen keine Rolle, da das Ergebnis immer positiv ist).