簡體   English   中英

使用javascript渲染瓷磚地圖

[英]render a tile map using javascript

我正在尋找一個邏輯理解與樣本實現的想法,采取如下這樣的tilemap:

http://thorsummoner.github.io/old-html-tabletop-test/pallete/tilesets/fullmap/scbw_tiles.png

並以這樣的邏輯方式呈現:

http://thorsummoner.github.io/old-html-tabletop-test/

我看到所有的瓷磚都在那里,但我不明白它們是如何以形成形狀的方式放置的。

到目前為止,我對渲染圖塊的理解很簡單,而且非常手動。 循環遍歷地圖數組,其中有數字(1,2,3,無論如何),渲染指定的圖塊。

var mapArray = [
    [0, 0, 0, 0 ,0],
    [0, 1, 0, 0 ,0],
    [0, 0, 0, 0 ,0],
    [0, 0, 0, 0 ,0],
    [0, 0, 1, 1 ,0]
];

function drawMap() {
    background = new createjs.Container();      
    for (var y = 0; y < mapArray.length; y++) {
        for (var x = 0; x < mapArray[y].length; x++) {
            if (parseInt(mapArray[y][x]) == 0) {
                var tile = new createjs.Bitmap('images/tile.png');
            }
            if (parseInt(mapArray[y][x]) == 1) {
                var tile = new createjs.Bitmap('images/tile2.png'); 
            }
            tile.x = x * 28;
            tile.y = y * 28;
            background.addChild(tile);
        }
    }
    stage.addChild(background);     
}   

得到我:

在此輸入圖像描述

但這意味着我必須手動確定每個瓷磚在陣列中的位置,以便形成邏輯形狀(岩層,草地補丁等)

很明顯,上面制作github代碼的人使用了不同的方法。 理解邏輯 (簡單的偽代碼)的任何指導都會非常有用

那里沒有任何邏輯。

如果您檢查頁面的源,您將看到正文中的最后一個腳本標記具有大量的圖塊坐標。

在這個例子中沒有任何魔術可以展示一個“智能”系統來確定如何形成形狀。

現在,那就是說,有這樣的事情......但是它們並不簡單。

更重要的簡單,更易於管理,是一個地圖編輯器。


平鋪編輯

盒子外面:

有很多方法可以做到這一點...有免費或廉價的程序可以讓你繪制瓷磚,然后吐出XML或JSON或CSV或任何給定的程序支持/導出。

Tiledhttp://mapeditor.org )就是這樣一個例子。
還有其他人,但是Tiled是我能想到的第一個,是免費的,而且實際上相當不錯。

優點:
直接的好處是,您可以獲得一個應用程序,可以加載圖像切片,並將它們繪制到地圖中。
這些應用程序甚至可能支持添加碰撞層和實體層(在[2,1]處放置一個敵人,在[3,5]處加電,在熔岩上放置一個“傷害玩家”觸發器)。

缺點: ...缺點是您需要確切地知道這些文件的格式,以便您可以將它們讀入您的游戲引擎。
現在,這些系統的輸出是相對標准化的......所以你可以將地圖數據插入不同的游戲引擎(重點是什么,否則?),而游戲引擎並不都使用完全正確的平鋪文件同樣,大多數優秀的平鋪編輯器允許導出為多種格式(有些可以讓您定義自己的格式)。

...所以說,替代(或真正,相同的解決方案,只是手工制作),將創建自己的瓷磚編輯器。

DIY
你可以在Canvas中創建它,就像創建引擎來繪制tile一樣容易。
關鍵的區別在於你有你的瓷磚地圖(比如來自StarCr的tilemap .png ......呃......來自這個例子的“發現藝術”)。
找到瓷磚的坐標並在與該指數匹配的世界坐標上繪制它們,而不是循環遍歷數組,你要做的是從地圖中選擇一個瓷磚(比如在MS Paint中選擇顏色),然后在哪里單擊(或拖動),找出與之相關的數組點,並將該索引設置為等於該圖塊。

