一文掌握游戲引導(dǎo)的實(shí)現(xiàn)思路

一年多以前寫了兩篇從零開始設(shè)計(jì)游戲引導(dǎo)框架,第二篇寫完后间雀,發(fā)現(xiàn)寫不下去了悔详。游戲引擎形形色色,語言多種多樣惹挟,如果繼續(xù)寫下去發(fā)現(xiàn)并不具有通用性茄螃,所以中斷了。現(xiàn)在连锯,引導(dǎo)的代碼經(jīng)過多個(gè)項(xiàng)目的打磨归苍,有了一定的改進(jìn),想著簡單分享一下引導(dǎo)的實(shí)現(xiàn)思路吧运怖!
本文以Lua代碼作為樣例拼弃,重在思路分享,其他語言亦可實(shí)現(xiàn)摇展。

1. 引導(dǎo)認(rèn)知

1.1 引導(dǎo)分類

引導(dǎo)的分類可分為新手引導(dǎo)吻氧、觸發(fā)式引導(dǎo)任務(wù)前往引導(dǎo)咏连。

1)新手引導(dǎo)

新注冊(cè)的賬號(hào)進(jìn)入游戲后盯孙,出現(xiàn)立繪對(duì)話、交代游戲背景捻勉、告知玩家基礎(chǔ)操作的引導(dǎo)镀梭,稱為新手引導(dǎo)。一般新手引導(dǎo)持續(xù)至玩家可以自由操作時(shí)結(jié)束踱启。

2)觸發(fā)式引導(dǎo)

玩家自由操作過程中报账,因達(dá)到某種條件而觸發(fā)的引導(dǎo),稱為觸發(fā)式引導(dǎo)埠偿。大多數(shù)情況下透罢,觸發(fā)式引導(dǎo)會(huì)隨著新系統(tǒng)的開啟。

3)任務(wù)前往引導(dǎo)

點(diǎn)擊任務(wù)前往按鈕后冠蒋,出現(xiàn)手指引導(dǎo)玩家按照任務(wù)實(shí)現(xiàn)流程去操作的過程羽圃,稱為任務(wù)前往引導(dǎo)

1.2 組別和步驟

1)組別

為方便后續(xù)內(nèi)容達(dá)成統(tǒng)一認(rèn)知抖剿,在此將一個(gè)個(gè)不同功能作用的引導(dǎo)以組別進(jìn)行區(qū)分朽寞。比如:一進(jìn)入游戲即出現(xiàn)的新手引導(dǎo)识窿、英雄升星引導(dǎo)、文字版的抽卡引導(dǎo)等脑融,每一個(gè)引導(dǎo)特定功能的引導(dǎo)都是一個(gè)組別喻频。

2)步驟

在一個(gè)引導(dǎo)組別里,每一步引導(dǎo)的操作都成為步驟肘迎,比如:引導(dǎo)點(diǎn)擊一個(gè)按鈕甥温、出現(xiàn)一個(gè)立繪對(duì)話、出現(xiàn)一個(gè)高亮框等妓布,都是引導(dǎo)的步驟姻蚓。

1.3 觸發(fā)條件與觸發(fā)點(diǎn)

觸發(fā)條件觸發(fā)點(diǎn),是引導(dǎo)組別的概念匣沼。
舉個(gè)例子狰挡,文字版里有一個(gè)抽卡引導(dǎo),條件是玩家通關(guān)1-4释涛。那么對(duì)于抽卡這個(gè)組別的引導(dǎo)圆兵,通關(guān)1-4就是它的觸發(fā)條件,而觸發(fā)點(diǎn)就是每一個(gè)關(guān)卡通關(guān)那一刻枢贿。通俗來講就是:

觸發(fā)點(diǎn):
什么時(shí)候判斷

觸發(fā)條件:
判斷是否滿足條件

1.4 操作

