Tutorial 5: Das erste 2D Game: Angriffe und leben

  • So Nun zum nächsten Teil: Die angriffe und die leben.

    Unswar wird man über das drücken der Leer-Taste Bomben werfen.

    Was euch also schon Klar sein sollte ist, dass wir in der update Methode eine weitere abfrage brauchen:


    Nun entsteht hierbei ein kleines Problem, aber darum kümmere ich mich später...

    Erst einmal muss nun eine neue bombe erstellt werden, die dann hinzugefügt wird:

    Code
    Bomb b = new Bomb();


    Nun muss die Startposition der bombe erstellt werden:

    Code
    b.pos = new Vector2([COLOR="orange"]player.tex.Width / 2[/COLOR] + player.pos.X, [COLOR="#ff00ff"]player.tex.Height[/COLOR] + player.pos.Y);


    Der orange teil sorgt dafür das die bombe in der Mitte der Spieler Textur entsteht, der Lilane damit sie unterhalb des Spielers entsteht.

    Als geschwindigkeit wird eine geste geschwindigkeit nach unten verwendet,

    Code
    b.speed = new Vector2([COLOR="orange"]player.speed.X / 3f[/COLOR] , [COLOR="#ff00ff"]135[/COLOR]);


    Den Orangen teil verwende ich diesmal um eine kleine bewegung in die richtung des spielers hinzubekommen, da die Bombe ja immernoch einen teil der geschwindigkeit hat.
    Lila ist die startgeschwindigkeit; 135 px/s nach unten.

    Der schaden soll ein wenig (pseudo-)Zufällig errechnet werden, dafür verwende ich die random Klasse

    Code
    //Neuen Pseudo-Zahl Generator
                    Random rnd = new Random(DateTime.Now.Millisecond);
                    //Damage bestimmen
                    b.damage = rnd.Next(5, 13);
                    //Generator löschen für den garbage Collector
                    rnd = null;


    Damit wird ein "Zufälliger wert zwischen 5 und zwölf ermittelt.

    Es bleiben noch BoomInstance(sound) und Tex(Textur)
    für beide könnte man ganz einfach den Content aufrufen, aber sowas in der Update Methode kostet wertvolle zeit. Deshalb erstellen wir vorher schon diese beiden objekte und schreiben dann nur einen verweis in die Bombe.
    Für das erstellen brauchen wir erst mal 2 weitere Variablen im GameEnvironment aus der Objekte.cs:


    dann müssen die in LoadContent auch noch geladen werden:

    Und nun gibt es nur noch einen neuen zeiger auf die bombe hinzuzufügen

    Jetzt geht es nur noch an die Bewegung der bomben:
    Dafür wird nun in der Update Methode eigentlich das Selbe gemacht wie für den gegner nur halt nach unten/oben:

    Code
    for (int i = 0; i <= player.Bombs.Count - 1; i++ )/*Jeden Bombenindex durchgehen*/ {
                    Bomb b = player.Bombs[i]; //Bombe am index aufrufen
                    b.pos += b.speed* (float)gameTime.ElapsedGameTime.TotalSeconds; //neue position ermitteln
                    player.Bombs.Add(b); //Neuen eintrag setzen
                    player.Bombs.RemoveAt(i); //Alten eintrag löschen
                }

    Bomben kolision:
    Das folgende verfahren ist total naiv und unprofessionell, und nur bei wenigen kollisionen zu enpfehlen, da ich jede bombe mit jedem objekt abgleiche
    die rechenleistung ist also

    Code
    Anzahl_DER_OBJEKTE^ANZAHL_DER_BOMBEN * LEISTUNG_PRO_ABFRAGE


    und dies kann einen enormen verschleiß an zeit haben, wenn man viele objekte hat.
    dennoch für das recht es.

    Für die kollisionserkennung verwenden wir die schleife zur bewegung, und hängen die abfrage einfach rein, sodass sollte eine kollision vorliegen das objekt einfach nicht mehr hinzugefügt wird:


    Das rote fragt ab ob der gegner berührt ist, wenn nicht wird mit dem orangenen abgefragt ob der boden berührt ist, wenn der gegner berührt ist wird der Sound gespielt und der gegner verliert leben, beim boden wird nur der sound gespielt, und nur wenn nichts davon Stimmt bleibt die bombe in der liste.

    Nun zu dem kleinen poblem:
    Sobald man auf leer klickt wirft man X bomben.
    Dies beheben wir mit einer wartezeit: also wenn die noch nicht um ist wird keine bombe geworfen.

    Dafür fügen wir 2 neue variablen zur player und zur enemy struktur hinzu:

    Code
    /// <summary>
            /// Der Zeitpunkt des letzten schusses
            /// </summary>
            public float lastShot { get; set; }
            /// <summary>
            /// Die Wartezeit bis zum nächsten
            /// </summary>
            public float waitTime { get; set; }


    nun müssen wir die natürlich auch mitladen, dafür gehen wir in die Initialize Methode aus der game.CS


    Nun bauen wir das mit einer simplen abfrage noch ein:


    mit (float)gameTime.TotalGameTime.TotalSeconds wird der float wert der aktuellen spiel zeit in sekunden rausgefunden, mit dem zeitpunkt des letzten schusses verglichen, und wenn die waitTime vorbei ist kann erneut geschossen werden.

    Jetzt muss das ganze nur noch auf den gegner umgeschrieben werden, da der gegner ein pc ist wird anstatt mit der tastenabfrage mit einem zufall von 1 und 2 entschieden ob geschossen wird oder nicht:


    Die änderungen sind: ich habe player und enemy vertauscht, den roten punkt zur kollisonsabfrage hinzugefügt(damit auch untendrunter abgefragt wird) und ich habe die richtung auf - gestellt, damit sie hoch fliegen, und mit den orangenen teil habe ich die rand kollision auf den oberen rand gestellt.

    Die leben:

    Zu erst laden wir die textur im load content(hab ich im anderen tutorial vergessen)

    für gewöhnlich würden wir die Leben so zeichnen lassen

    Code
    spriteBatch.Draw(enemy.liveTex, new Rectangle(0, 0, environment.windowWidth, 15), Color.White);


    da haben wir aber immer nur skalierte leben, um was abzuschneiden benötigen wir das source rectange.
    Dabei handelt es sich um den ausschnitt, der gezeigt werden soll, alles andere fällt weg
    um nur den lebensteil des gegners anzuzeigen brauchen wir

    Code
    spriteBatch.Draw(enemy.liveTex, new Rectangle(0, 0, (environment.windowWidth / 100) * enemy.lives, 15), new Rectangle(0, 0, (environment.windowWidth / 100) * enemy.lives, 15), Color.White); // ausschnitt zeichnen


    hier bei ist vor allem wichtig dass das destination rectangle(das erste) nicht größer als das source rectangle(das 2te) ist. das source rectangle geht von dem punkt 0,0 auf eurer textur, nicht von dem in dem programm aus also entspricht 0,0 der position der textur, während sich das destination rectangle nach den programm koordinaten richtet
    Die form der größen berechnung ist reine prozentrechnugn, und dass muss ich wohl von euch erwarten.

    die spieler textur wird so gezeichnet:

    Code
    spriteBatch.Draw(player.liveTex, new Vector2(environment.windowWidth-45, 15), new Rectangle(0, 0, 15*player.lives, 15), Color.White); // ausschnitt zeichnen

    dabei habe ich einen vector 2 genommen, da höhen und breiten angaben in diesem fall sinnlos sind(die textur hat ne feste größe)
    und dass new Rectangle(0, 0, 15*player.lives, 15) berechnet die anzahl der herzen(1 herz = 15 px)

    So gut wenn ihr das gemacht habt ist das spiel eigentlich soweit fertig, Was jetzt noch kommt hat weniger was mit XNA zu tun, das sind eher extras die durch reine anfrageng geschehen.

    Dann kommt am Ende noch einmal ein kleines tutorial wie man das ganze auf windows phone und XBox umschreibt.

    Die komplette bisherige projektmappe bekommt ihr hier:
    http://rapidshare.com/files/453578802/Bomber.zip

    Ach nochwas: Die hintergrund musik hab ich komplett selbst gemacht: die gehört mir(falls einer auf die idee kommen sollte das teil oder teile davon zu verwenden)

    Zitat von Steve Jobs

    Stay hungry - stay foolish.



  • Alles schön und gut, dass du dich bemühst, aber es kommt mir keine rechte Freude an so einigem auf.
    Nochmals, wieso nimmst du Strukturen statt Klassen für Objekte, die mit ner Klasse 1000x besser bedient sind.
    Außerdem kannste bei nicht benötigten Sachen gleich Dispose() aufrufen, nur auf den GC zu warten kann teilweise tödlich sein.
    Es mag stimmen, dass man während Update nich unbedingt was laden sollte, da es aufgrund der häufigen Aufruferei blöd wäre, aber es macht meistens auch mal sinn, etwas trotzdem dort nachzuladen, aber dafür zu sorgen, dass es am ende dennoch wieder geladen wird, wenn von XNA die LoadContent Methode aufgerufen wird, damits keine Probleme gibt.
    Achja, deine Kollisionsabfrage ist sehr umständlich und doof, benutz ein Rechteck um die Textur quasi als Bounding-Box und führe damit die Kollisionsabfrage durch, die sieht erstens besser aus und bringt mehr als deine Methode.

    Für mich sehen die Tutorials teilweise aus, wie als hättest du kaum Ahnung, willst aber was machen, die Mängel fliegen einem richtig zu in manchen Fällen.
    Gerade Spieleentwickler müssen Bescheid wissen von diesen Dingen:
    1. Kapselung der Daten in Klassen/Strukturen (wozu ist alles sonst Objektorientiert, wenn man eh alles irgendwie zusammenschmeißt)
    2. Namenskonventionen
    3. Saubere Programmierung (<-- das wichtigste)

    Achja, einige SCreens im Tut würden nie schaden und mehr erklären auch nicht.
    Und wenn Probleme auftauchen, schmeiß sie raus und sag nich, "dazu kommen wir gleich"
    Das is schon bei deiner Steuerungslogik, du sagst, es gäbe ein Problem mit dem vertauschen von den Richtungen und statt es gleich richtig zu machen, drehst du lieber ein Vorzeichen in ner spätern berechnung rum.
    Viel Spaß beim Bugfix, wenn du so weitermachst.

  • Zitat

    Nochmals, wieso nimmst du Strukturen statt Klassen für Objekte, die mit ner Klasse 1000x besser bedient sind.


    Klassen bringens nur wenn man Methoden verwenden will (Interne und Externe) während als Datenspeicher Strukturen vollkommen ausreichen

    Zitat

    Außerdem kannste bei nicht benötigten Sachen gleich Dispose() aufrufen, nur auf den GC zu warten kann teilweise tödlich sein.


    Natürlich auch diese form der Kollisionserkennung ist tötlich, doch bei diesem spiel machts keinen unterschied

    Zitat

    Es mag stimmen, dass man während Update nich unbedingt was laden sollte, da es aufgrund der häufigen Aufruferei blöd wäre, aber es macht meistens auch mal sinn, etwas trotzdem dort nachzuladen, aber dafür zu sorgen, dass es am ende dennoch wieder geladen wird, wenn von XNA die LoadContent Methode aufgerufen wird, damits keine Probleme gibt.


    Mit jedem mal Content.Load wird ein neuer Speicher im Ram erstellt, in dem das reingeschrieben wird, mit meiner methode wird nur einer erstellt auf den verwiesen wird.
    Bei Dingen die oft geladen werden kannst du davon ausgehen, dass das laden in der Update Methode 1000x tötlicher wäre als der GC

    Zitat

    1. Kapselung der Daten in Klassen/Strukturen (wozu ist alles sonst Objektorientiert, wenn man eh alles irgendwie zusammenschmeißt)


    Zu viele verschachtelungen machen das Ganze unübersichtlich, Jeder muss selbst wissen wie er das macht für mich wäre jede weitere abkapselung total unübersichtlich und ich würde überhaupt nicht klar kommen, wenns bei dir anders ist musst du es den anderen aber nicht aufbinden. Außerdem wenn du schon mit dem OOP kommst: bei dem OOP wird jede klasse einzeln initialisiert und abgefragt, und dass kostet wertvolle resseurcen und ram, Meiner meinung nach hat das OOP keinen vorteil der diesen nachteil überwiegt.

    Zitat

    2. Namenskonventionen


    Ich mache es so: Denglische namen, Klassen Groß geschrieben, Variablen und Methoden klein geschrieben, so hat man Klare unterschiede zwischen Player und player.

    Zitat

    Das is schon bei deiner Steuerungslogik, du sagst, es gäbe ein Problem mit dem vertauschen von den Richtungen und statt es gleich richtig zu machen, drehst du lieber ein Vorzeichen in ner spätern berechnung rum.


    Das hat einen bestimmten grund: wenn ich direkt die fehler umgehen würde würden leute das einfach abschreiben und warscheinlich nichtmal drüber nachdenken, wenn ich aber erst diesen fehler aufweise dann ist man gezwungen drüber nachzudenken, und an welcher stelle man den behebt ist doch egal.

    Zitat von Steve Jobs

    Stay hungry - stay foolish.



  • Für mich ist das Tutorial nur aus irgentwelchen sachen zusammengesetzt.
    Und das auch noch schlecht, was bringt es User die sich auf Spieleprogrammierung spezalisieren,
    und dan so etwas sehen. Das ist tut mir leid aber Augenkrebs in meinen Augen.

    Ich z.B Programmiere gerade ein Spiel, und wen ich das Anwenden würde was du hier schreibst...
    ayayay sag ich da nur. Schau du dir am besten nochmal Tutorials an bevor du welche schreibst.

    So etwas wie Internefreaks sein Tutorial ist ein richtiges:
    http://www.mmorpg-core.com/forum/tutorial…ngen-21957.html

    Ich behaupte nicht das du keine Ahnung davon hast, aber von jedem tutorial das ich von dir lese kommt es mir
    so vor.

    [CENTER]

    [COLOR=sandybrown][SIZE=4]Victory over all[/SIZE][/COLOR]
    [COLOR=orange]-*Victoria Justice*-[/COLOR]

    [COLOR=sandybrown]Besucht doch mal meinen Blog!
    Dort findet ihr aktuelle Projekte, Downloads und Code Snippets
    [/COLOR]
    [COLOR=darkorange]http://www.jok3r.de[/COLOR]
    [/CENTER]

  • Ich werde jetzt auch mit den Tutorials wieder aufhören, da ich jetzt ein neues buch über objc habe und mich nun wieder dem witme

    Zitat von Steve Jobs

    Stay hungry - stay foolish.



  • Klassen bringen aber trotzdem mehr als du denkst, so kannst du die ganze Logik des Players, der Gegner sowie der Bomben kapseln und hast weniger Arbeit, die Sachen in den Maincode einzubauen usw.
    Eine Klasse für Player usw ist besser als eine Struktur, allein wegen der Übersicht und so.

    Trotz allem ist ein Aufruf von Dispose die bessere Variante, als auf den GC zu warten, denn der tritt nicht immer in Aktion, dazu müssen schon bestimmte Dinge erfüllt sein, damit der wirklich kommt.
    Und deine Antwort mit Content.Load zeigt mir, dass du:
    1. Nich wirklich Ahnung von Content.Load hast
    2. Meinen Beitrag nicht gelesen hast bzw nicht richtig
    Content.Load lädt einen Inhalt nur einmal und gibt ansonsten immer wieder einen Verweis auf das Ding zurück, das wär ja noch schöner, wenns wirklich jedes mal geladen wird, wenn mans brauch, also so dumm sind die XNA entwickler auch nicht, dass sie nicht etwas auf den Speicherverbrauch achten.
    Aber dennoch sollte man nie immer alles direkt vorladen, man bedenke, dass XBox sowie das WindowsPhone nur begrenzt Speicher haben, da muss man auf alles achten.

    Die Kapselung in Klassen hat einige Vorteile:
    Man kann Methoden definieren, der Code wird sauberer usw, was wird da unübersichtlich, wenn du mal schnell ne Klasse anlegst für ein Spielobjekt usw.
    Und wenn du schon sagst, dass alles initialisiert und abgefragt wird und dies nur "Ressourcen" und "Ram" kostet, dann halte dich bitte von C# sowie VB.net fern.
    Denn da arbeitest du eigentlich soweit nur mit Klassen und Strukturen, das .NET Framework ist eine Klassenbibliothek.

    Fehler macht man, das ist klar.
    Aber es nicht definitiv nicht immer egal, wo man einen Fehler letztendlich behebt, das kann z.T sogar eher zum Nachteil werden, einen Fehler nicht da zu beheben, wo er sich befindet, sondern eher woanders auszugleichen.
    Und ob du nun den Fehler umgehst oder nicht, die Leute können immernoch C&P machen und nicht drüber nachdenken, außerdem soll ein Tutorial Wissen vermitteln und den Leuten zeigen, wie etwas geht und daher eigentlich von vornerein nicht unbedingt so aufgebaut sein, dass man zwangläufig auf nen Fehler trifft, also man soll sie nicht absichtlich einbauen, das ist nicht förderlich.

  • Zitat von Jok3r;227987

    Für mich ist das Tutorial nur aus irgen[COLOR="#ff0000"]d[/COLOR]welchen [COLOR="#ff0000"]S[/COLOR]achen zusammengesetzt.
    Und das auch noch schlecht, was bringt es User[COLOR="#ff0000"]n[/COLOR] die sich auf Spieleprogrammierung spez[COLOR="#ff0000"]i[/COLOR]alisieren,
    und dan[COLOR="#ff0000"]n[/COLOR] so etwas sehen. [COLOR="#ff0000"]Es[/COLOR] tut mir leid[COLOR="#ff0000"],[/COLOR] aber [COLOR="#ff0000"]das ist[/COLOR] Augenkrebs in meinen Augen.

    Ich z.B [COLOR="#ff0000"]p[/COLOR]rogrammiere gerade ein Spiel, und wen[COLOR="#ff0000"]n[/COLOR] ich das [COLOR="#ff0000"]a[/COLOR]nwenden würde was du hier schreibst...
    [COLOR="#ff0000"]A[/COLOR]yayay sag ich da nur. Schau du dir am [COLOR="#ff0000"]B[/COLOR]esten nochmal Tutorials an bevor du welche schreibst.

    So etwas wie Internefreaks sein Tutorial ist ein richtiges:
    http://www.mmorpg-core.com/forum/tutorial…ngen-21957.html

    Ich behaupte nicht das[COLOR="#ff0000"]s[/COLOR] du keine Ahnung davon hast, aber [COLOR="#ff0000"]bei[/COLOR] jedem[COLOR="#ff0000"] T[/COLOR]utorial das ich von dir lese kommt es mir
    so vor.


    Von deiner Rechtschreibung und Grammatik bekomme ich auch Augenkrebs...

    Wie schaffen Leute wie du eigentlich die Abschlussprüfung? Gibt es dort nicht massiven Abzug, wenn man in jeden Satz vier oder fünf Rechtschreibfehler haut und dazu eine... "experimentelle" Grammatik nutzt?

  • Zitat

    Klassen bringen aber trotzdem mehr als du denkst, so kannst du die ganze Logik des Players, der Gegner sowie der Bomben kapseln und hast weniger Arbeit, die Sachen in den Maincode einzubauen usw.

    Man kann sich drüber kloppen, aber ICH kapsele nur dann wenn ich es für wichtig halte(wenn es ganz alg methoden sind die ich noch öfters brauchen kann) spiel individuelles kommt bei mir in die main

    Zitat

    Und deine Antwort mit Content.Load zeigt mir, dass du:

    1. Nich wirklich Ahnung von Content.Load hast

    2. Meinen Beitrag nicht gelesen hast bzw nicht richtig

    Content.Load lädt einen Inhalt nur einmal und gibt ansonsten immer wieder einen Verweis auf das Ding zurück, das wär ja noch schöner, wenns wirklich jedes mal geladen wird, wenn mans brauch, also so dumm sind die XNA entwickler auch nicht, dass sie nicht etwas auf den Speicherverbrauch achten.

    Das ist jetzt pwinlich ich habs mit der quarz programmierung verwechselt

    Zitat

    Man kann Methoden definieren, der Code wird sauberer usw, was wird da unübersichtlich, wenn du mal schnell ne Klasse anlegst für ein Spielobjekt usw.

    Und wenn du schon sagst, dass alles initialisiert und abgefragt wird und dies nur "Ressourcen" und "Ram" kostet, dann halte dich bitte von C# sowie VB.net fern.


    Ich hasse es mich für einen kleinen logik fehler durch 15(hyperbel) dateien durchzuklicken wãhrend ich sonst den gesammten code auf einem haufen hab
    wenn überhaupt mache ich projekt unabhångige modele aber mehr auch nicht

    Zitat von Steve Jobs

    Stay hungry - stay foolish.



  • Hey leute,
    ich programmiere ein bomberman und Map und Spielerklasse mit Kollision und alles habe ich.
    Nun meine Frage an euch ist, ich habe eine Basisklasse namen feature, von der leite ich später alle Features, wie bomben, laternen blablab^^... um den Spieler schneller und stärker oder so zu machen.

    Auf jeden Fall, habe ich die Featureklasse so gebaut:

    public abstract class Features
    {
    public Texture2D texture;
    public Rectangle dimension;
    public Rectangle position;
    public SoundState music_states;
    public Song song;
    public Timer timer;
    /// <summary>
    /// Standardcontructor
    /// </summary>
    public Features()
    {


    }
    public virtual void Push(/* The feature object */)
    {


    }
    public virtual void ClearFeature(/* The feature object*/)
    {


    }
    public virtual void EventSound(/* Song for Event */)
    {

    }
    }
    }
    Und ich will eine <hat eine beziehung zwischen Spieler und Bombe, denn der Spieler hat ja eine Bombe.

    und ich hatte eine Methode in der Playerklasse definiert die heisst: Placebomb, nur ich weiss nicht so recht, was der Code dieser Funktion können soll, mangels Verständnisprobleme,:

    private void placeBomb()
    {
    if (Keyboard.GetState().IsKeyDown(Keys.Enter))
    {
    myBomb.position = new Rectangle(player_rect.X + 30, player_rect.Y, 30, 30);
    }
    }
    public void Draw(SpriteBatch spritebatch)
    {
    myBomb.position = new Rectangle(player_rect.X + 30, player_rect.Y, 30, 30);
    spritebatch.Draw(player_Text, player_rect, Color.White);
    spritebatch.Draw(bomb_text, myBomb.position,new Rectangle(),Color.White);
    }
    Und ich rufe sie auch auf, aber wenn gedebuggt wird, dann passiert alles was passieren soll, nur wenn ich enter drücke, passiert nix keine Bombe.

    Und ich wollte euch fragen, wie würdet ihr so eine klasse definieren?

    ich entschuldige mich, nur ich habe iwie ein blackout was das

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!