可視化編程插件Bolt的入門介紹及與PlayMaker的對比


更多更詳細的Bolt視頻教程可以去我B站的主頁觀看:https://space.bilibili.com/230809767


Bolt是什么线欲?

Bolt是一個比較新的Unity可視化編程插件一死,目前穩(wěn)定版本為1.4,alpha測試版本為2.0。

官網(wǎng)地址:https://ludiq.io/bolt
Asset Store購買地址:https://assetstore.unity.com/packages/tools/visual-scripting/bolt-87491

Bolt在設(shè)計理念和使用上都很類似于UE4的藍圖(Blueprints)坦报,屬于“流(flow)”式設(shè)計米绕。簡單地說款侵,“流”式設(shè)計就是“按順序依次執(zhí)行每一步”,這其實才是最符合程序代碼執(zhí)行邏輯的設(shè)計湃累,因為程序代碼的執(zhí)行邏輯就是“一行命令執(zhí)行完再執(zhí)行下一行命令”勃救。

市面上用“流”式設(shè)計的可視化編程插件其實也蠻多的碍讨,早期的uScript Professional,現(xiàn)在的flowCanvas都屬于此類蒙秒。

我們可以這么來理解這些“流”式設(shè)計的可視化編程插件:

  • 每一個“節(jié)點”代表一項命令勃黍;
  • 執(zhí)行完上一個“節(jié)點”所代表的命令之后再執(zhí)行下一個“節(jié)點”所代表的命令;
  • 數(shù)據(jù)(或變量)可以從一個“節(jié)點”輸入給另一個“節(jié)點”晕讲。

在Bolt中覆获,其基本的“節(jié)點”(被稱為“單元(unit)”)是Unity的各種API命令。Bolt號稱支持所有Unity內(nèi)置命令(大概有23000多種)瓢省,還允許手動添加其他的第三方插件的自定義類(class)弄息。因此,Bolt自夸:“凡是可以用代碼實現(xiàn)的功能勤婚,都可以用Bolt來實現(xiàn)”摹量。

If it can be done with code, it can be done with Bolt.

這句話說得有一點夸張,但也代表了Bolt的特征馒胆。它本質(zhì)上就是直接調(diào)用Unity的API命令缨称,用和程序腳本差不多的執(zhí)行邏輯來運行,這在本質(zhì)上與c#腳本是一致的祝迂。比如下面這個Bolt的Graph睦尽,就完全等價于后面的那個c#腳本:

public class test : MonoBehaviour {

    // Use this for initialization
    void Start () {
        Debug.Log ("Hello World!");
    }
    
    // Update is called once per frame
    void Update () {
        transform.Rotate (0f, Time.deltaTime * 30f, 0f);
    }
}

可以看到,Start ()Update ()函數(shù)變成了Event節(jié)點型雳,Debug.Log()当凡、Transform.Rotate ()Time.deltaTime也變成了普通節(jié)點四啰。有專門的String節(jié)點用來獲得一個String類型的值宁玫,也有Multiply節(jié)點來進行乘法計算。程序員如何“設(shè)計”一段代碼柑晒,我們就可以如何“設(shè)計”一個Bolt的Graph欧瘪。

當(dāng)然,從實際的使用感受來看匙赞,這樣的設(shè)計方式并不是很“人性化”会宪,那些“節(jié)點”的功能對于初學(xué)者來說也不是那么“一目了然”椰弊,還需要用戶具備一定的程序思維能力法严,才能將自己的需求轉(zhuǎn)換成流式的節(jié)點運行邏輯肥哎。坦白來講,Bolt的上手難度是要高于PlayMaker的坐榆。但是拴魄,一旦用戶跨過了“新手期”,就可以大量將已有的“代碼類”教程翻譯成Bolt流圖,獲得快速提升匹中。而不像PlayMaker夏漱,還需要將“流”式的代碼改寫成“狀態(tài)機”,然后再才能予以實現(xiàn)顶捷。

