Bu yazımı okumadan önce Windows Phone ve XNA konusundaki diğer makalelerimi okumanızı öneririm.
Önce görseller ve oyunun arkaplan ses dosyası;
İlk olarak XNA Game Studio 4.0 grubundaki Windows Phone Game şablonundan MiniCarGame isimli projeyi oluşturalım;
Game1.cs dosyasının ismini GameLoop.cs olarak değiştirdikten sonra, EnemyCar isminde yeni bir class ekleyelim;
public class EnemyCar { public Texture2D Texture;
public Vector2 Position;
public float Velocity;
public Rectangle Area;
Random r = new Random();
public EnemyCar(Texture2D CarTexture)
{
this.Texture = CarTexture;
this.Position = new Vector2(r.Next(450, 850), 1);
this.Velocity = (float)(r.NextDouble() * 4) + 3f;
this.Area = new Rectangle((int)this.Position.X, (int)this.Position.Y, this.Texture.Width, this.Texture.Height);
} }</pre>
EnemyCar sınıfı sayesinde, ekrana getireceğimiz diğer araçların görsellerini, konumlarını, çarpışma testi yapabilmek için ekranda kapladığı alanı ve hızlarını bileceğiz.
GameLoop sınıfına geri dönelim ve sınıf seviyesindeki değişkenlere aşağıdakileri ekleyelim;
GraphicsDeviceManager graphics; SpriteBatch spriteBatch; const int PENCERE_GENISLIK = 800; const int PENCERE_YUKSEKLIK = 480; Texture2D BackgroundTexture1; Texture2D BackgroundTexture2; Vector2 BackgroundPosition1 = new Vector2(0, -PENCERE_YUKSEKLIK); Vector2 BackgroundPosition2 = new Vector2(0, 0); Texture2D MainCarTexture; Vector2 MainCarPosition = new Vector2(300, 300); float KatedilenMesafe = 0f; Rectangle ScreenArea = new Rectangle(0, 0, PENCERE_GENISLIK, PENCERE_YUKSEKLIK); Rectangle MainCarArea = new Rectangle(300, 300, 67, 134); TimeSpan TotalElapsedTime; List<EnemyCar> CarList = new List<EnemyCar>(); Random r = new Random(); Texture2D[] CarTextures = new Texture2D[8];
Klavyedeki hangi tuşlara basıldığını kontrol edebilmek için KeyboardState değişkenlerimizi, arkaplanda sürekli tekrar eden ses çaldırmak için SoundEffectInstance değişkenimizi ve oyunun bittiğini takip edeceğimiz bool değişkeni de sınıf seviyesinde ekleyelim;
KeyboardState ks; KeyboardState pks; SoundEffectInstance BackgroundLoop; bool IsGameOver = false;
İlk yapacağımız iş GameLoop sınıfının constructor‘ında gerekli atamaları yapmak olacak;
public GameLoop() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferWidth = PENCERE_GENISLIK; graphics.PreferredBackBufferHeight = PENCERE_YUKSEKLIK; graphics.IsFullScreen = true; }
LoadContent() methodunda değişkenlerimiz aracılığıyla ses ve resim dosyalarını hafızaya yüklüyoruz;
protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); BackgroundTexture1 = Content.Load<Texture2D>("BackgroundRoad"); BackgroundTexture2 = BackgroundTexture1; MainCarTexture = Content.Load<Texture2D>("MainCar"); MesafeFont = Content.Load<SpriteFont>("Verdana14"); for (int i = 0; i < CarTextures.Length; i++) { CarTextures[i] = Content.Load<Texture2D<("Car" + (i + 2)); } BackgroundLoop = Content.Load<SoundEffect>("BackgroundLoop").CreateInstance(); GameOverFont = Content.Load<SpriteFont>("GameOverFont"); BackgroundLoop.IsLooped = true; BackgroundLoop.Play(); }
Update() method’unda ilk olarak oyundan çıkma ve baştan başlama durumunu sağlayacak kodları yazıyoruz;
</pre><pre class="brush:csharp">ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Escape)) { this.Exit(); }
if (IsGameOver && ks.IsKeyDown(Keys.Enter)) { IsGameOver = false; BackgroundLoop.Play(); KatedilenMesafe = 0f; MainCarPosition = new Vector2(600, 600); MainCarArea.X = (int)MainCarPosition.X; MainCarArea.Y = (int)MainCarPosition.Y; CarList.Clear(); }</pre>
Eğer oyun sonlanmadıysa, klavyedeki tuşların durumuna göre arabamızı hareket ettiriyoruz, en son araba eklediğimiz zamandan itibaren belli bir sürenin üzerinde geçtiyse yeni EnemyCar ekliyoruz, EnemyCar listesindeki her bir arabayı hareket ettiriyoruz, yol görselini içeren arkaplanı hareket ettiriyoruz, katedilen mesafeyi güncelleyip, bizim arabamız ile diğer arabaların çarpışma testini yapıyoruz;
if (!IsGameOver) { if (ks.IsKeyDown(Keys.Left)) { MainCarPosition.X -= 3; MainCarArea.X -= 3; } if (ks.IsKeyDown(Keys.Right)) { MainCarPosition.X += 3; MainCarArea.X += 3; } if (ks.IsKeyDown(Keys.Up)) { MainCarPosition.Y -= 3; MainCarArea.Y -= 3; } if (ks.IsKeyDown(Keys.Down)) { MainCarPosition.Y += 3; MainCarArea.Y += 3; } TotalElapsedTime += gameTime.ElapsedGameTime; if (TotalElapsedTime > TimeSpan.FromMilliseconds(1500)) { EnemyCar car = new EnemyCar(CarTextures[r.Next(0, 8)]); CarList.Add(car); TotalElapsedTime = TimeSpan.Zero; } foreach (EnemyCar car in CarList) { car.Position.Y += car.Velocity; car.Area.Y = (int)car.Position.Y; } BackgroundPosition1.Y += 2; BackgroundPosition2.Y += 2; if (BackgroundPosition2.Y > PENCERE_YUKSEKLIK) { BackgroundPosition1.Y = -PENCERE_YUKSEKLIK; BackgroundPosition2.Y = 0; } KatedilenMesafe += 0.005f; foreach (EnemyCar car in CarList) { if (car.Area.Intersects(MainCarArea)) { IsGameOver = true; BackgroundLoop.Stop(); } } }
Son olarak Update() methodunun son satırında KeyboardState‘i pks değişkenine atyoruz;
pks = ks;
Draw() methodunda kendi arabamızı, diğer arabaları ve katettiğimiz mesafeyi ekrana çiziyoruz;
GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(BackgroundTexture1, BackgroundPosition1, Color.White); spriteBatch.Draw(BackgroundTexture2, BackgroundPosition2, Color.White); spriteBatch.Draw(MainCarTexture, MainCarPosition, Color.White); spriteBatch.DrawString(MesafeFont, "Katedilen Mesafe: " + KatedilenMesafe.ToString("N2") + " km", new Vector2(51, 51), Color.Black); spriteBatch.DrawString(MesafeFont, "Katedilen Mesafe: " + KatedilenMesafe.ToString("N2") + " km", new Vector2(50, 50), Color.White); foreach (EnemyCar car in CarList) { spriteBatch.Draw(car.Texture, car.Position, Color.White); } if (IsGameOver) { spriteBatch.DrawString(GameOverFont, "GAME OVER", new Vector2(433, 353), Color.Yellow); spriteBatch.DrawString(GameOverFont, "GAME OVER", new Vector2(430, 350), Color.Red); } spriteBatch.End();
Senior Software Engineer, @Microsoft
Ada ve Ege'nin babası ;)
Makale Adedi: 484