[英]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或任何給定的程序支持/導出。
Tiled ( http://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.