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):
(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:
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
(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())
Alles anzeigen
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.
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
Alles anzeigen
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.
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:
und dann wird wie gehabt die geschwindigkeit errechnet
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
das macht
[/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
wird
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)
Alles anzeigen
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:
Alles anzeigen
Das wars auch schon bis hier hin
Nächstes mal kommen die bomben und Leben
Zu erst einmal zur Definition von bewegung(Physikalisch):
(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:
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
(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
Quellcode
(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())
Quellcode
- protected override void Update(GameTime gameTime)
- {
- // Ermöglicht ein Beenden des Spiels
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
- this.Exit();
- [COLOR="red"]KeyboardState ks = Keyboard.GetState();[/COLOR]
- enemy.pos += enemy.speed*(float)gameTime.ElapsedGameTime.TotalSeconds;
- base.Update(gameTime);
- }
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.
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
Quellcode
- protected override void Update(GameTime gameTime)
- {
- // Ermöglicht ein Beenden des Spiels
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
- this.Exit();
- KeyboardState ks = Keyboard.GetState();
- int mX = 0;
- int mY = 0;
- [COLOR="red"] if (ks.IsKeyDown(Keys.Up))
- mY += 1;
- if (ks.IsKeyDown(Keys.Down))
- mY -= 1;
- if (ks.IsKeyDown(Keys.Right))
- mX += 1;
- if (ks.IsKeyDown(Keys.Left))
- mX -= 1;[/COLOR]
- enemy.pos += enemy.speed*(float)gameTime.ElapsedGameTime.TotalSeconds;
- base.Update(gameTime);
- }
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.
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:
und dann wird wie gehabt die geschwindigkeit errechnet
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
das macht
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
wird
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)
Quellcode
- //rand kollision
- if (enemy.pos.X > environment.windowWidth- enemy.tex.Width)
- enemy.speed *= -1;
- if (enemy.pos.X < 0)
- enemy.speed *= -1;
- if (player.pos.X > environment.windowWidth - player.tex.Width)
- player.speed = new Vector2(-player.speed.X, player.speed.Y);
- if (player.pos.X < 0)
- player.speed = new Vector2(-player.speed.X, player.speed.Y);
- if (player.pos.Y > environment.windowHeight - player.tex.Height)
- player.speed = new Vector2(player.speed.X, -player.speed.Y);
- if (player.pos.Y < 0)
- player.speed = new Vector2(player.speed.X, -player.speed.Y);
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:
Quellcode
- protected override void Update(GameTime gameTime)
- {
- // Ermöglicht ein Beenden des Spiels
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
- this.Exit();
- //Variable die den tastenstatus enthält
- KeyboardState ks = Keyboard.GetState();
- //variablen für die richtung der beschläunigung
- int mX = 0;
- int mY = 0;
- //tasten abfrage
- if (ks.IsKeyDown(Keys.Up))
- mY += 1;
- if (ks.IsKeyDown(Keys.Down))
- mY -= 1;
- if (ks.IsKeyDown(Keys.Right))
- mX += 1;
- if (ks.IsKeyDown(Keys.Left))
- mX -= 1;
- float newX = mX * (float)gameTime.ElapsedGameTime.TotalSeconds * 80; //beschleunigungsfaktor für x errechnen
- float newY = -mY * (float)gameTime.ElapsedGameTime.TotalSeconds * 80; //beschleunigungsfaktor für y errechnen
- //beschläunigung zur aktuellen geschwindigkeit dazu rechnen
- player.speed = new Vector2(Math.Max(Math.Min((player.speed.X + newX),200), -200), Math.Max(Math.Min((player.speed.Y + newY),200), -200));
- //Neue position des players über die geschwindigkeit / sekunden(bzw geschindigkeit*1/zeit) rechnen
- player.pos += player.speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
- //Neue position des gegners über die geschwindigkeit / sekunden(bzw geschindigkeit*1/zeit) rechnen
- enemy.pos += enemy.speed*(float)gameTime.ElapsedGameTime.TotalSeconds;
- //rand kollision
- if (enemy.pos.X > environment.windowWidth- enemy.tex.Width)
- enemy.speed *= -1;
- if (enemy.pos.X < 0)
- enemy.speed *= -1;
- if (player.pos.X > environment.windowWidth - player.tex.Width)
- player.speed = new Vector2(-player.speed.X, player.speed.Y);
- if (player.pos.X < 0)
- player.speed = new Vector2(-player.speed.X, player.speed.Y);
- if (player.pos.Y > environment.windowHeight - player.tex.Height)
- player.speed = new Vector2(player.speed.X, -player.speed.Y);
- if (player.pos.Y < 0)
- player.speed = new Vector2(player.speed.X, -player.speed.Y);
- base.Update(gameTime);
- }
Das wars auch schon bis hier hin
Nächstes mal kommen die bomben und Leben