《DFQ》開發隨錄——隨機地圖

歡迎參與討論,轉載請註明出處。

前言

雖然先前未曾嚴明,但《DFQ》的全稱爲《DungeonFighterQuest》,由字面上便可得出,這是一款《DNF》的同人遊戲,那麼《DFQ》的地圖自然向《DNF》看齊了。而《DNF》的地圖衆所周知,具有一定的複雜度,在以往的作品開發過程中便是採取了手動製作的方式,可謂十分的費時費力。於是在《DFQ》便採用了生成隨機地圖的方式,與市面上許多獨立遊戲的做法不謀而合,畢竟手動做地圖實在是太辛苦了(汗)。本文便記錄其中心得。

地圖結構

map

如上圖所示,這便是一張隨機生成的地圖,它擁有以下組成:

  • 遠景層:地圖最底的背景,圖中表現爲山水。
  • 近景層:地圖較近的背景,圖中表現爲樹林。
  • 邊上層:地圖的上邊界,擁有若干地圖物件。
  • 地表層:地圖的地板,圖中表現爲草地。
  • 邊下層:地圖的下邊界,擁有若干地圖物件。
  • 活動層:地圖的主體,擁有若干活動的地圖物件。

在配置中以這種形式組成:

return {
    info = {
        width = {1440, 1280, 1024}, -- 寬度隨機選擇
        height = {600, 736}, -- 高度隨機選擇
        theme = "lorien", -- 地圖主體
        type = "dungeon", -- 地圖類型
        bgm = "lorien", -- 背景音樂
        bgs = "forest1", -- 背景音效
        name = {
            cn = "洛蘭",
            kr = "로리엔",
            jp = "ロリエン",
            en = "Lorien"
        } -- 用於顯示的地圖名稱,擁有中日韓英四語
    },
    floorHorizon = 327, -- 地表層起始Y座標
    scope = {
        x = 16,
        y = 368
    }, -- 可行走區域起始座標
    far = "$A/far", -- 遠景層
    near = "$A/near", -- 近景層
    floor = {
        left = "$A/tile/0",
        middle = "$A/tile/2",
        right = "$A/tile/1",
        bottom = "$A/tile/3"
    }, -- 地表層
    sprite = { -- 圖片
        up = {
            "$A/flower/0"
            ...
        }, -- 邊上層
        floor = {
            "$A/grass/0",
            ...
        } -- 地表層物件
    },
    actor = { -- 活動對象
        down = {
            "$A/tree/0",
            ...
        }, -- 邊下層
        article = {
            "$A/tree/1",
            ...
        } -- 活動層
    }
}

接下來將對逐層進行分析。

遠/近景層

遠景層與近景層的機制完全一致,所以可以拿來一起說明。當然之所以會分爲兩個層次而非合併,是因爲遠景與近景關於攝像機移動時的相對移動速度不一樣,以此形成縱深感。但在地圖生成這一塊,它們的機制是一致的:

    far = "$A/far", -- 遠景層
    near = "$A/near", -- 近景層

它們都是加載一張圖片,然後根據地圖的寬度進行平鋪操作即可。在最後階段會渲染成一張成品長圖,這是一種優化方法。

邊上層

邊上層爲地圖的上邊界,擁有若干地圖物件。這裏的地圖物件與其他層的並不一樣,在配置裏它的劃分是sprite,僅僅是單純的圖片罷了:

    sprite = { -- 圖片
        up = {
            "$A/flower/0"
            ...
        }, -- 邊上層
    }

因爲這些物件不需要與角色產生什麼互動,最後也會如遠/近景層一般,渲染成大塊的成圖。
  關於物件的放置,會採取生成寬高爲100的格子鋪滿整行,並隨機在這些格子上放置物件,如下圖所示:
up

邊下層

邊下層與邊上層類似,但是生成的地圖物件爲活動對象(actor):

    actor = { -- 活動對象
        down = {
            "$A/tree/0",
            ...
        }, -- 邊下層
    }

邊下層的地圖物件需要作爲活動對象主要是因爲某些物件會遮擋人物,所以需要採取靠近後透明化的措施。於是不方便作爲單純的圖片。
  物件放置方面與邊上層一致,這裏不再複述,如下圖所示:
down

地表層

地表層即地圖的地板,遠/近景層類似,也是採取平鋪的方針。但是在元素上更爲多樣:

    floor = {
        left = "$A/tile/0",
        middle = "$A/tile/2",
        right = "$A/tile/1",
        bottom = "$A/tile/3"
    }, -- 地表層

地表層的圖片分爲左中右下四種,左右兩種爲於地圖邊緣進行隨機選擇(左/右或中),中爲默認選擇,下爲平鋪Y方向。
  除此之外,地表層還會擁有一些類似邊上層的地圖物件:

sprite = { -- 圖片
    floor = {
        "$A/grass/0",
        ...
    } -- 地表層物件
},

這些物件也是不會與人物有所交互,最終與整個地表層渲染成大圖。與邊上/邊下層類似,地表層物件的放置會XY平鋪寬高爲64的格子,以此放置:
floor

活動層

活動層即地圖的主體,活動對象的放置層,諸如障礙、寶箱、怪物等皆置於此。放置的規則與地表層物件一致,與地表層物件的不同之處在於,活動層存在一些擁有障礙的物件:
obstacle

如上圖所示,《DFQ》採用的障礙方式爲傳統的格子流,這種形式便於配合類似A星的尋路算法。但如此存在障礙格子與物件素材的匹配問題,這方面都需要手動設置好。以及需要警惕因障礙範圍過大且恰好四周都是障礙物件圍住了人物的情況,好在實際上並不存在這樣的物件(障礙並不會很大),並不需要爲此做特殊措施。

隨機問題

在處理諸如物件放置的問題時,切忌採用遍歷+隨機數判斷的形式。因爲這是不符合概率論的(存在放置數量上限),如此便會導致地圖左邊的元素多於右邊(右邊存在輪不到的可能)。所以得采取將格子存儲在一個list中,以list[math.random(1, #list)]的方式提取要放置的格子,如此即可保證機率均等了。

後記

對於一些需要個性添加的元素(地圖特效、通行門、BOSS),一般會採取編寫專門的處理函數進行添加。對於一些需要固定化的地圖,也可以採取生成後輸出成文件以加載使用。目前這套很明顯的缺點在於無法生成崎嶇不一的地形,不過目前暫無需求,且日後再看吧。

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