使用Game Studio Express和XNA創建一個Tile引擎--beta2版

介紹

這個指南將指引我們一步步的通過使用Game Studio Express Beta2來創建一個簡單的基於貼片(tile)的引擎。這個引擎與那些以前的舊型RPG遊戲很相似。但是稍微比那些強一點(包括美工能力,因爲我的貼片(tile)實在太糟糕了!)你可以使用GSEgame studio express,以後簡稱GSE)很快捷的裝配一個比那些好看了多的貼片。

我要創建的引擎是一個基於正方形-貼片(square-tile)的系統。我打算在不久之後再推出一個製作基於等尺寸貼片(isometric tile)的引擎的教程。

概念

在這個指南當中,我們將要製作一個簡單的基於貼片的引擎。要開始工作,首先我們需要:

l         一個用來顯示貼片的地圖網格

l         一個“貼片集”(“Tile Set”),就是一個正方圖形,可以繪製在地圖上來表示玩家的位置。

創建工程

打開Game Studio Express Beta然後創建一個類型爲”Windows Game(XNA)”的新工程。別忘了爲你的工程起一個名字。儘管在指南I中我依然使用Game1.cs這個文件名,但是我建議大家不要使用默認的”Game1.cs”這個文件名。基本的”Windows Game(XNA)”模版包含了一個Graphics對象和一個代表你的遊戲的叫做Game1.cs的類。Game1.cs中的代碼包含如下五個重要的方法:

l         Initialize在遊戲啓動的時候執行。在這個函數裏你可以在你的遊戲啓動的時候註冊你的遊戲組件和其他的東西。

l         LoadGraphicsContent – 也是在遊戲啓動的時候執行,但是在遊戲丟失顯示焦點以後,需要重新加載非自動管理素材(content)時,還會再次執行。

l         UnloadGraphicsContent – 在遊戲退出時調用他來釋放素材(content)

l         Update – 這個函數在一個連續循環中不斷執行,你可以在這裏添加你的遊戲邏輯。而且在這裏你可以接收玩家的輸入信息,更新遊戲中物體的位置,等等。

l         Draw – 最後,Draw方法負責來渲染當前遊戲的場景狀態到屏幕。系統會盡其所能的不斷執行這個函數(翻譯的不大好,其實原句的意思就是系統會儘可能多的調用這個函數來獲得更好的顯示效果,即幀頻更高)。

創建我們的資源

在創建我們的引擎之前,我們需要一些用於顯示的貼片。我簡單的縮放了一些從The TextureBin 網站找到的紋理圖來製作了一些貼片。那些擁有繪畫才能的天才們可以自己繪製更漂亮的貼片集。創建的貼片每個與每個之間必須連接的很平滑,這也是相當重要的。

好了,下面就是我爲這個指南快速“創建”的貼片

                                           

(grass)              (Road)           石頭(Rock)       (water)

你可以下載並保存這些圖片到你的機器上供自己使用。在這個引擎例子種,我設置貼片的大小爲48×48像素。所有貼片集中的貼片(本引擎中)都必須是這個尺寸。

 

向工程中添加資源

爲了讓我們的遊戲能夠訪問這些資源,我們需要把他們添加到工程中去。因爲我們還沒有對這些精靈(sprites)設置透明,我們可以將他們仍舊保存爲.JPG文件。DirectX Texture Tool能夠用來創建帶有alpha通道的紋理。我們將在後續的課程講到如何在地圖中添加一個圖形來表示玩家的時候,講解如何使用DierctX Texture Tool

對於Beta 2版本,我們將使用素材管道來管理我們的圖形素材。素材管道能讓我們的資源變成一種既能在windows上也能在Xbox上使用的格式。

在解決方案資源管理器中用鼠標右鍵點擊你的工程的名字,然後選擇添加->新建文件夾。將文件夾命名爲”Content”。鼠標右鍵點擊Content文件夾,然後再一次選擇添加->新建文件夾。這次我們給新建的文件夾起名叫”Textures”

現在,使用Windows ExplorerWindows資源管理器)複製你的圖形資源到Textures文件夾下。當你做好這一切以後,Conternt/Textures文件夾下應該有4個後綴名爲.JPG文件。

回到Visual C#編譯器,然後右擊Texures文件夾然後選擇添加->現有項”,在出現的對話框中,選中這些貼片文件(你可能需要改變文件類型爲images以後纔可以看到他們譯註:使用images可能也不能看到,我在我的機器上發現images裏沒有支持jpg文件格式,所以應該選擇”all files”所有文件類型才能看到)然後點擊確定。素材管道將給我們每一個資源分配一個資源名。(在解決方案資源管理器下面的屬性窗口中可以看到)首先,我們要把我們的圖形設置爲始終複製,這樣他們就能夠在程序運行時可以被訪問到。素材管道知道如何來操作這些素材。

