[[http://www.siedler-games.de|{{:sg-link.jpg|}}]]
====== 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:
- Boolscher Wert (true/false) für Punkt 2 liegt innerhalb des Radius **und** des Sektors (wenn angegeben) oder nicht
- Distanz zwischen Punkt 1 und 2 (in Siedlerzentimetern)
- Winkel in Grad (Ganzzahl zwischen 0 und 360) zwischen Punkt 1 und Punkt 2
- 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
* Entity Id = Zahl = 77399
* Entity Name (benannte (Script-)Entity) = String = "Punkt_1"
* Positionstable = Table = {X = 12800, Y = 12800}
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:
{{utilfunctions:sektoren_01.png}}\\ //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).