Asteroids – Del 1

Inledning

Denna artikel är första delen av en större serie artiklar. Varje del tar upp och diskuterar bit för bit vad som behövs göras för att skapa ett spel av typen Asteroids. Det krävs inga större förkunskaper för att följa artikelserien, erfarna programmerare bör varnas då datalagring och koddesign inte tas upp förrän de sista artiklarna. Det räcker med att du kan loopar och kan hantera lagringsklassen List.

Du behöver XNA också, så det rekommenderas att du har tittat på artikeln Förberedelser om du inte redan har XNA installerat.

Historia

bild

Asteroids kom ut i sin originalversion första gången 1979. Spelet var företaget Ataris svar på Space Invaders, ett annat populärt spel som kom 1978. Spelet byggde på vector-grafik, en teknik som bygger på skarpa linjer. Spelet blev en succé och är idag en klassiker.

Konceptet är enkelt. Du styr ett rymdskepp som kan skjuta asteroider. Asteroiderna blir fler och fler och kommer med högre hastighet allteftersom du klarar olika nivåer.

Ett nytt Windows Game

Vi börjar med att skapa ett nytt XNA-projekt av typen Windows Game. Du väljer i menyn "File" och "New Project". Projekttypen Windows Game finns i trädet "XNA Game Studio 4.0".

bild

Välj namn på ditt projekt. Du kan kalla det "Asteroids" kort och gott.

XNA - En överblick

Vi ska ta en liten titt på vad du får när du skapat ett nytt Windows Game.

Exempel: Standard XNA Windows Game

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace WindowsGame1
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            base.Draw(gameTime);
        }
    }
}

Projektet ovan innehåller några olika metoder som är värda att omnämnas.

  • Game1(), här kan du ändra inställningar på skärmen via graphics, t.ex. upplösning och fullskärmsläge etc.
  • Initialize(), initiering av variabler kan du placera här.
  • LoadContent(), all inladdning från Content gör du här.
  • Update(GameTime gameTime), typisk för förflyttning och kollisionsberäkningar. All logik i spelet bör placeras här.
  • Draw(GameTime gameTime), all uppritning sköts härifrån.

De mesta centrala delarna är just Update och Draw. Dessa metoder körs hela tiden så ofta som det bara går och utgör själva hjärtat av spelet. Draw är som regel låst till att försöka köra 60 gånger per sekund (60 fps). Metoden Update kan köras mer än en gång mellan varje Draw.

XNA - Content Manager

Vårt första mål i denna artikelserie är ladda in grafik och få ut den på skärmen. Till vår hjälp har vi i XNA en klassen ContentManager som hanterar inladdning och processering av olika data. Via XNA's ContentManager kan vi ladda in följande:

  • 3D filformat, t.ex. fbx och x
  • 2D filformat, t.ex. dds, pgn, tga, jpg, bmp
  • Material, t.ex. fx
  • Ljudfiler, t.ex xap (xact)

Content Managern har som uppgift att underlätta hantering och inladdning av den data som du som programmerare behöver för att göra spel. Fördelarna med att ha en Content Manager är att du slipper lägga en massa tid på kodning som egentligen inte har med själva spelet att göra. Alltså mer tid över till annat!

Börja med att ladda hem filen ship.zip nedan, som innehåller grafiken till rymdskeppet.

bild

En viktig sak att nämna är valet av bakgrundsfärg. Färgen RGB 255, 0, 255 (#FF00FF) är den färg som i XNA automatisk blir genomskinglig i texturer.

Placera ship.bmp i katalogen Content i din projektmapp.

bild

I Solution Explorern i Visual Studio så har du en mapp som heter Content. Denna mapp är direkt kopplad till den inbyggda Content Managern. Allt innehåll vi vill kunna ladda via Content Managern måste läggas in i Solution Explorern.

bild

Högerklicka på Content i Solution Explorern och välj "Add -> Existing Item".

bild

Bläddra fram till filen ship.bmp och tryck "Add".

bild

Nu har vi gjort alla förberedelser för att gå vidare och börja koda.

Variabler

Vi kommer att behöva en rad variabler för att fixa utritningen och positioneringen av rymdskeppet. För 2D grafik finns klassen Texture 2D som då används för att ladda in den grafik vi behöver

Till positionering och senare hastigheter ska vi använda oss av en klass som heter Vector2. Detta är en klass som främst lagrar två float vid namn X o Y. En Vector2 innehåller alltså både ett värde på X och ett värde på Y. X och Y-värdena behövs när vi ska bestämma var på skärmen skeppet ska ritas ut.

Vi börjar alltså med att deklarera variablerna gfx och position.

Deklarering

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Texture2D gfx;
        Vector2 position;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

Ladda grafiken

Nu ska vi ladda grafiken via Content Manager. I XNA så sköter vi inladdningen i metoden LoadContent(). Vi passar även på att skapa ett Vector2-objekt för vår position.

Komplettering till LoadContent

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

            gfx = Content.Load<Texture2D>("ship");

            position = new Vector2(200, 200);
        }

I anropet Content.Load anger du vilken sorts data du vill ladda in. I vårt fall är datan av typen Texture2D som även matchar datatypen som vi valde på variabeln gfx. Som inparameter till Content.Load anger du vilken asset du vill ladda. Med detta menas någon fil som finns inlagd under Content i Solution Explorern. Notera att filändelsen inte ska anges.

Uppritning

I XNA ska all uppritning ske i metoden Draw(GameTime gameTime). Till hjälp har vi klassen SpriteBatch för att rita så kallade sprites. En sprite är grafik i 2D, i vårt fall rymdskeppet.

Komplettering till Draw

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

            spriteBatch.Begin();
            spriteBatch.Draw(gfx, position, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

Vårt objekt av klassen SpriteBatch heter spriteBatch, tänk vilken skillnad en lite bokstav kan göra! Med hjälp av spriteBatch kan vi rita ut gafik. Metoden Draw() kan rita ut på många olika sätt, 7 olika sätt för att vara exakt. Det hela beror på vilket sätt vi finner enklast. Den variant vi använder tar 3 parametrar.

Den första parametern talar om vilken grafik som ska användas, den måste då vara av typen Texture2D. Den andra parametern är en Vector2 som bestämmer var på skärmen grafiken ska hamna. Den sista parametern används för blending. Med blending kan du manipulera färgerna på den sprite som du ritar ut. Färgen Color.White gör så att det inte sker någon manipulering av färgerna. Testa gärna med Color.Red som sista parameter så får du en aning om vad du kan använda blending till.

Uppritning av sprites måste ske mellan anropen Begin() och End().

bild

Lämna ett svar

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

Scroll to top