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

18.08.2011, 00:23

Kollision mit collision mask

Hallo,

ich habe versucht mit der Suchfunktion etwas geeignetes zu finden, bin aber leider weder hier, noch auf Google auf brauchbare Resources gestoßen. :(
Deshalb dachte ich mir das ich einfach mal direkt zu meinem Problem frage:

Ich möchte gerne mithilfe einer Kollisionsmaske, die sich über die gesamte Karte erstreckt, die Kollision mit meinem Spieler testen. Das ganze funktioniert auch wunderbar und mithilfe der folgenden, von einer anderen Seite erhaltenen und modifizierten Funktion kriege ich ein Pixelgenaues Ergebnis + den dazugehörigen Positionsvektor der Kollision.

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
    private Vector2 CheckCollision(int Index)
    {
        Rectangle rectangleA, rectangleB;
        rectangleA = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
        rectangleB = new Rectangle((int)Level.CollisionMasks[Index].Position.X, (int)Level.CollisionMasks[Index].Position.Y, Level.CollisionMasks[Index].Texture.Width, Level.CollisionMasks[Index].Texture.Height);
        Color[] dataA, dataB;
        dataA = colorData;
        dataB = Level.CollisionMasks[Index].colorInfo;

        // Find the bounds of the rectangle intersection
        int top = Math.Max(rectangleA.Top, rectangleB.Top);
        int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
        int left = Math.Max(rectangleA.Left, rectangleB.Left);
        int right = Math.Min(rectangleA.Right, rectangleB.Right);

        // Check every point within the intersection bounds
        for (int y = top; y < bottom; y++)
        {
            for (int x = left; x < right; x++)
            {
                // Get the color of both pixels at this point
                Color colorA = dataA[(x - rectangleA.Left) +
                                     (y - rectangleA.Top) * rectangleA.Width];
                Color colorB = dataB[(x - rectangleB.Left) +
                                     (y - rectangleB.Top) * rectangleB.Width];

                // If both pixels are not completely transparent,
                if (colorA.A != 0 && colorB.A != 0)
                {
                    // then an intersection has been found
                    return new Vector2(x, y);
                }
            }
        }

        // No intersection found
        return new Vector2(1.337f, 1.337f);
    }

( Index gibt den Index der zu testenden Maske an )

Das ganze habe ich so in meine Update-Funktion eingebaut:

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
    override public void OnUpdate(GameTime gameTime)
    {  
        Vector2 previousPosition = Position;
        state = Player.State.Standing;

        if (Keyboard.GetState().IsKeyDown(Keys.A))
        {
            Velocity = new Vector2(-20, Velocity.Y);
            direction = Player.Direction.Left;
            state = Player.State.Walking;
        }
        else if (Keyboard.GetState().IsKeyDown(Keys.D))
        {
            Velocity = new Vector2(20, Velocity.Y);
            direction = Player.Direction.Right;
            state = Player.State.Walking;
        }
        else
            Velocity = Vector2.Zero;

        if (Keyboard.GetState().IsKeyDown(Keys.Space))
        {
            state = Player.State.Jumping;
        }

        Velocity += Acceleration * (float)gameTime.ElapsedGameTime.TotalSeconds;
        Position += Velocity;

        //check coli
        Vector2 PoC = CheckCollision(0);

        if (PoC != new Vector2(1.337f, 1.337f))
        {
            Position = previousPosition;
            MoveToContact();
        }

        switch (state)
        {
            case State.Walking: SetAnimation("Walk"); break;
            case State.Jumping: SetAnimation("Jump"); break;
            case State.Standing:
            default:SetAnimation("Stand"); break;
        }

        base.OnUpdate(gameTime);
    }
    private void MoveToContact()
    {
        Vector2 beforeCollision = Position;

        while (CheckCollision(0) == new Vector2(1.337f, 1.337f))
        {
            beforeCollision = Position;
            Position += new Vector2(0, 1);
        }

        Position = beforeCollision;
    }


Die Kollision die durch die Gravitation erzeugt wird ( Acceleration.Y ist vorher gesetzt worden als Gravitation ), funktioniert einwandfrei. Mein Problem ist nun das ich auch gerne Bewegung und Springen möglich machen möchte ( auch wenn der Spieler mit einem "Gegenstand" über ihn kollidiert ). Das ganze soll so laufen das eine bestimmte Steigung überwunden werden kann ( 4-5 Pixel ), alles was da drüber ist soll eine Kollision auslösen und den Spieler nicht ohne Springen passieren lassen. Ich habe mir nun schon allerlei Gedanken dazu gemacht und auch viele herangehensweisen, aber heraus kam bisher leider nichts funktionierendes. Deshalb möchte ich Fragen ob es irgendwo Artikel zu diesem Thema gibt die ich möglicherweise übersehen habe oder vielleicht sogar Code-Beispiele, die bei meinem Problem weiter helfen.

Vielen Dank für eure Hilfe!

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

2

18.08.2011, 00:31

Die beeindruckendste Seite zu TiledMaps und den Umgang mit ihnen in Bezug auf Spiele war meiner Meinung nach diese hier: http://www.tonypa.pri.ee/tbw/start.html Vllt. hilft es dir, ein Kapitel zu Sprüngen ist auch dabei.
Ist zwar Flash, aber der Sinn wird eig. deutlich.
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

3

18.08.2011, 01:11

Danke, ich habe mal einen fixen Blick rübergeworfen und bin mir nicht sicher ob sich das ganze auf meine, nicht Tile-basierte Maske und meiner pixelbasierenden Kollision übertragen lässt?
Hier ist ein Beispiel einer benutzten Maske:
http://dl.dropbox.com/u/2395375/collisionmask1.png (Achtung: Großes Bild)

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

4

18.08.2011, 10:11

Oh, das hab ich glatt überlesen. Hab dich wohl verwechselt.
Was waren denn deine bisherige Herangehensweise/Überlegungen? Und was waren die Folgen?
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

5

18.08.2011, 15:07

Ich habe zunächst einmal jeglich Bewegung gestoppt, sobald eine Kollision auftrat. Das Ergebnis war, das horizontale Bewegungen nicht mehr möglich waren, da sie permanent durch die Gravitation unterbrochen wurden.
Dann habe ich versucht herauszufinden, von welcher Seite die Kollision stattfand. Ob sie nun unten war oder auf einer der Seiten. Das Problem hier war, das nicht immer bestimmen konnte von wo die Kollision geschah ( da die Kollision meistens exakt an einem Eck-Pixel geschah).

Meine letzte vorangehensweise ist der oben gepostete Code, welcher den Spieler nach einer Kollision genau vor einer Kollision setzt. Dies klappt wunderbar beim fallen, aber das Bewegen funktioniert halt nicht.

Da ich ja auch gerne nur an gewissen Steigungen die Bewegung ermöglichen möchte ( momentan wäre mir aber immerhin horinzontale Bewegung schon ganz recht ), dachte ich mir, dass ich die Pixel vor einer Kollision "scanne", und die Steigung dort bestimmte. Mögliches Problem wäre wieder der nicht exakt vorhandene Kollisionspunkt ( oder mehrere, aber nur der 1. wird ausgegeben ) und eventuell zu viel benötigte Rechenleistung. ( Und die fehlende Idee für eine Herangehensweise hierbei )

Der obengezeigte Code lässt den Spieler vertikal kollidieren und positioniert ihn permanent exakt auf der Fläche. Bewegung ist nicht möglich, da wie gesagt Kollision auftretten, da die Fläche nicht zu 100% perfekt gerade ist.

Werbeanzeige