本質(zhì)上挂绰,PlayMaker中一個State中的Action也是以“流”的方式運行的(上方Action先執(zhí)行,下方Action后執(zhí)行)服赎,但一方面各種“Every Frame”和非“Every Frame”的Action混合在一起非常難以分辨葵蒂,另一方面很難表達“分叉”式的邏輯(比如“if... else...”這樣)。因此重虑,對于稍復(fù)雜一些的“流”式邏輯践付,就很難在一個State中實現(xiàn)出來,而要改寫成多個States之間的轉(zhuǎn)移變化嚎尤。
但實際上荔仁,“狀態(tài)機”其實是為了解決在一些特定問題上“流"式邏輯太復(fù)雜而提出的一種歸納整理的方案伍宦,將復(fù)雜的”流“拆成幾個相對簡單的”狀態(tài)“芽死,而到了PlayMaker里面,往往不得不將本來很簡單的”流“式邏輯改成甚至于更復(fù)雜的”狀態(tài)機“方案次洼,頗有點”脫了褲子放屁“的意思关贵。
Bolt本身也有狀態(tài)機(State Machine),但它的狀態(tài)機就是在流(Flow Machine)之上的卖毁,這才是符合程序設(shè)計邏輯的做法揖曾。


Bolt的安裝和設(shè)置

Bolt需要在Asset Store或者其官網(wǎng)上購買,購買后會獲得一個.unitypackage文件亥啦,用于導(dǎo)入到Unity項目中炭剪。

導(dǎo)入完成后會自動彈出設(shè)置窗口:

首先是歡迎界面,點擊Next按鈕設(shè)置Naming:

這里建議使用Human Naming翔脱,比較不那么“反人類”奴拦,但依然還是需要經(jīng)常反查Unity的腳本幫助文件來了解哪些可用的Bolt單元/Unity函數(shù)。

Documentation欄是用來建立本項目的幫助文件的届吁,點擊Generate Documentation可以建立編輯器內(nèi)顯示的幫助文檔错妖,如果出錯也不要緊,忽略即可疚沐。Inspectors欄也可以直接點擊Generate Inspectors暂氯,讓Bolt自動完成這一步工作。

如果希望在Bolt中控制第三方插件亮蛔,則需要在Assemblies欄中加載對應(yīng)的第三方插件的DLLs文件痴施。

如果只是一些自定義的庫(class)或者構(gòu)造體(struct),則需要在Types欄中予以添加,然后點擊Generate讓Bolt創(chuàng)建本項目所需要的codebase辣吃。這個codebase就是我們可以在Bolt中使用的全部單元的集合锉矢。

正在構(gòu)建Bolt單元數(shù)據(jù)庫

在使用過程中,我們也可以通過Bolt菜單中的相關(guān)命令齿尽,來添加新的Assemblies或者Types沽损,或重建單元數(shù)據(jù)庫。

  • Setup Wizard...:重新設(shè)置本項目的Bolt
  • Update Wizard...:更新本項目的Bolt設(shè)置到最新(升級了Bolt版本之后使用)
  • Configuration...:打開偏好設(shè)置窗口
  • Unit Options Wizard...:僅更新Assemblies和Types兩項Bolt設(shè)置(需要添加新的插件支持或新的自定義類時使用)
  • Build Unit Options:直接重建codebase和unit database(在修改自定義腳本之后使用)
  • Update Unit Options:僅直接重建unit database(在修改自定義腳本之后使用)

在偏好設(shè)置窗口中循头,我們可以對Bolt進行一些設(shè)置绵估,其中大部分選項都可以保持默認,但我個人比較建議在Ludiq一頁中把Snap To Grid選項勾上卡骂,這樣強迫癥患者就不需要對著參差不齊的流圖而揪心了国裳。


Bolt的基本概念

Machine(機)

Machine(機)是我們添加給游戲?qū)ο螅℅ame Object)的Bolt組件,相當(dāng)于一個完整的腳本全跨。Bolt有兩種Machine:Flow Machine(流機)和State Machine(狀態(tài)機)缝左。前者是用一個個Unit串成完整的流式邏輯,后者則是用流機來描述一個個不同的狀態(tài)(states)以及狀態(tài)與狀態(tài)之間轉(zhuǎn)換的條件(Transition)浓若。