操作是引導(dǎo)步驟的概念。
舉個(gè)例子刀脏,文字版抽卡引導(dǎo)的步驟流程是:

  • 出現(xiàn)立繪對(duì)話局荚,告知玩家“招仙臺(tái)”系統(tǒng)已開啟
  • 點(diǎn)擊主界面“道場(chǎng)”頁簽
  • 點(diǎn)擊“招仙臺(tái)”按鈕
  • 提示免費(fèi)單抽
  • 點(diǎn)擊“單抽”按鈕

上面的每一個(gè)步驟都是操作

操作根據(jù)表現(xiàn)形式可分為如下幾類:

  • 點(diǎn)擊
  • 拖動(dòng)
  • 立繪對(duì)話
  • 提示文本
  • 效果(高亮框等)

1.5 保存點(diǎn)

保存點(diǎn)的作用:為保證引導(dǎo)在玩家中途退出重進(jìn)時(shí)依然能從中斷點(diǎn)恢復(fù)愈污。保存點(diǎn)需要上傳記錄到服務(wù)端耀态。

結(jié)合以上幾點(diǎn),我們建立起對(duì)引導(dǎo)的認(rèn)知:
在某個(gè) 觸發(fā)點(diǎn) 暂雹,判斷某個(gè) 組別 的引導(dǎo)滿足 觸發(fā)條件 首装,于是一個(gè) 步驟 一個(gè)步驟地引導(dǎo)玩家去完成最基礎(chǔ)的系統(tǒng)流程的 操作 ,并且支持退出游戲重進(jìn)時(shí)能從中途的 保存點(diǎn) 恢復(fù)并繼續(xù)引導(dǎo)杭跪。

2. 引導(dǎo)的配表

引導(dǎo)的配表可分為:guide_group表仙逻、guide_step表、guide_text表涧尿。

2.1 guide_group配表

guide_group表系奉,主要控制某個(gè)組別的引導(dǎo)要不要觸發(fā),具體配置如下:

