MonoAsteroids – Del 3

Inledning

Denna artikel är en direkt fortsättning på artikeln MonoAsteroids - Del 2 . Vi ska nu lägga ljudeffekter, explosioner och fler typer av meteoriter i spelet.

Artikeln är mer ett stöd till den videogenomgång som mer steg för steg går igenom alla moment. Videogenomgången hittar du i slutet av artikeln.

Explosioner

Vi skapar en ny klass för explosionerna som döper vi till Explosion.cs. Denna klass är såklart också ett GameObject så vi för in arvet och börjar definiera upp hur en explosion ska fungera.

Eplosionerna ska bara leva en kort tid. Under denna tid så hade det varit snyggt om de roterar och "fade'ar" bort. Detta löser vi med en enkel timer samt en beräkning på en Color som kan användas som "blending color" vid uppritning. På så vis kan vi få explosionen att sakta tona bort.

Explosion.cs

using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MonoAsteroids
{
    class Explosion : GameObject
    {
        public float Scale { get; set; }
        private int timer = 30;

        public Color Color
        {
            get { return new Color(timer * 8, timer * 8, timer * 8, timer * 8); }
        }

        public void Update(GameTime gameTime)
        {
            if (timer > 0)
                timer--;
            else
                IsDead = true;

            Rotation += 0.02f;
            if (Rotation > MathHelper.TwoPi)
                Rotation = 0;
                
        }
    }
}

Videogenomgång

Ytterligare ändringar i kod

Som tidigare nämnts så är texten i artikeln här mest ett stöd för videogenomgången. Följ först videogenomgången sedan kan du jämföra din kod med den färdiga som listas under detta avsnitt.

Undvik klipp och klistra! Du lär dig mer av att skriva koden steg för steg när du följer videogenomgången.

Meteor.cs

using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;

namespace MonoAsteroids
{
    enum MeteorType
    {
        Big,
        Medium,
        Small
    }

    class Meteor : GameObject
    {
        public MeteorType Type { get; private set; }
        public float ExplosionScale { get; private set; }

        public Meteor(MeteorType type)
        {
            Type = type;

            switch(Type)
            {
                case MeteorType.Big:
                    Radius = 48;
                    ExplosionScale = 1.0f;
                    break;
                case MeteorType.Medium:
                    Radius = 21;
                    ExplosionScale = 0.5f;
                    break;
                case MeteorType.Small:
                    ExplosionScale = 0.2f;
                    Radius = 8; 
                    break;
            }
        }

        public void Update(GameTime gameTime)
        {
            Position += Speed;

            if (Position.X < Globals.GameArea.Left)
                Position = new Vector2(Globals.GameArea.Right, Position.Y);
            if (Position.X > Globals.GameArea.Right)
                Position = new Vector2(Globals.GameArea.Left, Position.Y);
            if (Position.Y < Globals.GameArea.Top)
                Position = new Vector2(Position.X, Globals.GameArea.Bottom);
            if (Position.Y > Globals.GameArea.Bottom)
                Position = new Vector2(Position.X, Globals.GameArea.Top);

            Rotation += 0.04f;
            if (Rotation > MathHelper.TwoPi)
                Rotation = 0;
        }

        public static IEnumerable<Meteor> BreakMeteor(Meteor meteor)
        {
            List<Meteor> meteors = new List<Meteor>();
            if (meteor.Type == MeteorType.Small)
                return meteors;

            for(int i=0; i<3; i++)
            {
                var angle = (float)Math.Atan2(meteor.Speed.Y, meteor.Speed.X) - MathHelper.PiOver4
                    + MathHelper.PiOver4 * i;

                meteors.Add(new Meteor(meteor.Type + 1)
                {
                    Position = meteor.Position,
                    Rotation = angle,
                    Speed = new Vector2((float)Math.Cos(angle), 
						(float)Math.Sin(angle)) * meteor.Speed.Length() * 0.5f
                });
            }

            return meteors;
        }
    }
}

