XNA 地圖編輯器(下)

  • 5813
  • 0

在上個範例中我們利用地圖編輯器完成了地圖的製作並把它存成文字檔,現在要把這個文字檔透過自建的內容管道(Content Pipeline extension library)載入到我們的專案裡,並且利用自建的Map類別將地圖繪出。

在上個範例中我們利用地圖編輯器完成了地圖的製作並把它存成文字檔,現在要把這個文字檔透過自建的內容管道(Content Pipeline extension library)載入到我們的專案裡,並且利用自建的Map類別將地圖繪出。

 

先將地圖分割圖(Tile Sheet)跟地圖文字檔加入專案。

image

 

為了載入文字檔,然後可以用 Content.Load()的方式載入,所以我們需要建立一個新的內容管道擴充專案,包含Importer跟Processor,用來匯入跟處理文字檔,步驟如下:

對著解決方案按右鍵>新增>新專案。

image

 

選擇內容管道擴充庫。

image

 

新增完畢後會多出一個專案,此專案下會有一個ContentProcessor1類別

image

 

專案裡已經預設有一個Processor類別,還缺一個Importer類別,對著內容管道擴充專案按右鍵,新增項目。

image

 

選擇Content Importer。

image

 

新增完如下圖。

image

 

接著我們要修改Importer跟Processor程式碼,先雙擊ContentImporter1.vb,我們在匯入附檔名屬性設定為 "*.txt",在Import()裡把文字檔讀入的文字傳到Processor裡。

image

 

在修改Processor之前要先做一個重要的步驟,要在ContentPipelineExtension1專案先把MyData.dll參考進去,MyData.dll是我用C#寫的一個類別,此類別是用來溝通遊戲專案跟ContentPipelineExtension1專案。

image

image

 

再來修改Processor程式碼,雙擊ContentProcessor1.vb,TInput就是從Importer傳過來的,TOutput就是要傳過去遊戲專案的MapData物件,而Process()裡我們New一個MapData物件,並把從Importer傳過來的內容放到MapData.text裡,回傳MapData物件。

image

 

修改完Importer跟Processor後建置專案,並在Content專案裡將ContentPipelineExtension1專案參考進來。

image

image

 

點擊Map.txt設定Content Importer跟Content Processor為我們剛剛建立的。

image

 

到這裡我們就完成了前半段工作,接下來我們要開始撰寫Game1的程式碼了,再這之前先將MyData.dll參考進來。

image

 

在Game1類別宣告變數

Public Class Game1
    Inherits Microsoft.Xna.Framework.Game
 
    Private WithEvents graphics As GraphicsDeviceManager
    Private WithEvents spriteBatch As SpriteBatch
 
    Dim width As Integer = 25     '圖片寬 幾格Tile
    Dim height As Integer = 15    '圖片高 幾格Tile
 
    Dim Map As Map                '可以用TileSheet跟地圖文字檔組出地圖
    Dim MapData As New tileLib.MapData  '文字檔內容會存放在MyData.text
    Dim tileSheet As Texture2D          '地圖的來源分割小圖
    Dim tileMap(,) As Integer           '存放小圖Id的陣列
End Class

在LoadContent()載入地圖,MapData = Content.Load(Of tileLib.MapData)("Map"),文字檔已經成功的用Content.Load()方式載入了,感動內。我們將文字檔的內容解析出來傳入Map.tileMap中。

Protected Overrides Sub LoadContent()
        ' Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = New SpriteBatch(GraphicsDevice)
 
        ' TODO: use Me.Content to load your game content here
        tileSheet = Content.Load(Of Texture2D)("TileSheet01")
        MapData = Content.Load(Of tileLib.MapData)("Map")
 
        Map = New Map()
 
        '將文字檔解析並存入陣列
        ReDim tileMap(width - 1, height - 1)
        Dim arr() As String
        arr = MapData.text.Split(ChrW(13))
 
        For j As Integer = 0 To height - 1
            Dim arr2() As String
            arr2 = arr(j).Split(","c)
 
            For i As Integer = 0 To width - 1
                tileMap(i, j) = CInt(arr2(i))
            Next
        Next
 
        Map.tileMap = tileMap
End Sub

 

在Draw()呼叫Map.DrawMap()就可以繪製出地圖了。

Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        GraphicsDevice.Clear(Color.CornflowerBlue)
 
        ' TODO: Add your drawing code here
        Map.DrawMap(spriteBatch, tileSheet)
 
        MyBase.Draw(gameTime)
End Sub

 

程式執行結果如下 (範例下載)

使用地圖編輯器除了可以縮小大地圖的檔案大小,也能很彈性的編輯不同關卡,大家可以用此範例下去自由發揮應用。

screenshot_11-6-2011_23.21.11.754

 

Map類別主要是做一些Tile Sheet分割圖片與地圖文字檔的對應轉換,以下附上程式碼供大家參考。

Class Map
    Dim size As Integer = 32
    Dim width As Integer = 25
    Dim height As Integer = 15
 
    Public tileMap(,) As Integer
 
    Sub New()
        ReDim tileMap(width - 1, height - 1)
 
        For j As Integer = 0 To height - 1
            For i As Integer = 0 To width - 1
                tileMap(i, j) = -1
            Next
        Next
    End Sub
 
    Public Sub DrawMap(spriteBatch As SpriteBatch, tileSheet As Texture2D)
        spriteBatch.Begin()
        For j As Integer = 0 To height - 1
            For i As Integer = 0 To width - 1
                Dim cell As Integer = tileMap(i, j)
                If cell > -1 Then
                    Dim srcBounds As Rectangle = Cell2Position(cell, tileSheet)
                    Dim Bounds As Rectangle = New Rectangle(i * size, j * size, size, size)
 
                    spriteBatch.Draw(tileSheet, Bounds, srcBounds, Color.White)
                End If
            Next
        Next
        spriteBatch.End()
    End Sub
 
    Function Cell2Position(cell As Integer, tileSheet As Texture2D) As Rectangle
        Dim rect As Rectangle
        Dim tileWidth As Integer = CInt(tileSheet.Width / 32)
        Dim j As Integer = CInt(cell \ tileWidth)
        Dim i As Integer = cell Mod tileWidth
 
        rect = New Rectangle(i * size, j * size, size, size)
        Return rect
    End Function
End Class