ID 說明 起始步驟 觸發(fā)條件 優(yōu)先級(jí)
_id _stepId _triggerCond _priority
I I [S I
1 初始的新手引導(dǎo) 101 0
2 抽卡引導(dǎo) 201 {"scene":"MainScene","form":"","missionId":100004} 1

2.2 guide_step配表

guide_step表姑廉,主要控制在某個(gè)組別的引導(dǎo)觸發(fā)時(shí)缺亮,每一步操作具體是什么。相同組別引導(dǎo)的步驟ID連續(xù)桥言,且ID不為100的倍數(shù)萌踱。具體配置如下:

ID 說明 操作 數(shù)值 其他參數(shù) 保存步驟
_id _action _val _param _saveId
H I I S I
201 立繪對(duì)話 30001 1002 202
202 點(diǎn)擊“道場(chǎng)”頁簽 10001 1 0
203 點(diǎn)擊“招仙臺(tái)”按鈕 10002 1 0
204 提示免費(fèi)單抽 40001 1002 {"form_show":105,"form":105,"node":"_btnLotteryOne","dir":"top"} 0
205 點(diǎn)擊“單抽”按鈕后關(guān)閉提示 10003 0 {"form":105,"node":"_btnLotteryOne"} 100

_action說明

10000+:點(diǎn)擊
10001 點(diǎn)擊主界面的頁簽 葵礼,val 表示第幾個(gè)頁簽
10002 點(diǎn)擊某個(gè)系統(tǒng)入口,val 表示哪個(gè)系統(tǒng)
10003 按照代碼變量名找到按鈕進(jìn)行點(diǎn)擊

20000+:拖拽
...

30000+:立繪對(duì)話
30001 普通立繪對(duì)話

40000+:文本提示
40001 普通文本提示

_val說明

不同_action并鸵,對(duì)應(yīng)_val表意不同

10001 主界面第幾個(gè)頁簽
10002 表示系統(tǒng)ID枚舉

30000+ 表示立繪對(duì)話的文本ID鸳粉,從guide_text表里讀取
40000+ 表示文本提示的文本ID,從guide_text表里讀取

_param說明

一些無法通過_val單個(gè)值表意的參數(shù)能真,用_param表意赁严。使用Json字符串配置,擴(kuò)展性較好粉铐,自由度大疼约,可根據(jù)需求任意定義。

form_show 某個(gè)界面打開的時(shí)候執(zhí)行操作蝙泼,數(shù)值為:界面ID枚舉
form 執(zhí)行當(dāng)前操作需要在哪個(gè)界面程剥,數(shù)值為:界面ID枚舉
node 關(guān)聯(lián)某個(gè)node,通常與form配合使用汤踏,旨在找到目標(biāo)節(jié)點(diǎn)织鲸,與不同_action關(guān)聯(lián),表意不同溪胶,與點(diǎn)擊 關(guān)聯(lián)搂擦,表示點(diǎn)擊哪個(gè)按鈕;與提示文本關(guān)聯(lián)哗脖,表示文本框依附于哪個(gè)UI控件
dir 表示文本框依附在UI控件的哪個(gè)方位瀑踢,數(shù)值可以是:"top"、"bottom"才避、"left"橱夭、"right"
...

_saveId說明

在當(dāng)前操作結(jié)束時(shí),將_saveId保存到服務(wù)器桑逝,下次斷線重連時(shí)棘劣,從保存點(diǎn)繼續(xù)引導(dǎo)

0 不設(shè)置保存點(diǎn),不做任何操作
100 將當(dāng)前引導(dǎo)保存點(diǎn)去掉楞遏,標(biāo)記當(dāng)前組別引導(dǎo)已完成
其他 保存該步驟ID到服務(wù)器

2.3 guide_text表

guide_text表茬暇,主要配置立繪對(duì)話、文本提示等操作的一些文本內(nèi)容橱健。具體配置如下:

ID 說明 文本內(nèi)容 參數(shù)
_id _textSid _param
I D S
1001 立繪對(duì)話 招仙臺(tái)已開啟而钞,請(qǐng)道友移步入內(nèi),招募仙士拘荡。 {"role_index":1,"role_id":1}
1002 文本提示 每隔一段時(shí)間都會(huì)獲得一次免費(fèi)召喚機(jī)會(huì)

_param說明

role_index 立繪的位置臼节,1:左,2:中,3:右
role_id 立繪角色I(xiàn)D

2.4 程序與策劃的配合

1)添加新的引導(dǎo)時(shí)

策劃出一份引導(dǎo)流程文檔网缝,程序根據(jù)負(fù)責(zé)添加引導(dǎo)的邏輯配表:guide_group巨税、guide_step,策劃配置負(fù)責(zé)配置引導(dǎo)的文案:guide_text粉臊。

2)修改引導(dǎo)時(shí)

如果僅涉及引導(dǎo)文案修改時(shí)草添,策劃只需要維護(hù)guide_text表即可,如果僅涉及文案增刪扼仲,策劃也可在了解引導(dǎo)配表邏輯的基礎(chǔ)上远寸,維護(hù)guide_step表;
如果涉及邏輯改動(dòng)屠凶,需要程序配合策劃進(jìn)行改表驰后,程序負(fù)責(zé)guide_group、guide_step矗愧,策劃負(fù)責(zé)guide_text灶芝。

可有效規(guī)避策劃和程序改一份表,影響引導(dǎo)邏輯唉韭。

3. 引導(dǎo)代碼的實(shí)現(xiàn)

根據(jù):

在某個(gè) 觸發(fā)點(diǎn) 夜涕,判斷某個(gè) 組別 的引導(dǎo)滿足 觸發(fā)條件 ,于是一個(gè) 步驟 一個(gè)步驟地引導(dǎo)玩家去完成最基礎(chǔ)的系統(tǒng)流程的 操作 属愤,并且支持退出游戲重進(jìn)時(shí)能從中途的 保存點(diǎn) 恢復(fù)并繼續(xù)引導(dǎo)女器。

