Hallo allerseits,
In meinem Spiel soll sich der Charakter durch eine Welt bewegen können. Seine Bewegungsrichtung ist komplett beliebig, d.h. er kann sich nicht nach Nord/Nord-Ost usw. bewegen sondern auch in einem z.B. 13° Winkel. In dem Spiel gibt es Wände mit denen der Charakter kollidieren kann. Und wenn der Spieler den Charakter auf eine Wand zu steuert, dann soll die beiden kollidieren und der Charakter soll sich nur noch in die Richtung bewegen die Parallel zum Verlauf der Wand ist (sowie man es aus allen Spielen kennt).
Zuerst hatte ich das nur für Wände gemacht die parallel zur X oder Y-Achse verliefen, aber nun mit dem Dazukommen von schrägen Wänden, hab ich so meine Probleme.
Das ist mein Kollisionscode, der erstmal nur prüft ob der Spieler mit der Wand kollidiert:
Variablen Erklärung:
nPos: Position des Spielers (vom Typ TMeleeCoord, besteht aus x, y (float) Koordinate);
nMov: Bewegungsvektor des Spielers
nSize: Radius der Kollisionsgröße des Spielers.
FLine.A: Startpunkt der Wand.
FLine.B: Endpunkt der Wand.
fv: Vektor von Start zu Endpunkt der Wand.
nv: Bewegungsvektor des Spielers
fvn: normalisiert(fv)
nvn: normalisiert(nv)
rN: Zahlen Teil von r (r =
rN + rS * s)
rS: s Teil von r (r = rN +
rS * s)
sN: Zahlen von s
hitlength: Verlängerungsmaß des Richtungsvektor um zu verhindern, dass wenn man schräg auf eine Wand zu geht, man dichter an die Wand gehen kann, als eigentlich von Kreisradius möglich wäre.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| function TMeColliderLine.IsColliding(const nPos, nMov: TMeleeCoord; nSize: single = 0): boolean; var fv, nv, fvn, nvn: TMeleeCoord; q: boolean; rN, rS, sN, hitlength: single; begin result := false; if (Abs(nPos.X - FLine.A.X) > ABS(FLine.B.X - FLine.A.X) + ABS(nMov.X)) or (Abs(nPos.Y - FLine.A.Y) > ABS(FLine.B.Y - FLine.A.Y) + ABS(nMov.Y)) then exit; fv := meCalculate(FLine.B, me_Substract, FLine.A); nv := nMov; q := meIsParallel(fv, nv); if q then exit; if fv.X <> 0 then begin rN := (nPos.X - FLine.A.X) / fv.X; rS := (nv.X) / fv.X; sN := (FLine.A.Y + fv.Y * rN - nPos.Y) / (nv.Y - fv.Y * rS); rN := rN + rS * sN; end else begin rN := (nPos.Y - FLine.A.Y) / fv.Y; rS := (nv.Y) / fv.Y; sN := (FLine.A.X + fv.X * rN - nPos.X) / (nv.X - fv.X * rS); rN := rN + rS * sN; end; hitlength := abs(nSize / meLength(nv) * tan(90 - arccos(meDot(meNormalize(fv), meNormalize(nv))))); if (rN > 0 - nSize / meLength(fv)) and (rN < 1 + nSize / meLength(fv)) and (sN > 0 - hitlength) and (sN < 1 + hitlength) then begin result := true; FHitPoint := meCalculate(FLine.A, me_Add, fv); end; end; |
Bei einer Kollision wird Folgendes noch ausgeführt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| var qVec: TMeleeCoord; x: single; begin qVec := meNormalize(meCalculate(FLine.B, me_Substract, FLine.A)); x := qVec.X; qVec.X := qVec.Y; qVec.Y := -x; qVec := meCalculate(qVec, me_Multiply, meLength(nMov) * meDot(qVec, meNormalize(nMov))); nPos := meCalculate(npos, me_Add, meCalculate(meNormalize(qVec), me_Multiply, )); nMov := meCalculate(nMov, me_Substract, qVec); end; |
Der Berechnungsteil ob sich die Geraden schneiden funktioniert, nur irgendwie kommt man zu Nahe an die Wand heran und stuckt in ihr. Manchmal kann man sich auch irgendwie durch sie hindurch bewegen, wenn man lange genug wild rumprobiert.
Wenn ihr eine andere Idee habt wie man das implementieren könnte so, dass es performant und "korrekt genug" ist immer her damit
(es soll sich halt flüssig anfühlen). Ihr könnt aber auch Veränderungen an meinem Code vorschlagen, die weiterhelfen würden. Danke auf jeden Fall schonmal!
"Wir können nicht fliehen!" "Wieso nicht?" "Sie haben mir die Schnürsenkel zusammengebunden!" "Die Schweine."