Es wäre praktisch, den gesamten Code (am besten als geziptes Projekt) hier bereitzustellen, damit man sehen kann, in welcher Reihenfolge
CGame::Collision(), CRect::Update() und das Zeichnen der Rechtecke ausgeführt wird.
Zuerst einmal noch eine kleine Anmerkung zu deinem Code:
Statt
|
C-/C++-Quelltext
|
1
2
3
4
5
6
|
vector<CSolid>::iterator it = Solidlist.begin();
for (it; it != Solidlist.end(); it++)
{
A = it->GetRect();
// Mach was mit A
}
|
kannst du auch einfach
|
C-/C++-Quelltext
|
1
2
3
4
|
for (const auto& solid : Solidlist)
{
// Verwende solid.GetRect(); Oder schreibe A = solid.GetRect() und verwende dann A
}
|
schreiben. Das nennt sich range-for und existiert seit C++11 (
range-based for loop).
Nun zu deinem eigentlichen Problem:
Das Problem liegt höchstwahrscheinlich in der Reihenfolge, in der die Dinge passieren. Mehr kann ich dazu aber nicht sagen, ohne nicht den gesamten Code gesehen zu haben.
Ich würde aber jetzt einfach mal sagen, dass die allgemeine Abfolge so aussehen sollte:
1. User Inputs verarbeiten (also die Geschwindigkeiten setzen)
2. Spieler bewegen
3. Kollisionsabfrage zwischen 'Player' und Umgebung:
-- Wenn Kollision: Position des Spielers so setzen, dass KEINE Kollision mehr stattfindet ohne User-Input (siehe Anhang 1 zur genaueren Ausführung)
-- Wenn keine Kollision: alles in Ruhe lassen
4. Objekte zeichnen
Dabei brauchst du außerdem nur eine x- und y-Pos und keine newPos mehr. Es wird einfach immer die aktuelle Position des Spielers manipuliert, und die Änderungen werden eh erst mit dem Zeichnen sichtbar.
Anhang 1:
Ich würde es so machen, dass es erst eine Kollision ist, wenn die Objekte ineinander sind, und im Fall einer Kollision die Position so setzen, dass sich die Objekte berühren, aber nicht überschneiden. Das heißt, bei der Kollisionsabrafe aus den
<= ein
< machen, und der Funktion
Set() einfach eine neue x und eine neue y Position übergeben. Die neue Position muss je nachdem wo die Kollision stattfand extra berechnet werden. (Bedenke: wenn der Player mit einer Ecke kollidiert, müssen sowohl die Änderungen in x und die Änderungen in y Richtung gemacht werden.)
Das ist dann etwas komplexer, da man sozusagen richtig entscheiden muss, wann die Kollision nur von oben, wann von links, wann von rechts unten, usw., kam. Denn je nachdem, muss die neue Position gesetzt werden. Am einfachsten hier wäre es aber, sich die letzte Position des Spielers ohne Kollision zu merken.
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
B = Rect->GetRect();
bool didCollide = false;
for (const auto& solid : Solidlist)
{
A = solid.getRect();
if (Checkcollision(A,B))
{
didCollide = true;
}
}
if (didCollide)
{
Rect->SetPositionToLastPositionWithoutCollision();
}
else
{
Rect->UpdateLastPositionWithoutCollision();
}
|
Wenn du aber simple Physik (Abprallen; bewegende Objekte, die einen verschieben; ...) implementieren willst, wird das sehr schnell recht aufwändig mit den ganzen if-Abfragen. Da bietet es sich dann an, den Vektor zwischen den beiden Objektmittelpunkten zu berechnen, dann den Schnittpunkt (= 'Aufprallpunkt') von diesem Vektor mit dem anderen Objekt zu berechnen, und mit diesem Vektor und Schnittpunkt die Objekte so bewegen, wie man es braucht (zum Beispiel einen Vektor bilden, der vom Schnittpunkt mit dem Eintrittswinkel weg geht => simples Abprallen).
Ich hoffe ich konnte helfen.
LG Patrick
Einen guten Rutsch und ein schönes neues Jahr!