代碼需要實(shí)現(xiàn)的邏輯包括:

  • 引導(dǎo)的觸發(fā)
  • 引導(dǎo)的操作
  • 引導(dǎo)的保存點(diǎn)(結(jié)合在操作中)
  • 引導(dǎo)步驟的連接(如何從當(dāng)前步驟跳到下一步)

我們把引導(dǎo)的框架邏輯寫在GuideMgr.lua里。

local M = class("GuideMgr")

function M.tryStart() end

function M.start(groupConfig) end

function M.step(stepId) end

function M.finish() end

function M.saveGuideStep(stepId) end

return M

3.1 引導(dǎo)的觸發(fā)

引導(dǎo)的觸發(fā)住诸,可分為:觸發(fā)總?cè)肟谙堋⒂|發(fā)條件判定和正式觸發(fā)。

1)觸發(fā)總?cè)肟?/h3>
local M = class("GuideMgr")

...

-- 引導(dǎo)觸發(fā)判定總?cè)肟?function M.tryStart()
    -- 引導(dǎo)禁用
    if M.isForbidGuide() then return end
    -- 正在引導(dǎo)只壳,不觸發(fā)判定
    if M.isGuiding() then return end
  
    -- 獲取沒有觸發(fā)過的引導(dǎo)組別,判定是否滿足觸發(fā)條件
    local groupConfigs = M.getGroupConfigs()
    for i = 1, #groupConfigs do
        local config = groupConfigs[i]
        -- 如果滿足觸發(fā)條件
        if CondMgr.isConditionArrayMet(config._triggerCond) then
            -- 觸發(fā)引導(dǎo)
            M.start(config)
            return true
        end
    end
end

-- 獲取沒有觸發(fā)過的引導(dǎo)組別
function M.getGroupConfigs()
    local configs = M._groupConfigs
    if configs == nil then
        configs = {}
            
        for k, v in pairs(D._guideGroupConfig) do
            -- 取沒有觸發(fā)過的引導(dǎo)組別
            if not M.isFinished(k) then
                configs[#configs + 1] = v
            end
        end
    
        table.sort(configs, function(a, b) return a._priority < b._priority end)
        M._groupConfigs = configs
    end
    return configs
end

...

return M

2)條件判定

