Tutorial 4: Das erste 2D Game: Bewegung

  • Im Letzten Tutorial wurde gezeichnet, aber ich denke jeder weiß, dass niemand ein spiel mit einem standbild will. D.h Geht es nun um bewegung

    Zu erst einmal zur Definition von bewegung(Physikalisch):

    Code
    Bewegung bezeichnet eine strecke S die ein objekt in einer gewissen zeit Z überwindet.
    Die Formel lautet daher: S/Z.


    (aus Physikheft)

    Nun wäre das in SI einheiten meter/sekunden, allerdings haben wir bei der Programmierung keine meter, d.h. verwenden wir pixel also p/s.

    Für mehr dynamik machen wir das ganze auch noch mit beschleunigung:

    Code
    Beschleunigung bezeichnet eine erreichte geschwindigkeit g über einen gewissen zeitraum z
    Die formel lautet g/z

    Wenn man das beides zusammen fügt so erhält man für die beschleunigung die formel
    m/s/s oder auch m/s²

    so viel zum kleinen physik exkurs...

    Nun geht es aber an die programmierung:
    Zu erst gehen wir an den gegner, da dieser eine konstante geschwindigkeit hat und d.h. keine beschleunigung braucht

    Wir müssen also einfach nur die Position (enemy.pos) mit der geschwindigkeit (enemy.speed) verrechnen
    solche berechnungen werden in der Update methode erledigt
    nun denkt man villeicht einfach mit

    Code
    enemy.pos += enemy.speed;


    (ein vorteil an vectoren ist dass man sie direkt miteinander verrechnen kann)
    sei das problem behoben, allerdings hat man vergessen dass die geschwindigkeit auf p/s ausgelegt ist, allerdings die aktualisierung mehr mals pro sekunde aufgerufen wird, und dass auch nicht immer in regelmäßigen abständen.

    Aus diesem grund liefert die game Klasse beim aufruf der Methoden Update und Draw immer die spielzeit(gameTime) mit, die enthält sowohl die gesammte zeit seit dem spiel start, als auch die verstrichene zeit seit dem letzten aufruf (das letzte mal seit dem die methode aufgerufen wurde).

    Also verrechnen wir das nun, dafür multiplizieren wir einfach die geschwindigkeit mit der verstrichenen zeit seit dem letzten aufruf in sekunden, um somit auch eine geschwindigkeit von pixeln pro sekunde zu bekommen


    (float)gameTime.ElapsedGameTime.TotalSeconds ist der float wert von der verstrichenen zeit seit dem letzten aufruf in sekunden(Total seconds damit man kommazahlen erhält)

    Beim starten sollte sich nun eine bewegung sehen lassen. Mit der geschwindigkeit könnt ihr variiren wie ihr wollt.


    Tasten abfrage:

    Nun soll sich der spieler ja auch bewegen können, dafür müssen wir abfragen ob eine taste gedrückt ist.

    Für sowas gibt es in XNA den KeyboardState.
    Dafür deklarieren wir einfach eine variable vom typ KeyboardState und nennen die einfach mal ks und geben dieser den aktuellen keyboard status (Keyboard.GetState())

    Mit diesem Code wird in die variable der aktuelle keyboard status geschrieben, sie enthält also den status jeder taste(ob gedrückt oder nicht).

    Mit dieser variable können wir nun über simple if abfragen überprüfen ob eine taste gedrückt ist.

    Code
    if (ks.IsKeyDown(Keys.Up)) { 
                
                }


    So wird überprüft ob die taste Hoch geklickt ist.
    Nun müssen wir das nur noch anwenden, dafür verwende ich 2 variablen eimal mX und einmal mY
    Wenn hoch geklickt ist wird mY = 1 sein und wenn runter dann wird mY = -1
    und bei mx ist es das gleiche mit rechts und links


    Ich verwende einzelne abfragen und keine große mit else if, da ja auch 2 tasten gedrückt sein können
    und das += bzw -= verwende ich damit wenn 2 tasten geklickt sind sie sich aufheben können.

    Nun können wir diese variable verwenden um die richtung der geschwindigkeit zu errechnen(da eine zahl*-1= -zahl)

    Das machen wir erst mal mit 2 neuen float variablen: newX und newY, diese werden dann die geschwindigkeit die drauf gerechnet wird enthalten.

    Code
    float newX = mX * (float)gameTime.ElapsedGameTime.TotalSeconds * 80;
                float newY = mY * (float)gameTime.ElapsedGameTime.TotalSeconds * 40;


    mit dem mX/mY wird die richtung(positiv oder negativ) angegeben
    (float)gameTime.ElapsedGameTime.TotalSeconds wird verwendet um den zeitfaktor reinzubringen(da ja beschleunigung=g/z), also um die geschwindigkeit auf die zeit anzupassen
    und 80 ist die kraft/geschwindigkeit(pixel pro sekunde) mit der gerechnet wird (9,81 wäre die erdanziungskraft) mit der muss man rumspielen um die beschläunigungszeit zu ändern.

    diese Beschleunigung wird jetzt auf die geschwindigkeit gerechnet:

    Code
    //beschläunigung zur aktuellen geschwindigkeit dazu rechnen
                player.speed = new Vector2(player.speed.X + newX, player.speed.Y + newY);

    und dann wird wie gehabt die geschwindigkeit errechnet

    Code
    player.pos += player.speed * (float)gameTime.ElapsedGameTime.TotalSeconds;

    Nun sollte euch beim debuggen auffallen das hoch und runter vertauscht sind, dass liegt daran dass wie bereits vorher erwähnt die y achse umgedreht ist.
    dieses problem lässt sich aber ganz einfach lösen indem ihr aus

    Code
    float newX = mX * (float)gameTime.ElapsedGameTime.TotalSeconds * 80;
                float newY = mY * (float)gameTime.ElapsedGameTime.TotalSeconds * 40;


    das macht

    Code
    [CODE]            float newX = mX * (float)gameTime.ElapsedGameTime.TotalSeconds * 80;
                float newY = [COLOR="red"]-mY[/COLOR] * (float)gameTime.ElapsedGameTime.TotalSeconds * 40;[/CODE]

    Wer gut aufgepasst hat dem sollte aufgefallen sein dass ich die ganze zeit von /zeit gesprochen habe aber letztendlich *zeit genommen habe.
    Das liegt daran dass der wert (float)gameTime.ElapsedGameTime.TotalSeconds für die rechnung nicht zeit darstellt sondern 1/zeit, das bedeutet dass wenn man wenn man /(float)gameTime.ElapsedGameTime.TotalSeconds macht eigentlich *zeit rechnet, und wenn man *(float)gameTime.ElapsedGameTime.TotalSeconds eigentlich /zeit rechnet (Mathe 6te klasse bruchrechnung...)

    jetzt wird das teil aber irgendwann unkontrolierbar schnell, darum bauen wir noch eine geschwindigkeits begrenzung von 200px/s in jede richtung also etwa max 280px/s insgesammt
    dafür brauchen wir nur eine simple änderung:
    aus

    Code
    player.speed = new Vector2(player.speed.X + newX, player.speed.Y + newY);


    wird

    Code
    player.speed = new Vector2(Math.Max(Math.Min((player.speed.X + newX),200), -200), Math.Max(Math.Min((player.speed.Y + newY),200), -200));


    Was math.min und math.max ist erkläre ich hier nicht dafür gibts msdn(einfach googlen)
    es heißt nur wenn die neue geschwindigkeit größer als 200 ist so wird 200 rausgegeben und wenn sie kleiner als -200 ist wird -200 rausgegeben.

    Allerdings ist irgendwann der gegner und der spieler aus dem feld draußen und kommt auch nicht mehr rein, dafür wird eine kleine rand Kollision erstellt, damit wenn man an der rand kommt, die geschwindigkeit in die entgegengesetzte richtung umgedreht wird(wie beim ping pong, einfallswinkel=ausfallswinkel)

    das heißt einfach nur wenn die position von gegner oder spieler größer als die fenster größe ist geht die bewegung grade in die andere richtung

    Nun nocheinmal die ganze update methode, bis jetzt:


    Das wars auch schon bis hier hin

    Nächstes mal kommen die bomben und Leben

    Zitat von Steve Jobs

    Stay hungry - stay foolish.



  • Schon lang nicht mehr so ein schlechtes Tutorial gelesen...
    Wenn du kein Bock hast dann lass es lieber anstatt so ne halbe Sache hinzuklatschen... --.--

    Zeitverschwendung... (Nimm mal lieber Nachhilfe, in Deutsch!)

    Btw:

    Dein Programmierstil ist auch ziemlich schlecht... o.O

  • Zitat von Kwaggax;241262

    Schon lang nicht mehr so ein schlechtes Tutorial gelesen...
    Wenn du kein Bock hast dann lass es lieber anstatt so ne halbe Sache hinzuklatschen... --.--

    Zeitverschwendung... (Nimm mal lieber Nachhilfe, in Deutsch!)

    Btw:

    Dein Programmierstil ist auch ziemlich schlecht... o.O



    Machs besser?

  • Lalox3
    Ich muss deinem Vorposter aber teilweise schon recht geben
    Er überlädt die Methode zu stark mit seinen ganzen Abfragen für Bewegung usw, das hätte sich weitaus schöner über Klassen regeln lassen.
    Außerdem verstößt er mit seiner 1-Datei-Technologie gegen die Konventionen von C#, die besagt, dass pro Datei lediglich eine Klasse/Struktur/Schnittstelle drin sein darf.
    Fakt ist jedenfalls, das das ganze etwas besser formatiert werden könnte.

  • Zitat von internetfreak;241284

    Lalox3
    Ich muss deinem Vorposter aber teilweise schon recht geben
    Er überlädt die Methode zu stark mit seinen ganzen Abfragen für Bewegung usw, das hätte sich weitaus schöner über Klassen regeln lassen.
    Außerdem verstößt er mit seiner 1-Datei-Technologie gegen die Konventionen von C#, die besagt, dass pro Datei lediglich eine Klasse/Struktur/Schnittstelle drin sein darf.
    Fakt ist jedenfalls, das das ganze etwas besser formatiert werden könnte.

    Drotzdem ist es ein Tutorial. Und ich denke/hoffe doch das es dann auch funktioniert wie es beschrieben wurde.
    Es gibt halt unübersichtliche und übersichtliche Tutorial's. Was für mich, wenn es funktioniert eigentlich nicht's dagegen
    Sprechen würde. Man könnte ja, wenn das Tutorial so Negativ beurteilt wird das Tutorial auch umschreiben. Damit
    man zeigt wie man es richtig macht.

    Denn nur Sagen das es schlecht ist, kann jeder aber zeigen wie es richtig ist, macht fast niemand.

  • Ich hab ja mit meiner Tutorialserie einen Weg eingeschlagen, der einem XNA Stück für Stück näher bringen soll durch kleinere Teile, in denen immer ein Gebiet behandelt wird, bevor es später an ein Spiel geht.
    Funktionieren sollte es normalerweise, aber eine gewisse Form sollte das Tutorial auch haben, da es sonst schnell für Anfänger usw unübersichtlich wird oder diese falsche Sachen haben.

  • Er geht auf manche Stellen viel zu wenig ein, dann schreibt er nicht wo er die Zeile einfügt usw.
    Grafiken fehlen 2. -..-

    Also da kann man echt besseres erwarten, vil. erstmal sein eigenes Wissen aufbessern bevor man anderen helfen will.

    Da ist das Tut von Internetfreak ein Augenschmaus dagegen, leider kenn ich das alles schon in der Welt von XNA, würde mich freuen, wenn du anfängst ein Spiel zu machen. (Jump´n Run)
    Wie MegaMan, des wär klasse. : )

    Da ich bei XNA erst neu bin und eig. mit Forms arbeite, in der Firma.
    Somit will ich daheim mit XNA spielen.

    Da sowas find ich klasse: Klick
    Vom Aufbau mein ich, aber Jump´n Run wär natürlich noch besser. : )


    Grüße

Jetzt mitmachen!

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