優點:
天空才是極限; 你可以制作任何你想要的東西,使它適合你想要使用的任何文件格式,並讓它處理你想要拋出的任何瘋狂的東西......
缺點:
...當然,這意味着你必須自己制作它,並定義你想要使用的文件格式,並編寫邏輯來處理所有這些想法......

基本實施
雖然我通常會嘗試使這個整潔,並且JS-paradigm友好,這將導致大量的代碼,在這里。
因此,我將嘗試表示它應該分解為單獨的模塊。

// assuming images are already loaded properly
// and have fired onload events, which you've listened for
// so that there are no surprises, when your engine tries to
// paint something that isn't there, yet


// this should all be wrapped in a module that deals with
// loading tile-maps, selecting the tile to "paint" with,
// and generating the data-format for the tile, for you to put into the array
// (or accepting plug-in data-formatters, to do so)
var selected_tile = null,
    selected_tile_map = get_tile_map(), // this would be an image with your tiles
    tile_width  = 64, // in image-pixels, not canvas/screen-pixels
    tile_height = 64, // in image-pixels, not canvas/screen-pixels

    num_tiles_x = selected_tile_map.width  / tile_width,
    num_tiles_y = selected_tile_map.height / tile_height,

    select_tile_num_from_map = function (map_px_X, map_px_Y) {
        // there are *lots* of ways to do this, but keeping it simple
        var tile_y = Math.floor(map_px_Y / tile_height), // 4 = floor(280/64)
            tile_x = Math.floor(map_px_X / tile_width ),

            tile_num = tile_y * num_tiles_x + tile_x;
            // 23 = 4 down * 5 per row + 3 over

        return tile_num;
    };

    // won't go into event-handling and coordinate-normalization
    selected_tile_map.onclick = function (evt) {
        // these are the coordinates of the click,
        //as they relate to the actual image at full scale
        map_x, map_y;
        selected_tile = select_tile_num_from_map(map_x, map_y);
    };

現在你有一個簡單的系統來確定點擊了哪個瓷磚。
同樣,有很多方法可以構建它,你可以使它更多OO,
並制作一個適當的“平鋪”數據結構,您希望在整個引擎中閱讀和使用。

現在,我只是返回從零開始的數字,從左到右,從上到下閱讀。
如果每行有5個圖塊,並且有人選擇第二行的第一個圖塊,那就是圖塊#5。

然后,對於“繪畫”,你只需要聽一下畫布點擊,弄清楚X和Y是什么,弄清楚世界的位置,以及等於的陣列點。
從那里,你只需要轉儲selected_tile的值,這就是它。

// this might be one long array, like I did with the tile-map and the number of the tile
// or it might be an array of arrays: each inner-array would be a "row",
// and the outer array would keep track of how many rows down you are,
// from the top of the world
var world_map = [],

    selected_coordinate = 0,

    world_tile_width  = 64, // these might be in *canvas* pixels, or "world" pixels
    world_tile_height = 64, // this is so you can scale the size of tiles,
                            // or zoom in and out of the map, etc

    world_width  = 320,
    world_height = 320,


    num_world_tiles_x = world_width  / world_tile_width,
    num_world_tiles_y = world_height / world_tile_height,

    get_map_coordinates_from_click = function (world_x, world_y) {
        var coord_x = Math.floor(world_px_x / num_world_tiles_x),
            coord_y = Math.floor(world_px_y / num_world_tiles_y),

            array_coord = coord_y * num_world_tiles_x + coord_x;

        return array_coord;
    },

    set_map_tile = function (index, tile) {
        world_map[index] = tile;
    };

    canvas.onclick = function (evt) {
        // convert screen x/y to canvas, and canvas to world
        world_px_x, world_px_y;
        selected_coordinate = get_map_coordinates_from_click(world_px_x, world_px_y);

        set_map_tile(selected_coordinate, selected_tile);
    };