聲明變量

首先第一件我們需要做的事就是聲明一些我們將在遊戲中表示我們遊戲中物體的變量。既然這樣,我們需要一個地圖,繪製貼片的精靈,還有一些在DrawUpdate中操作遊戲狀態的控制變量。

在解決方案資源管理器中右鍵單擊Game1.cs然後選擇查看代碼。找到構造函數(Public Game1())然後將下面的代碼複製到構造函數結束大括號的後面(譯註:即在構造函數的兩個大括號外面,千萬不要放到構造函數內部了)(這些變量在所有的方法之外,所以他們可以被類中的所有方法訪問)

        // An array of "Texture2D" objects to hold our Tile Set

        Texture2D[] t2dTiles = new Texture2D[4];

        const int iMapWidth = 20;

        const int iMapHeight = 20;

        // Our simple integer-array based map

        int[,] iMap = new int[iMapHeight,iMapWidth] {

                             { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},

                             { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        };

        // Variable we will need for Keyboard Input

        KeyboardState ksKeyboardState;

        //Map coordinates for upper left corner

        int iMapX = 0;

        int iMapY = 0;

        // How far from the Upper Left corner of the display do we want our map to start

        int iMapDisplayOffsetX = 30;

        int iMapDisplayOffsetY = 30;

        // How many tiles should we display at a time

        int iMapDisplayWidth = 6;

        int iMapDisplayHeight = 6;

        // The size of an individual tile in pixels

        int iTileWidth = 48;

        int iTileHeight = 48;

        // How rapidly do we want the map to scroll?

        float fKeyPressCheckDelay = 0.25f;

        float fTotalElapsedTime=0;

        //this is the object that will draw the sprites

        SpriteBatch spriteBatch;

這裏的變量有不少,我來一步一步的講解:

        // An array of "Texture2D" objects to hold our Tile Set

        Texture2D[] t2dTiles = new Texture2D[4];

這裏聲明瞭一個名字爲t2dTiles的“Texture2D”類型的對象的數組,我們在引擎中定義了4個文件。這個對象數組爲精靈保存位圖數據,這個精靈將用於貼片集。

        const int iMapWidth = 20;

        const int iMapHeight = 20;

        // Our simple integer-array based map

        int[,] iMap = new int[iMapHeight,iMapWidth] {

                             { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},

                             { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

                             { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        };

這是個非常簡化的遊戲地圖的表示。我們定義了這個地圖的尺寸爲2020個貼片(通過iMapWidthiMapHeight常量),然後簡單的聲明瞭一個表示地圖數組。一個更加真實的系統應該是從外部讀取地圖數據的,或者是一個使用地圖編輯器製作的固定的資源。不過對於這個指南來說,這已經足夠了。數組的元素數目即地圖中貼片的數目。

        // Variable we will need for Keyboard Input

        KeyboardState ksKeyboardState;

當我們在後續教程中允許玩家按下鍵盤上的某鍵來進行移動的時候,我們會需要這個變量的。

        //Map coordinates for upper left corner

        int iMapX = 0;

        int iMapY = 0;

        // How far from the Upper Left corner of the display do we want our map to start

        int iMapDisplayOffsetX = 30;

        int iMapDisplayOffsetY = 30;

        // How many tiles should we display at a time

        int iMapDisplayWidth = 6;

        int iMapDisplayHeight = 6;

        // The size of an individual tile in pixels

        int iTileWidth = 48;

        int iTileHeight = 48;

這裏應該沒有仔細解釋的必要了吧。這些變量將在Draw方法中用來確定如何複製精靈來顯示。

        // How rapidly do we want the map to scroll?

        float fKeyPressCheckDelay = 0.25f;

        float fTotalElapsedTime=0;

這些變量用於控制地圖要多快的響應用戶的輸入。我們不需要一點點的漫步,當玩家按下一個鍵然後地圖應該快速向玩家指定的那個方向移動,應該和Update函數的調用一樣快。

        //this is the object that will draw the sprites

        SpriteBatch spriteBatch;

最後我們需要一個在Draw方法內使用的SpriteBatch對象。SpriteBatch負責複製精靈變量中的貼片到顯示緩存中。

加載資源

我們工程的默認框架中爲我們創建了”LoadGraphicsContent”方法,而且會在遊戲啓動時自動調用。要加載我們的素材,使用下面的代碼:

   protected override void LoadGraphicsContent(bool loadAllContent)

        {

            if (loadAllContent)

            {

                // TODO: Load any ResourceManagementMode.Automatic content

                t2dTiles[0] = content.Load<Texture2D>(@"content/textures/tilemap_tut_grass");

                t2dTiles[1] = content.Load<Texture2D>(@"content/textures/tilemap_tut_water");

                t2dTiles[2] = content.Load<Texture2D>(@"content/textures/tilemap_tut_road");

                t2dTiles[3] = content.Load<Texture2D>(@"content/textures/tilemap_tut_rock");

                spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

            }

            // TODO: Load any ResourceManagementMode.Manual content

        }

如果loadAllContent爲真,我們就應該加載所有(表示我們是在遊戲啓動的第一次調用這個函數)。如果不爲真,那麼就只需要加載我們手動控制的資源。我們將管理這些資源的工作交給XNA來作,所以我們只需要調用他們一次就夠了。

注意我們沒有在紋理文件的後面加上擴展名。這是因爲素材管道自動分配了一個名字給每個資源,默認是這個文件的去掉擴展名的文件名,由於素材管道的作用實際上我們這裏並不是直接操作的文件。

繪製地圖

如果你現在編譯並執行你的工程,你將只會得到一個默認的藍色窗口,因爲我們還沒有對兩個遊戲循環函數做任何修改。將Draw方法修改爲:

        protected override void Draw(GameTime gameTime)

        {

            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

 

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

            // Draw the map

            for (int y = 0; y < iMapDisplayHeight; y++)

            {

                for (int x = 0; x < iMapDisplayWidth; x++)

                {

                    spriteBatch.Draw(t2dTiles[iMap[y + iMapY, x + iMapX]],

                                     new Rectangle((x * iTileWidth) + iMapDisplayOffsetX,

                                     y * iTileHeight + iMapDisplayOffsetY, iTileWidth, iTileHeight),

                                     Color.White);

                }

            }

            spriteBatch.End();

            base.Draw(gameTime);

        }

這裏是我們地圖引擎的核心,所以我們將一行一行的解釋。所有我們的繪製工作都是在BeginScene()EndScene()函數的中間進行的。

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

通知spriteBact對象,我們將要開始繪製精靈。使用”SpriteBlendMode.AlphaBlend”可以保證spriteBatch在繪製時將帶有alpha通道(透明)。我們在地圖最初的顯示時並不是用alpha通道,等到我們講到對象(也就是,玩家)在地圖上的遮蓋效果時就會有用處了。

            // Draw the map

            for (int y = 0; y < iMapDisplayHeight; y++)

            {

                for (int x = 0; x < iMapDisplayWidth; x++)

                {

                    spriteBatch.Draw(t2dTiles[iMap[y + iMapY, x + iMapX]],

                                     new Rectangle((x * iTileWidth) + iMapDisplayOffsetX,

                                     y * iTileHeight + iMapDisplayOffsetY, iTileWidth, iTileHeight),

                                     Color.White);

                }

            }

在這裏我們實際上繪製了所有組成這個地圖的精靈。我們設置了兩個for循環,一個用於Y軸,一個用於X,iMapDisplayHeightiMapDisplayWidth變量決定了總共要繪製的貼片的數目。

我們調用spriteBatch.Draw方法來實際繪製一個精靈到顯示緩存中。SpriteBatch.Draw函數的第一個參數是我們要繪製的精靈。我們通過iMap數組找到要繪製的精靈是哪一個。我們將從這個數組中得到一個03之間的數字,這正好對應與我們儲存在貼片集中的貼片。

第二個參數是一個也矩形對象,這個矩形對象用於表示我們要在顯示緩存的哪裏顯示。我們使用了循環計數值,貼片的寬度,還有DisplayOffset變量來創建這個矩形。

最後,第三個參數爲繪製精靈時的色調(tinting),我們並不是用色調,所以指定Color.White值就可以了。

            spriteBatch.End();

在所有工作完成以後,我們結束這段批處理。

 

           base.Draw(gameTime);

        }

這裏只是簡單的調用基類的Draw方法。運行這個工程,你可以看到一個地圖,這個地圖將顯示在窗口的左上角的(30,30)座標處(單位是像素) ,地圖的高和寬爲6個貼片。

處理玩家的輸入

現在我們可以繪製地圖了,我們應該允許玩家按下方向鍵來移動。爲了實現這個,我們需要修改Update方法來監測鍵盤的輸入。

Update方法替換爲:

        protected override void Update(GameTime gameTime)

        {

            // Allows the default game to exit on Xbox 360 and Windows

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)

                this.Exit();

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            fTotalElapsedTime += elapsed;

            ksKeyboardState = Keyboard.GetState();

            if (ksKeyboardState.IsKeyDown(Keys.Escape))

            {

                this.Exit();

            }

 

            // See if enough time has elapsed since we last moved on the map.

            if (fTotalElapsedTime >= fKeyPressCheckDelay)

            {

                if (ksKeyboardState.IsKeyDown(Keys.Up))

                {

                    iMapY--;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Down))

                {

                    iMapY++;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Left))

                {

                    iMapX--;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Right))

                {

                    iMapX++;

                    fTotalElapsedTime = 0.0f;

                }

                if (iMapX < 0) { iMapX = 0; }

                if (iMapX > iMapWidth - iMapDisplayWidth) { iMapX = iMapWidth - iMapDisplayWidth; }

                if (iMapY < 0) { iMapY = 0; }

                if (iMapY > iMapHeight - iMapDisplayHeight) { iMapY = iMapHeight - iMapDisplayHeight; }

            }

            base.Update(gameTime);

        }

還是和以前一樣,這裏有很多代碼,我們一步一步的講解:

            // Allows the default game to exit on Xbox 360 and Windows

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)

                this.Exit();

這一部分是默認的模版自動生成的。如果玩家按下xbox 360控制器上的”Back”鍵,遊戲就會退出。

            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            fTotalElapsedTime += elapsed;

這裏允許我們累計程序已經運行的時間,並將時間保存在一個名爲elapsed的浮點變量中,我們可以使用這個變量來決定地圖移動的速度。

            ksKeyboardState = Keyboard.GetState();

這裏,我們獲得當前的鍵盤狀態信息,並將這個信息保存在一個變量中,這個變量將用來檢測玩家按下的鍵。

            if (ksKeyboardState.IsKeyDown(Keys.Escape))

            {

                this.Exit();

            }

爲了方便,如果Escape被按下,那麼就退出程序。很明顯你不希望在一個真實的程序中這樣做(因爲玩家可能會不小心按倒)。你可以彈出一個退出確認對話框來避免這種狀況。

            // See if enough time has elapsed since we last moved on the map.

            if (fTotalElapsedTime >= fKeyPressCheckDelay)

            {

在我們檢查玩家是否按下了移動鍵之前,我們需要首先檢查一下是否已經滿足了最小地圖滾動間隔時間(minimum map scroll time)(我將默認設置爲0.25)。如果我們沒有加入這行代碼的話,地圖將會滾動的非常快。

                if (ksKeyboardState.IsKeyDown(Keys.Up))

                {

                    iMapY--;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Down))

                {

                    iMapY++;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Left))

                {

                    iMapX--;

                    fTotalElapsedTime = 0.0f;

                }

                if (ksKeyboardState.IsKeyDown(Keys.Right))

                {

                    iMapX++;

                    fTotalElapsedTime = 0.0f;

                }

