Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

09.08.2022, 15:07

C++ Sfml Kollisionsabfrage von 4 Seiten

Hallo, ich habe mal eine Frage zur Kollision von zwei Vierecken. Ein Viereck ist der Spieler den ich steuern kann, das andere Viereck ist etwas größer, an dem ich die Kollisionsabfrage versuche, mit dem Ziel das der Spieler nicht hindurch gehen kann, eine Art Mauer.
Die Kollisionsabfrage funktioniert bei nur drei Seiten, wenn ich die vierte hinzufüge klappt es auf einmal nur noch allein bei dieser. Des Weiteren springt der Spiele ein wenig wenn er mit den Ecken des größeren Viereck kollidiert. Könnte mir jemand sagen was ich im folgenden Code falsch mache, ist in c++ sfml:

C-/C++-Quelltext

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
40
41
42
43
44
45
46
47
48
49
for(int i = 0; i < walls.size(); i++){
    
    
    FloatRect wallBounds = walls[i].getGlobalBounds();
    FloatRect playerBounds = player.getGlobalBounds();
    
    Vector2f plrVecPos = player.getPosition();
    Vector2f wallVecPos = walls[i].getPosition();

...

if(playerBounds.intersects(walls[i].getGlobalBounds())){
    
    
 
// Left Collision 
 if ( playerBounds.top < wallBounds.top &&
playerBounds.left < wallBounds.left + wallBounds.width   && playerBounds.left + playerBounds.width > wallBounds.left) 
     { 
     
 player.setPosition(playerBounds.left, wallBounds.top  - playerBounds.height); 
      }

//Right Collision
if( wallBounds.top < playerBounds.top &&
 wallBounds.left < playerBounds.left + playerBounds.width && wallBounds.left + wallBounds.width  > playerBounds.left ) 
      {
        
        player.setPosition(playerBounds.left, wallBounds.top + wallBounds.height); 
      
        }   
   
// Top
if(playerBounds.left < wallBounds.left &&
playerBounds.top < wallBounds.top + wallBounds.height   && playerBounds.top + playerBounds.height > wallBounds.top) 
     { 
player.setPosition(wallBounds.left - playerBounds.width, playerBounds.top); 
      }
     
// Down <---- Wenn ich die folgende if Funktion einfügen funktionieren die drei obigen nicht mehr
/*
else if( wallBounds.left < playerBounds.left &&
 wallBounds.top < playerBounds.top + playerBounds.height && wallBounds.top + wallBounds.height  > playerBounds.top ) 
      {
        
        player.setPosition( wallBounds.left + wallBounds.width,   playerBounds.top  ); 
     
        }   
}

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Jan666« (09.08.2022, 15:26)


2

09.08.2022, 20:44

Hey,

auf den ersten Blick fällt mir auf, dass du die letzte Seite mit else if implementierst. Das führt dazu, dass diese Bearbeitung nur erfolgt wenn die dritte Abfrage (Top) fehlschlägt.

Würde es hier Sinn machen alle Seiten mit else if zu verknüpfen?
"Wer Angst hat, dass ihm seine Ideen geklaut werden, der scheint nicht viele zu haben. "

3

09.08.2022, 21:40

Ne leider nicht bzw. nur zwei Seiten funktionieren dann

4

10.08.2022, 01:26

Hallo Jan666,

ich würde erstmal damit anfangen eine Funktion zu schreiben, die prüft, ob sich zwei Achsen ausgerichtete Rechtecke überlappen. Eine Erklärung findest du zum Beispiel hier: https://www.youtube.com/watch?v=U1iAY0gNFtE

Edit: Das passiert schon in Zeile 12

Dann würde ich erstmal den Spieler zurücksetzen auf die Position von der er gekommen ist.
Als nächstes würde ich mir überlegen was weiter passieren soll oder ob das schon reicht.
Außerdem wäre gut zu wissen in welche Richtungen sich der Spieler bewegen kann.
Also, 4-Richtungen, auch diagonal oder beliebig in jede Richtung?


Ok, es ist spät und hab eben die Überschrift gelesen. 4 Richtungen also.

Dann musst du raus bekommen in welche Richtung sich der Spieler bewegt.
Entweder aus dem Bewegungsvektor oder einfach überprüfen welche Taste gedrückt wurde.
Wenn zum Beispiel Links gedrückt wurde verschiebst du den x wert des Spieler so, dass er rechts neben der Wand steht.

Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von »Hannes« (10.08.2022, 02:32)


Timmyew

Treue Seele

Beiträge: 128

Beruf: Fachinformatiker für Anwendungsentwicklung

  • Private Nachricht senden

5

10.08.2022, 12:35

Leider habe ich nicht viel Zeit, daher habe ich dir ein Bild gezeichnet :).
»Timmyew« hat folgendes Bild angehängt:
  • Kollision.png

KahnSoft

Frischling

Beiträge: 59

Wohnort: Berlin

  • Private Nachricht senden

6

10.08.2022, 18:46

Zuerst must Du einen Furstum vor Dir hertragen um filetieren zu können welche Faces zur Untersuchung überhaupt herangezogen werden sollen.
Und dann kannst Du testen ob Sphäre Box oder Point eine Plane intersektiert.

C-/C++-Quelltext

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
40
41
42
43
44
45
46
47
48
// Test If A Point Is In The Frustum.
bool CGLfrustum::PointIn( const CVertex a)
{
    for( register int p = 0; p < 6; p++ )
        if( frustum[p][0] * a.x + frustum[p][1] * a.y + frustum[p][2] * a.z + frustum[p][3] <= 0 )
            return false;

    return true;
}

// Test If A Sphere Is In The Frustum
bool CGLfrustum::SphereIn( const CVertex a, float radius )
{
    for( register int p = 0; p < 6; p++ )
        if( frustum[p][0] * a.x + frustum[p][1] * a.y + frustum[p][2] * a.z + frustum[p][3] <= -radius )
            return false;

    return true;
}


// Test If A Cube tail Is In The Frustum
bool CGLfrustum::CubeIn( const CVertex box, float size)
{
    for( register int p = 0; p < 6; p++ )
    {
        if( (frustum[p][0] * (box.x - size)) + (frustum[p][1] * (box.y - size)) + (frustum[p][2] * (box.z - size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x + size)) + (frustum[p][1] * (box.y - size)) + (frustum[p][2] * (box.z - size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x - size)) + (frustum[p][1] * (box.y + size)) + (frustum[p][2] * (box.z - size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x + size)) + (frustum[p][1] * (box.y + size)) + (frustum[p][2] * (box.z - size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x - size)) + (frustum[p][1] * (box.y - size)) + (frustum[p][2] * (box.z + size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x + size)) + (frustum[p][1] * (box.y - size)) + (frustum[p][2] * (box.z + size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x - size)) + (frustum[p][1] * (box.y + size)) + (frustum[p][2] * (box.z + size)) + frustum[p][3] > 0 )
            continue;
        if( (frustum[p][0] * (box.x + size)) + (frustum[p][1] * (box.y + size)) + (frustum[p][2] * (box.z + size)) + frustum[p][3] > 0 )
            continue;

        return false;
    }

    return true;
}


Der benötigte Furstum hat 6 faces near and farplane top left bottom right

Gewinne den furstum aus deiner Projektions und Modelmatrix : (ExtractFurstum)

C-/C++-Quelltext

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
void CGLfrustum::Extract() // Extracts The Current View Frustum Plane Equations
{
    float *pro=m_pro.GetPtr();
    float *clp=m_clip.GetPtr();
    float *mod=GetPtr();
    float t;                            // Temporary Work Variable

    Mult(mod, pro, clp);

    // Extract the RIGHT clipping plane
    frustum[0][0] = clp[ 3] - clp[ 0];
    frustum[0][1] = clp[ 7] - clp[ 4];
    frustum[0][2] = clp[11] - clp[ 8];
    frustum[0][3] = clp[15] - clp[12];

    // Normalize it
    t = sqrtf( frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2] );
    frustum[0][0] /= t;
    frustum[0][1] /= t;
    frustum[0][2] /= t;
    frustum[0][3] /= t;

    // Extract the LEFT clipping plane
    frustum[1][0] = clp[ 3] + clp[ 0];
    frustum[1][1] = clp[ 7] + clp[ 4];
    frustum[1][2] = clp[11] + clp[ 8];
    frustum[1][3] = clp[15] + clp[12];

    // Normalize it
    t = sqrtf( frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2] );
    frustum[1][0] /= t;
    frustum[1][1] /= t;
    frustum[1][2] /= t;
    frustum[1][3] /= t;

    // Extract the BOTTOM clipping plane
    frustum[2][0] = clp[ 3] + clp[ 1];
    frustum[2][1] = clp[ 7] + clp[ 5];
    frustum[2][2] = clp[11] + clp[ 9];
    frustum[2][3] = clp[15] + clp[13];

    // Normalize it
    t = sqrtf( frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2] );
    frustum[2][0] /= t;
    frustum[2][1] /= t;
    frustum[2][2] /= t;
    frustum[2][3] /= t;

    // Extract the TOP clipping plane
    frustum[3][0] = clp[ 3] - clp[ 1];
    frustum[3][1] = clp[ 7] - clp[ 5];
    frustum[3][2] = clp[11] - clp[ 9];
    frustum[3][3] = clp[15] - clp[13];

    // Normalize it
    t = sqrtf( frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2] );
    frustum[3][0] /= t;
    frustum[3][1] /= t;
    frustum[3][2] /= t;
    frustum[3][3] /= t;

    // Extract the FAR clipping plane
    frustum[4][0] = clp[ 3] - clp[ 2];
    frustum[4][1] = clp[ 7] - clp[ 6];
    frustum[4][2] = clp[11] - clp[10];
    frustum[4][3] = clp[15] - clp[14];

    // Normalize it
    t = sqrtf( frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2] );
    frustum[4][0] /= t;
    frustum[4][1] /= t;
    frustum[4][2] /= t;
    frustum[4][3] /= t;

    // Extract the NEAR clipping plane.  This is last on purpose (see pointinfrustum() for reason)
    frustum[5][0] = clp[ 3] + clp[ 2];
    frustum[5][1] = clp[ 7] + clp[ 6];
    frustum[5][2] = clp[11] + clp[10];
    frustum[5][3] = clp[15] + clp[14];

    // Normalize it
    t = sqrtf( frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2] ); 
    frustum[5][0] /= t;
    frustum[5][1] /= t;
    frustum[5][2] /= t;
    frustum[5][3] /= t;
}


In Action siehts dann so aus, mit dem klassischen Verhalten an der Wand. https://www.twitch.tv/videos/1557029363

7

10.08.2022, 18:46

Versteh ich nicht die Zeichnung, aber danke für die Mühe

8

10.08.2022, 20:05

Puh das mit dem Furstum klingt sehr kompliziert, hab das in Verbindung mit Sfml auch noch nie gehört, trotzdem danke

KahnSoft

Frischling

Beiträge: 59

Wohnort: Berlin

  • Private Nachricht senden

9

10.08.2022, 20:18

Hallo Jan,

ja stimmt, man ist dann selber der Matrixhalter, aber es geht auch einfacher, dein 3D Objekt besteht ja zumindest aus einem Dreieck, dies ist ein Triangle
sagt man also gerne
CTriangle
CVertex a;
CVertex b;
CVertex c;
}

ein CVertex hat zb als struct x,y,z , jetzt kannst du einen triangle(Dreieck) auch prüfen ob ein Punkt die Plane(Faces) Intersektiert:


C-/C++-Quelltext

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
float CTriangle::Intersect(CTriangle &tri,CVertex &pos)
 {
  tri.v0 -= pos,
  tri.v1 -= pos,
  tri.v2 -= pos;
 
  float   mag0(tri.v0.Magnitude()),
          mag1(tri.v1.Magnitude()),
          mag2(tri.v2.Magnitude());
             

  return  acosf( tri.v0.Dot(tri.v1) / (mag0 * mag1))+
          acosf( tri.v1.Dot(tri.v2) / (mag1 * mag2))+
          acosf( tri.v2.Dot(tri.v0) / (mag2 * mag0));
}

 float CTriangle::Intersect(CVertex &pos)
 {
     v0 -= pos,
     v1 -= pos,
     v2 -= pos;

     float   mag0(v0.Magnitude()),
             mag1(v1.Magnitude()),
             mag2(v2.Magnitude());

     return  acosf(v0.Dot(v1) / (mag0 * mag1)) +
             acosf(v1.Dot(v2) / (mag1 * mag2)) +
             acosf(v2.Dot(v0) / (mag2 * mag0));
 }




Mag und Dot wie sich das auflöst weißt Du vielleicht :

Ein Dot ist ein Punktprodukt:

C-/C++-Quelltext

1
2
3
4
float CVertex::Dot(const CVertex &v1) 
{
    return x*v1.x + y*v1.y + z*v1.z;
}



Ein Mag ist die Magnetude

C-/C++-Quelltext

1
2
3
4
float CVertex::Magnitude()//direction
{
  return sqrtf( (x*x) + (y*y) + (z*z) );//dont null
}



Grüße gehen raus, zeit nehmen dafür ist natürlich machbar.
K. aus B.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »KahnSoft« (10.08.2022, 20:24)


10

10.08.2022, 20:45

Das ist nur 2d, also einfach nur zwei simple Rechtecke, einer ist der Spieler der andere die Mauer, an der der Spieler praktisch nicht hin durch darf, die Kollisionsabfrage klappt ja, nur nicht das der Spieler an allen vier Seiten der Mauer hindurch läuft

Werbeanzeige