正如您所看到的,執行另一個的過程與執行另一個過程非常相似(因為它是 - 在一個坐標集中給定x和y,將其轉換為另一個比例/集)。

那么,繪制瓷磚的過程幾乎完全相反。
給定world-index和tile-number,反向查找world-x / y和tilemap-x / y。
您也可以在示例代碼中看到該部分。

這種瓷磚繪畫是制作2D地圖的傳統方式,無論我們是在談論星際爭霸,塞爾達還是馬里奧兄弟。
並非所有人都擁有“使用瓷磚繪畫”編輯器的奢侈品(有些是手工制作文本文件,甚至是電子表格,以獲得正確的間距),但是如果加載星際爭霸甚至是魔獸爭霸III(這是3D),並進入他們的編輯,瓷磚畫家正是你得到的,這正是暴雪制作這些地圖的方式。

增加

在基本前提下,您現在還需要其他“地圖”:您需要一個碰撞圖來了解哪些瓷磚可以/不能走,實體圖,到顯示哪里有門,或者是電源或礦物,或者敵人產生的,或者是過場動物的事件觸發器......

並非所有這些都需要在與世界地圖相同的坐標空間中運行,但它可能會有所幫助。

此外,您可能想要一個更智能的“世界”。
能夠在一個級別中使用多個平鋪貼圖,例如......
並在tile-editor中下拉以交換tile-maps。

...一種省略瓷磚信息的方法(不僅僅是X / Y,還有關於瓷磚的其他信息),並保存完成的“地圖”數組,填充了瓷磚。

即使只是復制JSON,並將其粘貼到自己的文件中......


程序生成

另一種方式,你之前建議的方式(“知道如何連接岩石,草等”)稱為程序生成
這是一個更難和更多參與。
像暗黑破壞神這樣的游戲會使用它,這樣你每次玩游戲時都會處於不同的隨機生成環境中。 Warframe是一個使用程序生成來做同樣事情的FPS。

前提:
基本上,你從瓦片開始,而不是僅僅是作為圖像的瓦片,瓦片必須是具有圖像和位置的對象,但是還具有可能圍繞它的事物的列表。
當你放下一片草時,那草就有可能在它旁邊產生更多的草。
草可能會說,周圍的四個方向中的任何一個都有10%的幾率水,20%的岩石幾率,30%的污垢幾率和40%的草。

當然,它真的不是那么簡單(或者如果你錯了的話)。

雖然這就是這個想法,但程序生成的棘手部分實際上是確保一切正常運行而不會破壞。
限制
你不能,例如在這個例子中,懸崖牆出現在高地的內側。 它只能出現在上方和右上方的高地,以及左下方的低地(並且星際爭霸編輯器會自動執行此操作,如您所繪)。 斜坡只能連接有意義的瓷磚。 你不能將門擋住,也不能將世界包裹在阻止你移動的河流/湖泊中(或者更糟糕的是,阻止你完成一個級別)。

利弊
對於長壽來說真的很棒,如果你可以讓你的所有尋路和限制工作 - 不僅是偽隨機生成地形和布局,還有敵人放置,戰利品放置等等。
近14年后,人們仍在玩暗黑破壞神II。

缺點
當你是一個單人團隊時(在業余時間他們不是數學家/數據科學家),真的很難做對。
確保地圖有趣/平衡/競爭真的很糟糕......
星際爭霸永遠不會使用100%隨機生成公平的游戲玩法。
程序生成可以用作“種子”。
你可以點擊“隨機化”按鈕,看看你得到了什么,然后從那里進行調整和修復,但是對於“平衡”,或者為了限制傳播而編寫的游戲規則,你將會有很多修復,最終會花費更多的時間修理發電機,而不僅僅是自己繪制地圖。

有一些教程,並且學習遺傳算法,尋路等等,都是很好的技能......為了學習制作2D自上而下的瓷磚游戲,buuuut有點過頭了而且,在您獲得一兩個游戲/引擎后,需要考慮的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM