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

Luca

Treue Seele

  • »Luca« ist der Autor dieses Themas

Beiträge: 188

Wohnort: Braunschweig

  • Private Nachricht senden

1

28.05.2012, 21:47

sfml - Frage zur Kollision

Hallo,

Ich habe eine kleine Frage zur Kollision und zwar:

Habe ich erfolgreich eine Kollisionsabfrage geschrieben. Diese gibt 'collision detected' aus, wenn ich gegen mein Objekt namens 'Coin' mit meinem 'Player' laufe. Nun wollte ich es so machen, dass Coin 'fest' ist, also dass ich dagegen laufe und stehen bleibe. Also muss ich ja nur die Kollision prüfen und sobald der Player z.B. in X Richtung gegen meine Coin läuft muss ich den Plauer auf die Position (X = Coin.x, Y = Player.y) setzen. Verstanden habe ich das Prinzip ja, aber bei der Umsetzung hängts. Habe jetzt folgendes gescripted:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
// Collision
        if ((spritePlayer.getPosition().x+32 >= spriteCoin.getPosition().x && spritePlayer.getPosition().x <= spriteCoin.getPosition().x+16)&&(spritePlayer.getPosition().y+32 >= spriteCoin.getPosition().y && spritePlayer.getPosition().y <= spriteCoin.getPosition().y+16))
        {
            if (spritePlayer.getPosition().x+32 >= spriteCoin.getPosition().x)
            {
                spritePlayer.setPosition(spriteCoin.getPosition().x-32, spritePlayer.getPosition().y);
            }
            else if(spritePlayer.getPosition().y+32 >= spriteCoin.getPosition().y)
            {
                spritePlayer.setPosition(spritePlayer.getPosition().x, spriteCoin.getPosition().y-32);
            }
        }


Ich weiß selber, dass das falsch ist, aber ich habe keine Ahnung, wie ich das Grundgerüst sonst aufbauen muss...

Gruß,
Luca

Geheim

Treue Seele

Beiträge: 202

Wohnort: Salzburg

Beruf: Schüler

  • Private Nachricht senden

2

29.05.2012, 08:22

Hi Luca,

Du rechnest dir die neue x-Position aus, prüfst ob dein Spieler mit den neuen Werten kollidieren würde, wenn ja, verringerst du die vorberechnete Position solange, bis es zu keiner Kollision mehr kommt und setzt sie dann, dasselbe dann für die y-Position.

Btw: 32 ist die Breite/Höhe von den Sprites? Wenn du dafür Variablen benützen würdest, ist der Code übersichtilicher und man kann später alles einfach ändern, wenn man den Wert nur 1 mal ändert und nicht jedesmal wo du ihn brauchst ;)

Luca

Treue Seele

  • »Luca« ist der Autor dieses Themas

Beiträge: 188

Wohnort: Braunschweig

  • Private Nachricht senden

3

30.05.2012, 17:50

Ah, klasse Idee. Werds gleich mal umsetzen

Luca

Treue Seele

  • »Luca« ist der Autor dieses Themas

Beiträge: 188

Wohnort: Braunschweig

  • Private Nachricht senden

4

31.05.2012, 16:06

So, habe ein Problem, an dem ich schon seit ner ganzen Zeit verzweifle. Das Prinzip der Idee habe ich verstanden, aber ich weiß nicht, wie ich das umsetzen soll.

Also ich habe die x Pos meines Players:

C-/C++-Quelltext

1
spritePlayer.getPosition().x


Dann prüfe ich, ob die aktuellen Koordinaten mit der Coin kollidieren (s. den Code oben).

Als nächstes verringere ich die Pos. des Spieler so lange, bis es zu keiner Kollision mehr kommt.
Also anhand der x Pos des Spielers:

C-/C++-Quelltext

1
spritePlayer.setPosition(spritePlayer.getPosition().x-1, spritePlayer.getPosition().y)


Das Prinzip funktioniert. Nur steuere ich meinen Player mittels den Pfeiltasten und um eine flüssige Bewegung hinzubekommen, habe ich eine Clock initialisiert. Dadurch bleibt der Player nicht stehe, wenn ich gegen die Coin laufe, sondern 'gleitet' praktisch zurück, da pro Millisekunde der Player um 1 Pixel verschoben wird.
Hier nochmal der gesamte Code:

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
88
89
90
91
92
93
// ##################
//  Name: Kollision #
// ##################

