XNA之RPG游戏开发教程之四

继续上一节,今天主要是要完成游戏中地图的绘制;这里将会用到tiling方法,通过拼图的方式绘制整幅地图。任务如下:搭建有关Tile engine的整体架构

第一步就是把我们游戏中要用到的Tile下载下来,并添加到EyesOfTheDragonContent中去,下载地址: http://xnagpa.net/xna4/downloads/tilesets.zip

我们这里使用的Tile引擎是最简单的一种,是分层拼图引擎,很好理解,将地图上的精灵分层绘制,不同层次有不同的精灵元素。在XRpgLibrary下添加一个新的文件夹TileEngine,添加Engine类如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
namespace XRpgLibrary.TileEngine
{
public class Engine
 {
 #region Field Region
static int tileWidth;//屏幕宽度方向上tile的个数
static int tileHeight;//屏幕高度方向上tile的个数 #endregion #region Property Region//这两个属性的对外接口 public static int TileWidth { get { return tileWidth; } } public static int TileHeight { get { return tileHeight; } } #endregion #region Constructors public Engine(int tileWidth, int tileHeight) { Engine.tileWidth = tileWidth; Engine.tileHeight = tileHeight; } #endregion #region Methods//获取一个向量在tile矩阵中的位置 public static Point VectorToCell(Vector2 position) { return new Point((int)position.X / tileWidth, (int)position.Y / tileHeight); } #endregion } }

地图上的tile当然不是一个,我们要构建一个tileset类来对一个tile集合进行管理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace XRpgLibrary.TileEngine
{
public class Tileset
 {
 #region Fields and PropertiesTexture2D image;
int tileWidthInPixels;//图片中一个tile的宽度(以像素作为计量)
int tileHeightInPixels;
int tilesWide;//图片宽度方向的tile个数
int tilesHigh;
Rectangle[] sourceRectangles;//图片中每个tile对应矩形的集合数组
 #endregion
 #region Property Region//对外接口
public Texture2D Texture
 {
get { return image; }
private set { image = value; }
 }
public int TileWidth
 {
get { return tileWidthInPixels; }
private set { tileWidthInPixels = value; }
 }
public int TileHeight
 {
get { return tileHeightInPixels; }
private set { tileHeightInPixels = value; }
 }
public int TilesWide
 {
get { return tilesWide; }
private set { tilesWide = value; }
 }
public int TilesHigh
 {
get { return tilesHigh; }
private set { tilesHigh = value; }
 }
public Rectangle[] SourceRectangles
 {
get { return (Rectangle[])sourceRectangles.Clone(); }
 }
 #endregion
 #region Constructor Region
public Tileset(Texture2D image, int tilesWide, int tilesHigh, int tileWidth, int
tileHeight)
 {
 Texture = image;
 TileWidth = tileWidth;
 TileHeight = tileHeight;
 TilesWide = tilesWide;
 TilesHigh = tilesHigh;
int tiles = tilesWide * tilesHigh;
 sourceRectangles = new Rectangle[tiles];
int tile = 0;
//初始化图片中tile所对应的矩形区域
for (int y = 0; y < tilesHigh; y++) for (int x = 0; x < tilesWide; x++) { sourceRectangles[tile] = new Rectangle( x * tileWidth, y * tileHeight, tileWidth, tileHeight); tile++; } } #endregion #region Method Region #endregion } }

以上代码可以看出,对于tile对象的管理是通过其在tileset中的索引来实现的,为了更好的管理tile,同时也为实现多层的map,构建以tile类来对其信息进行管理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XRpgLibrary.TileEngine{
public class Tile
 {
 #region Field Region
 int tileIndex;//tile在当前集合中的索引
 int tileset;//tile所在集合的索引
 #endregion
 #region Property Region
public int TileIndex
 {
  get { return tileIndex; }
  private set { tileIndex = value; }
 }
public int Tileset
 {
  get { return tileset; }
  private set { tileset = value; }
 }
 #endregion
 #region Constructor Region
public Tile(int tileIndex, int tileset)
 {
  TileIndex = tileIndex;
  Tileset = tileset;
 }
 #endregion
 }
}

下面构建一个地图层级类,来管理每一层地图的绘制,代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace XRpgLibrary.TileEngine
{
public class MapLayer
 {
 #region Field Region
 Tile[,] map;//Tile类型的数组,用于存储一层中所有Tile对象
 #endregion
 #region Property Region
public int Width
 {
get { return map.GetLength(1); }//获得地图的宽
 }
public int Height
 {
get { return map.GetLength(0); }//获得地图的高
 }
 #endregion
 #region Constructor Region//用tile数组对象来初始化地图层对象
public MapLayer(Tile[,] map)
 {
this.map = (Tile[,])map.Clone();
 }
//用宽,高来初始化一层地图对象
public MapLayer(int width, int height) { map = new Tile[height, width]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { map[y, x] = new Tile(0, 0);//地图中的每个对象都初始化为第0个tileset集合中的第0个tile } } } #endregion #region Method Region//对外接口 public Tile GetTile(int x, int y) { return map[y, x]; } public void SetTile(int x, int y, Tile tile) { map[y, x] = tile; } public void SetTile(int x, int y, int tileIndex, int tileset) { map[y, x] = new Tile(tileIndex, tileset); } #endregion } }

紧接着就是构造TileMap类,这也是整个地图机制中的核心类,绘制地图的主要逻辑实现都在该类中,先看代码吧

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace XRpgLibrary.TileEngine
{
public class TileMap
 {
 #region Field Region
List<Tileset> tilesets;//tile集合队列
List<MapLayer> mapLayers;//地图层级队列
 #endregion
 #region Property Region
 #endregion
 #region Constructor Region//构造函数
public TileMap(List<Tileset> tilesets, List<MapLayer> layers)
 {
this.tilesets = tilesets;
this.mapLayers = layers;
 }public TileMap(Tileset tileset, MapLayer layer)
 {
 tilesets = new List<Tileset>();
 tilesets.Add(tileset);
 mapLayers = new List<MapLayer>();
 mapLayers.Add(layer);
 }
 #endregion
 #region Method Region
//地图绘制 public void Draw(SpriteBatch spriteBatch) {
//根据Engine对象初始化一个绘制矩形区域 Rectangle destination
= new Rectangle(0, 0, Engine.TileWidth, Engine.TileHeight); Tile tile;
//最外层的是地图层级的遍历
foreach (MapLayer layer in mapLayers) {
//对该层地图上的每个tile进行遍历,绘制
for (int y = 0; y < layer.Height; y++) { destination.Y = y * Engine.TileHeight; for (int x = 0; x < layer.Width; x++) { tile = layer.GetTile(x, y); destination.X = x * Engine.TileWidth; spriteBatch.Draw( tilesets[tile.Tileset].Texture, destination, tilesets[tile.Tileset].SourceRectangles[tile.TileIndex], Color.White); } } } } #endregion } }

最后一步就是要将地图的绘制到GamePlayScreen页面上,该页面代码更改如下

#region Field Region
Engine engine = new Engine(32, 32);
Tileset tileset;
TileMap map;
#endregion

先添加几个类级变量,接下来要在LoadContent方法中加载绘制地图要用的相关对象

protected override void LoadContent()
{ 
 Texture2D tilesetTexture = Game.Content.Load<Texture2D>(@"Tilesets\tileset1");
 tileset = new Tileset(tilesetTexture, 8, 8, 32, 32);
 MapLayer layer = new MapLayer(40, 40);
for (int y = 0; y < layer.Height; y++)
 {
for (int x = 0; x < layer.Width; x++)
 {
 Tile tile = new Tile(0, 0);
 layer.SetTile(x, y, tile);
 }
 }
 map = new TileMap(tileset, layer);
base.LoadContent();
}

最后是绘制地图

public override void Draw(GameTime gameTime)
{
 GameRef.SpriteBatch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.PointClamp,
null,
null,
null,
Matrix.Identity);
 map.Draw(GameRef.SpriteBatch);
base.Draw(gameTime);
 GameRef.SpriteBatch.End();
}

posted on 2013-04-04 14:46  翠竹林  阅读(1170)  评论(0编辑  收藏  举报

导航