本文中不會多講State Machine渺杉,在剛剛接觸Bolt的時候,能用Flow Machine完成的交互設(shè)計都應(yīng)該盡量用Flow Machine來完成挪钓,一方面是因為沒必要是越,另一方面也是因為在Bolt中的State Machine設(shè)置起來其實還是蠻復(fù)雜的。

Embed VS. Macro

Machine可以內(nèi)嵌(Embed)于Unity場景碌上,也可以作為宏(Macro)保存在Asset文件夾里作為一個可以重復(fù)使用的游戲資源倚评。

建議最好在剛創(chuàng)建完Machine就決定究竟是使用哪種方式,因為雖然可以從一種方式轉(zhuǎn)換為另一種方式馏予,但這個過程并不是100%無損的天梧,復(fù)雜的Graph幾乎不可能不在轉(zhuǎn)換后出現(xiàn)各種各樣的問題。

我個人的建議是霞丧,如果一個Machine所代表的功能會被用在不同的地方呢岗,就請盡量使用Macro,或者說蚯妇,如果你準(zhǔn)備“復(fù)制/粘貼”某個Machine中的Graph到一個新的Machine中去敷燎,那么就將這個Machine轉(zhuǎn)換成Macro,然后在新Machine中調(diào)用箩言。

Graph(圖)

在Bolt中硬贯,Graph(圖)是程序命令執(zhí)行邏輯的可視化呈現(xiàn)。Flow Machine中呈現(xiàn)的是Flow Graph陨收,State Machine中呈現(xiàn)的是State Graph饭豹。

Flow Graph呈現(xiàn)出來的是一堆彼此相連的units(單元)鸵赖,其中必定有一個起點,這個起點通常是一個Event類型的unit拄衰,比如常見的StartUpdate它褪。代表著“當(dāng)……發(fā)生時,開始執(zhí)行本Graph”翘悉。

比如前面示例中的左邊的Graph茫打,就是在說:“當(dāng)本游戲?qū)ο蟊惠d入時,在console面板中輸出一行字符串’Hello World!’”妖混。

一個Machine中可以有多個Graphs老赤,用來區(qū)分在不同事件發(fā)生時所觸發(fā)的不同程序命令執(zhí)行邏輯。通常還可以將同一事件所觸發(fā)的多段邏輯分開成不同的Graph抬旺,以方便調(diào)試。比如“行走”和“跳躍”都會被Update所觸發(fā)振坚,但我們可以在一個Flow Machine中用兩個Update打頭的Graph來分別制作這兩個交互行為传货。不過,如果這兩個交互行為互相之間有所關(guān)聯(lián),或者需要有嚴格的前后執(zhí)行順序,那么最好還是做成一個單獨的Graph,避免出現(xiàn)問題。

嚴格來說,Bolt其實是將Machine中的所有內(nèi)容定義成一個Graph栏饮,但我個人認為這樣反而不好伺通,所以在這里解釋成“一個graph代表一個完整的彼此相連的units執(zhí)行流程結(jié)構(gòu)”弓柱。希望不會對大家的理解造成誤會屁药。

Unit(單元)

單元的類型

Unit是Bolt中最基本的元素缭嫡,一個unit代表一個操作命令有勾,多個unit按照順序組合成Graph荤懂,從而實現(xiàn)某一個特定的程序功能节仿。默認情況下,Bolt有超過23000個不同的unit掉蔬,我們可以把它們分成幾個大的類別:

  • 事件單元(events):決定“當(dāng)……發(fā)生時”的各種unit廊宪,通常都會顯示為綠色,被用在一個Flow Graph的起點
  • 命令單元(actions):決定“做什么”的各種unit
  • 數(shù)據(jù)單元(data):輸入各種數(shù)據(jù)的unit女轿,比如各種以“Literal”結(jié)尾的unit箭启。這些單元可以無需調(diào)用變量而獲得一個Unity數(shù)據(jù),比如浮點數(shù)(float)蛉迹、字符串(string)傅寡、光線(ray)、層遮罩(layer mask)等
  • 計算單元(calculation):用來處理數(shù)據(jù)北救、計算數(shù)據(jù)的各種unit荐操,比如加減乘除,各種數(shù)學(xué)函數(shù)等
  • 變量單元(variable):用來調(diào)用或修改變量的unit扭倾,主要是Set VariableGet Variable兩個
  • 邏輯單元(logic):用來控制Graph的運行邏輯走向的單元淀零,比如Branch(相當(dāng)于“if... else...”條件語句)和Loop(相當(dāng)于“for...”循環(huán)語句)等等