#include <SFML/Graphics.hpp>
#include <iostream>

using namespace std;

int main()
{
    // window settings
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Kollision");
    window.setFramerateLimit(60);
    window.setMouseCursorVisible(false);

    // objekte definieren
    sf::Texture texturePlayer;
    sf::Texture textureCoin;
    sf::Sprite spritePlayer;
    sf::Sprite spriteCoin;

    // objekte zuweisen
    texturePlayer.loadFromFile("Texture/player.png");
    spritePlayer.setTexture(texturePlayer);
    textureCoin.loadFromFile("Texture/coin.png");
    spriteCoin.setTexture(textureCoin);

    // objekte anpassen
    spriteCoin.setPosition(300, 300);

    // Variablen
    int speed = 200;
    sf::Clock clock;

    // window loop
    while(window.isOpen())
    {
        sf::Event windowEvent;
        while(window.pollEvent(windowEvent))
        {
            // close window
            if (windowEvent.type == sf::Event::Closed)
                window.close();
        }

        // Player Keys
        // Left
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
            spritePlayer.move(-speed*clock.getElapsedTime().asSeconds(), 0);
        }
        
        // Right
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
            spritePlayer.move(+speed*clock.getElapsedTime().asSeconds(), 0);
        }

        // Down
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
            spritePlayer.move(0, +speed*clock.getElapsedTime().asSeconds());
        }

        // Up
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
        {
            spritePlayer.move(0, -speed*clock.getElapsedTime().asSeconds());
        }

        // rendering
        window.clear();

        // Kollision zwischen Player und Coin
        if (spritePlayer.getPosition().x+32 >= spriteCoin.getPosition().x && spritePlayer.getPosition().x <= spriteCoin.getPosition().x+16)
        {
            spritePlayer.setPosition(spritePlayer.getPosition().x-1, spritePlayer.getPosition().y);

            if (spritePlayer.getPosition().y+32 >= spriteCoin.getPosition().y && spritePlayer.getPosition().y <= spriteCoin.getPosition().y+16)
            {
            }
        }

        window.clear(sf::Color::White);
        window.draw(spriteCoin);
        window.draw(spritePlayer);
        clock.restart();
        window.display();
    }

    return EXIT_SUCCESS;
}

Geheim

Treue Seele

Beiträge: 202

Wohnort: Salzburg

Beruf: Schüler

  • Private Nachricht senden

5

31.05.2012, 19:10

Die Idee ist, dass du dir die Position VORberechnest, heißt du bewegst anstatt deinen Spieler Variablen (xPos und yPos)
Zuerst bewegst du xPos, dann prüfst du ob xPos und yPos kollidieren würden, wenn ja setzt du xPos solange zurück bis keine Kollision mehr stattfindet.
Dasselbe dann mit yPos und zum Schluss setzt du die Position des Spielers mit xPos und yPos.

Luca

Treue Seele

  • »Luca« ist der Autor dieses Themas

Beiträge: 188

Wohnort: Braunschweig

  • Private Nachricht senden

6

31.05.2012, 19:23

Hm, okay. Gibt es ne Möglichkeit mir einen kleinen Beispielcode mal zu zeigen? Oder ein Link zu so etwas? Habe im Internet nicht wirklich was gefunden...
Gruß und danke im Voraus,
Luca

Geheim

Treue Seele

Beiträge: 202

Wohnort: Salzburg

Beruf: Schüler

  • Private Nachricht senden

7

31.05.2012, 20:30

Die Möglichkeit gäbe es schon, aber ob dir irgendein Code viel weiterhilft sei dahingestellt...
Ich probiers dir anhand deines schon vorhandenen Codes zu erklären:

Du hast 2 if´s für die Bewegung des Spielers auf der x-Achse: if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left/Right))
Und anstatt den Spieler zu bewegen benutzt du eine Variable (zB. xPos): -> xPos = xPos von Spieler +/- deine Geschwindigkeit
Jetz hast du dir die Position vorberechnet und prüfst ob die VORberechnete Position mit der Münze kollidiert.
Wenn ja, setzt du die VORberechnete Position solange etwas zurück, bis keine Kollison mehr stattfindet. Dasselbe mit der y-Position. Wenn alles passt, setzt du den Spieler mit diesen Werten.

