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

AntroX-Arthas

Frischling

  • »AntroX-Arthas« ist der Autor dieses Themas

Beiträge: 6

Beruf: Tischler

  • Private Nachricht senden

1

07.08.2014, 18:06

Runde Kollisionsabfrage unter C++ mit SDL 1.2 realisieren

Moin moin,
wie die Überschrift schon verrät, möchte ich für ein kleines Übungstowerdef. Spiel eine Kollisionsabfrage gestalten.
4-eckig ist das ja kein Hit, aber ich möchte eine Formel schreiben, welche einen Kreis um meinen Geschützturm gestaltet wodurch er halt Gegner die sich ihm in Luftlinie nähern beschießt.
Wenn man das Bildzeile für Bildzeile in einer For-Anweisung mit komplizierter Formel schreibt könnte das bei mehreren Türmen jeden CPU zum erbrechen bringen.
Hat einer ne Idee?

2

07.08.2014, 18:38

Guck mal bei Youtube und suche "letsgamedev kollision" Der Typ erklärt dir das Wunderbar ;)

3

07.08.2014, 18:45

Siehe dazu diese Wikipage und/oder dieses Video.

MfG
Check

AntroX-Arthas

Frischling

  • »AntroX-Arthas« ist der Autor dieses Themas

Beiträge: 6

Beruf: Tischler

  • Private Nachricht senden

4

07.08.2014, 19:10

lol Goil danke dir ;)

Hab den Typen gleich ma Aboniert.

Für alle die es noch interessiert hier die Kurzform:

Satz des Pythagoras: A² + B² = C² ist der Schlüssel. (Hätte ich drauf kommen können tsts ;) )

Um bei einem Dreieck mit rechtem Winkel die Länge einer Seite zu berrechnen kann man das mit diesem Satz. Bei einem Dreieck:

..|\
..|.\
..|..\
A|...\ C
..|....\
..|.....\
..|____\
B

hat man Seite A zb. 500 Pixel gegeben
und Seite B (300 Pixel) so muß man 500² + 300² = C²
Nun aus C die Wurzel ziehen und man hat die dritte Länge. Soweit so gut, also müssen wir die Position von Objekt 1 als Nullpunkt auf einem Koordinatensystem setzen.


(Link)


Wir brauchen den Weg bis vom Nullpunkt bis zum Objekt und das ergibt ein Dreieck mit rechtem Winkel.

Die Länge und Höhe bis zu dem Punkt (Objekt) vom Mittelpunkt des
Koordinatensystems ist gegeben durch die X und Y Position in einem 2D
Spiel.
Seite C wird mit Pythagoras errechnet und schon haben wir es.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

5

07.08.2014, 20:00

Ich weiß noch, wie ich mich vor vielen Jahren das gleiche gefragt habe.
Da hatten wir in der Schule noch keinen Satz des Pythagoras gelernt, und Internet gab's auch noch nicht für mich.
-> ich hab's nicht hingekriegt ;)

AntroX-Arthas

Frischling

  • »AntroX-Arthas« ist der Autor dieses Themas

Beiträge: 6

Beruf: Tischler

  • Private Nachricht senden

6

08.08.2014, 16:08

Ohne Inet hätte ich C++ nach 2 Stunden aufgegeben^^.

Ich hab die Abfrage gebastelt und wohlte sie in Kritikfeuer werfen:


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void CBogenturm1::AutoAngriff(int m_fReichweite, list<CDummy1>m_pDummylist)
{

    SDL_Rect RectDummy;
        
    list<CDummy1>::iterator it;
    for (it = m_pDummylist.begin(); it != m_pDummylist.end(); it++)
    {
        RectDummy = it->GetRect();

            double zwischenwert = (int)pow(abs((int)m_fXPos - (int)it->m_fXPos),2) +  (int)pow(abs((int)m_fYPos - (int)it->m_fYPos),2);
            
            if (sqrt(zwischenwert) <= 100 && sqrt(zwischenwert) >= -100) 
            {
                ProcessShooting(it->m_fXPos, it->m_fYPos);
            }
    }
    
}


RectDummy ist für die Gegner und ihre aktuelle Position.

list<CDummy1>::iterator it; ist für die Liste der Gegner zum durchspulen

zwischenwert für die Formel. (Wollte nicht alles in die If Anweisung packen)

die vielen (int) er hat dauernd gemeckert wegen der float Werte. Also zum umwandeln.

pow(x,2) für die Potenzen

abs(x) sollten die werte negativ sein, weil die Gegner am Turm vorbei laufen, dann werden sie zu positiven umgerechnet.

sqrt(x) die Wurzel ziehen.

und dann: Sollten die Werte kleiner als 100 sein (dort kommt noch die Variable rein) dann Feuer. Die Funktion

C-/C++-Quelltext

1
ProcessShooting(it->m_fXPos, it->m_fYPos);

bekommt dann die Koordinaten vom Ziel zugeteilt. Dort wird dann natürlich eine globale Abklingzeit erstellt, damit diese kein Dauerfeuer machen.

Ein Haken hatte das ganze. Wie erwartet fängt bei ein paar Gegnern und mehreren Türmen mein Pc (Intel I7 3,6 Ghz) an zu stocken. (Zumindest das SDL Fenster denn das bekommt sicher nicht viel Leistung zugeteilt und der Rest läuft noch normal)

Um das zu beheben hab ich folgendes geschrieben:

C-/C++-Quelltext

1
2
3
4
5
6
7
m_fAngriffverzögerungTimer += g_pTimer->GetElapsed(); 

if (m_fAngriffverzögerungTimer > 5)
{
    CheckAttack ();
    m_fAngriffverzögerungTimer = 0;
}


Damit wird die Aktualisierung nicht jeden Frame ausgeführt. Der Wert kann noch tiefer.

Bin für Kritik offen.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

7

08.08.2014, 16:50

1. Das Casten nach int solltest du dir sparen, völlig unnötig. Jedenfalls ist das nicht das, was du willst.
2. abs ist ebenfalls unnötig, da du quadrierst. Da ist es egal, ob die Zahl positiv oder negativ ist, weil x² = (-x)².
3. Die Wurzel muss man nur einmal ziehen (kannst du direkt in deinen "Zwischenwert" integrieren).
4. Eigentlich muss man die Wurzel überhaupt nicht ziehen, denn aus §\sqrt{x} \leq y§ kannst du §x \leq y^2§ machen. Das zu testen geht schneller.
5. Quadrieren mit pow finde ich unschön, lieber einfach durch Multiplikation mit sich selbst (Variablen für Differenzen in x und y nutzen).
6. Die Iterator-Variable musst du nicht vor der Schleife definieren, am besten innerhalb des for (à la for(int x = 0; x < 10; ++x)).
7. Benutze ++it statt it++, das hat theoretisch einen kleinen Performance-Vorteil.
8. Eigentlich brauchst du gar keinen Iterator. Stattdessen benutze range-based for loops mit konstanten Referenzen.
9. Du kopierst in jedem Durchlauf die SDL_Rect-Instanz. Benutze stattdessen eine konstante Referenz, d.h. const SDL_Rect&, auch bei GetRect.
10. Du übergibst deiner Funktion den Parameter m_pDummylist als Wert, nicht als Zeiger oder Referenz. Dadurch wird die Liste bei jedem Aufruf komplett kopiert.
11. Dass es anfing zu ruckeln, lag sicher nicht an der Schleife, auch wenn sie sehr viel Luft nach oben hat. Hier solltest du mit einem Profiler arbeiten und wirklich messen, was wie viel Zeit braucht.

Werbeanzeige