• 手把手教用XNA开发winphone7游戏(五)大结局


     Alien Game逻辑

    在这最有一个部分你将创建game-specific logic helper方法和类。胜利就在眼前,你的第一个winphone7程序就要出现了,加油加油!!(感谢http://winphone.us/)。另外最近imagecup要开始了,帮小美女推一下,学生们有时间都去参加。为了帮大家了解imagecup和winphone7的开发,我可能会针对学生讲一些入门级webcast,有详细计划再通知大家。刚刚翻译了imagecup的winphone7的评判标准,觉得有一条很好玩,就是要让使用了你的程序的人想去买一部winphone,呵呵这个占20%,大家加油了。另外有人要源代码,我把最后成品的源代码放到下一篇“番外篇”了,大家感兴趣可以去下载。

    1.       GameplayScreen.cs 文件里,创建一个新的helper (GameplayScreen类之外)根据下面的代码:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Bullet class)

    C#

    /// <summary>

    /// Represents either an alien or player bullet

    /// </summary>

    public class Bullet

    {

       public Vector2 Position;

       public Vector2 Velocity;

       public bool IsAlive;

    }

    2.       Bullet 类后面添加两个helper:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player and Alien classes)

    C#

    /// <summary>

    /// The player's state

    /// </summary>

    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;

    }

     

    /// <summary>

    /// Data for an alien. The only difference between the ships

    /// and the badguys are the texture used.

    /// </summary>

    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;

    }

    3.       添加如下GameplayScreen类的变量:

    (Code Snippet – Game Development with XNA – Gameplay Screen – even more variables)

    C#

    Player player;

    List<Alien> aliens;

    List<Bullet> alienBullets;

    List<Bullet> playerBullets;

    4.       在构造函数中初始化这些变量,如下所示:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player and Alien Initialization)

    C#

    public GameplayScreen()

    {

        ...

     

        player = new Player();

        playerBullets = new List<Bullet>();

     

        aliens = new List<Alien>();

        alienBullets = new List<Bullet>();

     

        Accelerometer = new Accelerometer();

        if (AccelerometerSensor.Default.State == SensorState.Ready)

        {

            ...

        }

        ...

    }

     

    5.       初始化player变量Width HeightLoadContent 方法中 (初始化ParticleSystem之后):

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player Initialization in LoadContent method)

    C#

    public override void LoadContent()

    {

        ...

     

        particles = new ParticleSystem(ScreenManager.Game.Content, ScreenManager.SpriteBatch);

        player.Width = tankTexture.Width;

        player.Height = tankTexture.Height;

     

        base.LoadContent();

    }

    6.       下面的一小段代码将添加游戏的逻辑。他们将根据用户的输入来改变“player1”的移动。导航到 HandleInput 的方法,并找到以下行:

    C#

    //TODO: Update player Velocity over X axis #1

    在它的后面添加如下代码段:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player Movements 1 in HandleInput method)

    C#

    player.Velocity.X = movement;

    7.       找到以下行 (HandleInput 方法中):

    C#

    //TODO: Update player velocity over X axis #2

    在其后添加如下代码:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player Movements 2 in HandleInput method)

    C#

    player.Velocity.X = -1.0f;

    8.       找到以下行 (HandleInput 方法中):

    C#

    //TODO: Update player velocity over X axis #3

    在其后添加如下代码:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player Movements 3 in HandleInput method)

    C#

    player.Velocity.X = 1.0f;

    9.       找到以下行 (HandleInput 方法中):

    C#

    //TODO: Update player velocity over X axis #4

    在其后添加如下代码:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Player Movements 4 in HandleInput method)

    C#

    player.Velocity.X = MathHelper.Min(input.CurrentGamePadStates[0].ThumbSticks.Left.X * 2.0f, 1.0f);

     

    10.   找到以下行:

    C#

    //TODO: Fire the bullet

    更改"if"语句根据下面的代码片断::

    (Code Snippet – Game Development with XNA – Gameplay Screen – HandleInput firing the bullet code)

    C#

    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 = 1.0f;

     

        particles.CreatePlayerFireSmoke(player);

        playerFired.Play();

    }

    else if (gameOver)

        finishCurrentGame();

    11.   创建 GameplayScreen 类中的以下方法:

    此方法将创建Bullet类的一个实例。 此实例使用在前面的代码段。

    (Code Snippet – Game Development with XNA – Gameplay Screen – CreatePlayerBullet method)

    C#

    /// <summary>

    /// Returns an instance of a usable player bullet. Prefers reusing an /// existing (dead)

    /// bullet over creating a new instance.

    /// </summary>

    /// <returns>A bullet ready to place into the world.</returns>

    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;

    }

    12.   更改Update方法。在"base.Update()"方法调用之前,添加下面的蓝色突出显示的代码段:

    此块的代码实际上提供了游戏的逻辑 它移动玩家和调用该方法来更新异型和重新计算子弹的位置。

    (Code Snippet – Game Development with XNA – Gameplay Screen – Update method)

    C#

    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.0f)

                particles.CreatePlayerDust(player);

     

            particles.Update(elapsed);

        }

     

        base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

    }

    13.   GameplayScreen 类中添加helper方法:

    Note: 下面的代码段中添加大量的帮助器方法。 方法用途如下:

    重生: 检查是否,玩家已经"死亡"但这场游戏还没有结束, 如果这,它完成等待 respawnTimer结束后创建一个新的玩家实例屏幕的中间。

    UpdateBullets 检查和更新屏幕上的玩家和异形子弹的位置。

    UpdateAliens 移动异形,并计算是否发射子弹和朝哪个方向。

    CheckHits 检查所有的子弹和玩家/异形的碰撞。它还将处理游戏逻辑,当命中发生时,进行让死亡,加分或者结束游戏等。

    (Code Snippet – Game Development with XNA – Gameplay Screen – Helper update methods)

    C#

    /// <summary>

    /// Handles respawning the player if we are playing a game and the player is dead.

    /// </summary>

    /// <param name="elapsed">Time elapsed since Respawn was called last.</param>

    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 - groundTexture.Height + 2 - player.Height);

                player.Velocity = Vector2.Zero;

                player.Lives--;

            }

        }

    }

     

    /// <summary>

    /// Moves all of the bullets (player and alien) and prunes "dead" bullets.

    /// </summary>

    /// <param name="elapsed"></param>

    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;

        }

    }

     

    /// <summary>

    /// Moves the aliens and performs their "thinking" by determining if they

    /// should shoot and where.

    /// </summary>

    /// <param name="elapsed">The elapsed time since UpdateAliens was called last.</param>

    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--;

            }

        }

    }

     

    /// <summary>

    /// 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.

    /// </summary>

    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;

                }

            }

     

        }

    }

     

    /// <summary>

    /// Advances the difficulty of the game one level.

    /// </summary>

    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;

        }

    }

    14.   GameplayScreen 类中添加如下代码:

    Note: 下面的代码片断还增加了大量的帮助器方法。 他们的目的是,如下所示: CreateAlienBullet 创建的异形的子弹,将用于异形向玩家开火

    SpawnAlien 初始化一个新的异形实例,设置了的初始位置、速度,选择颜色纹理等。

    CreateAlien 创建新异形的实例,并将其添加到异形集合

    (Code Snippet – Game Development with XNA – Gameplay Screen – Helper aliens methods)

    C#

    /// <summary>

    /// Returns an instance of a usable alien bullet. Prefers reusing an existing (dead)

    /// bullet over creating a new instance.

    /// </summary>

    /// <returns>A bullet ready to place into the world.</returns>

    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;

    }

     

    /// <summary>

    /// Creates an instance of an alien, sets the initial state, and places it into the world.

    /// </summary>

    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 = 24.0f + 80.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 = screenHeight / newAlien.Velocity.Length();

     

        newAlien.FireTimer = duration * (float)random.NextDouble();

        newAlien.FireCount = 1;

     

        newAlien.Accuracy = alienMaxAccuracy;

    }

     

    /// <summary>

    /// Returns an instance of a usable alien instance. Prefers reusing an existing (dead)

    /// alien over creating a new instance.

    /// </summary>

    /// <returns>An alien ready to place into the world.</returns>

    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;

    }

    15.   .导航到Draw方法并添加下面的蓝色突出显示的代码段,Screen.SpriteBatch.Begin() Screen.SpriteBatch.End() 之间:

    这样更改方法方法将呼调用helper方法以在屏幕上绘制变化后的内容。

    (Code Snippet – Game Development with XNA – Gameplay Screen – Draw method update)

    C#

    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();

     

        ScreenManager.SpriteBatch.End();

    }

    16.   Draw 方法后面添加如下方法:

    Note: 下面的代码段中添加大量的绘图相关的Helper方法。 方法用途如下: DrawPlayer 绘制玩家的坦克。

    DrawAliens 绘制所有异形

    DrawBullets 绘制所有的子弹 (玩家的和异形的)。

    DrawForeground 作为前台绘制云,并将其移动。

    DrawBackground 绘制草、 丘陵、 山地和太阳/月亮。 此外处理白天和黑夜之间转换。

    DrawHud 绘制分数、剩余的生命值和" GAME OVER "需要的时候。

    drawString 绘制隐藏的文本的通用方法。

    (Code Snippet – Game Development with XNA – Gameplay Screen – Draw methods)

    C#

    /// <summary>

    /// Draws the player's tank

    /// </summary>

    void DrawPlayer()

    {

       if (!gameOver && player.IsAlive)

       {

          ScreenManager.SpriteBatch.Draw(tankTexture,                player.Position, Color.White);

       }

    }

     

    /// <summary>

    /// Draws all of the aliens.

    /// </summary>

    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);

       }

    }

     

    /// <summary>

    /// Draw both the player and alien bullets.

    /// </summary>

    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);

       }

    }

     

    /// <summary>

    /// 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.

    /// </summary>

    /// <param name="elapsedTime">The elapsed time since last Draw</param>

    private void DrawForeground(float elapsedTime)

    {

       // Move the clouds. Movement seems like an Update thing to do, but this animations

       // have no impact over gameplay.

       cloud1Position += new Vector2(24.0f, 0.0f) * elapsedTime;

       if (cloud1Position.X > screenWidth)

          cloud1Position.X = -cloud1Texture.Width * 2.0f;

     

       cloud2Position += new Vector2(16.0f, 0.0f) * elapsedTime;

       if (cloud2Position.X > screenWidth)

          cloud2Position.X = -cloud1Texture.Width * 2.0f;

     

       ScreenManager.SpriteBatch.Draw(cloud1Texture,             cloud1Position, Color.White);

       ScreenManager.SpriteBatch.Draw(cloud2Texture,     cloud2Position, Color.White);

    }

     

    /// <summary>

    /// Draw the grass, hills, mountains, and sun/moon. Handle transitioning

    /// between day and night as well.

    /// </summary>

    /// <param name="elapsedTime">The elapsed time since last Draw</param>

    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 Vector2(0, screenHeight - mountainsTexture.Height),            tint);

     

       // Draw the hills

       ScreenManager.SpriteBatch.Draw(hillsTexture, new Vector2(0, screenHeight - hillsTexture.Height), tint);

     

       // Draw the ground

       ScreenManager.SpriteBatch.Draw(groundTexture, new     Vector2(0, screenHeight - groundTexture.Height),               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)));

    }

     

    /// <summary>

    /// Draw the hud, which consists of the score elements and the GAME OVER tag.

    /// </summary>

    void DrawHud()

    {

       float scale = 2.0f;

     

       if (gameOver)

       {

          Vector2 size = menuFont.MeasureString("GAME OVER");

          DrawString(menuFont, "GAME OVER", new Vector2(ScreenManager.Game.GraphicsDevice.Viewport.Width / 2 - size.X, ScreenManager.Game.GraphicsDevice.Viewport.Height / 2 - size.Y / 2), new Color(255, 64, 64), scale);

     

       }

       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(leftOffset, topOffset), Color.Yellow, scale);

     

         string text = "LIVES: " +  player.Lives.ToString(System.Globalization.CultureInfo .CurrentCulture);

         Vector2 size = scoreFont.MeasureString(text);

         size *= scale;

     

         // Lives

         DrawString(scoreFont, text, new Vector2(screenWidth -           leftOffset - (int)size.X, topOffset),                  Color.Yellow,  scale);

     

         DrawString(scoreFont, "LEVEL: " + (((baseLevelKillCount - 5) / 5) + 1).ToString(System.Globalization.CultureInfo.CurrentCulture), new Vector2(leftOffset, screenHeight - bottomOffset), Color.Yellow, scale);

     

         text = "HIGH SCORE: " +     highScore.ToString(System.Globalization.CultureInfo

    .CurrentCulture);

     

         size = scoreFont.MeasureString(text);

     

         DrawString(scoreFont, text, new Vector2(screenWidth -           leftOffset - (int)size.X * 2, screenHeight -           bottomOffset), Color.Yellow, scale);

       }

    }

     

    /// <summary>

    /// A simple helper to draw shadowed text.

    /// </summary>

    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);

    }

     

    /// <summary>

    /// A simple helper to draw shadowed text.

    /// </summary>

    void DrawString(SpriteFont font, string text,

    Vector2 position, Color color, float fontScale)

    {

       ScreenManager.SpriteBatch.DrawString(font, text, new Vector2(position.X + 1, position.Y + 1), Color.Black,     0, new Vector2(0, font.LineSpacing / 2), fontScale,     SpriteEffects.None, 0);

       ScreenManager.SpriteBatch.DrawString(font, text, position, color, 0, new Vector2(0, font.LineSpacing /  2), fontScale, SpriteEffects.None, 0);

    }

     

    17.   找到 LoadContent 方法,在base.LoadContent() 调用后面体检如下代码:

    C#

    public override void LoadContent()

    {

        ...

        player.Width = tankTexture.Width;

        player.Height = tankTexture.Height;

     

        base.LoadContent();

     

        LoadHighscore();

        Start();

    }

    18.   找到 UnloadContent 方法并particles = null;之前的位置添加下面的代码:

    C#

    public override void UnloadContent()

    {

        SaveHighscore();

     

        particles = null;

     

        base.UnloadContent();

    }

    19.   创建一个区域loading/unloading high scores logic。我们需要通过Isolated Storage来读取Windows Phone 文件系统中的数据。用如下代码在GameplayScreen类中创建logic:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Highscore storage methods)

    C#

    #region Highscore loading/saving logic

    /// <summary>

    /// Saves the current highscore to a text file. The StorageDevice was selected during screen loading.

    /// </summary>

    private void SaveHighscore()

    {

        using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())

        {

            using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream("highscores.txt", FileMode.Create, isf))

            {

                using (StreamWriter writer = new StreamWriter(isfs))

                {

                    writer.Write(highScore.ToString(System.Globalization.CultureInfo.InvariantCulture));

                    writer.Flush();

                    writer.Close();

                }

            }

        }

    }

     

    /// <summary>

    /// Loads the high score from a text file. The StorageDevice was selected during the loading screen.

    /// </summary>

    private void LoadHighscore()

    {

        using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())

        {

            if (isf.FileExists("highscores.txt"))

            {

                using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream("highscores.txt", FileMode.Open, isf))

                {

                    using (StreamReader reader = new StreamReader(isfs))

                    {

                        try

                        {

                            highScore = Int32.Parse(reader.ReadToEnd(), System.Globalization.CultureInfo.InvariantCulture);

                        }

                        catch (FormatException)

                        {

                            highScore = 10000;

                        }

                        finally

                        {

                            if (reader != null)

                                reader.Close();

                        }

                    }

                }

            }

        }

    }

    #endregion

    20.   GameplayScreen 类中创建Start方法来开始一个新游戏:

    (Code Snippet – Game Development with XNA – Gameplay Screen – Start method)

    C#

    /// <summary>

    /// Starts a new game session, setting all game states to initial values.

    /// </summary>

    void Start()

    {

        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;

    }

    21.   打开 ParticleSystem.cs文件

    22.   添加如下命名申明:

    (Code Snippet – Game Development with XNA – ParticleSystem – using statement)

    C#

    using AlienGame;

    23.   在这个步骤,你将添加两个方法。一个用来创建玩家控制坦克时泥土/灰尘的效果。一个用来创建玩家发射子弹时,火焰的效果。添加如下方法到ParticleSystem 类中:

    (Code Snippet – Game Development with XNA – ParticleSystem – Helper player effects methods)

    C#

    /// <summary>

    /// Creates the mud/dust effect when the player moves.

    /// </summary>

    /// <param name="position">Where on the screen to create the effect.</param>       

    public void CreatePlayerDust(Player player)

    {

        for (int i = 0; i < 2; ++i)

        {

            Particle p = CreateParticle();

            p.Texture = smoke;

            p.Color = new Color(125, 108, 43);

            p.Position.X = player.Position.X + player.Width * (float)random.NextDouble();

            p.Position.Y = player.Position.Y + player.Height - 3.0f * (float)random.NextDouble();

            p.Alpha = 1.0f;

            p.AlphaRate = -2.0f;

            p.Life = 0.5f;

            p.Rotation = 0.0f;

            p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble();

            p.Scale = 0.25f;

            p.ScaleRate = 0.5f;

            p.Velocity.X = -4 + 8.0f * (float)random.NextDouble();

            p.Velocity.Y = -8 + 4.0f * (float)random.NextDouble();

        }

    }

     

    /// <summary>

    /// Creates the effect for when the player fires a bullet.

    /// </summary>

    /// <param name="position">Where on the screen to create the effect.</param>       

    public void CreatePlayerFireSmoke(Player player)

    {

        for (int i = 0; i < 8; ++i)

        {

            Particle p = CreateParticle();

            p.Texture = smoke;

            p.Color = Color.White;

            p.Position.X = player.Position.X + player.Width / 2;

            p.Position.Y = player.Position.Y;

            p.Alpha = 1.0f;

            p.AlphaRate = -1.0f;

            p.Life = 1.0f;

            p.Rotation = 0.0f;

            p.RotationRate = -2.0f + 4.0f * (float)random.NextDouble();

            p.Scale = 0.25f;

            p.ScaleRate = 0.25f;

            p.Velocity.X = -4 + 8.0f * (float)random.NextDouble();

            p.Velocity.Y = -16.0f + -32.0f * (float)random.NextDouble();

        }

    }

    24.   编译并运行该应用程序。 选择"开始游戏"菜单项,并享受你自己编写的游戏吧。

    Note: 在模拟器中我们使用桌面的键盘移动车辆,您需要首先按PAUSE /BREAK 键。 这将开启或者关闭仿真程序软件输入面板 (SIP) 或者桌面的键盘。因为键盘不能同时作为仿真程序软件输入面板 (SIP)和桌面的键盘,这个问题将在后面的版本里解决。

    1

    完工的游戏

    恭喜你,你终于完成了一个属于你自己的winphone7手机程序。

    在今天的部分的过程中,您创建包括玩家和异形的移动计算、 命中的检测、 屏幕绘制,和其他一些的 AlienGame 逻辑。

    虽然这个游戏完成了,但是我想大家可能有更多的疑问和想改进的地方,那让我们进入

    手把手教用XNA开发winphone7游戏中级教程

  • 相关阅读:
    [原创]NT系统信息察看工具 : NtInfoGuy
    [原创]obj-c编程17:键值观察(KVO)
    python使用django框架模板的基本使用
    mysql链接查询
    mysql数据库的增删改查
    python使用django创建项目详解
    python中sdk的使用 (一)
    unittest单元测试框架小白入门
    nosql数据库与sql数据库
    javascript数组的定义及基本操作详解
  • 原文地址:https://www.cnblogs.com/zouyuntao/p/1876269.html
Copyright © 2020-2023  润新知