Luca

Treue Seele

  • »Luca« ist der Autor dieses Themas

Beiträge: 188

Wohnort: Braunschweig

  • Private Nachricht senden

8

31.05.2012, 22:19

Danke erstmal für die Antwort!
So, hab dies nun mal berücksichtigt. Bin zu folgendem Ergebnis gekommen:

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
        // Player Keys
        // Left
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
        {
            PlayerX = spritePlayer.getPosition().x - speed;
        }
        
        // Right
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
        {
            PlayerX = spritePlayer.getPosition().x + speed;
        }

        // Down
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
        {
            PlayerY = spritePlayer.getPosition().y + speed;
        }

        // Up
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
        {
            PlayerY = spritePlayer.getPosition().y - speed;
        }

        
        // Kollision prüfen
        while(PlayerX+32 >= spriteCoin.getPosition().x && PlayerX <= spriteCoin.getPosition().x+16)
        {
            PlayerX-1;
        }

        while(PlayerY+32 >= spriteCoin.getPosition().y && PlayerY <= spriteCoin.getPosition().y+16)
        {
            PlayerY-1;
        }

        // neue Position setzen
        spritePlayer.setPosition(PlayerX, PlayerY);


Funktioniert nur leider nicht. Ich glaube ich habe da irgendwo einen Denkfehler drin. Nach meiner Vorstellung sollte es so funktionieren:

1. Tastendruck abfragen (Pfeiltasten) -> Ergebnis wird in PlayerX bzw. PlayerY gespeichert.
2. Kollisionsabfrage -> Ich prüfe, ob die gespeicherten Werte die Coin überschneiden. Einmal in einer while Schleife für die X Pos. und einmal in einer Schleife für eine Y Pos. -> Die while Schleife überprüft, ob es eine Kollision gab, wenn ja wird PlayerX bzw. PlayerY verringert ( -1 ) und zwar so lange, bis dies eben nicht mehr zutrifft.
3. Schließlich werden die neuen Positionen gesetzt.

Problem:
Bewegung funktioniert gut, jedoch bleibt mein Player stehen und lässt sich nicht mehr bewegen, wenn ich gegen die Coin stoße.

Wie schon gesagt, das Prinzip habe ich verstanden, aber an der Umsetzung hackts... :(

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Luca« (31.05.2012, 22:33)


Geheim

Treue Seele

Beiträge: 202

Wohnort: Salzburg

Beruf: Schüler

  • Private Nachricht senden

9

31.05.2012, 23:11

So ganz verstanden scheinst du es auch nicht zu haben ;)
Erstens benutz bei so etwas immer die Frametime, sonst bewegst du dich nicht immer gleichmäßig:
PlayerX = spritePlayer.getPosition().x - speed;

Und ich habe gemeint, dass du zuerst Links und Rechts den Tastendruck abfragst und dann kommt sofort die 1. Kollisionskontrolle, danach kommen erst Oben und Unten und dann die 2. Kontrolle. Und eine Kollisionskontrolle hat 4 Richtungen, oben, unten, links und rechts.
Am Besten du schreibst dir eine eigene Funktion für die Kollisionskontrolle, die dann die Werte überprüft und dann true zurückliefert, wenn was kollidiert und false wenn nichts mehr kollidiert.
Sonst scheint alles zu passen und es sollte dann auch richtig funktonieren ;)

Raidenkk

Treue Seele

Beiträge: 151

Wohnort: Bergkamen/Oberaden

Beruf: Multimedia Informatik

  • Private Nachricht senden

10

01.06.2012, 16:06

Geheim könntest du 1 Kollisionsabfrage mal verdeutlichen oder perfekter weise mal kurz hinzaubern?
Ich habe das gleiche Problem und frage mich wie du das meinst mit 4 Richtungen.
Wenn ich Pfeil (Hoch und Runter) benutze gleite ich schräg durch mein Objekt.

Werbeanzeige