新建/替換單元

在Graph窗口的空白處點擊鼠標(biāo)右鍵,選擇Add Unit...膛壹,就可以通過搜索關(guān)鍵字來創(chuàng)建新的unit。如果在一個已有的unit上點擊鼠標(biāo)右鍵唉堪,選擇Replace...模聋,可以替換這個unit。

新建Unit
替換Unit

Fuzzy Finder(單元搜索器)

用來搜索unit的窗口叫“Fuzzy Finder”唠亚,目前還是比較好用的链方,搜索速度也比較快。但要注意的是灶搜,如果用多個關(guān)鍵字搜索祟蚀,這多個關(guān)鍵字的順序必須和結(jié)果中這些關(guān)鍵字的出現(xiàn)順序保持一致才行工窍,比如我搜“position” + “transform”就得不到“transform.position”,必須搜“transform” + ”position”才行前酿。

Connections(連接) & Ports(接口)

  • 三角形線框圖標(biāo)指向的(綠色的寬體箭頭)叫Connections(連接)患雏,是用來連接不同units以決定其執(zhí)行順序的端口
  • 圓形線框圖標(biāo)指向的(其他各種)叫Ports(接口),是用來傳遞數(shù)據(jù)的端口罢维,根據(jù)數(shù)據(jù)類型的不同淹仑,有不同的普調(diào)樣式,左邊的是接受其他數(shù)據(jù)的接口肺孵,右邊的是輸出數(shù)據(jù)的接口

并不是每個unit都需要用被Connection相連接才能起效匀借,有的unit根本就沒有Connection端口。一般來說平窘,執(zhí)行計算任務(wù)的unit都不需要連接Connection吓肋,比如下圖:

當(dāng)然,這個圖里面輸出的數(shù)據(jù)最終還是需要被傳遞給某個連接了Connection的unit才會真的被執(zhí)行瑰艘。

Overloads(分身)

一個Unity命令可以有多種調(diào)用方式蓬坡,叫做Overloads。Bolt中使用不同的unit來對應(yīng)各個Overloads磅叛,我個人將其翻譯成“分身”屑咳。

c#腳本中的Overloads
對應(yīng)Bolt Unit的Overloads

我個人不太喜歡這種將每個Overload都做成單獨節(jié)點的做法,每次都要找半天弊琴,而且很容易看錯兆龙。但貌似也沒有更合適的辦法了。

Variables(變量)

在Bolt中敲董,有5種不同形式的變量:

  • 圖示變量(Graph):圖示變量是圖示例中的局部變量紫皇。它們具有最小的可調(diào)用范圍,不能在其圖示之外訪問或修改腋寨。
  • 對象變量(Object):對象變量屬于游戲?qū)ο螅℅ameObject)聪铺。他們在該游戲?qū)ο蟮乃袌D示上共享。
  • 場景變量(Scene):場景變量在本場景的所有圖示上共享萄窜。
  • 應(yīng)用變量(Application):即使場景改變铃剔,應(yīng)用變量仍然存在。一旦應(yīng)用程序退出查刻,它們將被重置键兜。
  • 存儲變量(Saved):即使應(yīng)用程序退出,存儲變量也會也會繼續(xù)存在穗泵。他們可以被用作一個簡單但功能強大的存儲系統(tǒng)普气。它們被保存在Unity的玩家選項,這意味著它們不能像游戲?qū)ο蠛徒M件那樣被引用佃延。

