Bewegungslehre
-> Don't touch me
Aufgabenstellung:
Ein Sprite soll sich mit einem Mindestabstand von einem anderen Objekt fernhalten.

Wenn ein Sprite mindestens eine bestimmte Distanz zu einem anderen Sprite (oder Punkt) halten soll, so ist ist die Vorgangsweise zur Scripterstellung sehr einfach:
  1. Überprüfen, ob die aktuelle Distanz ausreichend ist.
  2. Wenn notwendig das Sprite wegbewegen: die Verbindungslinie zum anderen Objekt verlängern, und nix wie weg.

ad 1) die Distanz

Wer immer noch nicht auswendig weiß, wie der Pythagoras funktioniert, oder wem es zu langweilig wird, die vielen "sqrt" und "float" zu tippen, der kann ja diesen Handler verwenden:
 
on GetDistance P1, P2
  xd = P2[1] - P1[1]
  yd = P2[2] - P1[2]
  RETURN sqrt(float(xd * xd) + float(yd * yd))
end



ad 2) die Distanz vergrößern

Und noch einmal will ich die 2 Möglichkeiten beschreiben, wie man einen neuen Punkt mit vorgegebener Distanz und Richtung in Bezug auf einen anderen Punkt berechnen kann:

a) mittels Vektor-Berechnung

momentanerVektor = aktuellerPunkt - Kreismittelpunkt -- Tomate - Bombe
momentaneDistanz = GetDistance(aktuellerPunkt, Kreismittelpunkt) -- Distanz zw. Tomate und Bombe
-- der Einheitsvektor (momentanerVektor/momentaneDistanz) wird mit der gewünschten Distanz multipliziert
neuerPunkt = Kreismittelpunkt + (gewünschteDistanz * momentanerVektor / momentaneDistanz)
 
Example: avoidMouse1a.dir
b) mittels Winkelfunktionen
-- Winkel zw. Tomate und Bombe im Bezug aufs Koordinatensystem:
momentanerWinkel = GetAngle(aktuellerPunkt - Kreismittelpunkt)
-- der finale Punkt liegt auf dem Kreis rund um die Bombe, mit dem Radius "gewünschteDistanz"
neuerPunkt = Kreismittelpunkt + GetCirclePoint(momentanerWinkel, gewünschteDistanz)
-- PS: GetAngle() und GetCirclePoint() sind Handler beschrieben im Kapitel "kreisförmige Bewegung"
 
Example: avoidMouse1b.dir

Insbesondere bei beweglichen Elementen, denen das Sprite ausweichen soll, kann man schon wieder die schönen 2 Zeilen Code hinzufügen, die das Sprite langsam abbremsen lassen. :-)
 
property pLoc, pSlowLoc, pDistance

on beginSprite me
  pLoc = sprite(me.spriteNum). loc -- Position wird festgehalten
  pSlowLoc = duplicate(pLoc) -- Position fürs Bremsen wird festgehalten
  pDistance = 100 -- eine minimale Distanz wird festgelegt
end

on exitFrame me
  ML = the mouseLoc -- der Bezugspunkt soll die Maus sein
  distance = GetDistance(pLoc, ML) -- Distanz zw. Sprite und Maus

  if distance < pDistance then -- wenn das Sprite zu nah ist, dann...
    if distance = 0 then distance = 0.0001
    pLoc = ML - (pDistance * (ML - pLoc) / distance) -- wird ein neuer Punkt berechnet
  end if

  -- aber die wirkliche Position des Sprites wird durch Verzögerunger berechnet
  pSlowLoc = pSlowLoc + ((pLoc - pSlowLoc) / 6.0)
  sprite(me.spriteNum).loc = pSlowLoc
end

Example: avoidMouse2.dir


Aufgabenstellung: Das Sprite soll auch wieder zurückkehren

Ausgehend von dem letzten Script ist nur eine kleine Änderung im exitFrame-Handler notwendig, damit das Sprite wieder zu seinem Ausgangspunkt zurückkehrt.
 
on exitFrame me
  ML = the mouseLoc
  distance = GetDistance(pLoc, ML)
   -- das Sprite versucht nun auf alle Fälle wieder zurückzukehren, 
  -- und bezieht sich deshalb auf den Ausgangs-Punkt (pOrigLoc):
  pLoc = pLoc + ((pOrigLoc - pLoc) / 6.0)
  if distance < pDistance then
    if distance = 0 then distance = 0.0001
    pLoc = ML - (pDistance * (ML - pLoc) / distance)
  end if

  sprite(me.spriteNum).loc = pLoc
end



Example: avoidMouse3.dir

Last: Verwendung von Bezierkurven