關卡 (levels)

關卡是透過 Level.lua 管理。 Level.lua 會根據 gameConfig.gameLevels 調整關卡內容。關卡分類如下:

魔王關卡 (Boss Level)

被標記為 Boss Level 的關卡,開始前會先出現警告。Boss Level 會有一個魔王 (Boss),在無限模式中,玩家必須要打倒魔王才能繼續前進。

普通關卡 (Normal Level)

除了 Boss Level 外的關卡皆為 Normal Level,Normal Level 可以有很多種變化,像是消滅一定數量的敵人、解救人質、閃避隕石等等。

新增一般關卡

新增一般關卡的方式非常簡單:

新增關卡檔:

關卡必需繼承 Sublevel.lua,這裡提供一個簡單的範例:level_simplest_example.lua,示範如何用最少的程式碼實作一個關卡。這個例子裡,我們指定 duration 為 30000 毫秒(30秒),這代表如果玩家在此關卡開始後, 過了 30 秒依然存活的話,便會結束目前關卡,接著進行下一關。也由於沒有新增任何遊戲物件的關係,遊戲開始後的畫面只會出現玩家。9999999-015 是關卡的 id,每個關卡都必須有一個獨一無二的 level id,這會被用來區分每個關卡單獨執行時的得分。由於 level id 最長 20 碼,而且必須獨一無二。

--levels.myLevel.level_simplest_example.lua
local Sublevel = require("Sublevel")
local myLevel = Sublevel.new("9999999-015", "level name", "author name", {duration = 30000})

function myLevel:show(options)

end

return myLevel

當關卡檔案完成後,我們必須要將它放在 levels 資料夾裡。關於放置的方法:你可以直接將檔案放進去,這時候關卡路徑會是 levels/level_simplest_example.lua:

.
├── levels
│   ├── default
│   │   ├── level_1.lua
│   │   ├── level_2.lua
│   │   ├── level_3.lua
│   │   ├── level_4.lua
│   │   ├── level_5.lua
│   │   ├── level_6.lua
│   │   ├── level_bonus.lua
│   │   ├── level_boss_1.lua
│   │   └── level_test.lua
│   ├── level_bossfight_warning.lua
│   └── level_simplest_example.lua

或是放進建立的子目錄內:levels/myLevel/level_simplest_example.lua。這邊為了方便管理,採用的是後者的方法。

.
├── levels
│   ├── default
│   │   ├── level_1.lua
│   │   ├── level_2.lua
│   │   ├── level_3.lua
│   │   ├── level_4.lua
│   │   ├── level_5.lua
│   │   ├── level_6.lua
│   │   ├── level_bonus.lua
│   │   ├── level_boss_1.lua
│   │   └── level_test.lua
│   ├── level_bossfight_warning.lua
│   └── myLevel
│       └── level_simplest_example.lua

設定 gameConfig.lua:

無限模式設定方式

不論你選擇如何放置你的關卡檔案,都要在 gameLevels 設定關卡位置,這樣一來模板才能順利將指定的關卡顯示出來:

預設:

config.gameLevels = {
    "default.level_boss_1",
    "default.level_1",
    "default.level_2",
    "default.level_3",
    "default.level_4",
    "default.level_5",
    "default.level_bonus"
}

修改後:

config.gameLevels = {
    "default.level_boss_1",
    "default.level_1",
    "default.level_2",
    "default.level_3",
    "default.level_4",
    "default.level_5",
    "default.level_bonus",
    "myLevel.level_simplest_example" --added level
}

修改之後,遊戲變便會隨機執行設定檔內的這 9 個關卡檔案,當然為了方便測試,你也可以只留下你所以設計的關卡,這樣遊戲便會重複執行同一關:

config.gameLevels = {
    "myLevel.level_simplest_example" --added level
}

在關卡內新增敵人

這裡我們利用模板中已經建立好的遊戲物件:Enemy.EnemyPlane ,來示範如何用最少的程式碼在關卡內新增敵人。

-- levels/myLevel/level_single_enemy.lua
local gameConfig = require("gameConfig")
local Sublevel = require("Sublevel")
local EnemyPlane = require("enemies.EnemyPlane")
local myLevel = Sublevel.new("9999999-016", "level name", "author name", {duration = 4000})

function myLevel:show(options)
    local enemy = EnemyPlane.new()
    self:insert(enemy)
    --place the enemy out of the screen
    enemy.x = gameConfig.contentWidth/4
    enemy.y = -100
    --move the enemy from the top to bottom with speed 100 pixels/second
    enemy:setLinearVelocity( 0, 100 )
    --destroy the enemy properly
    enemy:autoDestroyWhenInTheScreen()
end

return myLevel

