Nick Yeh
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 設計模式與遊戲開發的完美結合 此文檔純粹為本書之讀書心得,若有興趣請至[天瓏書局](https://www.tenlong.com.tw/products/9789864340835?list_name=t-%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F)購買。 同場加映: [鴨仔大大的心得](https://douduck08.wordpress.com/2016/08/10/when-i-first-time-use-design-pattern/)、[淺墨大神的Github](https://github.com/QianMo/Unity-Design-Pattern)、[Refactoring guru](https://refactoring.guru/) :::info **[part1 : 設計模式與遊戲設計 +基礎系統(上)](/rRnpqbQFRY2VQrGuN7xSjQ)**:mega: **[Part2 : 基礎系統(下)](/crMMLhU4Sg6MK2B3BX-TrQ)** **[Part3 : 角色的設計(上)](/80AlZxlvTOmPgpx-KNToEQ)** **[Part3-2 : 角色的設計(下)](/DiP_doU3Si2Czq4RDfjzQg)** **[part4 : 角色的產生](/jQl7Iu7sQGCqoqQayT_tCA)** **[part5 : 戰爭開始](/RZqXsKC0QqSTyR65DePN_A)** **[part6 : 輔助系統](/8u-WT-dhSgiclRUbplvCWg)** **[part7 : 調整與最佳化](/iORzUj4KQnqf5gGykIljRw)** ::: ## Chap1 遊戲實作中的設計模式 ### 1.1 起源 1994年由Erih Gamma、Richard Helm、Ralph Johnson、John Vlissider共同著作的 <*Design Patterns: Elements of Reusable Object-Oriented Software*>,提出和總結 了對於一些常見軟體設計問題的標準解決方案,稱為軟體設計模式。 因此,四位作者被稱呼為四人幫(GoF: Gang of Four) > 模式的概念,讓軟體設計也能像建築設計一樣,可以透過經驗累計的方式,來解決一再出現的問題。 > ### 1.2 什麼是設計模式 * 解決一再出現的問題 * 解決問題的方案 * 可以重複使用的解決方案 ### 1.3 OOP的設計原則 * [單一職責原則 (SRP:Single Responsibility Principle)](http://teddy-chen-tw.blogspot.com/2011/12/3.html) * [開放封閉原則 (OCP: Open-Closed Principle)](http://teddy-chen-tw.blogspot.com/2011/12/2.html) * 對**擴充**開放,對**修改**關閉 * [里式替代原則 (LSP: Liskov Substitution Principle)](http://teddy-chen-tw.blogspot.com/2012/01/4.html) * **子類別必須能夠替換父類別**,以確保底層的實作會遵守上層介面所定義的**行為**。 * [相依性反向原則 (DIP: Dependence Iversion Principle)](http://teddy-chen-tw.blogspot.com/2012/01/5dependency-inversion-principle.html) * 高層模組不應該相依於低層模組,兩者都應該相依於抽象概念 * 抽象介面不應該相依於實作,而實作應該相依於抽象介面 * [介面分割原則 (ISP: Interface Segregation Ptinciple)](http://teddy-chen-tw.blogspot.com/2014/04/solid.html) * 客戶端不應該被迫使用他們用不到的介面方法 * 最少知識原則 (LKP: Least Knowledge Principle) * 降低耦合度 * 少用繼承多用組合 Reference: [Unity3D學習網](http://www.unity.5helpyou.com/2572.html)、[鴨仔大大](https://douduck08.wordpress.com/2016/04/23/some-principle-of-object-oriented-design/) ### 1.4 Why design patterns > **設計模式** 就是學習**物件導向程式設計**的最佳範本 ### 1.5 遊戲程式設計與軟體設計模式 * 市場變化: 專屬團隊的遊戲開發框架 * 需求變化: 敏捷開發、定期發布、單元測試、強化OOAD,利用設計模式去應對**變化** * 應用平台: 核心保有獨立性,遊戲核心玩法 與 應用平台或開發工具 之間的關聯必須降到最低 * 技術多樣化: 將各項技術作介面切割,並讓功能元件保持最小知識原則 ### 1.6 模式的應用與學習 - Gang of Four Patterns (23種設計模式) #### Behavioral Patterns 行為模式 : 類別或物件之間互動或是責任分配的方式 * [Command Pattern 命令模式](/RZqXsKC0QqSTyR65DePN_A) * [State Pattern 狀態模式](/rRnpqbQFRY2VQrGuN7xSjQ) * [Observer Pattern 觀察者模式] * [Chain of Responsibility Pattern 責任鍊模式] * [Mediator Pattern 仲介者模式](/crMMLhU4Sg6MK2B3BX-TrQ) * Interpreter Pattern 解釋器模式 * Iterator Pattern 迭代器模式 * [Memento Pattern 備忘錄模式] * [Strategy Pattern 策略模式](/80AlZxlvTOmPgpx-KNToEQ) * [Template Method Pattern 模板方法模式](/DiP_doU3Si2Czq4RDfjzQg) * [Visitor Pattern 訪問者模式] #### Structural Patterns 結構模式 : 類別或物件之間組合的方式 * [Adapter Pattern 轉換器模式] * [Bridge Pattern 橋接模式](/80AlZxlvTOmPgpx-KNToEQ) * [Composite Pattern 組合模式](/RZqXsKC0QqSTyR65DePN_A) * [Decorator Pattern 裝飾模式] * [Facade Pattern 外觀模式](/rRnpqbQFRY2VQrGuN7xSjQ) * [Flyweight Pattern 享元模式](/jQl7Iu7sQGCqoqQayT_tCA) * [Proxy Pattern 代理模式] #### Creational Patterns 生成模式 : 產生物件的過程與方式 * Prototype Pattern 原型模式 * [Singleton Pattern 單例模式](/crMMLhU4Sg6MK2B3BX-TrQ) * Abstract Factory Pattern 抽象工廠模式 * [Builder Pattern 建造者模式](/jQl7Iu7sQGCqoqQayT_tCA) * [Factory Method Pattern 工廠方法模式](/jQl7Iu7sQGCqoqQayT_tCA) ## Chap2 遊戲範例說明 此章為本書Project的使用說明 略 ## Chap3 遊戲場景的轉換-State狀態模式 ### 3.1 遊戲場景 ![](https://i.imgur.com/1iaSMF0.png) #### 範例的場景規劃 ![](https://i.imgur.com/boSQBBU.png) #### 一般場景控制的寫法 ```C# public class SceneManger { private string m_state = "開始"; //改換場景 public void ChangeScene(string StateName) { m_state = StateName; switch(m_state) { case "選單": Application.LoadLevel(MainMenuScene); break; case"主場景": Application.LoadLevel(GameScene); break; } } //改換場景 public void Update() { switch(m_state) { case "開始": //... break; case "選單": //... break; case"主場景": //... break; } } } ``` #### 缺點 1. 增加狀態困難 2. 每一個狀態相依的物件都必須在此SceneManager,當這些物件被多個狀態共用時,除錯困難 3. 每一個狀態使用不同的物件,造成SceneManager過度依賴其他類別,移植困難 ### 3.2 狀態模式 #### 定義 > 讓一個物件的行為隨著內部狀態改變而變化,其物件就像是換了類別一樣 > > [name=GoF] 以遊戲角度來看就會變這樣 > 當德魯伊(物件)由人形轉化為獸型狀態(狀態改變),其施展的技能(物件的行為)也會有所變化,玩家此時就像是在操作另一個不同的角色(換了類別) > #### UML ![](https://i.imgur.com/oQWpCg5.gif) * **Context(狀態擁有者)** * 是一個具有**狀態**屬性的類別,可以制定相關介面,讓外部能夠**得知狀態改變**或**改變狀態**。 * **State(狀態介面類別)** * 負責規範Context在特定狀態下的行為。 * **ConcreteState(具體狀態類別)** * 繼承State。 * 實作Context在特定狀態下的行為,也就是override Handle函式。 #### 實作範例 ```C#= using UnityEngine; using System.Collections; namespace DesignPattern_State { // 持有目前的狀態,並將有關的訊息傳給狀態 public class Context { State m_State = null; public void Request(int Value) { m_State.Handle(Value); } public void SetState(State theState ) { Debug.Log ("Context.SetState:" + theState); m_State = theState; } } // 負責封裝當Context處於特定狀態時所該展現的行為 public abstract class State { protected Context m_Context = null; public State(Context theContext) { m_Context = theContext; } public abstract void Handle(int Value); } // 狀態A public class ConcreteStateA : State { public ConcreteStateA( Context theContext):base(theContext) {} public override void Handle (int Value) { Debug.Log ("ConcreteStateA.Handle"); if( Value > 10) m_Context.SetState( new ConcreteStateB(m_Context)); } } // 狀態B public class ConcreteStateB : State { public ConcreteStateB( Context theContext):base(theContext) {} public override void Handle (int Value) { Debug.Log ("ConcreteStateB.Handle"); if( Value > 20) m_Context.SetState( new ConcreteStateC(m_Context)); } } // 狀態C public class ConcreteStateC : State { public ConcreteStateC( Context theContext):base(theContext) {} public override void Handle (int Value) { Debug.Log ("ConcreteStateC.Handle"); if( Value > 30) m_Context.SetState( new ConcreteStateA(m_Context)); } } } ``` ```C#= using UnityEngine; using System.Collections; using DesignPattern_State; public class StateTest : MonoBehaviour { // Use this for initialization void Start () { UnitTest(); } // void UnitTest () { Context theContext = new Context(); theContext.SetState( new ConcreteStateA( theContext )); theContext.Request( 5 ); theContext.Request( 15 ); theContext.Request( 25 ); theContext.Request( 35 ); } } ``` ### 3.3 狀態模式實作遊戲場景的轉換 #### 心得前言 本書的遊戲場景為單一場景,但現階段的Unity可能會有多場景編輯的案例,請按規畫使用。 有興趣可以看看這部 **Unite 2016 - Tools, Tricks and Technologies for Reaching Stutter Free 60 FPS in INSIDE** {%youtube mQ2KTRn4BMI %} #### P級陣地結構 ![](https://i.imgur.com/Ouklmrn.png) #### State Pattern實作遊戲場景的優點 * 不要使用Switch,減少錯誤的發生與提高可維護性 * 場景之間的物件關係單純化 * 重用性高,尤其對於網路連線型的遊戲專案,開始場景中處理玩家的連線、登入、驗證、資料同步等過程可以跨專案來使用,以節省開發時間與成本。 #### Gameloop及場景轉換說明 PS: 這裡的Gameloop是繼承Unity的MonoBehaiour ,因此腳本Lifecycle是Unity的流程 1. 透過StartScene中唯一的Gameloop遊戲物件上的gameloop腳本元件,將整個遊戲運作起來。 2. Gameloop的Start方法中,設定起始場景SetState(new StartState(控制器), "")。 3. Gameloop的Update方法將控制權轉交給SceneStateControllor。 4. SceneStateControllor紀錄當前場景狀態,並呼叫StateUpdate方法來執行紀錄的場景狀態的StateUpdate方法 ![](https://i.imgur.com/FjNfYWQ.png) ### 3.4 狀態模式遇到變化時 當專案進度進到後期,增加的遊戲功能例如,增加關卡、角色圖鑑、排行榜、商城等等功能,如果無法在現有的場景下實作,就必須在新的場景實作。此時的現有架構下只需要作下列變更: 1. Unity新增場景 2. 加入新的SceneState類別,並實作其功能 3. 決定狀態轉換規則,並修改載入順序 盡量遵守開放封閉原則,只需加入新的State,無須修改原有程式。 ### 結論 優點: 減少因新增狀態而需要大量修改的維護成本 缺點: 大量狀態的系統,就會遇到**產生過多狀態類別**之情形 #### 與其他模式合作 PBaseDefensegame使用Singleton 、 Facade,使BattleState可以取得唯一物件又不用知道其內部實作方式。 ## Chap4 遊戲主要類別-Facade外觀模式 ### 4.1 遊戲子功能的整合 一款遊戲通常由內部多個子系統組合而成,以「P級陣地」來說,由下列遊戲系統組成: * 事件系統 * 兵營系統 * 關卡系統 * 角色管理系統 * 行動力系統 * 成就系統 這些子系統的溝通與初始化,盡量在內部完成,降低系統對客戶端(Unity)的依賴 舉例: 上一章的BattleState,就必須用到遊戲系統功能的客戶端,其主要負責遊戲戰鬥的執行 ```C# // 戰鬥狀態 public class BattleState : ISceneState { // 遊戲系統 private GameEventSystem m_GameEventSystem = null; // 遊戲事件系統 private CampSystem m_CampSystem = null; // 兵營系統 private StageSystem m_StageSystem = null; // 關卡系統 private CharacterSystem m_CharacterSystem = null; // 角色管理系統 private APSystem m_ApSystem = null; // 行動力系統 private AchievementSystem m_AchievementSystem = null;// 成就系統 public BattleState(SceneStateController Controller):base(Controller) { this.StateName = "BattleState"; //初始遊戲子系統 InitGameSystem(); } // 初始遊戲子系統 private void InitGameSystem() { m_GameEventSystem = new GameEventSystem(); // 遊戲事件系統 m_CampSystem = new CampSystem(); // 兵營系統 m_StageSystem = new StageSystem(); // 關卡系統 m_CharacterSystem = new CharacterSystem(); // 角色管理系統 m_ApSystem = new APSystem(); // 行動力系統 m_AchievementSystem = new AchievementSystem(); // 成就系統 } // 更新遊戲子系統 private void UpdateGameSystem() { m_GameEventSystem.Update(); m_CampSystem.Update(); m_StageSystem.Update(); m_CharacterSystem.Update(); m_ApSystem.Update(); m_AchievementSystem.Update(); } //以下略 } ``` 1. 以**單一職責原則**而言,BattleState負責的是遊戲在「戰鬥狀態」下的**功能執行與狀態切換**,不應該負責子系統的初始化、執行操作與相關的整合。 2. 以**可重用性**而言,與過多子系統綁定(產生關聯),因此喪失重用性。 因此應用了外觀模式(Facade)來整合子系統,使它們成為單一介面提供給外界使用。 ### 4.2 Facade外觀模式 #### 定義 > 替子系統定義一組統一的介面,這個高階的介面會讓子系統更容易被使用 > > [name=GoF] > > 本書以微波爐為例,其內部包含電源供應系統、冷卻系統、電波加熱系統、外裝防護系統等。 而我們只需要利用微波爐上的控制面板就能完成需求,無須了解內部系統。 所以,外觀模式重點在於: * 系統內部的互動細節隱藏起來,提供簡易的介面供給使用者。 #### UML ![](https://i.imgur.com/AerCEKj.png) * **Client(使用者)** * 從原本需要操作多個子系統的狀況,改為只需要面對一個整合後的介面。 * **subSystem(子系統)** * 原本會由不同的客戶端(非同一系統相關)來操作,改由內部系統之間交互使用。 * **Facade(統一對外的介面)** * 整合子系統的介面與功能,提供高階介面供使用者使用。 * 接收客戶端的訊息後,將訊息傳送給負責的子系統。 ### 4.3 Facade外觀模式實作遊戲主程式 #### UML ![](https://i.imgur.com/mHCATe6.png) #### 現階段的PBaseDefensegame.cs 、 BattleState.cs ```C# public class PBaseDefenseGame { // 遊戲系統 private GameEventSystem m_GameEventSystem = null; // 遊戲事件系統 private CampSystem m_CampSystem = null; // 兵營系統 private StageSystem m_StageSystem = null; // 關卡系統 private CharacterSystem m_CharacterSystem = null; // 角色管理系統 private APSystem m_ApSystem = null; // 行動力系統 private AchievementSystem m_AchievementSystem = null;// 成就系統 public void Initinal() { // 場景狀態控制 m_bGameOver = false; // 遊戲系統 m_GameEventSystem = new GameEventSystem(this); // 遊戲事件系統 m_CampSystem = new CampSystem(this); // 兵營系統 m_StageSystem = new StageSystem(this); // 關卡系統 m_CharacterSystem = new CharacterSystem(this); // 角色管理系統 m_ApSystem = new APSystem(this); // 行動力系統 m_AchievementSystem = new AchievementSystem(this); // 成就系統 } // 釋放遊戲系統 public void Release() { // 遊戲系統 m_GameEventSystem.Release(); m_CampSystem.Release(); m_StageSystem.Release(); m_CharacterSystem.Release(); m_ApSystem.Release(); m_AchievementSystem.Release(); } // 更新遊戲子系統 private void Update() { m_GameEventSystem.Update(); m_CampSystem.Update(); m_StageSystem.Update(); m_CharacterSystem.Update(); m_ApSystem.Update(); m_AchievementSystem.Update(); } // 遊戲狀態 public bool ThisGameIsOver() { return m_bGameOver; } // 目前敵人數量 public int GetEnemyCount() { if( m_CharacterSystem !=null) return m_CharacterSystem.GetEnemyCount(); return 0; } // 目前各單位數量 public int GetUnitCount(ENUM_Soldier emSolider) { return m_CharacterSystem.GetUnitCount(emSolider); } public int GetUnitCount(ENUM_Enemy emEnemy) { return m_CharacterSystem.GetUnitCount(emEnemy); } } ``` #### 新的battleState.cs 這裡面的PBaseDefenseGame.Instance.方法(),請看下一章的單例模式 ```C# public class BattleState : ISceneState { public BattleState(SceneStateController Controller):base(Controller) { this.StateName = "BattleState"; } // 開始 public override void StateBegin() { PBaseDefenseGame.Instance.Initinal(); } // 結束 public override void StateEnd() { PBaseDefenseGame.Instance.Release(); } // 更新 public override void StateUpdate() { // 遊戲邏輯 PBaseDefenseGame.Instance.Update(); // Render由Unity負責 // 遊戲是否結束 if( PBaseDefenseGame.Instance.ThisGameIsOver()) m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuScene" ); } } ``` ### 4.4 外觀模式遇到變化時 隨著**開發需求的變更**,任何遊戲子系統的**修改**及**更換**,都被限縮在PBaseDefenseGame這個Facade模式類別中。這樣子就能減少更動範圍。 ### 結論 #### 優點 **核心: Client減少對系統的耦合度** * 節省時間 對C/C++ 而言,標頭檔(.h)代表某一個類別所提供的介面,當介面中的方法有所更動時,任何引用到該標頭檔的單元都必須重新編譯。以採用編譯器來編譯的語言,一個包含上千個C/C++ 檔案的中大型專案,會因為設計不良,使得變動一個.h檔中的方法,造成專案過半的檔案都必需重新編譯。 在Unity中,不少使用到Facade模式的系統,例如:物理系統、渲染系統、例子系統...等。 開發者只需專注在遊戲效果跟玩法上,不須自己去開發內建的系統功能。 * 易於分工 理論上開發者只須了解對方提供的Facade介面,不必了解內部運作,也不必花費太多時間與對方的系統連接,讓自己寫的功能容易維護。(但是實際上,有人員變動(沒有留Doc)、溝通成本、團隊規模等等的問題,不一定能解決分工問題,務必依情況來使用) * 增加系統安全性 這裡的安全性所指,系統執行時**意外當機或出錯**的情況。因為有時候子系統之間的溝通及建構順序上,有一定的步驟,例如:某一功能要先通知A子系統,才能呼叫B子系統完成後續功能,這樣的建立順序應該由Facade介面完成,不該由Client去實作。如果讓Client實作呼叫順序,不巧這個順序被更動或錯誤,開發者一看! 挖X! Client不只一個,那就是一場災難! #### 缺點 當介面類別過於龐大難以維護時,需要重構Facade介面類別,將功能相近的子系統再次整合,減少內部系統的相依性或是搭配其他模式減少Facade介面過度膨脹。 #### 與其他模式合作 PBaseDefenseGame用Singleton + Facade ,內部子系統使用Mediator互相溝通,而GameEventSystem使用Observer實作,主要目地為減少PBaseDefenseGame類別介面過於龐大。 #### 其他應用方式 **網路引擎**: 連線管理系統、傳輸信息系統、封包管理系統、分流負載系統等等子系統,用Facade包成一個完整的系統。 **資料庫**: 將<關聯式資料庫>(MySQL)相關的操作,以一種較高階的介面隔離,包含一般所需的:連線、增、刪、改、查、Join等操作加以包裝、提供給前端來操作使用。

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully