Tutorials

XNA Game Components Tutorial

Nivå : 200
Forfatter : Raymond   Link

Her skal jeg prøve å forklare hva "Game Components" i XNA er.

 

La oss tenke oss at vi lager et rollespill. Hva er det vi trenger?

Vi trenger bl.a en verden, en helt og våpenet til helten vår

 

Alle disse er kandidater til en "DrawableGameComponent". Dette er en komponent som kan oppdatere seg selv og tegne seg selv på skjermen.

 

"GameComponent" kan bare oppdatere seg. Eksempler på det kan være kamera og bruker interaksjon (keyboard, joystick). DrawableGameComponent er en utvidelse av GameComponent objektet.

 

 

Hvordan lager man en Game Component?

 

Aller først må man ha et XNA prosjekt. Så kan du høyreklikke på prosjektnavnet i Solution Explorer og velge "Add Item". Her kan du velge "GameComponent".

Da vil du få en ferdig klasse med overrides på Initialize og Update, samt en konstruktør som gir deg "game" objektet vårt.

 

Det er ikke mulig å velge en DrawableGameComponent så skal vi ha en det må vi bare bytte navnet på klassen vi arver fra (GameComponent) til DrawableGameComponent og så legge til nye overrides.

 

    public class Camera : Microsoft.Xna.Framework.GameComponent

    {

        public Camera(Game game)

            : base(game)

        {

  }

 

        public override void Initialize()

        {

            base.Initialize();

        }

 

        public override void Update(GameTime gameTime)

        {

            base.Update(gameTime);

  }

 

    }

 

 

Her har vi laget en game component som heter Camera.

 

En DrawableGameComponent vil se sånn ut:

 

        public override void Initialize()

        {

            base.Initialize();

        }

 

        protected override void LoadGraphicsContent(bool loadAllContent)

        {

            base.LoadGraphicsContent(loadAllContent);

        }

 

        protected override void UnloadGraphicsContent(bool unloadAllContent)

        {

            base.UnloadGraphicsContent(unloadAllContent);

        }

 

        public override void Update(GameTime gameTime)

        {

            base.Update(gameTime);

        }

 

        public override void Draw(GameTime gameTime)

        {

            base.Draw(gameTime);

        }

 

Hva/Hvor med kode?

 

I konstruktøren lager vi som regel objektene vi skal bruke I komponenten.

La oss si at vi skal legge til en "Avatar" komponent.

 

Så vil vi legge til et Interface vi har laget til kameraet vårt, da kan vi skrive: camera = (ICamera)Game.Services.GetService(typeof(ICamera));

Hvor camera er en klassevariabel av typen ICamera.

Legg merke til at jeg har lagt til camera objektet i Services til Game. Her kan du legge interfacene dine som du vil at alle komponentene dine skal få tilgang til.

 

Så har vi forskjellige overrides som:

 

  • public override void Initialize()

Her kan vi sette properties på child på objektene, som camera.

La oss si at vi skal fortelle kameraet vårt at den skal begynne på posisjonen 0,0,0:

camera.Position = Vector3.Zero;

 

  • protected override void LoadGraphicsContent(bool loadAllContent)

Dette er et perfekt sted å laste inn modellen(e) våre: avatar = Game1.content.Load<Model>("Content\\Models\\warlock");

Hvor content er et statisk objekt av en ContentManager i Game1 klassen.

 

  • protected override void UnloadGraphicsContent(bool unloadAllContent)

Close() og Dispose() objektene dine her. Dette er spesielt viktig på Xbox der du har en "undeterministic" garbage collection, nemlig en veldig lat en. Xbox bruker en spesialtilpasset versjon av .NET Compact Framework. Se her: http://blogs.msdn.com/shawnhar/archive/2007/06/29/how-to-tell-if-your-xbox-garbage-collection-is-too-slow.aspx

 

  • override void Update(GameTime gameTime)

Hvis kameraet vårt skal følge avateren kan vi oppdatere posisjonen til kameraet her.

 

  • public override void Draw(GameTime gameTime)

Her tegner vi avataren vår på skjermen:

 

if (avatar != null)

      {

          Matrix[] transforms = new Matrix[avatar.Bones.Count];

          avatar.CopyAbsoluteBoneTransformsTo(transforms);

 

          foreach (ModelMesh mesh in avatar.Meshes)

          {

              foreach (BasicEffect effect in mesh.Effects)

              {

                  effect.TextureEnabled = true;

                  effect.Texture = warlockTexture;

                  effect.EnableDefaultLighting();

 

                   if (camera != null)

                   {

                       effect.View = camera.View;

                       effect.Projection = camera.Projection;

                   }

          

                   effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateTranslation(position);

               }

               mesh.Draw();

          }

}

 

 

Hvordan snakker XNA med mine game components?

 

For at XNA skal kalle opp funksjonene våre som Draw() og Update(), må vi legge dem til "Components" listen i "Game" objektet, som her:

 

    public class Game1 : Microsoft.Xna.Framework.Game

    {

        protected override void Initialize()

        {

            this.Components.Add(new Camera(this));

            base.Initialize();

        }

         

      .....

 

Game objektet er det bare et av.

"Game" inneholder bl.a. "Game components" og "Services".

 

Her lager vi objektet med det samme, så konstruktøren til "Camera" blir kalt opp først, sammen med klassens lokale variabler.

Etter base.Initialize(); vil XNA gå gjennom alle initialize funksjonene i komponentene vi har lagt til.

I en DrawableGameComponent vil LoadGraphicsContent() kalles opp med det samme vi kaller opp base.Initialize(); .

 

Det kan noen ganger være uklart i hvilken rekkefølge dette skjer og hvilke game components som blir Initiert/Oppdatert eller Tegnet først. Det beste er da å debugge og gå gjennom programmet linje for linje. Det er viktig å vite så du ikke gjør tings som å bruke et uinitialisert objekt. Derfor er det lurt å sjekke om Texture objekter o.l som brukes i  protected override void Draw(GameTime gameTime) er null.

 

Du kan bruke this.UpdateOrder i komponentene for å bestemme hvem som skal oppdateres først. Komponenten med laveste verdi oppdateres først.

 

Så da er det bare å sette i gang og bygge game components! J

Lykke til.

 

NB! Her er noen linker (på engelsk) som også forteller om XNA Game Components:

 

http://www.xnaresources.com/pages.asp?pageid=20

http://www.nuclex.org/articles/xna-gamecomponents-and-gameservices

 

Comments

 

Diaboli said:

Hadde satt pris på om du også kunne vise til hvordan man skriver Interface-delen

ellers lurer jeg også på hvordan et gamecomponent kan lage et annet gamecomponent?

januar 21, 2008 9:46
 

Diaboli said:

Det siste der var et dumt spørsmål.... et klart bevis på at for lite mat + å være sliten har negative effekter på evnen til kognitiv tenking...

januar 21, 2008 11:49
 

raymond said:

Hei!

Jo, ideen ar at du lager et interface av en game component, som f. eks et kamera. I dette interfacet definerer du properties/methods du vil skal være tilgjengelig for andre game components.

Et hot tips er å gå i class designeren, så kan du velge game component klassen din og velge "extract interface". Jeg skal snart lage en serie med tutorials  hvor jeg beskriver alt dette på detaljnivå :)

februar 13, 2008 7:09