這個關卡會出現一架由上往下飛行的飛機。首先我們先新增敵人物件(第 8 行),並記得透過方法 insert 加入關卡之中。加入關卡的物件才能順利地被遊戲功能所套用,像是暫停、恢復、重新開始。

注意遊戲物件在關卡結束前必須適當的回收,否則遊戲會因為不斷增加的物件而崩潰。所以這裡我們調用方法 autoDestroyWhenInTheScreen,會在物件進入遊戲畫面時,開始自動回收,所謂的自動回收是指:當物件離開遊戲畫面時,會被系統所回收。

如果你希望你的遊戲物件可以反覆的進出遊戲畫面,那麼 autoDestroyWhenInTheScreen 就不適合,因為你會發現當你的遊戲物件離開遊戲畫面後,它就會消失了。這時候你必須自己呼叫遊戲物件中的方法 clear() 來回收。

自訂關卡結束條件

要自訂關卡結束的條件,你必須先移除 duration 設定,並且覆寫判斷關卡結束的方法 Sublevel:isFinish()。關卡管理器會在每幀檢查這個方法的回傳值,如果回傳的是 True,則會結束此關,反之則會繼續讓關卡執行。注意,所謂的結束關卡不代表遊戲會自動回收目前遊戲畫面上的所有物件,而是會接著進行下一關。你必須善盡回收遊戲物件的責任。

--levels/myLevel/level_custom_finish.lua
local gameConfig = require("gameConfig")
local Sublevel = require("Sublevel")
local EnemyPlane = require("enemies.EnemyPlane")
local util = require("util")
local myLevel = Sublevel.new("9999999-012", "level name", "author name")

function myLevel:show(options)
    local enemy = EnemyPlane.new()
    self:insert(enemy)
     --place the enemy out of the screen
     enemy.x = gameConfig.contentWidth/4
     enemy.y = -100
     --move the enemy from the top to bottom with speed 100 pixels/second
     enemy:setLinearVelocity( 0, 100 )
     --destroy the enemy properly
     enemy:autoDestroyWhenInTheScreen()
     self.enemy = enemy
end

function myLevel:isFinish()
     if util.isExists(self.enemy) then
         return false
     else
         return true
    end
end

return myLevel

以上的例子使用 util.isExist 判斷遊戲物件是否消失,如果物件消失了,便結束關卡。而且為了讓 myLevel:isFinish() 能順利取得 enemy 物件,我們在第 17 行將它設定為此關卡的屬性。

動態關卡 (Dynamic Level)

在這個遊戲模板中,遊戲模式可以分為無限模式 (Infinite Mode) 與單一關卡模式 (Single Level Mode) ,無限模式如之前所提,開始遊玩後關卡間會不斷循環,直到玩家死亡。而在單一關卡模式中 (如下圖) 玩家可以從多個關卡中選擇一關遊玩。

單一關卡的關卡檔案與無限模式並無不同,但是必須在 gameConfig.lua 中的 config.seperateLevels 註冊:

config.seperateLevels = {
    "default.level_1",
    "default.level_2",
    "default.level_3",
    "default.level_4",
    "default.level_5",
    "myLevel.level_dynamic",
}

那麼什麼是動態關卡呢?動態關卡的意思即是:將同一個關卡檔案運用在不同的遊戲模式中。

你可以透過 sublevel 中的 gameMode 屬性取得當前的遊戲模式,如果gameModeGameConfig.MODE_SINGLE_LEVEL 則代表玩家目前正在遊玩單一關卡模式,如果是 GameConfig.MODE_INFINITE_LEVEL 則代表目前正在遊玩無限模式。

下面的例子即是透過這樣的技巧,讓同一個關卡的敵人在不同模式中有不同的行為,在單一關卡模式中,該敵人會往下飛行,而在無限模式中,則會往右下方飛行:

--/levels/myLevel/level_dynamic.lua
local gameConfig = require("gameConfig")
local Sublevel = require("Sublevel")
local EnemyPlane = require("enemies.EnemyPlane")
local myLevel = Sublevel.new("9999999-016", "level name", "author name", {duration = 4000})

function myLevel:show(options)
    local enemy = EnemyPlane.new()
    self:insert(enemy)
    --place the enemy out of the screen
    enemy.x = gameConfig.contentWidth/4
    enemy.y = -100
    print(self.gameMode)
    if self.gameMode == gameConfig.MODE_SINGLE_LEVEL then
        enemy:setScaleLinearVelocity( 0, 100 )
    elseif self.gameMode == gameConfig.MODE_INFINITE_LEVEL then
        enemy:setScaleLinearVelocity( 15, 100 )
    end
    --destroy the enemy properly
    enemy:autoDestroyWhenInTheScreen()
end

return myLevel

results matching ""

    No results matching ""