ID 說明 起始步驟 觸發(fā)條件 優(yōu)先級(jí)
_id _stepId _triggerCond _priority
I I [S I
2 抽卡引導(dǎo) 201 {"scene":"MainScene","form":"","missionId":100004} 1
local M = class("CondMgr")

...

--[[--
配表類型:[S
配表寫法:{"form": 101, "hero_level": 20} | {"form":101, "vip_level":3}
在101界面暑塑,英雄等級(jí)達(dá)到20級(jí)或vip等級(jí)達(dá)到3級(jí)吼句,觸發(fā)引導(dǎo)

cond參數(shù)結(jié)構(gòu):
table數(shù)組
{
    {form = 101, hero_level = 20},
    {form = 101, vip_level = 3}
}

只要數(shù)組中其中一個(gè)條件滿足即可
--]]--
function M.isConditionArrayMet(conds)
    for i = 1, #conds do
        if M.isConditionMet(conds[i]) then
            return true
        end
    end
    return false
end

function M.isConditionMet(cond)
    for k, v in pairs(cond) do
        if not M.CondCheck[k](v) then return false end
    end
    return true
end

M.CondCheck = {
    ["form"] = function(val)
        local form = Form.getTop()
        return form and form._id == val
    end,
    ["hero_level"] = function(val)
        local lv = P._playerHero:getOwnedHeroMaxLevel()
        return lv >= val
    end,
    ["vip_level"] = function(val)
        return P:vipLevel() >= val
    end
}

...

return M

3)觸發(fā)引導(dǎo)

local M = class("GuideMgr")

...

function M.start(groupConfig)
    -- 如果有引導(dǎo)正在進(jìn)行,結(jié)束所有引導(dǎo)事格,開始觸發(fā)傳入組別的引導(dǎo)
    M.finish()

    -- 保存當(dāng)前正在觸發(fā)的引導(dǎo)組別ID
    local groupId = groupConfig._id
    M.saveGuideGroup(groupId)
  
    local stepId = groupConfig._stepId
    M.saveGuideStep(stepId)
  
    -- 引導(dǎo)視圖層準(zhǔn)備工作
    M.prepareLayer()
  
    -- 開始當(dāng)前引導(dǎo)組的第一步操作
    M._groupId = groupId
    M._stepId = stepId
    M.step(stepId)
end

-- 創(chuàng)建引導(dǎo)圖層惕艳,后續(xù)的所有操作添加的元素都放在這里
function M.prepareLayer()
    local layer = M._layer
    if layer == nil then
        layer = class(nil, V).new(lc.CocosClass.ui_widget)
        layer:setContentSize(lc.ScrSize)
        lc.addChildToCenter(Scene._current, layer, V.ZOrder.guide)
        M._layer = layer

        layer:setTouchListener(function() end)
    end
end

function M.saveGuideGroup(groupId)
    -- TODO:保存到服務(wù)端
    ...
end

function M.saveGuideStep(stepId)
    -- TODO:保存到服務(wù)端
    ...
end

...

return M

3.2 引導(dǎo)的操作

引導(dǎo)的操作涉及:保存點(diǎn)邏輯、參數(shù)邏輯驹愚、具體操作(點(diǎn)擊远搪、對(duì)話等)。

1)引導(dǎo)步驟

local M = class("GuideMgr")

...

function M.step(stepId)
    -- 保證step在引導(dǎo)中執(zhí)行(由M.start發(fā)起)
    if not M.isGuiding() then return end

    --[[--
    stepId不為空逢捺,表示開始當(dāng)前步驟操作谁鳍;
    stepId為空,表示在M._stepId基礎(chǔ)上,進(jìn)入下一步操作倘潜;
    --]]--
    if stepId == nil then
        stepId = M._stepId
 
        -- 在當(dāng)前步驟結(jié)束绷柒,準(zhǔn)備進(jìn)入下一步時(shí),記錄當(dāng)前步驟的保存點(diǎn)
        local stepConfig = D._guideStepConfig[stepId]
        local saveId = stepConfig._saveId
        if saveId then
            if saveId == 100 then
                M.setGroupFinished(M._groupId)
                M.saveGuideStep()

            elseif saveId > 0 then
                M.saveGuideStep(saveId)
            end
        end

        stepId = stepId + 1
    end
  
    -- 傳入的步驟ID不存在涮因,結(jié)束引導(dǎo)
    local config = D._guideStepConfig[stepId]
    if config == nil then
        M.finish()
        return
    end
  
    M._stepId = stepId

    -- 清除所有引導(dǎo)元素
    M.clearLayer()

    -- 根據(jù)步驟參數(shù)做相應(yīng)處理
    -- (后面繼續(xù))
    ...
end

function M.isGuiding()
    return M._stepId and D._guideStepConfig[M._stepId]
end

-- 清理所有l(wèi)ayer上的引導(dǎo)元素废睦,包括手指、高亮养泡、立繪對(duì)話等
function M.clearLayer()
    local layer = M._layer
    if layer == nil then return end

    layer:setSwallowTouches(true)
    layer:setTouchListener(function() end)

    M.removeFinger()
    M.removeDilog()
    M.removeTipText()
    ...
end

...

return M

2)參數(shù)處理