個人認為现诀,Bolt的變量形式被設(shè)計得很奇怪夷磕。很難將其與正常腳本中設(shè)置的變量對應(yīng)起來理解。

  • Graph Variable有點類似private variable(私有變量)仔沿,但又必須提前定義好坐桩,遠不如腳本中那么方便使用;
  • Object Variable類似public variable(公開變量)于未,可以被外部訪問撕攒,但Bolt的Object Variable是通過在同一個Game Object上的一個叫做“Variables”腳本來定義的,相當(dāng)于是在獲取另一個組件的變量在用烘浦,而不是在本組件中定義可以公開訪問的變量抖坪;
  • Scene Variable類似global variable(全局變量),但其實是在場景中新建了一個叫“Scene Variables”的空游戲?qū)ο竺撇妫缓笸ㄟ^“Variables”腳本來定義擦俐,相當(dāng)于是在獲取同一場景中另一個游戲?qū)ο蟮淖兞吭谟茫?/li>
  • Application Variable才好像是真的全局變量;
  • Saved Variable實際上是在操作Unity的PlayerPrefs握侧,算是一個簡單實現(xiàn)“存檔”功能的方法吧蚯瞧,但還是顯得不倫不類的。

此外品擎,Bolt能夠用幾乎所有Unity數(shù)據(jù)類型做為變量埋合,比如:

  • 浮點數(shù)(Float)
  • 整數(shù)(Integar)
  • 布爾型(Boolean):是/否
  • 字符串(String)
  • 字符(Char):字符串中的一個字符
  • 枚舉類型(Enums):預(yù)先設(shè)定好的有限的枚舉選項,例如下拉菜單中的所有選項
  • 向量(Vector):向量其實是一個struct萄传,Unity中的向量包括二維向量(Vector2)甚颂、三維向量(Vector3)、四維向量(Vector4)
  • 游戲?qū)ο螅℅ame Object):Unity場景中的基本實體秀菱,每個游戲?qū)ο蠖加幸粋€名稱(name)振诬,一個位置和旋轉(zhuǎn)的轉(zhuǎn)換(transform),以及一個組件列表(components)
  • 列表(List):列表是元素的有序集合衍菱。元素可以是任意類型的赶么,但大多數(shù)情況下,列表中的所有元素必須是同一類型的脊串”枭耄可以通過從0開始的索引位置(index)檢索和分配列表中的每個元素
  • 字典(Dictionary):字典是一個集合,其中元素有一個唯一的鍵洪规,映射到它的值印屁。可以通過字典的鍵來檢索和分配字典的每個元素斩例。比如:可以按名稱(字符串鍵)創(chuàng)建年齡字典(整數(shù)值)
  • 對象(Object):“對象”是一種特殊類型。各種Unity專有的數(shù)據(jù)類型都被歸為Objects从橘。

變量窗口可以通過菜單Window -> Variables打開:

我個人強烈建議將這個窗口dock到編輯器的UI里念赶,雖然Graph窗口中會自動出現(xiàn)Variables窗口础钠,但那需要Graph窗口足夠大,而大多數(shù)時候叉谜,我們都不會將Graph窗口放大到那么大旗吁。

最左邊是我自己dock的窗口,緊挨著的是自動彈出來的窗口停局,但自動彈窗并不是一直都在的

最后很钓,我們可以通過將variable拖動到Graph窗口中來創(chuàng)建Get Variable單元,以使用這個variable董栽,也可以按住Alt鍵拖動variable到Graph窗口來創(chuàng)建Set Variable單元码倦,以設(shè)置這個variable

這個Graph做的事情是:獲取自身(self)游戲?qū)ο蟮奈恢茫╒ector3)锭碳,并減去儲存在“Player”這個變量中的游戲?qū)ο蟮奈恢茫╒ector3)袁稽,并將其結(jié)果(Vector3)設(shè)置給Offset變量。

Bolt的限制

Bolt所號稱的“凡是可以用代碼實現(xiàn)的功能擒抛,都可以用Bolt來實現(xiàn)”其實是有水份的推汽。

