Monday, October 13, 2008

XNA Part 5 - Game Object Class

Up until now we have had our sprite be a simple Texture2D object with its position property as a separate Vector2 object. To simplify our coding, we are going to create another class to handle our in game items. First right click on your "Project" in the solution explorer and click add -> Class. Name this class GameObject. A new class will be created in your project within your namespace. You will however want to replace the block of using statements at the top of your new class file with the ones from the Game1.cs file.

Within the class GameObject we will define our basic class members.

class GameObject
{
Texture2D sprite;
Vector2 position;
float rotation;
Color tint;
}

Each game object will contain a Texture2D to hold its image, a position, a rotation and a tint color.

Now for some basic C#. We need to create a constructor to initialize our object;

public GameObject(Texture2D content)
{
sprint = content;
position = Vector2.Zero;
rotation = 0.0f;
tint = Color.White;
}

Our constructor will take a parameter of type Texture2D and we set sprite to it, and then we initialize our other parameters to good basic values;

Now I will add some properties to let the client code update and access our variables.
public Texture2D Sprite
{
get { return sprite; }
set { sprite = value; }
}
public Vector2 Position
{
get { return position; }
}
public float X
{
get { return position.X; }
set { position.X = value; }
}
public float Y
{
get { return position.Y; }
set { position.Y = value; }
}
public float Rotation
{
get { return rotation; }
set { rotation = value; }
}
public Color Tint
{
get { return tint; }
set { tint = value; }
}

Now back in our game code I remove the alien Texture2D object and the position object. and in it's place add

GameObject alien;

I remove the position setting line from Initialize and the change the loading line in LoadContent to the following

alien = new GameObject(Content.Load("sprites\\alien"));

Which creates a reference to a new gameobject passing it a reference to the Texture2D created by the Content.Load call.

In update, I change my references to alien to the following

if (state.IsKeyDown(Keys.Left)) { alien.X -= 5; }
if (state.IsKeyDown(Keys.Right)){ alien.X += 5; }
if (state.IsKeyDown(Keys.Up)) { alien.Y -= 5; }
if (state.IsKeyDown(Keys.Down)) { alien.Y += 5; }

and my draw call to the following

spriteBatch.Draw(alien.Sprite, alien.Position, alien.Tint);

so now all the parameters in the draw call come from an existing object rather than being hard coded into the draw call.

Just for fun, we will return to the update method and add the following check

if (state.IsKeyDown(Keys.Space)){ alien.Rotation += 0.1f; }

and change our draw call to this overloaded method

spriteBatch.Draw(alien.Sprite,
alien.Position,
null,
alien.Tint,
alien.Rotation,
new Vector2(0,0),
1,
SpriteEffects.None,
0);

Which gives 9 parameters rather than 3.
  • The Texture2D,
  • the position,
  • the null is a placeholder for a parameters we are not using at the moment,
  • the tint,
  • the rotation,
  • the "origin" of the texture or point of rotation/position,
  • the scale of the object (how big to draw it),
  • the spriteeffect (if we want to flip the image)
  • the depth to draw the image
Now when you run your program, if you press the spacebar, your image will rotate.

Here is the code from the game file:



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 TutorialGame
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

GameObject alien;

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

protected override void Initialize()
{

base.Initialize();
}

protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
alien = new GameObject(Content.Load
("sprites\\alien"));
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

KeyboardState state = Keyboard.GetState();

if (state.IsKeyDown(Keys.Left)) { alien.X -= 5; }
if (state.IsKeyDown(Keys.Right)){ alien.X += 5; }
if (state.IsKeyDown(Keys.Up)) { alien.Y -= 5; }
if (state.IsKeyDown(Keys.Down)) { alien.Y += 5; }
if (state.IsKeyDown(Keys.Space)){ alien.Rotation += 0.1f; }

base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(alien.Sprite,
alien.Position,
null,
alien.Tint,
alien.Rotation,
new Vector2(0,0),
1,
SpriteEffects.None,
0);
spriteBatch.End();
base.Draw(gameTime);
}
}
}



and the code from the GameObject File (I've made it a little bigger this time):

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 TutorialGame
{
class GameObject
{
Texture2D sprite;
Vector2 position;
float rotation;
Color tint;

public GameObject(Texture2D content)
{
sprite = content;
position = Vector2.Zero;
rotation = 0.0f;
tint = Color.White;
}

public Texture2D Sprite
{
get { return sprite; }
set { sprite = value; }
}
public Vector2 Position
{
get { return position; }
}
public float X
{
get { return position.X; }
set { position.X = value; }
}
public float Y
{
get { return position.Y; }
set { position.Y = value; }
}
public float Rotation
{
get { return rotation; }
set { rotation = value; }
}
public Color Tint
{
get { return tint; }
set { tint = value; }
}

}
}

2 comments:

Anonymous said...

Just a small typo ... in your article's constructor you're setting the variable "sprint" as opposed to "sprite"

It's not a huge deal and is corrected in the "full code" dump, but just thought I'd mention it.

Unknown said...

"sprint = content;"