MiniGame Problem



  • Hallo Leute,
    ich habe ein kleines Spiel ähnlich "CurveAttack" oder "Snake" via C++ & WINAPI programmiert.
    Dabei lasse ich pro Spieler eine Linie von einem const. Punkt aus mit SetPixel(...) zeichnen.
    Verloren hat der Spieler, der das Spielfeld verlässt oder mit seiner oder der gegnerischen Linie kollodiert.

    Mein Problem ist nun, dass ich nicht weiß, wie ich die letztere Abbruchbedingung realisieren soll..
    Was ich mir bisher gedacht hab ist, dass ich alle verwendeten Koordinaten in einem Array oder einer .txt-Datei speicher
    und dann mit den Aktuellen vergleiche.

    Das halte ich aber für etwas umständlich.

    Hat jemand eine Idee dazu?

    Schonmal danke im voraus.



  • leg ein Array für jedes Feld an und markiere es mit Leer/Spieler1/Spieler2. dann brauchste immer nur das eine Feld raussuchen das grad neu beschrieben werden soll und kannst dann testen ob das eine Kollision darstellt. Also ganz trivial: bevor du setPixel(...) aufrufst, erstmal die Farbe des Pixels abfragen.


  • Mod

    wenn du mit setpixel die punkte setzt, wird als return die vorherige pixelfarbe zurueckgegeben. falls diese nicht dem leeren pixel entspricht, muss wohl vorher schon jemand einen wert gesetzt haben und du weisst dass es eine kolision gab.



  • Danke für die Hilfe..
    Hab jetz vorerst das mit dem Array versucht und es funktioniert gut 🙂

    Aber das mit dem Rückgabewert von SetPixel hört sich irgendwie einfacher an..

    Allerdings krieg ich das nicht hin:

    bool CGAME::bCrash(COLORREF Color)
    {
    	if(GetRValue(Color) == 255 || GetGValue(Color) == 255)    return true;
    	else    return false;
    }
    
    int CGAME::iMove(void)
    {
            .
            .
            .
        colCrash = SetPixel(hDC, corP1.X, corP1.Y, RGB(0, 255, 0));    // Player 1
        if(bCrash(colCrash))    return 1;
            .
            .
            .
        colCrash = SetPixel(hDC, corP2.X, corP2.Y, RGB(255, 0, 0));    // Player 2
        if(bCrash(colCrash))    return 2;
            .
            .
            .
    }
    

    Was mach ich falsch?



  • Hast du als Hintergrund weiß? Weil dann würde deine bCrash Funktion immer true zurückliefern.

    bool CGAME::bCrash(COLORREF Color)
    {
        if( (GetRValue(Color) == 255 && GetGValue(Color) == 0 ) || 
            (GetGValue(Color) == 255 && GetRValue(Color) == 0 ) )
            return true;
        else    
            return false;
    }
    

    Das sollte funktionieren.

    Oder alternativ und sicher übersichtlicher:

    //                        bbggrr
    #define COLOR_RED     0x000000FF
    #define COLOR_GREEN   0x0000FF00
    
    bool CGAME::bCrash(COLORREF Color)
    {
        return ( Color == COLOR_GREEN || Color == COLOR_RED );
    }
    


  • Ich hab jetzt beide Versionen ausprobiert, aber es Funktioniert immer noch nich. Der Rückgabewert ist immer false 😞

    Meine Hintergrundfarbe ist schwarz (BLACK_BRUSH) und ich benutze den Multibyte-Zeichensatz falls das weiter hilft..?



  • rapso schrieb:

    wenn du mit setpixel die punkte setzt, wird als return die vorherige pixelfarbe zurueckgegeben. falls diese nicht dem leeren pixel entspricht, muss wohl vorher schon jemand einen wert gesetzt haben und du weisst dass es eine kolision gab.

    In der MSDN:

    If the function succeeds, the return value is the RGB value that the function sets the pixel to.

    Also gehts doch nicht mit dem Rückgabewert, ich selber habs zuerst nicht nachgeschaut weil ich Rapso vertraut habe 😉

    int CGAME::iMove(void)
    {
            .
            .
            .
        colCrash = GetPixel(hDC, corP1.X, corP1.Y);
        SetPixel(hDC, corP1.X, corP1.Y, RGB(0, 255, 0));    // Player 1
        if(bCrash(colCrash))    return 1;
            .
            .
            .
        colCrash = GetPixel(hDC, corP2.X, corP2.Y);
        SetPixel(hDC, corP2.X, corP2.Y, RGB(255, 0, 0));    // Player 2
        if(bCrash(colCrash))    return 2;
            .
            .
            .
    }
    

    So, das sollte aber gehen. (zusammen mit der zweiten Version meiner bCrash Funktion)



  • So funktionierts 🙂

    Danke für die Hilfe.
    Hab allerdings noch zwei weitere Fragen:

    • Wie kann man Button deaktivieren? Also das man sie unter bestimmten Bedingungen nicht mehr drücken kann.
    • Bisher kann ich meine Spieler nur im rechten Winkel abbiegen lassen, fänd eine Kurve von einem const. Radius aber schöner.. Wie kann man das machen?


  • Frage 1 hat sich erledigt.. ( EnableWindow(...) )



  • Zur zweiten Frage: mit Mathematik 😉
    Deine "Abbiegekurve" ist ja quasi ein viertel Kreis um ein Drehzentrum welches etwas versetzt zu deiner Linie liegt. Wenn deine Schlange sich gerade horizontal bewegt und du nach oben abbiegen willst währe dieser zum Beispiel etwas oberhalb des Punktes an dem du abbiegen willst. Die Koordinaten deiner Kurve sollten sich dann über sin/cos berechnen lassen.



  • Problem gelöst -> "Bresenham-Kreis-Algorithmus" (allerdings vorerst wieder verworfen)

    Hab das Spiel und den Code mal hochgaladen (http://www.file-upload.net/download-2745919/Snake-Attack.zip.html) und hätte gern mal ein paar Meinungen dazu gehört.

    PS:
    Das war mein erstes Spiel & "größeres" Projekt 😃
    Außerdem benutze ich eine kleine statische Bibliothek namens SFC.lib für Schreibfaule (über dessen Inhalt sich streiten lässt)
    Eine kleine Erklärung liegt vor.
    (bitte nur Meinungen zum Spiel und NICHT zur LIB - da recht sinnfrei)

    Nochmals danke für die Hilfe 🙂



  • Also, ich bekomme beim Start zwei Fehler, "Cannot open mp3" und "Cannot Start mp3", das Spiel startet dann aber.
    Zweitens: Wo ist das Futter? 🙂
    Drittens: Du solltest das Bild beim Game-Over stehen lassen damit man sieht wer wie gefailed hat.
    Viertens: Währe eine Steuerung über WASD für den einen Spieler und Pfeiltasten für den anderen Spieler nicht sinnvoller? Mir war nicht intuitiv klar in welche Richtung meine Schlange "abbiegt".
    Und fünftens finde ich das Spielfeld zu groß. Eventuell solltest du die Schlangen dicker bzw schneller machen.

    Aber du hattest ja gesagt dass das dein erstes Spiel ist und von daher: Es funktioniert, das ist erstmal die Hauptsache 🙂

    /Edit: hab die Musik mal manuell gestartet, die SuperMario Musik ist einfach legendär.



  • Ups, das mit der mp3 hab ich total vergessen..
    Es müsste funktionieren, wenn du die beiliegende mp3 (oder eine mit selben Namen) auf deine Festplatte 'D' verschiebst.

    Alles weitere werd ich mir nochmal angucken 😉
    Darüber hab ich mir noch nicht wirklich gedanken gamacht, aber die Vorschläge sind nicht schlecht..

    Gib es vllt. noch etwas am Code selbst was man besser machen kann?



  • NEO.PIXEL schrieb:

    Ups, das mit der mp3 hab ich total vergessen..
    Es müsste funktionieren, wenn du die beiliegende mp3 (oder eine mit selben Namen) auf deine Festplatte 'D' verschiebst.

    Gib doch den Pfad zu der MP3 relativ an, also ohne Laufwerksbuchstaben.



  • Hört sich gut an.. Wie macht man das denn? 😕



  • Naja du hast ja ein sogenanntes "Working Directory", also ein Arbeitsverzeichnis in dem deine .exe ausgeführt wird. Das taucht zum Beispiel in ner Verknüpfung auf als "Ausführen in". Wenn du jetzt einen relativen Pfad angibst, also zum Beispiel "music\supermario.mp3" dann hängt Windows diesen Pfad an dein Working Directory an.
    Wenn du deine .exe einfach so per Doppelklick ausführst dann ist das Working Directory das Verzeichnis in dem deine .exe liegt. Stell dir vor deine .exe liegt in "D:\CPP\ErstesSpiel", und du gibst als Pfad "music\supermario.mp3" an, dann muss deine MP3 dort sein: "D:\CPP\ErstesSpiel\music\supermario.mp3".



  • Achso danke.. Das is gut zu wissen 🙂

    Eine Frage hab ich aber noch..
    Ich hab in meinem Spiel die zwei Klassen (Haupt- und Spielklasse) dynamisch angelegt.. Ist das so sinnvoll oder legt man die besser automatisch oder so an??



  • Hat sich erledigt.. Hauptklasse besser automatisch und die Spielklasse dynamisch.. 🙂



  • Ist eigentlich total egal, außer du hast in deinem Construktor etwas eingebaut was von einer Initialisierung irgendwo anders abhängt. Und das währe IMHO nicht unbedingt ein guter Programmierstil.
    Ich mache das eigentlich immer so dass ich im Constructor nur die "einfachen" Variablen der Klasse initialisiere und ggf. den Basis-Construktor aufrufe.
    Für alle Initialisierungen die einen Funktionsaufruf oder ähnliches benötigen füge ich eine Init() Funktion hinzu welche zur Programmlaufzeit aufgerufen wird. In dieser kann man ja ggf. durch BasisKlasse::Init( <Argumente> ) die Init-Funktion der Basisklasse aufrufen.



  • Das mit dem Init() hab ich unter anderem schon eingebaut 😃

    Hab allerdings noch einen letzten Fehler gefunden und ich hab keine Ahnung wie ich den beheben könnte:
    Wenn man das Fester verschiebt oder die Größe ändert, funktioniert das Spiel nicht mehr, dh. es hat sofort beim Start ein Spieler verloren..
    Ich denke es hapert an meiner bIsPointInApp-Funktion:

    bool CGAME::bIsPointInApp(COORD corPixel)
    {
    	RECT rect;
    	GetWindowRect(hScreen, &rect);
    	if( corPixel.X >= rect.left-105 &&
    		corPixel.X <= rect.right-105 &&
    		corPixel.Y >= rect.top-130 &&
    		corPixel.Y <= rect.bottom-130)
    		return true;
    	else
    		return false;
    }
    

    PS:
    Die Größenänderung von rect (rect.top-130...) war auch nur eine Notlösung, da ich auch ohne Verschieben oder so das Problem schon hatte.

    Hat jemand eine Idee dazu?



  • 😕


Anmelden zum Antworten