雖然Bolt支持幾乎所有的Unity函數(shù)命令,但并不等于我們就能完全無縫地將所有c#腳本代碼翻譯成Bolt流圖歧沪。至少:

  • Bolt目前還不支持Editor類的Unity函數(shù)命令歹撒。也就是說,沒有辦法用Bolt來做編輯器拓展诊胞。
  • Bolt目前不能直接支持自定義類(class)或者構(gòu)造體(Struct)暖夭。不是不能用,而是需要先用c#寫出來然后再加載進Bolt厢钧,才能在Graph中創(chuàng)建相應(yīng)的單元(unit)鳞尔。
  • Bolt目前還沒有完美的辦法實現(xiàn)自定義函數(shù)。Custom Event很類似了早直,但Custom Event不能定義輸出結(jié)果是在是很淡疼的一件事情寥假。而且Custom Event的本意是為了在c#腳本中調(diào)用Bolt的自定義事件。

這些缺失大多可以通過自己寫一些腳本來“彌補”霞扬,但如果自己都能寫腳本的糕韧,那還用Bolt干什么呢?況且喻圃,如果有專門的程序員幫我們寫擴展來“彌補”缺失萤彩,那我們干嘛不用PlayMaker呢,反正缺什么Action就讓人寫就是了斧拍。

另外雀扶,Bolt的Graph的復(fù)雜度其實要比程序代碼高很多,比如上面一條簡單的transform.Rotate (0f, Time.deltaTime * 30f, 0f);就要用3層結(jié)構(gòu)4個單元來組合完成,可想而知一個復(fù)雜的程序代碼翻譯成流圖之后會有多么復(fù)雜愚墓。而且予权,Bolt的運行效率(尤其是編輯器中的運行效率)比起代碼來要低很多,項目小還好浪册,一旦項目大起來扫腺,估計電腦差了連調(diào)試都調(diào)試不動呢。

因此村象,Bolt并不是一個“完美”的可視化編程插件笆环,只是比現(xiàn)有的解決方案要好一些罷了。與其將其當(dāng)做一個“生產(chǎn)力工具”厚者,不如將其當(dāng)做一個“學(xué)習(xí)工具”或者一個“原型工具”躁劣。在學(xué)習(xí)Bolt的過程中,盡量去了解正常的程序設(shè)計思維是如何進行的籍救,去熟悉Unity的各種API命令习绢,去掌握不同交互邏輯的實現(xiàn)手段和技巧,才是這個插件對于我們的最大價值蝙昙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闪萄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子奇颠,更是在濱河造成了極大的恐慌败去,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烈拒,死亡現(xiàn)場離奇詭異圆裕,居然都是意外死亡,警方通過查閱死者的電腦和手機荆几,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門吓妆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吨铸,你說我怎么就攤上這事行拢。” “怎么了诞吱?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵舟奠,是天一觀的道長。 經(jīng)常有香客問我房维,道長沼瘫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任咙俩,我火速辦了婚禮耿戚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己溅话,他們只是感情好晓锻,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布歌焦。 她就那樣靜靜地躺著飞几,像睡著了一般。 火紅的嫁衣襯著肌膚如雪独撇。 梳的紋絲不亂的頭發(fā)上屑墨,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音纷铣,去河邊找鬼卵史。 笑死,一個胖子當(dāng)著我的面吹牛搜立,可吹牛的內(nèi)容都是我干的以躯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啄踊,長吁一口氣:“原來是場噩夢啊……” “哼忧设!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起颠通,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤址晕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后顿锰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谨垃,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年硼控,在試婚紗的時候發(fā)現(xiàn)自己被綠了刘陶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡牢撼,死狀恐怖匙隔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情浪默,我是刑警寧澤牡直,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站纳决,受9級特大地震影響碰逸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阔加,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一饵史、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦胳喷、人聲如沸湃番。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吠撮。三九已至,卻和暖如春讲竿,著一層夾襖步出監(jiān)牢的瞬間泥兰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工题禀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鞋诗,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓迈嘹,卻偏偏與公主長得像削彬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子秀仲,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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