ID 說明 操作 數(shù)值 其他參數(shù) 保存步驟
_id _action _val _param _saveId
H I I S I
204 40001 1002 {"form_show":105,"form":105,"node":"_btnLotteryOne","dir":"top"} 0
205 10003 0 {"form":105,"node":"_btnLotteryOne"} 100
local M = class("GuideMgr")

...

function M.step(stepId)
    ...
  
    -- (接上面的代碼)
    local config = D._guideStepConfig[stepId]

    -- 根據(jù)步驟參數(shù)做相應(yīng)處理
    local param = M.getStepParam(config)
    if param then
        -- 允許玩家自由點(diǎn)擊
        if param.free_op then
            M._layer:setSwallowTouches(false)
        end

        M._waitParam = nil

        if param.delay then
            M._waitParam = V.scheduleCall(function() M.doAction() end, param.delay)

        elseif param.event then
            _, M._waitParam = lc.event.once(param.event, function() M.doAction() end)

            if not param.free_op then
                M._layer:setTouchListener(function()
                    -- 提示當(dāng)前無法點(diǎn)擊
                end)
            end
      
        elseif param.form_show then
            local form = Form.getTop()
            if form == nil or form._id ~= param.form_show or not form._isShown then
                _, M._waitParam = lc.event.on("form.show", function(form)
                    if form._id == param.form_show then M.doAction() end
                end)
            end
      
        elseif param.form_close then
            local form = Form.getTop()
            if form and form._id == param.form_close then
                _, M._waitParam = lc.event.on("form.close", function(formId)
                    if param.form_close == formId then M.doAction() end
                end)
            end
        end
    
        if M._waitParam == nil then
            M.doAction()
        end
    end
end

function M.getStepParam(stepConfig)
    stepConfig = stepConfig or D._guideStepConfig[M._stepId]
    return json.decode(stepConfig._param or "")
end

...

return M

3)執(zhí)行操作

local M = class("GuideMgr")

...

function M.doAction()
    if not M.isGuiding() then return end
  
    local config = D._guideStepConfig[M._stepId]
    M._waitParam = nil
  
    local layer = M._layer
    layer:setSwallowTouches(true)
  
    local action = config._action
    if action == 0 then
        -- 執(zhí)行下一步操作
        M.step()

    else
        local func = M.ActionFuncs[action]
        if func then
            if not func(config) then
                M.finish()
            end
  
        else
            -- 交給外部處理
            V.scheduleCall(function() lc.event.emit("guide.step", config) end, lc.FrameInterval)
        end
    end
end

M.Action = {
    click_main_tab = 10001,
    click_sys_entrance = 10002,
    click_by_name = 10003,
    ...
    dialog = 30001,
    ...
    tip_text = 40001,
    ...
}

M.ActionFuncs = {
    [M.Action.click_main_tab] = function(config)
        local index = config._val
        local tab = table.walk(Scene._curent, "_tabs", index)
        if tab and tab:isVisible() then
            M.addTouchFinger(tab)
            return true
        end
    end,
    [M.Action.click_sys_entrance] = function(config) ... end,
    [M.Action.click_by_name] = function(config) ... end,
  
    [M.Action.role_dialog] = function(config)
        local textConfig = D._guideTextConfig[config._val]
        M.addDialog(textConfig)
        return true
    end,
  
    [M.Action.tip_text] = function(config)
        local textConfig = D._guideTextConfig[config._val]
        M.addTipText(textConfid._textSid, config._param)
        return true
    end
}

...

return M

回顧

10000+:點(diǎn)擊
10001 點(diǎn)擊主界面的頁簽 嗜湃,val 表示第幾個(gè)頁簽
10002 點(diǎn)擊某個(gè)系統(tǒng)入口,val 表示哪個(gè)系統(tǒng)
10003 按照代碼變量名找到按鈕進(jìn)行點(diǎn)擊

20000+:拖拽
...

30000+:立繪對(duì)話
30001 普通立繪對(duì)話

40000+:文本提示
40001 普通文本提示