如果任意一個方向鍵被按下了,那麼就通過更新X/Y座標來讓地圖向那個方向移動。

                if (iMapX < 0) { iMapX = 0; }

                if (iMapX > iMapWidth - iMapDisplayWidth) { iMapX = iMapWidth - iMapDisplayWidth; }

                if (iMapY < 0) { iMapY = 0; }

                if (iMapY > iMapHeight - iMapDisplayHeight) { iMapY = iMapHeight - iMapDisplayHeight; }

最後,我們檢測是否XY的座標已經超出了地圖,如果是的話則將座標維持在邊界。

總結

到現在爲止,你應該已經有了一個基於貼片的地圖了。

然而,還有很多的事情我們還沒有做,這個簡單的系統還可以繼續增強其功能。在接下來的指南里我們將可能實現以下的功能:

l         爲玩家增加一個”avatar”。這應該是一個通過alpha混合繪製在地圖中央的精靈動畫。

l         通過記錄獨立的貼片的偏移來使地圖移動的更平滑。當移動鍵被按下時調整少量的繪製位置,而不是以一個貼片爲移動量。注意你可能希望調整fKeyPressCheckDelay來改變你移動速度慢了48倍的事實,

l         在地圖的四周製作一個界面,也許會用角色的狀態等等。

l         供選擇的,設置iMapDisplayOffsetXiMapDisplayOffSetY0並且設置iMapDisplayWidth14iMapDisplayHeight10,這樣地圖將成爲一個640480的窗口。

當然,你也可以期望使用這個實際的系統來製作一個遊戲。

 

譯者czhou的聯繫方式:[email protected]m

  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章