MonoAsteroids.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MonoAsteroids
{
    public class MonoAsteroids : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D backgroundTexture;
        Player player;
        KeyboardState previousKbState;

        List<Shot> shots = new List<Shot>();
        Texture2D laserTexture;

        List<Meteor> meteors = new List<Meteor>();
        Texture2D meteorBigTexture;
        Texture2D meteorMediumTexture;
        Texture2D meteorSmallTexture;
        Random rnd = new Random();

        SoundEffect laserSound;
        SoundEffect explosionSound;
        Texture2D explosionTexture;
        List<Explosion> explosions = new List<Explosion>();

        public MonoAsteroids()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = Globals.ScreenHeight;
            graphics.PreferredBackBufferWidth = Globals.ScreenWidth;

            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            player = new Player(this);
            Components.Add(player);
            ResetMeteors();

            base.Initialize();
        }

        public void ResetMeteors()
        {
            while (meteors.Count < 10)
            {
                var angle = rnd.Next() * MathHelper.TwoPi;
                var m = new Meteor(MeteorType.Big)
                {
                    Position = new Vector2(Globals.GameArea.Left + (float)rnd.NextDouble() * Globals.GameArea.Width,
                        Globals.GameArea.Top + (float)rnd.NextDouble() * Globals.GameArea.Height),
                    Rotation = angle,
                    Speed = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * rnd.Next(20, 60) / 30.0f
                };

                if (!Globals.RespawnArea.Contains(m.Position))
                    meteors.Add(m);
            }
        }


        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            backgroundTexture = Content.Load<Texture2D>("background");
            laserTexture = Content.Load<Texture2D>("laser");
            meteorBigTexture = Content.Load<Texture2D>("meteorBrown_big4");
            meteorMediumTexture = Content.Load<Texture2D>("meteorBrown_med1");
            meteorSmallTexture = Content.Load<Texture2D>("meteorBrown_tiny1");

            laserSound = Content.Load<SoundEffect>("laserSound");
            explosionSound = Content.Load<SoundEffect>("explosionSound");
            explosionTexture = Content.Load<Texture2D>("explosion");
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            KeyboardState state = Keyboard.GetState();

            if (state.IsKeyDown(Keys.Up))
                player.Accelerate();
            if (state.IsKeyDown(Keys.Left))
                player.Rotation -= 0.05f;
            else if (state.IsKeyDown(Keys.Right))
                player.Rotation += 0.05f;

            if(state.IsKeyDown(Keys.Space))
            {
                Shot s = player.Shoot();
                if (s != null)
                {
                    laserSound.Play();
                    shots.Add(s);
                }
            }

            foreach (Shot shot in shots)
            {
                shot.Update(gameTime);
                Meteor meteor = meteors.FirstOrDefault(m => m.CollidesWith(shot));

                if(meteor != null)
                {
                    meteors.Remove(meteor);
                    meteors.AddRange(Meteor.BreakMeteor(meteor));
                    explosions.Add(new Explosion()
                    {
                        Position = meteor.Position,
                        Scale = meteor.ExplosionScale
                    });
                    shot.IsDead = true;
                    explosionSound.Play(0.7f, 0f, 0f);
                }
            }

            foreach (Explosion explosion in explosions)
                explosion.Update(gameTime);

            foreach (Meteor metor in meteors)
                metor.Update(gameTime);

            shots.RemoveAll(s => s.IsDead || !Globals.GameArea.Contains(s.Position));
            explosions.RemoveAll(e => e.IsDead);
            
            player.Update(gameTime);
            previousKbState = state;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();

            for (int y = 0; y < Globals.ScreenHeight; y += backgroundTexture.Width)
            {
                for (int x = 0; x < Globals.ScreenWidth; x += backgroundTexture.Width)
                {
                    spriteBatch.Draw(backgroundTexture, new Vector2(x, y), Color.White);
                }
            }

            foreach (Shot s in shots)
            {
                spriteBatch.Draw(laserTexture, s.Position, null, Color.White, s.Rotation,
                new Vector2(laserTexture.Width / 2, laserTexture.Height / 2), 1.0f, SpriteEffects.None, 0f);
            }

            foreach(Meteor meteor in meteors)
            {
                Texture2D meteorTexture = meteorSmallTexture;

                switch(meteor.Type)
                {
                    case MeteorType.Big: meteorTexture = meteorBigTexture; break;
                    case MeteorType.Medium: meteorTexture = meteorMediumTexture; break;
                }

                spriteBatch.Draw(meteorTexture, meteor.Position, null, Color.White, meteor.Rotation,
                new Vector2(meteorTexture.Width / 2, meteorTexture.Height / 2), 1.0f, SpriteEffects.None, 0f);
            }

            foreach(Explosion explosion in explosions)
            {
                spriteBatch.Draw(explosionTexture, explosion.Position, null, explosion.Color, explosion.Rotation,
					new Vector2(explosionTexture.Width / 2, explosionTexture.Height / 2), explosion.Scale, SpriteEffects.None, 0f);
            }

            player.Draw(spriteBatch);

            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *

Scroll to top