3.3 引導(dǎo)的結(jié)束

引導(dǎo)的結(jié)束包括:引導(dǎo)數(shù)據(jù)處理澜掩、視圖層移除购披、嘗試?yán)^續(xù)觸發(fā)下一組引導(dǎo)。所有邏輯囊括在GuideMgr.finish()方法里输硝。

local M = class("GuideMgr")
...

function M.finish()
    -- 數(shù)據(jù)層
    M.saveGuideGroup()
    M.saveGuideStep()

    if M._groupId then
        M.setGroupFinished(M._groupId)
    end
  
    M._groupId = 0
    M._stepId = 0

    -- 視圖層
    M.clearLayer()
    M.removeLayer()

    local param = M._waitParam
    if param then
        -- 移除事件監(jiān)聽
        if param._event then
            lc.event.remove(param)
        
        -- 移除延遲操作的定時(shí)器
        else
            param:unschedule()
        end
        M._waitParam = nil
    end
  
    -- 延遲一幀判斷是否有新的引導(dǎo)可以觸發(fā)
    V.scheduleCall(M.tryStart, lc.FrameInterval)
end

...

return M

3.4 步驟間的連接

步驟間的連接今瀑,也就是當(dāng)前步驟如何跳到下一步驟,需要根據(jù)操作情景做特殊處理点把,這里以點(diǎn)擊橘荠、立繪對(duì)話為例,做一下講解郎逃。

1)點(diǎn)擊

local M = class("GuideMgr")
...

function M.addTouchFinger(node, ...)
    ...
    node._lastListener = node._listener
    node._listener = M.fingerTouchListener
    ...
end

function M.fingerTouchListener(...)
    ...
    if node._lastListener then
        node._lastListener(...)
        node._listener = node._lastListener
    end
  
    -- 按鈕點(diǎn)擊后哥童,執(zhí)行下一步
    M.step()
    ...
end

...
return M

2)立繪對(duì)話、文本

點(diǎn)擊屏幕任意位置褒翰,執(zhí)行下一步引導(dǎo)操作贮懈。

local M = class("GuideMgr")
...

function M.addDialog()
    ...
  
    M._layer:setTouchListener(function()
        ...
        -- 設(shè)置layer點(diǎn)擊事件
       M.step()
        ...
    end)
  
    ...
end

function M.addTipText()
    ...
  
    M._layer:setTouchListener(function()
        ...
        -- 設(shè)置layer點(diǎn)擊事件
        M.step()
        ...
    end)
  
    ...
end

...
return M
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市优训,隨后出現(xiàn)的幾起案子朵你,更是在濱河造成了極大的恐慌,老刑警劉巖揣非,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抡医,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡早敬,警方通過查閱死者的電腦和手機(jī)忌傻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搞监,“玉大人水孩,你說我怎么就攤上這事∷雎浚” “怎么了俘种?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵秤标,是天一觀的道長。 經(jīng)常有香客問我安疗,道長抛杨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任荐类,我火速辦了婚禮怖现,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘玉罐。我一直安慰自己屈嗤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布吊输。 她就那樣靜靜地躺著饶号,像睡著了一般。 火紅的嫁衣襯著肌膚如雪季蚂。 梳的紋絲不亂的頭發(fā)上茫船,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音扭屁,去河邊找鬼算谈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛料滥,可吹牛的內(nèi)容都是我干的然眼。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼葵腹,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼高每!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起践宴,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤鲸匿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后阻肩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晒骇,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年磺浙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徒坡。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撕氧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出喇完,到底是詐尸還是另有隱情伦泥,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站不脯,受9級(jí)特大地震影響府怯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜防楷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一牺丙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧复局,春花似錦冲簿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至角钩,卻和暖如春吝沫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背递礼。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國打工惨险, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宰衙。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓平道,卻偏偏與公主長得像,于是被迫代替她去往敵國和親供炼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子一屋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容