Freestyle Coding

Programming in the Real World

  Home  |   Contact  |   Syndication    |   Login
  55 Posts | 0 Stories | 41 Comments | 0 Trackbacks

News

Tag Cloud


Archives

Post Categories

Charity

Conferences

Professional

Projects

Social Networks

Welcome to our first XNA column. As time goes on, I'm completely open for suggestions on columns.

Today, I want to talk about our old friend, the Viewport. In informal terms, the viewport is a canvas that is painted to the screen. For example, if you're playing a game in 4 player split-screen, you'd probably give each player a viewport. Then, you could "paste" the 4 viewports on the screen.

For game development purposes, the historical significance of Super Mario Bros. was the birth of the true side scrolling games. Nintendo was able to make a huge game by creatively reusing a few assets. Look at a video of world 1-1 and count the distinct sprites. Use a few pointers and arrays; make a huge world with almost no resourses.

The magic was this same idea. Use a huge world and move the viewport. We can do something similar to this in XNA. We begin with a simple game class, and a few sprites (Player and Tile.) I'm omitting the code because it is completely trivial.

Now, we need to place the player in the center of the viewport.

Vector2 _PlayerPosition = new Vector2(
( GraphicsDevice.Viewport.X + ( GraphicsDevice.Viewport.Width / 2 ) ) - ( Player.Width / 2 ),
( GraphicsDevice.Viewport.Y + ( GraphicsDevice.Viewport.Height / 2 ) ) - ( Player.Height / 2 ) );

spriteBatch.Draw( Player, _PlayerPosition, Color.White );

Now, I want to world to move around the player. To do this, I need to compose the world in some fashion. If you were doing this in the "Nintendo" way, you would have a 2D array with a pointers to the sprites that compose the world. I'll let you do that. For the sake of ease, I'm just going to loop out a default world. I'll get to this in a minute.

Before we paste out the world, we need to know which part of the world we care about. Traditionally, we would take user input and move the position of the player accordingly. However, we want to move the world around a fixed player. To do this, I keep track of the top-left corner of the world. Then, I move this offset to the world.

protected int Speed = 5;
protected Vector2 WorldOffset = Vector2.Zero;
protected override void Update( GameTime gameTime ) {
foreach( Keys _Key in Keyboard.GetState().GetPressedKeys() ) {
switch( _Key ) {
case Keys.Escape:
this.Exit();
break;
case Keys.Right:
WorldOffset.X -= Speed;
break;
case Keys.Left:
WorldOffset.X += Speed;
break;
case Keys.Up:
WorldOffset.Y += Speed;
break;
case Keys.Down:
WorldOffset.Y -= Speed;
break;
default:
break;
}
}
base.Update( gameTime );
}

The more astute of you probably noticed that my pluses and minuses are backwards from the traditional use. This is because I'm moving the world behind the player, not the player on top of the world. Now, I can loop out out world and offset everything based on the part we care about.

const int TILE_WITDH_COUNT = 256;
const int TILE_HEIGHT_COUNT = 256;
for( int _x = 0; _x < TILE_WITDH_COUNT; ++_x ) {
for( int _y = 0; _y < TILE_HEIGHT_COUNT; ++_y ) {
Vector2 _TilePosition = new Vector2( Tile.Width * _x, Tile.Height * _y );
spriteBatch.Draw( Tile, _TilePosition + WorldOffset, new Color( _x, 0, _y, 255 ) );
}
}

Of course, this pastes out the whole world. A little math would make sure you only render out the parts people will actually see. I had to leave something for you to do...

posted on Friday, June 17, 2011 8:24 PM