//----------------------------------------------------------------------------- // GameplayScreen.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Storage; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Media; namespace AlienGameSample { /// /// This component draws the entire background for the game. It handles /// drawing the ground, clouds, sun, and moon. also handles animating them /// and day/night transitions /// public class GameplayScreen : GameScreen { // // Game Play Members // Player player; List aliens; List alienBullets; List playerBullets; Rectangle worldBounds; bool gameOver; int baseLevelKillCount; int levelKillCount; float alienSpawnTimer; float alienSpawnRate; float alienMaxAccuracy; float alienSpeedMin; float alienSpeedMax; int alienScore; int nextLife; int hitStreak; int highScore; Random random; // // Rendering Members // Texture2D cloud1Texture; Texture2D cloud2Texture; Texture2D sunTexture; Texture2D moonTexture; Texture2D groundTexture; Texture2D tankTexture; Texture2D alienTexture; Texture2D badguy_blue; Texture2D badguy_red; Texture2D badguy_green; Texture2D badguy_orange; Texture2D mountainsTexture; Texture2D hillsTexture; Texture2D bulletTexture; Texture2D laserTexture; SpriteFont scoreFont; SpriteFont menuFont; Vector2 cloud1Position; Vector2 cloud2Position; Vector2 sunPosition; // Level changes, nighttime transitions, etc float transitionFactor; // 0.0f == day, 1.0f == night float transitionRate; // > 0.0f == day to night ParticleSystem particles; // // Audio Members // SoundEffect alienFired; SoundEffect alienDied; SoundEffect playerFired; SoundEffect playerDied; Song backMusic; public GameplayScreen() { random = new Random(); worldBounds = new Rectangle(0, 0, 320, 480); player = new Player(); playerBullets = new List(); aliens = new List(); alienBullets = new List(); gameOver = true; TransitionOnTime = TimeSpan.FromSeconds(0.0); TransitionOffTime = TimeSpan.FromSeconds(0.0); } #region LOADING AND UNLOADING /// /// Loads all of the content needed by the game. All of this should have already been cached /// into the ContentManager by the LoadingScreen. /// public override void LoadContent() { backMusic = ScreenManager.Game.Content.Load("backmusic"); cloud1Texture = ScreenManager.Game.Content.Load("cloud1"); cloud2Texture = ScreenManager.Game.Content.Load("cloud2"); sunTexture = ScreenManager.Game.Content.Load("sun"); moonTexture = ScreenManager.Game.Content.Load("moon"); groundTexture = ScreenManager.Game.Content.Load("ground"); tankTexture = ScreenManager.Game.Content.Load("tank"); mountainsTexture = ScreenManager.Game.Content.Load("mountains_blurred"); hillsTexture = ScreenManager.Game.Content.Load("hills"); alienTexture = ScreenManager.Game.Content.Load("alien1"); badguy_blue = ScreenManager.Game.Content.Load("badguy_blue"); badguy_red = ScreenManager.Game.Content.Load("badguy_red"); badguy_green = ScreenManager.Game.Content.Load("badguy_green"); badguy_orange = ScreenManager.Game.Content.Load("badguy_orange"); bulletTexture = ScreenManager.Game.Content.Load("bullet"); laserTexture = ScreenManager.Game.Content.Load("laser"); alienFired = ScreenManager.Game.Content.Load("Tank_Fire"); alienDied = ScreenManager.Game.Content.Load("Alien_Hit"); playerFired = ScreenManager.Game.Content.Load("Tank_Fire"); playerDied = ScreenManager.Game.Content.Load("Player_Hit"); scoreFont = ScreenManager.Game.Content.Load("ScoreFont"); menuFont = ScreenManager.Game.Content.Load("menufont"); player.Width = tankTexture.Width; player.Height = tankTexture.Height; cloud1Position = new Vector2(224 - cloud1Texture.Width, 32); cloud2Position = new Vector2(64, 80); sunPosition = new Vector2(16, 16); particles = new ParticleSystem(ScreenManager.Game.Content, ScreenManager.SpriteBatch); LoadHighscore(); base.LoadContent(); // Automatically start the game once all loading is done Start(); } /// /// Save the scores and dispose of the particles /// public override void UnloadContent() { particles = null; base.UnloadContent(); } /// /// Saves the current highscore to a text file. The StorageDevice was selected during the loading screen. /// private void SaveHighscore() { StorageDevice device = (StorageDevice)ScreenManager.Game.Services.GetService(typeof(StorageDevice)); if (device != null) { StorageContainer container = device.OpenContainer("AlienGame"); StreamWriter writer = new StreamWriter(Path.Combine(container.Path, "highscores.txt")); writer.Write(highScore.ToString(System.Globalization.CultureInfo.InvariantCulture)); writer.Flush(); writer.Close(); container.Dispose(); } } /// /// Loads the high score from a text file. The StorageDevice was selected during the loading screen. /// private void LoadHighscore() { StorageDevice device = (StorageDevice)ScreenManager.Game.Services.GetService(typeof(StorageDevice)); if (device != null) { StorageContainer container = device.OpenContainer("AlienGame"); if (File.Exists(Path.Combine(container.Path, "highscores.txt"))) { StreamReader reader = null; try { reader = new StreamReader(Path.Combine(container.Path, "highscores.txt")); highScore = Int32.Parse(reader.ReadToEnd(), System.Globalization.CultureInfo.InvariantCulture); } catch(FormatException) { highScore = 10000; } finally { if (reader != null) { reader.Close(); reader.Dispose(); } } } container.Dispose(); } } #endregion #region UPDATE AND SIMULATION /// /// Runs one frame of update for the game. /// /// Provides a snapshot of timing values. public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen) { float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; if (IsActive) { // Move the player if (player.IsAlive == true) { player.Position += player.Velocity * 128.0f * elapsed; player.FireTimer -= elapsed; if (player.Position.X <= 0.0f) player.Position = new Vector2(0.0f, player.Position.Y); if (player.Position.X + player.Width >= worldBounds.Right) player.Position = new Vector2(worldBounds.Right - player.Width, player.Position.Y); } Respawn(elapsed); UpdateAliens(elapsed); UpdateBullets(elapsed); CheckHits(); if (player.IsAlive && player.Velocity.LengthSquared() > 0.1f) particles.CreatePlayerDust(player); particles.Update(elapsed); } base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); } /// /// Input helper method provided by GameScreen. Packages up the various input /// values for ease of use. Here it checks for pausing and handles controlling /// the player's tank. /// /// The state of the gamepads public override void HandleInput(InputState input) { if (input == null) throw new ArgumentNullException("input"); if (input.PauseGame) { if (gameOver == true) { MediaPlayer.Stop(); foreach (GameScreen screen in ScreenManager.GetScreens()) screen.ExitScreen(); ScreenManager.AddScreen(new BackgroundScreen()); ScreenManager.AddScreen(new MainMenuScreen()); } else { ScreenManager.AddScreen(new PauseMenuScreen()); } } else { bool touchShoot = false; #if TARGET_IPHONE_SIMULATOR // This section handles tank movement. We only allow one "movement" action // to occur at once so that touchpad devices don't get double hits. player.Velocity.X = MathHelper.Min(input.CurrentGamePadStates.ThumbSticks.Left.X * 2.0f, 1.0f); touchShoot = input.MenuSelect; #else // Add the accelerometer support player.Velocity.X = MathHelper.Min(Accelerometer.GetState().Acceleration.X * 2.0f, 1.0f); // tap the screen to shoot foreach (TouchLocation location in input.TouchStates) { switch (location.State) { case TouchLocationState.Pressed: touchShoot = true; break; case TouchLocationState.Moved: break; case TouchLocationState.Released: break; } } #endif if (touchShoot) { //Mouse.SetPosition(0,0); if (player.FireTimer <= 0.0f && player.IsAlive && !gameOver) { Bullet bullet = CreatePlayerBullet(); bullet.Position = new Vector2((int)(player.Position.X + player.Width / 2) - bulletTexture.Width / 2, player.Position.Y - 4); bullet.Velocity = new Vector2(0, -256.0f); player.FireTimer = 0.5f; particles.CreatePlayerFireSmoke(player); playerFired.Play(); } } } } /// /// Handles respawning the player if we are playing a game and the player is dead. /// /// Time elapsed since Respawn was called last. void Respawn(float elapsed) { if (gameOver) return; if (!player.IsAlive) { player.RespawnTimer -= elapsed; if (player.RespawnTimer <= 0.0f) { // See if there are any bullets close... int left = worldBounds.Width / 2 - tankTexture.Width / 2 - 8; int right = worldBounds.Width / 2 + tankTexture.Width / 2 + 8; for (int i = 0; i < alienBullets.Count; ++i) { if (alienBullets[i].IsAlive == false) continue; if (alienBullets[i].Position.X >= left || alienBullets[i].Position.X <= right) return; } player.IsAlive = true; player.Position = new Vector2(worldBounds.Width / 2 - player.Width / 2, worldBounds.Bottom - (int)(groundTexture.Height*1.3f) + 2 - player.Height); player.Velocity = Vector2.Zero; player.Lives--; } } } /// /// Moves all of the bullets (player and alien) and prunes "dead" bullets. /// /// void UpdateBullets(float elapsed) { for (int i = 0; i < playerBullets.Count; ++i) { if (playerBullets[i].IsAlive == false) continue; playerBullets[i].Position += playerBullets[i].Velocity * elapsed; if (playerBullets[i].Position.Y < -32) { playerBullets[i].IsAlive = false; hitStreak = 0; } } for (int i = 0; i < alienBullets.Count; ++i) { if (alienBullets[i].IsAlive == false) continue; alienBullets[i].Position += alienBullets[i].Velocity * elapsed; if (alienBullets[i].Position.Y > worldBounds.Height - groundTexture.Height - laserTexture.Height) alienBullets[i].IsAlive = false; } } /// /// Moves the aliens and performs there "thinking" by determining if they /// should shoot and where. /// /// The elapsed time since UpdateAliens was called last. private void UpdateAliens(float elapsed) { // See if it's time to spawn an alien; alienSpawnTimer -= elapsed; if (alienSpawnTimer <= 0.0f) { SpawnAlien(); alienSpawnTimer += alienSpawnRate; } for (int i = 0; i < aliens.Count; ++i) { if (aliens[i].IsAlive == false) continue; aliens[i].Position += aliens[i].Velocity * elapsed; if ((aliens[i].Position.X < -aliens[i].Width - 64 && aliens[i].Velocity.X < 0.0f) || (aliens[i].Position.X > worldBounds.Width + 64 && aliens[i].Velocity.X > 0.0f)) { aliens[i].IsAlive = false; continue; } aliens[i].FireTimer -= elapsed; if (aliens[i].FireTimer <= 0.0f && aliens[i].FireCount > 0) { if (player.IsAlive) { Bullet bullet = CreateAlienBullet(); bullet.Position.X = aliens[i].Position.X + aliens[i].Width / 2 - laserTexture.Width / 2; bullet.Position.Y = aliens[i].Position.Y + aliens[i].Height; if ((float)random.NextDouble() <= aliens[i].Accuracy) { bullet.Velocity = Vector2.Normalize(player.Position - aliens[i].Position) * 64.0f; } else { bullet.Velocity = new Vector2(-8.0f + 16.0f * (float)random.NextDouble(), 64.0f); } alienFired.Play(); } aliens[i].FireCount--; } } } /// /// Performs all bullet and player/alien collision detection. Also handles game logic /// when a hit occurs, such as killing something, adding score, ending the game, etc. /// void CheckHits() { if (gameOver) return; for (int i = 0; i < playerBullets.Count; ++i) { if (playerBullets[i].IsAlive == false) continue; for (int a = 0; a < aliens.Count; ++a) { if (aliens[a].IsAlive == false) continue; if ((playerBullets[i].Position.X >= aliens[a].Position.X && playerBullets[i].Position.X <= aliens[a].Position.X + aliens[a].Width) && (playerBullets[i].Position.Y >= aliens[a].Position.Y && playerBullets[i].Position.Y <= aliens[a].Position.Y + aliens[a].Height)) { playerBullets[i].IsAlive = false; aliens[a].IsAlive = false; hitStreak++; player.Score += aliens[a].Score * (hitStreak / 5 + 1); if (player.Score > highScore) highScore = player.Score; if (player.Score > nextLife) { player.Lives++; nextLife += nextLife; } levelKillCount--; if (levelKillCount <= 0) AdvanceLevel(); particles.CreateAlienExplosion(new Vector2(aliens[a].Position.X + aliens[a].Width / 2, aliens[a].Position.Y + aliens[a].Height / 2)); alienDied.Play(); } } } if (player.IsAlive == false) return; for (int i = 0; i < alienBullets.Count; ++i) { if (alienBullets[i].IsAlive == false) continue; if ((alienBullets[i].Position.X >= player.Position.X + 2 && alienBullets[i].Position.X <= player.Position.X + player.Width - 2) && (alienBullets[i].Position.Y >= player.Position.Y + 2 && alienBullets[i].Position.Y <= player.Position.Y + player.Height)) { alienBullets[i].IsAlive = false; player.IsAlive = false; hitStreak = 0; player.RespawnTimer = 3.0f; particles.CreatePlayerExplosion(new Vector2(player.Position.X + player.Width / 2, player.Position.Y + player.Height / 2)); playerDied.Play(); if (player.Lives <= 0) { gameOver = true; SaveHighscore(); } } } } /// /// Starts a new game session, setting all game state to initial values. /// void Start() { MediaPlayer.Volume = 0.2f; MediaPlayer.Play(backMusic); if (gameOver) { player.Score = 0; player.Lives = 3; player.RespawnTimer = 0.0f; gameOver = false; aliens.Clear(); alienBullets.Clear(); playerBullets.Clear(); Respawn(0.0f); } transitionRate = 0.0f; transitionFactor = 0.0f; levelKillCount = 5; baseLevelKillCount = 5; alienScore = 25; alienSpawnRate = 1.0f; alienMaxAccuracy = 0.25f; alienSpeedMin = 24.0f; alienSpeedMax = 32.0f; alienSpawnRate = 2.0f; alienSpawnTimer = alienSpawnRate; nextLife = 5000; } /// /// Advances the difficulty of the game one level. /// void AdvanceLevel() { baseLevelKillCount += 5; levelKillCount = baseLevelKillCount; alienScore += 25; alienSpawnRate -= 0.3f; alienMaxAccuracy += 0.1f; if (alienMaxAccuracy > 0.75f) alienMaxAccuracy = 0.75f; alienSpeedMin *= 1.35f; alienSpeedMax *= 1.35f; if (alienSpawnRate < 0.33f) alienSpawnRate = 0.33f; if (transitionFactor == 1.0f) { transitionRate = -0.5f; } else { transitionRate = 0.5f; } } /// /// Returns an instance of a usable player bullet. Prefers reusing an existing (dead) /// bullet over creating a new instance. /// /// A bullet ready to place into the world. Bullet CreatePlayerBullet() { Bullet b = null; for (int i = 0; i < playerBullets.Count; ++i) { if (playerBullets[i].IsAlive == false) { b = playerBullets[i]; break; } } if (b == null) { b = new Bullet(); playerBullets.Add(b); } b.IsAlive = true; return b; } /// /// Returns an instance of a usable alien bullet. Prefers reusing an existing (dead) /// bullet over creating a new instance. /// /// A bullet ready to place into the world. Bullet CreateAlienBullet() { Bullet b = null; for (int i = 0; i < alienBullets.Count; ++i) { if (alienBullets[i].IsAlive == false) { b = alienBullets[i]; break; } } if (b == null) { b = new Bullet(); alienBullets.Add(b); } b.IsAlive = true; return b; } /// /// Returns an instance of a usable alien instance. Prefers reusing an existing (dead) /// alien over creating a new instance. /// /// An alien ready to place into the world. Alien CreateAlien() { Alien b = null; for (int i = 0; i < aliens.Count; ++i) { if (aliens[i].IsAlive == false) { b = aliens[i]; break; } } if (b == null) { b = new Alien(); aliens.Add(b); } b.IsAlive = true; return b; } /// /// Creats an instance of an alien, sets the initial state, and places it into the world. /// private void SpawnAlien() { Alien newAlien = CreateAlien(); if (random.Next(2) == 1) { newAlien.Position.X = -64.0f; newAlien.Velocity.X = random.Next((int)alienSpeedMin, (int)alienSpeedMax); } else { newAlien.Position.X = worldBounds.Width + 32; newAlien.Velocity.X = -random.Next((int)alienSpeedMin, (int)alienSpeedMax); } newAlien.Position.Y = 31.2f + 105.0f * (float)random.NextDouble(); // Aliens if (transitionFactor > 0.0f) { switch (random.Next(4)) { case 0: newAlien.Texture = badguy_blue; break; case 1: newAlien.Texture = badguy_red; break; case 2: newAlien.Texture = badguy_green; break; case 3: newAlien.Texture = badguy_orange; break; } } else { newAlien.Texture = alienTexture; } newAlien.Width = newAlien.Texture.Width; newAlien.Height = newAlien.Texture.Height; newAlien.IsAlive = true; newAlien.Score = alienScore; float duration = 320.0f / newAlien.Velocity.Length(); newAlien.FireTimer = duration * (float)random.NextDouble(); newAlien.FireCount = 1; newAlien.Accuracy = alienMaxAccuracy; } #endregion #region DRAWING /// /// Draw the game world, effects, and hud /// /// The elapsed time since last Draw public override void Draw(GameTime gameTime) { float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; ScreenManager.SpriteBatch.Begin(); DrawBackground(elapsedTime); DrawAliens(); DrawPlayer(); DrawBullets(); particles.Draw(); DrawForeground(elapsedTime); DrawHud(); #if TARGET_IPHONE_SIMULATOR // Draw the GamePad GamePad.Draw(gameTime,ScreenManager.SpriteBatch); #endif ScreenManager.SpriteBatch.End(); } /// /// Draws the player's tank /// void DrawPlayer() { if (!gameOver && player.IsAlive) { ScreenManager.SpriteBatch.Draw(tankTexture, player.Position, Color.White); } } /// /// Draws all of the aliens. /// void DrawAliens() { for (int i = 0; i < aliens.Count; ++i) { if (aliens[i].IsAlive) ScreenManager.SpriteBatch.Draw(aliens[i].Texture, new Rectangle((int)aliens[i].Position.X, (int)aliens[i].Position.Y, (int)aliens[i].Width, (int)aliens[i].Height), Color.White); } } /// /// Draw both the player and alien bullets. /// private void DrawBullets() { for (int i = 0; i < playerBullets.Count; ++i) { if (playerBullets[i].IsAlive) ScreenManager.SpriteBatch.Draw(bulletTexture, playerBullets[i].Position, Color.White); } for (int i = 0; i < alienBullets.Count; ++i) { if (alienBullets[i].IsAlive) ScreenManager.SpriteBatch.Draw(laserTexture, alienBullets[i].Position, Color.White); } } /// /// Draw the foreground, which is basically the clouds. I think I had planned on one point /// having foreground grass that was drawn in front of the tank. /// /// The elapsed time since last Draw private void DrawForeground(float elapsedTime) { // Move the clouds. Movement seems like a Update thing to do, but this animations // have no impact over gameplay. cloud1Position += new Vector2(24.0f, 0.0f) * elapsedTime; if (cloud1Position.X > 320.0f) cloud1Position.X = -cloud1Texture.Width * 2.0f; cloud2Position += new Vector2(16.0f, 0.0f) * elapsedTime; if (cloud2Position.X > 320.0f) cloud2Position.X = -cloud1Texture.Width * 2.0f; ScreenManager.SpriteBatch.Draw(cloud1Texture, cloud1Position, Color.White); ScreenManager.SpriteBatch.Draw(cloud2Texture, cloud2Position, Color.White); } /// /// Draw the grass, hills, mountains, and sun/moon. Handles transitioning /// between day and night as well. /// /// The elapsed time since last Draw private void DrawBackground(float elapsedTime) { transitionFactor += transitionRate * elapsedTime; if (transitionFactor < 0.0f) { transitionFactor = 0.0f; transitionRate = 0.0f; } if (transitionFactor > 1.0f) { transitionFactor = 1.0f; transitionRate = 0.0f; } Vector3 day = Color.White.ToVector3(); Vector3 night = new Color(80, 80, 180).ToVector3(); Vector3 dayClear = Color.CornflowerBlue.ToVector3(); Vector3 nightClear = night; Color clear = new Color(Vector3.Lerp(dayClear, nightClear, transitionFactor)); Color tint = new Color(Vector3.Lerp(day,night,transitionFactor)); // Clear the background, using the day/night color ScreenManager.Game.GraphicsDevice.Clear(clear); // Draw the mountains ScreenManager.SpriteBatch.Draw(mountainsTexture, new Rectangle(0, 480 - (int)(mountainsTexture.Height*1.3f),320,(int)(mountainsTexture.Height*1.3f)), tint); // Draw the hills ScreenManager.SpriteBatch.Draw(hillsTexture, new Rectangle(0, 480 - (int)(hillsTexture.Height*1.3f),320,(int)(hillsTexture.Height*1.3f)), tint); // Draw the ground ScreenManager.SpriteBatch.Draw(groundTexture, new Rectangle(0, 480 - (int)(groundTexture.Height*1.3f),320,(int)(groundTexture.Height*1.3f)), tint); // Draw the sun or moon (based on time) ScreenManager.SpriteBatch.Draw(sunTexture, sunPosition, new Color(255,255,255, (byte)(255.0f * (1.0f - transitionFactor)))); ScreenManager.SpriteBatch.Draw(moonTexture, sunPosition, new Color(255,255,255, (byte)(255.0f * transitionFactor))); } /// /// Draw the hud, which consists of the score elements and the GAME OVER tag. /// void DrawHud() { if (gameOver) { Vector2 size = menuFont.MeasureString("GAME OVER"); DrawString(menuFont, "GAME OVER", new Vector2(ScreenManager.Game.GraphicsDevice.Viewport.Width / 2 - size.X / 2, ScreenManager.Game.GraphicsDevice.Viewport.Height / 2 - size.Y / 2), new Color(255,64,64)); } else { int bonus = 100 * (hitStreak / 5); string bonusString = (bonus > 0 ? " (" + bonus.ToString(System.Globalization.CultureInfo.CurrentCulture) + "%)" : ""); // Score DrawString(scoreFont, "SCORE: " + player.Score.ToString(System.Globalization.CultureInfo.CurrentCulture) + bonusString, new Vector2(6, 4), Color.Yellow); string text = "LIVES: " + player.Lives.ToString(System.Globalization.CultureInfo.CurrentCulture); Vector2 size = scoreFont.MeasureString(text); // Lives DrawString(scoreFont, text, new Vector2(314 - (int)size.X, 4), Color.Yellow); DrawString(scoreFont, "LEVEL: " + (((baseLevelKillCount - 5) / 5) + 1).ToString(System.Globalization.CultureInfo.CurrentCulture), new Vector2(6, 460), Color.Yellow); text = "HIGH SCORE: " + highScore.ToString(System.Globalization.CultureInfo.CurrentCulture); size = scoreFont.MeasureString(text); DrawString(scoreFont, text, new Vector2(314 - (int)size.X, 460), Color.Yellow); } } /// /// A simple helper to draw shadowed text. /// void DrawString(SpriteFont font, string text, Vector2 position, Color color) { ScreenManager.SpriteBatch.DrawString(font, text, new Vector2(position.X + 1, position.Y + 1), Color.Black); ScreenManager.SpriteBatch.DrawString(font, text, position, color); } #endregion } /// /// Represents either an alien or player bullet /// public class Bullet { public Vector2 Position; public Vector2 Velocity; public bool IsAlive; } /// /// The player's state /// public class Player { public Vector2 Position; public Vector2 Velocity; public float Width; public float Height; public bool IsAlive; public float FireTimer; public float RespawnTimer; public string Name; public Texture2D Picture; public int Score; public int Lives; } /// /// Data for an alien. The only difference between the ships /// and the badguys are the texture used. /// public class Alien { public Vector2 Position; public Texture2D Texture; public Vector2 Velocity; public float Width; public float Height; public int Score; public bool IsAlive; public float FireTimer; public float Accuracy; public int FireCount; } }