<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Haox Land</title>
  
  
  <link href="https://blog.harrison-chen.dev/atom.xml" rel="self"/>
  
  <link href="https://blog.harrison-chen.dev/"/>
  <updated>2026-02-25T00:47:12.004Z</updated>
  <id>https://blog.harrison-chen.dev/</id>
  
  <author>
    <name>Harrison Chen</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>打造self host的第二大腦</title>
    <link href="https://blog.harrison-chen.dev/2026/01/18/%E6%89%93%E9%80%A0self%20host%E7%9A%84%E7%AC%AC%E4%BA%8C%E5%A4%A7%E8%85%A6/"/>
    <id>https://blog.harrison-chen.dev/2026/01/18/%E6%89%93%E9%80%A0self%20host%E7%9A%84%E7%AC%AC%E4%BA%8C%E5%A4%A7%E8%85%A6/</id>
    <published>2026-01-18T14:29:35.000Z</published>
    <updated>2026-02-25T00:47:12.004Z</updated>
    
    <content type="html"><![CDATA[<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>我以前一直就是<a href="https://zh.wikipedia.org/zh-tw/Pocket">pocket</a>這個軟體的大粉絲，很喜歡在pocket存一些medium或是hackernews看到的有趣的知識文章、技術文章，甚至是一些人生相關的優文。</p><p><br/></p><p>沒想到去年五月的時候Mozilla宣布把pocket關閉，在那之後我就只剩下把這些資料存到telegram的saved message中（然後就再也懶得打開）</p><p><br/></p><p>仔細想想這樣真的是有點慘，今天早上心血來潮，覺得重拾這個知識管理系統，這次要用可以self-host的東西才不會再次被別人收掉。</p><p><br/></p><p>這次我跟著gemini聊天一邊follow up一邊把我的系統建立起來，發一篇文章留個紀錄。</p><p><br/></p><h2 id="為什麼選用gemini聊天"><a href="#為什麼選用gemini聊天" class="headerlink" title="為什麼選用gemini聊天"></a>為什麼選用gemini聊天</h2><p><br/></p><p>為什麼這次我選擇用web的聊天介面，而不是claude code / github copilot / open code或是antigravity這種開發介面？</p><p><br/></p><p>因為我目前已經有部署好的vps，架設好的n8n，和一個已經在運行的telegram bot作為我的calendar agent，我總覺得直接建立一個新的web服務不會是最順暢的流程。</p><p><br/></p><p>正好，幾年前就有耳聞obsidian非常厲害，這次想說來使用self-host在GitHub上面的obsidian流程來做做看。所以和gemini聊了聊系統設計。</p><p><br/></p><h2 id="Obsidian的vault建立"><a href="#Obsidian的vault建立" class="headerlink" title="Obsidian的vault建立"></a>Obsidian的vault建立</h2><p>這步驟好像也不需要用到ai，簡單找了一篇教學下載Git plugin + GitHub快速建立了自己knowledge based的repo後，就可以快速建立iPad / MacOS / Windows可以互相共通的筆記本流。</p><p><img data-src="/img/ 打造self host的第二大腦/img_1.png" alt="image"></p><h2 id="n8n-與-tg-bot的串聯"><a href="#n8n-與-tg-bot的串聯" class="headerlink" title="n8n 與 tg bot的串聯"></a>n8n 與 tg bot的串聯</h2><p>這次的整個經驗學到最多的，其實反而是n8n的agent based設計理念的完整實踐。</p><p><br/></p><p>原本我可能會想說是不是拉一個完整的Flow來做這些事情，但是這個其實就不是agent的做法。</p><p><br/></p><p>Gemini建議我，可以建立一些sub-workflow，製作成agent可以使用的工具來進行。</p><p><br/></p><p>最後建立了以下兩個工具</p><ol><li>Tool - Save to Obsidian</li></ol><p>這個工具做的事情很簡單，就是可以給agent呼叫，來在指定位置建立新的檔案，類似我想要的pocket存檔</p><p><img data-src="/img/ 打造self host的第二大腦/img_5.png" alt="image"></p><ol><li>Tool - Jina Reader</li></ol><p>Jina AI是一個LLM友善的輔助爬蟲工具，有免費流量在我個人使用上非常足夠，這個工具可以呼叫一個url來取得文章內容。</p><p><img data-src="/img/ 打造self host的第二大腦/img_3.png" alt="image"></p><p><br/></p><p>加入這兩個工具再微調prompt後，我原本拿來紀錄calendar事件的bot，搖身一邊獲得了可以自動記錄obsidian文章的能力，也就是我要的pocket功能了！</p><p><img data-src="/img/ 打造self host的第二大腦/img_4.png" alt="image"></p><p><br/></p><p>在Telegram中聊天感覺如下</p><p><img data-src="/img/ 打造self host的第二大腦/img_2.png" alt="image"></p><p><br/></p><p>成功完成當初想要的pocket功能，而且在文章中，還可以有AI的摘要、翻譯等優點，可以說比當年的pocket更加強大。</p><p><img data-src="/img/ 打造self host的第二大腦/img_6.png" alt="image"></p>]]></content>
    
    
    <summary type="html">使用 Obsidian + n8n + Telegram Bot 打造可以 self-host 的知識管理系統，取代已關閉的 Pocket 服務。</summary>
    
    
    
    <category term="Software Development" scheme="https://blog.harrison-chen.dev/categories/Software-Development/"/>
    
    
    <category term="Linux" scheme="https://blog.harrison-chen.dev/tags/Linux/"/>
    
    <category term="Docker" scheme="https://blog.harrison-chen.dev/tags/Docker/"/>
    
    <category term="Software Development" scheme="https://blog.harrison-chen.dev/tags/Software-Development/"/>
    
    <category term="Backend" scheme="https://blog.harrison-chen.dev/tags/Backend/"/>
    
  </entry>
  
  <entry>
    <title>vps心得＆部署一些工具感想</title>
    <link href="https://blog.harrison-chen.dev/2024/12/14/vps%E5%BF%83%E5%BE%97%EF%BC%86%E9%83%A8%E7%BD%B2%E4%B8%80%E4%BA%9B%E5%B7%A5%E5%85%B7%E6%84%9F%E6%83%B3/"/>
    <id>https://blog.harrison-chen.dev/2024/12/14/vps%E5%BF%83%E5%BE%97%EF%BC%86%E9%83%A8%E7%BD%B2%E4%B8%80%E4%BA%9B%E5%B7%A5%E5%85%B7%E6%84%9F%E6%83%B3/</id>
    <published>2024-12-14T17:44:38.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p><br/></p><p>最近因為朋友的surfshark到期了，加上自己想獲得一個連線到日本的節點，以及希望有一個public ip可以拿來建立一些web service，上網研究了一下購入了日本的VPS服務。</p><p>在一篇講馬娘如何繞過cygames的檢查的巴哈文章裡面看到了 <a href="https://web.arena.ne.jp/indigo/">WebArena Indigo</a> ，一個月只要400多日幣就可以開一台VPS （spec如下，少的可憐 ＱＱ）對於我目前的需求來說還是蠻夠用了。</p><p><img data-src="/img/vps心得＆部署一些工具感想/img_1.png" alt="image"></p><span id="more"></span><p><br/></p><h2 id="Instance選擇？"><a href="#Instance選擇？" class="headerlink" title="Instance選擇？"></a>Instance選擇？</h2><p>因為WebArena蠻多中國的文章都有詳述，開instance的介面說實在也蠻單純的，這邊就直接跳過開機的步驟（我也沒截圖 嘻嘻）。</p><p>機器本身就是一台qemu/kvm，可以選centos/ubuntu等常見的distrubtion，似乎也有windows server的選項，但想到license的溢價，對我個人來說是完全沒考慮過，就一台vps打天下吧！</p><p>另外平台也有提供snapshot功能，但snapshot也要依照儲存時間計費，實在太不划算了，趕緊弄一弄自己的IaC做自動部署環境那些，感覺還比較實際。</p><p><br/></p><h2 id="首先拿來幹嘛"><a href="#首先拿來幹嘛" class="headerlink" title="首先拿來幹嘛"></a>首先拿來幹嘛</h2><p>我個人的使用目的第一號，是想要一個日本的網路節點可以拿來看一些日本動畫之類的（動畫瘋不是什麼都有），但大家也知道日本的網路服務非常的鎖國外IP，甚至三大csp/oracle的都被ban光光，更別說那些每天看得到廣告的vpn品牌可以說是完全不用想拿來看任何日本網站。</p><p>所以首先就使用這邊開的instance來嘗試連線，很幸運的沒有在我想使用的服務的block list中，順利用100多台幣獲得一台好夥伴。</p><p><br/></p><h2 id="部署了什麼服務"><a href="#部署了什麼服務" class="headerlink" title="部署了什麼服務"></a>部署了什麼服務</h2><h3 id="TW-forum-feed-化大作戰"><a href="#TW-forum-feed-化大作戰" class="headerlink" title="TW forum feed 化大作戰"></a>TW forum feed 化大作戰</h3><p>在去年開啟了gcp試用的期間，我使用golang簡單寫了一些cloud function拿來做ptt/噗浪的貼文feed化，repo在這邊<a href="https://github.com/Harrison-Dev/go_feed_tool">go-feed-tool</a>原本是使用cloud function形式，試用了<a href="https://www.cursor.com/">Cursor</a>來進行web server的改版，用起來還挺得心應手，大約在半小時～一小時的區間就成功部署成為web server app，還做了一些功能的調整更新。</p><p><br/></p><h3 id="RSS-feed-telegram-bot"><a href="#RSS-feed-telegram-bot" class="headerlink" title="RSS feed telegram bot"></a>RSS feed telegram bot</h3><p>因為我個人和交友圈，最常使用的social app其實是telegram，telegram有著碾壓其他社群軟體的跨平台同步速度，更扯的是他的bot是完全不用收錢，為了讓自己更方便「被動」獲取一些論壇資訊（真的花太多時間滑PTT= =）我使用了公開repo <a href="https://github.com/Rongronggg9/RSS-to-Telegram-Bot">RSS-To-Telegram-Bot</a>，部署到自己的機器上，在做for個人的RSS通知機器人。</p><p>順帶一提這個作者也有一個共同使用的bot公開，但為了自己rss註冊表資料的可控、隱私、還有爬文web app說實在也不想隨便暴露，所以自己建在自己機器上對我來說比較適合一些。</p><p><br/></p><h3 id="Nuget-To-Unitypackage-服務"><a href="#Nuget-To-Unitypackage-服務" class="headerlink" title="Nuget To Unitypackage 服務"></a>Nuget To Unitypackage 服務</h3><p>使用Unity的時候，如果想使用nuget的package(例如大家都愛的Newtonsoft.Json)其實是一件相當麻煩的苦差事，現在大部分使用 <a href="https://github.com/GlitchEnzo/NuGetForUnity">NuGetForUnity</a> 專案來管控下載以及dependency等，但有時候只是想單獨使用某一包，也不想安裝這個專案（有時候覺得太過龐大），所以簡單做了一個web service + executable的程式，可以使用nuget下載package，自動選擇對unity專案較為適合的target，建立asmdef的關聯，最後打包成unitypackage可以一鍵置入專案。</p><p>專案在這：<a href="https://github.com/Harrison-Dev/nuget-2-dll-go">nuget-2-dll-go</a></p><p>值得一提的是，在部署這個服務的時候遇到蠻多問題，第一個是目前前面的服務docker image都是基於alpine就可以運行，但這個專案因為需要nuget，使用debian會是相對穩定的執行環境，所以程式在build的時候雖然一樣基於golang的alpine環境建立，但執行環境我選擇了debian:bullseye-slim，沒想到才是噩夢的開始…</p><p>首先是因為其他docker-compose都在正常進行中，所以機器本來記憶體就所剩不多，在安裝debian的nuget的時候又會調用到蠻大量的記憶體，結果我這台只有1G記憶體的vps直接吃不消，被out of memory killer砍翻了，機器當掉好幾次。</p><p>後來開著htop同時監督，才發現這個階段記憶體完全用到超過90%，後面是不可能完成的，還好這vps雖小還是給了20GB的SSD，趕緊的切了2GB當swap file，才真的成功部署到機器上（kernal版本不給我跑zram orz，不然真的不太想直接開到swap file）。</p><h3 id="其他部署問題"><a href="#其他部署問題" class="headerlink" title="其他部署問題"></a>其他部署問題</h3><p>因為這期間我也購入了自己的domain name，所以用了traefik來做簡易的LB/reverse proxy，把這些服務都分到不同的subdomain去。</p><p>結果發現Cloudflare的dns，好像會自動上https，所以處理CA憑證那邊也花了快半小時左右，才成功把這些service公開出來讓自己的rss reader使用。</p><p><br/></p><h2 id="接下來要做什麼"><a href="#接下來要做什麼" class="headerlink" title="接下來要做什麼"></a>接下來要做什麼</h2><p>目前還在想有什麼服務可以部署，但作為一個遊戲開發者，感覺自己應該要開始拓展多人遊戲的開發技能了。</p><p>這個機器小到離譜，所以如果拿來做relay server感覺可能會翻車，目前構想應該是做簡單的match-making/lobby，然後打通STUN之後讓玩家們直接nat punchthrough來連線？ 不曉得unity netcode有沒有別人寫好的套件可用，Unity自己要賣Cloud Service的Relay Server，感覺肯定不會推薦用p2p遊玩 lul。</p><p><br/></p><p>總之最近買了vps/domain name等，又複習了一大堆linux admin的設定，還有現代雲的一些常用工具等等，接下來如果可以蹭到一些oracle的機器，感覺可以開始導入一些Terraform之類的IaC之類的來做自動化部署etc。</p><p>後端技能樹越點越多的Game Programmer是不是搞錯了什麼？ 為了自清自己是Game Programmer指好放一下自己上電視的片段已證清白 ｈａｈａ</p><div id="wrap"><iframe width="560" height="315" src="https://www.youtube.com/embed/RLgXk2xy79c?si=C6IK0kDtmsGzyqDO&amp;start=496" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></div>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;最近因為朋友的surfshark到期了，加上自己想獲得一個連線到日本的節點，以及希望有一個public ip可以拿來建立一些web service，上網研究了一下購入了日本的VPS服務。&lt;/p&gt;
&lt;p&gt;在一篇講馬娘如何繞過cygames的檢查的巴哈文章裡面看到了 &lt;a href=&quot;https://web.arena.ne.jp/indigo/&quot;&gt;WebArena Indigo&lt;/a&gt; ，一個月只要400多日幣就可以開一台VPS （spec如下，少的可憐 ＱＱ）對於我目前的需求來說還是蠻夠用了。&lt;/p&gt;
&lt;p&gt;&lt;img data-src=&quot;/img/vps心得＆部署一些工具感想/img_1.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Software Development" scheme="https://blog.harrison-chen.dev/categories/Software-Development/"/>
    
    
    <category term="Linux" scheme="https://blog.harrison-chen.dev/tags/Linux/"/>
    
    <category term="Docker" scheme="https://blog.harrison-chen.dev/tags/Docker/"/>
    
    <category term="Software Development" scheme="https://blog.harrison-chen.dev/tags/Software-Development/"/>
    
    <category term="Backend" scheme="https://blog.harrison-chen.dev/tags/Backend/"/>
    
  </entry>
  
  <entry>
    <title>京都BitSummit遊記</title>
    <link href="https://blog.harrison-chen.dev/2023/09/10/Travel/%E4%BA%AC%E9%83%BDBitSummit%E9%81%8A%E8%A8%98/"/>
    <id>https://blog.harrison-chen.dev/2023/09/10/Travel/%E4%BA%AC%E9%83%BDBitSummit%E9%81%8A%E8%A8%98/</id>
    <published>2023-09-10T15:14:27.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>雖然說是遊記，但是其實這趟前往BitSummit是代表遊戲去出差的，這邊再放一次遊戲的連結，有興趣的麻煩加一下願望清單。</p><p><br/></p><iframe src="https://store.steampowered.com/widget/1619230/" frameborder="0" width="100%" height="190"></iframe><p><br/></p><span id="more"></span><h3 id="第一天行程：前往京都"><a href="#第一天行程：前往京都" class="headerlink" title="第一天行程：前往京都"></a>第一天行程：前往京都</h3><p>時隔已久的來到機場掛行李處</p><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_4.jpeg" alt="Untitled"></p><p><br/></p><p>發現前往日本的人潮遠遠不及前往韓國的航班，我們搭乘的這班飛機甚至還沒客滿</p><p><br/></p><p>經過沒幾小時的飛行後，終於抵達關西國際機場，上次來這邊是小時候家庭出遊時跟團，可以說對這邊真的是非常陌生 🥹</p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_9.jpeg" alt="Untitled"></p><p><br/></p><p>這次出差住在日本星野集團的OMO 5京都三条，房間雖然不大但是睡起來還是滿舒適的</p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_6.jpeg" alt="Untitled"></p><p><br/></p><p>經過一天的舟車勞頓，在飯店的對面吃了一家居酒屋，有超棒的生魚片拼盤～</p><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_2.jpeg" alt="Untitled"></p><p><br/></p><p>吃完後回飯店養精蓄銳，準備第二天要開始擺攤之路了～</p><p><br/></p><h3 id="第二天：擺攤第一天-business-day"><a href="#第二天：擺攤第一天-business-day" class="headerlink" title="第二天：擺攤第一天 (business day)"></a>第二天：擺攤第一天 (business day)</h3><p><br/></p><p>這次承蒙資策會的邀請，在digi+的攤位展示我們的新作 star named eos</p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_10.jpeg" alt="Untitled"></p><p><br/></p><p>攤位的正對面就是馬娘跟love live，被大型攤位攤夾擊壓力山大 </p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_1.jpeg" alt="Untitled"></p><p><br/></p><p>趁活動還沒開始，側拍了一下我們的前作Behind the Frame在任天堂的booth展出中～</p><iframe src="https://store.steampowered.com/widget/1634150/" frameborder="0" width="100%" height="190"></iframe><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_7.jpeg" alt="Untitled"></p><p><br/></p><p>BitSummit整場有非常 非常 非常多的知名獨立遊戲擺攤，也有一堆我超愛的遊戲的開發者在這，可惜第一天忙著擺攤與介紹給媒體們，沒有機會可以去和他們打招呼，像這個 alice esacped就是我特別愛的遊戲之一：</p><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_8.jpeg" alt="Untitled"></p><iframe src="https://store.steampowered.com/widget/1489410/" frameborder="0" width="100%" height="190"></iframe><p><br/></p><p>在第一天的最後，有幸遇到SIE的兩位開發者支援大大，<a href="https://twitter.com/GregRicey">Greg Rice</a>跟<a href="https://twitter.com/yosp">吉田修平</a>試玩我們家遊戲🥰</p><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_3.jpeg" alt="Untitled"></p><p><br/></p><p>第一天擺攤結束後，進入開發者party環節，大家一起在會場裡面吃吃喝喝，結束了第一天的活動！</p><p><br/></p><p><img data-src="/img/京都BitSummit遊記 （前半）/img_5.jpeg" alt="Untitled"></p><p><br/></p><p><br/></p><p>以上就是我的流水帳BitSummit遊記前半，最後來講點心得好了。</p><p><br/></p><p>過去我在台北電玩展擺過幾次攤，也以玩家身份去參加過一次東京電玩展，我得說BitSummit和這些商業為主的電玩展真的非常不同。</p><p>對於一個單機遊戲愛好者來說，這裡可以說是天堂，非常多超級有趣的獨立遊戲，也有一些大廠放了單機遊戲來給玩家體驗，最大的差異就是其他的電玩展多少還是存在一些舞台活動、或是遊戲本身以外贈品發送等誘因來讓玩家前往，但這個展幾乎所有攤位都是以遊戲為主，大家用遊戲溝通，用內容來交流，這件事真的作為一個玩家或是開發者都非常感動。</p><p>台灣最接近的活動應該是<a href="https://geight.io/">G8電玩展</a>了，希望G8展也可以越辦越好！</p><p><br/></p><p>後面幾天玩家日雖然也很忙碌，但我也忙裡偷閒玩了好幾款喜歡的遊戲</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;雖然說是遊記，但是其實這趟前往BitSummit是代表遊戲去出差的，這邊再放一次遊戲的連結，有興趣的麻煩加一下願望清單。&lt;/p&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;
&lt;iframe src=&quot;https://store.steampowered.com/widget/1619230/&quot; frameborder=&quot;0&quot; width=&quot;100%&quot; height=&quot;190&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="travel" scheme="https://blog.harrison-chen.dev/categories/travel/"/>
    
    
    <category term="game development" scheme="https://blog.harrison-chen.dev/tags/game-development/"/>
    
  </entry>
  
  <entry>
    <title>Fiber based job system</title>
    <link href="https://blog.harrison-chen.dev/2022/07/27/Game%20Programming/Fiber%20Job%20System/"/>
    <id>https://blog.harrison-chen.dev/2022/07/27/Game%20Programming/Fiber%20Job%20System/</id>
    <published>2022-07-27T17:51:53.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h2><p>工作上使用unity開發遊戲時，在效能有瓶頸的區塊時常會使用到Job System來提升效能，<br>去年因為興趣使然稍微研究了Job System的底層實作，在公司內部報告使用過，<br>藉著最近有點時間將這些資訊整理起來發成部落格文章。</p><p>寫完之後回頭來看，必須先提醒一下，這篇會使用到<strong>相當多</strong>作業系統的背景知識，<br>建議讀者需要先具備作業系統的基礎再做閱讀。</p><p><img data-src="/img/FiberJob/job_schedule.png" alt=""></p><span id="more"></span><h2 id="What-is-Job-System"><a href="#What-is-Job-System" class="headerlink" title="What is Job System"></a>What is Job System</h2><p>Job system是一種管理<strong>多執行緒(multi-thread)</strong>程式的封裝，藉由將執行的程式碼打包成一個個任務，來抽象化執行續本身的使用。</p><p>Job System藉由管理一組 worker thread進行跨CPU core的資源使用，通常使用與CPU core數量相同的worker thread數量，來避免頻繁的上下文交換(context switching)所帶來的效能損失。(即使作業系統或其他程序可能會使用到一些核心的資源)</p><p>Job System 藉由將 Job 推入一個 Queue (或是priority queue)，將他們依序放入worker thread執行，同時Job System會管理他們之間的依賴關係來確保 Job 依照邏輯順序進行。(像是NPC走到定點後，才開始進行巡邏)</p><h3 id="Naive-Job-System-Structure"><a href="#Naive-Job-System-Structure" class="headerlink" title="Naive Job System Structure"></a>Naive Job System Structure</h3><ul><li>Worker threads : 使用std::thread::hardware_concurrency() 獲得CPU核心數，生成對應數量worker thread</li><li>Job queue : 由各個worker thread在空閒時自己抓取，所以需要是thread safe的資料結構</li><li>Counter : 紀錄目前還在進行的job數量，可以使用 std::atomic</li></ul><h2 id="Fiber"><a href="#Fiber" class="headerlink" title="Fiber"></a>Fiber</h2><h3 id="About-Fiber-based-Job-System"><a href="#About-Fiber-based-Job-System" class="headerlink" title="About Fiber-based Job System"></a>About Fiber-based Job System</h3><p>Naughty Dog在<a href="https://www.gdcvault.com/play/1022186/Parallelizing-the-Naughty-Dog-Engine">GDC 2015的演講</a>是提出這個實作並且推進遊戲使用的非常重要的一篇文章，非常推薦大家閱讀。</p><h3 id="What-is-Fiber"><a href="#What-is-Fiber" class="headerlink" title="What is Fiber?"></a>What is Fiber?</h3><p>根據<a href="https://docs.microsoft.com/en-us/windows/win32/procthread/fibers"> Microsoft Win32 的 Manaul</a> 所述:</p><pre><code>A fiber is a unit of execution that must be manually scheduled by the application. Fibers run in the context of the threads that schedule them.</code></pre><p>Fiber具有以下特性：</p><ul><li>一個小型的 thread，由使用者提供stack space，並且具有更小的 context，可以將register暫存在stack上</li><li>由 worker thread 執行</li><li>Cooperative (合作性) 的多執行緒執行，由fiber之間yield做切換，而不主動搶佔</li><li>極小成本，不會有thread的context switching在fiber切換時發生 (只有register的save/load必然發生)，因為context都還在stack上</li></ul><p>同上所述，Fiber 之間的切換是使用yield進行，也就是所謂的cooperative scheduling，Fiber將這個cpu scheudling和context switching(kernel-space)的操作拉到使用者(user-space)進行，並且讓這些操作成為寫程式的基本步驟。<br>這使得工程師可以在多執行緒的程式設計中取得更多的操縱權。</p><p>在各式各樣的語言中都有著類似的東西，更多時候被稱為<strong>User-space thread</strong>或是<strong>green thread(Ruby, Java)</strong>。</p><p>有些語言也有著coroutine的概念，fiber和coroutine也有相當程度的相似，只不過coroutine通常是語言層級的概念，而fiber通常做為系統層(system-level)的概念存在。</p><h3 id="Fiber-的實作"><a href="#Fiber-的實作" class="headerlink" title="Fiber 的實作"></a>Fiber 的實作</h3><p>Fiber的實作是在組合語言層級進行，將所需的register存放到對應的stack空間，再藉由jmp跳到其他的上下文執行。<br>如果沒有瘋到想自己實作，大可使用OS Support的Library來使用<br>例如：<a href="https://docs.microsoft.com/zh-tw/windows/win32/procthread/fibers">Win32</a>、<a href="https://pubs.opengroup.org/onlinepubs/7908799/xsh/ucontext.h.html">Unix</a>、<a href="https://www.boost.org/doc/libs/1_76_0/libs/context/doc/html/index.html">boost/context</a></p><h2 id="FTL-fiber-based-tasking-library"><a href="#FTL-fiber-based-tasking-library" class="headerlink" title="FTL (fiber-based tasking library)"></a>FTL (fiber-based tasking library)</h2><p>為了進行實作練習，我找到一個滿完整的fiber job system開源專案進行參考</p><p><a href="https://github.com/RichieSams">RichieSams</a>/<a href="https://github.com/RichieSams/FiberTaskingLib">FiberTaskingLib</a></p><p>FTL使用上面提到的boost作為fiber的實作</p><h2 id="FTL-的-Fiber-實作"><a href="#FTL-的-Fiber-實作" class="headerlink" title="FTL 的 Fiber 實作"></a>FTL 的 Fiber 實作</h2><p>Yield to other task</p><p>分成兩個區塊進行，如圖：<br><img data-src="/img/FiberJob/ftl_context_switching.png" alt=""></p><p>第一部分是使用boost/context的api，將context打包成fiber bundle，儲存到stack上，並且將目前的task丟進等待 queue 中</p><p>第二部分則是從queue中找尋目前等候執行的task，將他填入目前的TLS (thread local storage)</p><p>最後使用fiber api進行user-space的context switch就完成切換</p><h3 id="如何使用FTL"><a href="#如何使用FTL" class="headerlink" title="如何使用FTL"></a>如何使用FTL</h3><ul><li>Caller<br>呼叫Job執行的部分，需要執行底下步驟</li></ul><ol><li>初始化 job scheduler (in stack)</li><li>創造task陣列 (也是stack)</li><li>初始化job的參數</li><li>將job kick到scheduler中</li><li>等待atomic counter歸零 (job執行完成)</li></ol><p>程式碼如圖：<br><img data-src="/img/FiberJob/ftl_caller.png" alt=""></p><ul><li>Callee<br>作為Job的function必須符合底下格式：</li></ul><p><img data-src="/img/FiberJob/ftl_function.png" alt=""></p><p>如圖所示，送入目標的task scehduler以及參數來執行job化的程式碼</p><p>簡單的一個例子如下：</p><p><img data-src="/img/FiberJob/ftl_callee.png" alt=""></p><p>這是簡單對數字進行加法的程式，</p><p>第一塊是主要邏輯進行的部分，也就是我們要平行化的部分</p><p>第二塊是假如後面程式碼需要依賴其他task的結果，可以將目前context暫存，把執行資源yield給其他task執行，<br>等待依賴的task執行完畢</p><p>第三塊則是可以從這個job中開始其他的job的執行。</p><h2 id="實作"><a href="#實作" class="headerlink" title="實作"></a>實作</h2><p>我使用了FTL進行經典的flocking演算法boid的實作，<br>2000隻的鳥群，在單核心的執行如下：</p><p><img data-src="/img/FiberJob/single_core_boid.png" alt=""></p><p>使用job system優化後如下：</p><p><img data-src="/img/FiberJob/jobify_boid.png" alt=""></p><p>還有進行一些kick now, gather later，以及double buffering之類的技巧優化<br>以及將render thread和game logic thread拆開，因為不是這篇主題的重點，就不細講，<br>有興趣的可以參考實作的Repo：</p><p><a href="https://github.com/Harrison-Dev/Boid-Jobify">Harrison-Dev/Boid-Jobify</a></p><p>別忘了幫我留下一顆星星！</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p><a href="https://wickedengine.net/2018/11/24/simple-job-system-using-standard-c/">Job concept</a><br><a href="https://graphitemaster.github.io/fibers/">Fiber Concept</a><br><a href="https://docs.microsoft.com/zh-tw/windows/win32/procthread/using-fibers">MS Fiber</a><br><a href="https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2015/presentations/Gyrling_Christian_Parallelizing_The_Naughty.pdf">Naughty Dog’s Slide</a><br><a href="https://github.com/RichieSams/FiberTaskingLib">Fiber Tasking lib</a><br><a href="https://github.com/Tencent/flare/blob/master/flare/doc/fiber.md">Fiber vs Coroutine</a></p>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;Preface&quot;&gt;&lt;a href=&quot;#Preface&quot; class=&quot;headerlink&quot; title=&quot;Preface&quot;&gt;&lt;/a&gt;Preface&lt;/h2&gt;&lt;p&gt;工作上使用unity開發遊戲時，在效能有瓶頸的區塊時常會使用到Job System來提升效能，&lt;br&gt;去年因為興趣使然稍微研究了Job System的底層實作，在公司內部報告使用過，&lt;br&gt;藉著最近有點時間將這些資訊整理起來發成部落格文章。&lt;/p&gt;
&lt;p&gt;寫完之後回頭來看，必須先提醒一下，這篇會使用到&lt;strong&gt;相當多&lt;/strong&gt;作業系統的背景知識，&lt;br&gt;建議讀者需要先具備作業系統的基礎再做閱讀。&lt;/p&gt;
&lt;p&gt;&lt;img data-src=&quot;/img/FiberJob/job_schedule.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Game Programming" scheme="https://blog.harrison-chen.dev/categories/Game-Programming/"/>
    
    
    <category term="Computer Orgnization" scheme="https://blog.harrison-chen.dev/tags/Computer-Orgnization/"/>
    
    <category term="Operating System" scheme="https://blog.harrison-chen.dev/tags/Operating-System/"/>
    
    <category term="C++" scheme="https://blog.harrison-chen.dev/tags/C/"/>
    
  </entry>
  
  <entry>
    <title>UniTask：利用async/await優雅的撰寫callback</title>
    <link href="https://blog.harrison-chen.dev/2021/09/05/Unity/UniTask/"/>
    <id>https://blog.harrison-chen.dev/2021/09/05/Unity/UniTask/</id>
    <published>2021-09-05T18:30:45.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<!-- Ref : https://neuecc.medium.com/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd --><h2 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h2><p>前些日子因為一點小意外，需要在一兩天時間從零開始弄一個web service上雲，因為部分邏輯已經先用C#寫好了，平常也天天在用C#，沒想太多就用上了 ASP.NET core，沒想到意外的很香。</p><p>除了.NET Core很香之外，這兩天的時間寫了寫MVC的Web service，意外地發現和寫遊戲前端截然不同的寫法，在寫web service的時候，C#的async功能可以說是用個不停。</p><p>從以前就久聞UniRx差分出來的UniTask的大名，卻遲遲沒有機會與他相見，想說趁這個機會來碰一碰吧，碰巧，最近下班玩的一個插件，剛好使用Coroutine作為接口，趁這個機會，來試試UniTask可以怎麼讓程式撰寫變得有所不同。</p><span id="more"></span><h2 id="Sync-vs-Async"><a href="#Sync-vs-Async" class="headerlink" title="Sync vs Async"></a>Sync vs Async</h2><p>印象好像從大一的計概？還是後來的組合語言或計組之類的課程，都常常提到同步和非同步的差別。<br>不太確定課本精準的定義，不過<strong>Synchronize(sync, 同步)</strong>大致上是指在程式執行過程中，<strong>必須等前一個訊號執行完成，才繼續進行下一個指令</strong>，而<strong>Asynchronize(async, 非同步)</strong>則是反過來，這個訊號並<strong>不一定要等到執行到了盡頭，才開始下一個指令的運行</strong>。</p><p>在一般寫程式的時候，大部分的程式碼都是逐行、同步進行的(雖然流水線、指令級同步等東西存在，但邏輯上還是逐行在跑)，然而，可想而知，有許多的指令會造成執行上的瓶頸，例如：IO, 網路相關的動作，相對於程式碼都是緩慢的，以同步方式執行，就必須要在這裡等到天荒地老，CPU直接等到睡著，可想而知這不是個好點子。</p><h2 id="Callback"><a href="#Callback" class="headerlink" title="Callback"></a>Callback</h2><p>此時，就需要用到callback function這種做法。<br>傳進一個delegate (或是function pointer，如果你熱愛C語言的話)，等到事件結束後，再繼續執行這個完成後的function，當然可以將IO得到的資訊作為參數之類的。</p><p>許多library都是類似底下這種形式呼叫：</p><pre><code class="lang-csharp">void DoSomethingCool()&#123;    DoSomethingNeedToWait(ioStuff =&gt;     &#123;        DoSomethingAfterHugeIO(ioStuff);    &#125;);&#125;void DoSomethingNeedToWait(System.Action&lt;IOStuff&gt; callback)&#123;    var IOStuff = SomethingHugeIO();    callback(IOStuff);&#125;void DoSomethingNeedToWait(System.Action callback)&#123;    SomethingHugeIO();    callback();&#125;</code></pre><p>扣掉這樣IO其實還是同步的吐槽，這樣的作法已經非常酷，但想像到底下的狀況<br>當IO結束之後，必須送到某個伺服器等待回應，程式碼就會開始出現怪味：</p><pre><code class="lang-csharp">void DoSomethingCool()&#123;    DoSomethingNeedToWait(ioStuff =&gt;     &#123;        DoSomethingNeedACoolServer(ioStuff, res =&gt;        &#123;            DoTheRealCoolThings(res);        &#125;);    &#125;);&#125;void DoSomethingNeedToWait(System.Action&lt;IOStuff&gt; callback)&#123;    var IOStuff = SomethingHugeIO();    callback(IOStuff);&#125;void DoSomethingNeedACoolServer(IOStuff coolData, System.Action&lt;Response&gt; onResponsed)&#123;    var response = SomethingWaitServer();    onResponsed(response);&#125;</code></pre><p>當然，扣掉request好像完全不需要handle error的吐槽，我們可以看到DoSomethingCool的主函式，已經開始出現波動拳的力量。</p><p>這對於一個加班N小時候看到這段程式碼的工程師來說，很有可能就是壓垮他的最後一片稻草了。</p><p>想想一般的工程師，回到家之後沒有女僕龍可以陪伴，我們真的不需要互相傷害，製造出這種callback hell，幸好，Unity裡面早有一個常見方式可以克服這件事，那就是Coroutine。</p><h2 id="Coroutine"><a href="#Coroutine" class="headerlink" title="Coroutine"></a>Coroutine</h2><p>Coroutine使用C#的迭代器模式，利用一個返回迭代器的Function來進行序列執行，並且在每一次Update後，做一次tick觸發。</p><p>原本的程式碼，可以改寫成這種形式：</p><pre><code class="lang-csharp">IOStuff _ioStuff;Response _response;void Start()&#123;    StartCoroutine(DoSomethingCool());&#125;IEnumerator DoSomethingCool()&#123;    yield return DoSomethingNeedToWait();    yield return DoSomethingNeedACoolServer(_ioStuff);    DoTheRealCoolThings(_response);&#125;IEnumerator DoSomethingNeedToWait()&#123;    yield return SomethingHugeIO(out _ioStuff);&#125;IEnumerator DoSomethingNeedACoolServer(IOStuff coolData)&#123;    yield return SomethingWaitServer(out _response);&#125;</code></pre><p>顯然可以感覺到，比波動拳安全許多，yield return後的事情，只會在一個frame進行一次，<br>如果還沒完成，會等到下一次tick時再次檢查，這樣可以迴避掉波動拳，並且讓半夜看到這段程式碼的工程師感到舒暢許多，明顯可以一眼看出在等什麼以及資料流的走向。</p><p>然而，Coroutine必須綁定monobehaviour進行，以及每一次Update時unity都需要費心來關切他，而且try-catch區段在yield語法下不可用，或許我們不需要那麼多心思在製作這樣的串列上，而是有其他替代方法。</p><h2 id="UniTask"><a href="#UniTask" class="headerlink" title="UniTask"></a>UniTask</h2><p>UniTask是利用C#的async/await語言機制整合進unity元件的一個解決方法，<br>可以用雷同C# Task的方式來進行unity元件的操作，獲得一個更優雅的call chain，並且不需要擔心allocation問題(至少readme上是寫no allocation)。<br>(async在語言層面上應該是類似C++的std::this_thread::yield，將這個thread的優先權交出，但C#的async會不會真的交出優先權我不曉得)</p><p>我想這邊開始就不用上面提到的那些假舉例，而是用我最近實際遇到的使用情境來說明。</p><p>前些日子在特價的時候，我買了MoreMountain的<a href="https://assetstore.unity.com/packages/tools/particles-effects/feel-183370">Feel</a>這個插件，他可以使用預先做好的元件，做出許多很酷的效果，包含Cinemachine的一些元件互動，或是Post Effect的動態等。</p><p>可以做出像這樣的打擊效果：<br><img data-src="/img/UniTask/juicy.gif" alt="Juicy"></p><p>順帶一提，再加入效果前的樣子是這樣的：</p><p><img data-src="/img/UniTask/no_juicy.gif" alt="NoJuicy"></p><p>可以說是相當方便的插件，端詳他的程式碼後，發現他實作一連串演出的呼叫<strong>MMFeedbacks</strong>是使用coroutine呼叫的，倘若我們想要在這一連串演出結束過後，再銜接什麼演出，就必須遇到前面提到的Coroutine問題。</p><p>MMFeedback的呼叫介面如下：</p><pre><code class="lang-csharp">public virtual void PlayFeedbacks()&#123;    StartCoroutine(PlayFeedbacksInternal(this.transform.position, FeedbacksIntensity));&#125;</code></pre><p>其實他有提供幾個Event可以直接對接，但如果我們想和其他coroutine，或是tweening演出一起寫成一個function，使用event的撰寫就會變得冗長且難以維護。</p><p>用Event的方式來註冊的話，可以寫成如下：</p><pre><code class="lang-csharp">private void HitSomething(Collider[] hits)&#123;    m_HitPos = GetRecent(3);    OnHit?.Invoke();    FeedbackHandler.Events.OnComplete.AddListener(() =&gt;    &#123;        TriggerAfterFeedback(hits);    &#125;);    FeedbackHandler.PlayFeedbacks();&#125;</code></pre><p>這段程式碼有幾個問題，第一個是Event裡面的匿名function，執行時間其實在PlayFeedbacks底下，這導致了程式碼的順序與執行順序的不同，降低了一部分的可讀性。</p><p>再者，這段程式碼其實沒有寫到RemoveListener的部分，如果每次呼叫都AddListener一次，會造成顯著的memory leak，當然我們也可以將event的註冊拉到物件初始化的時候，但這樣會將邏輯更進一步的分離，可讀性再次下降。</p><p>最後，就是許多演出的串列如果在同一個function實作，最終會變成上面所說的波動拳問題，要將這個做法寫得漂亮，需要耗費許多苦心。</p><p>還好，這個插件還提供第二個方案，也就是前面提到Unity對於callback hell的一個解法，也就是Coroutine。</p><p>MMFeedback對於Coroutine的接口如下：</p><pre><code class="lang-csharp">public virtual IEnumerator PlayFeedbacksCoroutine(Vector3 position3,...)&#123;    return PlayFeedbacksInternal(position, feedbacksIntensity, forceRevert);&#125;</code></pre><p>可以看到，這個接口直接回傳了一個迭代器，我們可以簡單的利用這個IEnumrator改寫成如下：</p><pre><code class="lang-csharp">private void HitSomething(Collider[] hits)&#123;    StartCoroutine(DoHitSomething(hits));&#125;private IEnumerator DoHitSomething(Collider[] hits)&#123;    m_HitPos = GetRecent(3);    OnHit?.Invoke();    yield return FeedbackHandler.PlayFeedbacksCoroutine(this.transform.position);    TriggerAfterFeedback(hits);&#125;</code></pre><p>這樣就可以用Coroutine的方式，解決掉event可能產生的一些問題，但這樣就會產生一些coroutine的對應消耗，以及handle coroutine結束與否的問題，而前面提到的UniTask，可以用更優雅的方式做到。</p><p>我們可以先為MMFeedbacks添加一個接口function如下：</p><pre><code class="lang-csharp">public virtual async UniTask PlayFeedbacksAsync()&#123;    await PlayFeedbacksInternal(this.transform.position, FeedbacksIntensity);&#125;</code></pre><p>UniTask會時做一個awaiter，將coroutine的執行完成與否這件事封裝到UniTask自己的internal enumerator之中，這樣我們呼叫時，就可以簡單地寫成這樣：</p><pre><code class="lang-csharp">private async UniTask OnHitSomething(Collider[] hits)&#123;    m_HitPos = GetRecent(3);    OnHit?.Invoke();    await FeedbackHandler.PlayFeedbacksAsync();    TriggerAfterFeedback(hits);&#125;</code></pre><p>這樣整個演出就可以簡單的寫成一個async function，其中的calling chain也會變得優雅許多，甚至如果有多個演出同時進行的時候，可以寫成下面的形式：</p><pre><code class="lang-csharp">private async void DoTonsOfScreenPlay()&#123;    List&lt;UniTask&gt; screenPlays = new List&lt;UniTask&gt;();    screenPlays.Add(OnHitSomething());     screenPlays.Add(OnHitSomethingCool());     screenPlays.Add(OnHitSomethingCute());     screenPlays.Add(OnHitSomethingAhoy());    screenPlays.Add(LoadNextPartyAddressables());    await UniTask.WhenAll(screenPlays);    // After all screenplay end    await SceneManager.LoadSceneAsync(&quot;Next Party&quot;);&#125;</code></pre><p>這樣我們可以在播出許多演出的同時，偷偷地在背後讀取Assets，直到一切都準備就緒了，馬上開始進行下一個場景的切換，達成一些無縫切換的效果。<br>順帶一提，轉場的概念可以去看我最敬愛的blog writer，羽毛的熱門文章：<a href="https://featherchung.wordpress.com/2017/07/10/unity%E5%9F%BA%E6%9C%AC%E5%8A%9F8-%E9%87%8D%E6%96%B0%E8%BC%89%E5%85%A5%E5%A0%B4%E6%99%AF%E8%BD%89%E6%8F%9B/">重新載入&amp;場景轉換</a>，肯定會獲益良多。</p><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h2><p>UniTask是個非常酷的插件，可以將許多演出與callback的可怕義大利麵程式碼，轉換成一眼就能看出結果的程式碼，同個作者的UniRx也是非常酷的插件，有興趣的可以去看看這個作者的repo們。</p><h2 id="延伸閱讀"><a href="#延伸閱讀" class="headerlink" title="延伸閱讀"></a>延伸閱讀</h2><p><a href="https://github.com/Cysharp/UniTask">UniTask Repo</a></p><p><a href="https://neuecc.medium.com/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd">UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ</a></p><p><a href="https://www.youtube.com/watch?v=Lvbs22iZFPk">【Unite 2017 Tokyo】「黒騎士と白の魔王」にみるC#で統一したサーバー/クライアント開発と現実的なUniRx使いこなし術</a></p><p><a href="https://github.com/neuecc/UniRx">UniRx Repo</a></p><p><a href="https://github.com/Cysharp/UniTask#external-assets">UniRx DoTween Integration</a></p>]]></content>
    
    
    <summary type="html">&lt;!-- Ref : https://neuecc.medium.com/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd --&gt;
&lt;h2 id=&quot;Preface&quot;&gt;&lt;a href=&quot;#Preface&quot; class=&quot;headerlink&quot; title=&quot;Preface&quot;&gt;&lt;/a&gt;Preface&lt;/h2&gt;&lt;p&gt;前些日子因為一點小意外，需要在一兩天時間從零開始弄一個web service上雲，因為部分邏輯已經先用C#寫好了，平常也天天在用C#，沒想太多就用上了 ASP.NET core，沒想到意外的很香。&lt;/p&gt;
&lt;p&gt;除了.NET Core很香之外，這兩天的時間寫了寫MVC的Web service，意外地發現和寫遊戲前端截然不同的寫法，在寫web service的時候，C#的async功能可以說是用個不停。&lt;/p&gt;
&lt;p&gt;從以前就久聞UniRx差分出來的UniTask的大名，卻遲遲沒有機會與他相見，想說趁這個機會來碰一碰吧，碰巧，最近下班玩的一個插件，剛好使用Coroutine作為接口，趁這個機會，來試試UniTask可以怎麼讓程式撰寫變得有所不同。&lt;/p&gt;</summary>
    
    
    
    <category term="Unity" scheme="https://blog.harrison-chen.dev/categories/Unity/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Unity" scheme="https://blog.harrison-chen.dev/tags/Unity/"/>
    
    <category term="Programming Tips" scheme="https://blog.harrison-chen.dev/tags/Programming-Tips/"/>
    
  </entry>
  
  <entry>
    <title>Game Physics - Constraint</title>
    <link href="https://blog.harrison-chen.dev/2020/04/25/Game%20Physics/Physics%20Constraint/"/>
    <id>https://blog.harrison-chen.dev/2020/04/25/Game%20Physics/Physics%20Constraint/</id>
    <published>2020-04-25T04:00:00.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p><img data-src="/img/pexels-photo-2017868.jpeg" alt="首頁用圖"></p><h2 id="Preface"><a href="#Preface" class="headerlink" title="Preface"></a>Preface</h2><p>先前2月參加了Unity應用領域舉辦的CJ貓大大的講座，</p><p>非常感謝CJ大大的分享跟連大辛苦尋找場地，</p><p>想說也將自己吸收學習到的內容整理成文章，與各位的開發者大大們一起參考學習。</p><p>文章的內容是參考CJ大大的專案內容與Box2D作者ErinCatto大大的GDC演講所整理，<br>這兩份資料都在文章最下方的reference中</p><span id="more"></span><h2 id="Constraint"><a href="#Constraint" class="headerlink" title="Constraint"></a>Constraint</h2><p>每一個物理系統時常會有一些約束，物體的運動也必須遵守這些約束。例如，簡單擺系統的約束是擺繩的長度是常數，擺錘與支撐點的距離必須是這長度。 (來自維基百科)</p><p>基本概念就是：</p><ul><li>約束是拿來在像是Joint、Motor、Restitution, Friction與Contact等物理模擬中使用</li><li>像是疊箱子或是ragdoll的四肢的接點等也會運用到約束</li><li>解約束是透過計算衝量或作用力並且將這些結果貼回受約束物體的過程</li></ul><h2 id="地面約束"><a href="#地面約束" class="headerlink" title="地面約束"></a>地面約束</h2><p>地面約束是被地板擋住的簡單約束，我們想將物體限制在地面上，<br>所以位置方程式可以表示成：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.566ex;" xmlns="http://www.w3.org/2000/svg" width="8.737ex" height="2.262ex" role="img" focusable="false" viewBox="0 -750 3861.6 1000" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-N-29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(760,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(1149,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mo" transform="translate(1639,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g><g data-mml-node="mo" transform="translate(2305.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(3361.6,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>可想而知，如果C等於0，他對時間的導數也會為0。<br>所以速度約束可以表示成：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="5.868ex" height="2.516ex" role="img" focusable="false" viewBox="0 -1030 2593.6 1112" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-2D9" d="M190 609Q190 637 208 653T252 669Q275 667 292 652T309 609Q309 579 292 564T250 549Q225 549 208 564T190 609Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(474.5,261) translate(-250 0)"><use data-c="2D9" xlink:href="#MJX-1-TEX-N-2D9"></use></g></g></g><g data-mml-node="mo" transform="translate(1037.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(2093.6,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>將速度的y方向做限制，得到：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.667ex;" xmlns="http://www.w3.org/2000/svg" width="11.176ex" height="2.998ex" role="img" focusable="false" viewBox="0 -1030 4939.6 1325" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-2D9" d="M190 609Q190 637 208 653T252 669Q275 667 292 652T309 609Q309 579 292 564T250 549Q225 549 208 564T190 609Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(474.5,261) translate(-250 0)"><use data-c="2D9" xlink:href="#MJX-1-TEX-N-2D9"></use></g></g></g><g data-mml-node="mo" transform="translate(1037.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msub" transform="translate(2093.6,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(3383.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4439.6,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>畢竟真實的物理世界並不是如此僵硬的直接彈回去，為了擬真會再加上一個偏誤值做緩慢修正：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.798ex;" xmlns="http://www.w3.org/2000/svg" width="29.04ex" height="3.006ex" role="img" focusable="false" viewBox="0 -975.7 12835.8 1328.5" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-N-2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"></path><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path><path id="MJX-1-TEX-N-3E" d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z"></path><path id="MJX-1-TEX-I-1D6FD" d="M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z"></path><path id="MJX-1-TEX-I-210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(1234.7,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(2234.9,0)"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mi" transform="translate(2994.9,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mo" transform="translate(3762.7,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4818.5,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mo" transform="translate(5596.3,0)"><g data-mml-node="text"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="text" transform="translate(778,0)"><use data-c="3E" xlink:href="#MJX-1-TEX-N-3E"></use></g></g><g data-mml-node="msub" transform="translate(7430,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(8664.7,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mfrac" transform="translate(9665,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(10512.3,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mo" transform="translate(11280,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(12335.8,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>我們就可以得到地面約束的速度數學式：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.798ex;" xmlns="http://www.w3.org/2000/svg" width="10.094ex" height="3.006ex" role="img" focusable="false" viewBox="0 -975.7 4461.3 1328.5" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path><path id="MJX-1-TEX-I-1D6FD" d="M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z"></path><path id="MJX-1-TEX-I-210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(1290.3,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mo" transform="translate(2346,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mfrac" transform="translate(3124,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(3971.3,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g></g></svg></mjx-container><p>程式碼實作可以參考<a href="https://github.com/TheAllenChou/unity-physics-constraints/blob/master/src/Physics%20Constraints/Assets/Examples/01a%20-%20Inline%20Ground%20Constraint/InlineGroundConstraintMain.cs#L23">CJ大大的repo</a></p><h2 id="通則化"><a href="#通則化" class="headerlink" title="通則化"></a>通則化</h2><p>這部分相當的數學，我參考消化花了不少時間，如果有什麼地方寫得不清楚，歡迎留言詢問。</p><h3 id="Jacobian矩陣"><a href="#Jacobian矩陣" class="headerlink" title="Jacobian矩陣"></a>Jacobian矩陣</h3><p>根據Chain Rule，推導出的速度限制會有如下形式：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="7.266ex" height="2.516ex" role="img" focusable="false" viewBox="0 -1030 3211.6 1112" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-2D9" d="M190 609Q190 637 208 653T252 669Q275 667 292 652T309 609Q309 579 292 564T250 549Q225 549 208 564T190 609Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(474.5,261) translate(-250 0)"><use data-c="2D9" xlink:href="#MJX-1-TEX-N-2D9"></use></g></g></g><g data-mml-node="mo" transform="translate(1037.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mi" transform="translate(2093.6,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(2726.6,0)"><use data-c="1D463" xlink:href="#MJX-1-TEX-I-1D463"></use></g></g></g></svg></mjx-container><p>J是一個row vector，被稱作Jacobian Matrix，會取決於被限制物體的位置。</p><p>根據速度約束，我們最後要得出的結果是：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.667ex;" xmlns="http://www.w3.org/2000/svg" width="11.176ex" height="2.998ex" role="img" focusable="false" viewBox="0 -1030 4939.6 1325" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-2D9" d="M190 609Q190 637 208 653T252 669Q275 667 292 652T309 609Q309 579 292 564T250 549Q225 549 208 564T190 609Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(474.5,261) translate(-250 0)"><use data-c="2D9" xlink:href="#MJX-1-TEX-N-2D9"></use></g></g></g><g data-mml-node="mo" transform="translate(1037.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msub" transform="translate(2093.6,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(3383.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4439.6,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>轉換為Jacobian矩陣的形式，也就是：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.186ex;" xmlns="http://www.w3.org/2000/svg" width="11.414ex" height="2.516ex" role="img" focusable="false" viewBox="0 -1030 5045.1 1112" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D436" d="M50 252Q50 367 117 473T286 641T490 704Q580 704 633 653Q642 643 648 636T656 626L657 623Q660 623 684 649Q691 655 699 663T715 679T725 690L740 705H746Q760 705 760 698Q760 694 728 561Q692 422 692 421Q690 416 687 415T669 413H653Q647 419 647 422Q647 423 648 429T650 449T651 481Q651 552 619 605T510 659Q484 659 454 652T382 628T299 572T226 479Q194 422 175 346T156 222Q156 108 232 58Q280 24 350 24Q441 24 512 92T606 240Q610 253 612 255T628 257Q648 257 648 248Q648 243 647 239Q618 132 523 55T319 -22Q206 -22 128 53T50 252Z"></path><path id="MJX-1-TEX-N-2D9" d="M190 609Q190 637 208 653T252 669Q275 667 292 652T309 609Q309 579 292 564T250 549Q225 549 208 564T190 609Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mover"><g data-mml-node="mi"><use data-c="1D436" xlink:href="#MJX-1-TEX-I-1D436"></use></g><g data-mml-node="mo" transform="translate(474.5,261) translate(-250 0)"><use data-c="2D9" xlink:href="#MJX-1-TEX-N-2D9"></use></g></g></g><g data-mml-node="mo" transform="translate(1037.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mi" transform="translate(2093.6,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(2726.6,0)"><use data-c="1D463" xlink:href="#MJX-1-TEX-I-1D463"></use></g><g data-mml-node="mo" transform="translate(3489.3,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4545.1,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g></g></svg></mjx-container><p>由此可知，Jacobian這個向量是與速度垂直的。<br>(row vector J 內積 column vector v結果為0)</p><p>以前面地面約束舉例，可以寫成以下形式：<br><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.798ex;" xmlns="http://www.w3.org/2000/svg" width="32.876ex" height="3.006ex" role="img" focusable="false" viewBox="0 -975.7 14531.3 1328.5" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path><path id="MJX-1-TEX-N-2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"></path><path id="MJX-1-TEX-I-1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-I-1D6FD" d="M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z"></path><path id="MJX-1-TEX-I-210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z"></path><path id="MJX-1-TEX-N-5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z"></path><path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path id="MJX-1-TEX-N-5D" d="M22 710V750H159V-250H22V-210H119V710H22Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(633,0)"><use data-c="1D463" xlink:href="#MJX-1-TEX-I-1D463"></use></g><g data-mml-node="mo" transform="translate(1340.2,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(2340.4,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(3047.2,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4103,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(4603,0)"></g><g data-mml-node="msub" transform="translate(4603,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(5837.7,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mfrac" transform="translate(6837.9,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(7685.2,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mo" transform="translate(8453,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(9508.8,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(10008.8,0)"></g><g data-mml-node="mi" transform="translate(10008.8,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mo" transform="translate(10919.6,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mrow" transform="translate(11975.3,0)"><g data-mml-node="mo"><use data-c="5B" xlink:href="#MJX-1-TEX-N-5B"></use></g><g data-mml-node="mtable" transform="translate(278,0)"><g data-mml-node="mtr"><g data-mml-node="mtd"><g data-mml-node="mn"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g><g data-mml-node="mtd" transform="translate(1500,0)"><g data-mml-node="mn"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g></g><g data-mml-node="mo" transform="translate(2278,0)"><use data-c="5D" xlink:href="#MJX-1-TEX-N-5D"></use></g></g><g data-mml-node="mspace" transform="translate(14531.3,0)"></g></g></g></svg></mjx-container></p><p>所以最後通則化的結果：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -2.2ex;" xmlns="http://www.w3.org/2000/svg" width="33.533ex" height="5.532ex" role="img" focusable="false" viewBox="0 -1472.5 14821.7 2445" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path><path id="MJX-1-TEX-N-2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"></path><path id="MJX-1-TEX-I-1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path><path id="MJX-1-TEX-N-5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path id="MJX-1-TEX-N-32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path id="MJX-1-TEX-N-5D" d="M22 710V750H159V-250H22V-210H119V710H22Z"></path><path id="MJX-1-TEX-S3-5B" d="M247 -949V1450H516V1388H309V-887H516V-949H247Z"></path><path id="MJX-1-TEX-I-1D465" d="M52 289Q59 331 106 386T222 442Q257 442 286 424T329 379Q371 442 430 442Q467 442 494 420T522 361Q522 332 508 314T481 292T458 288Q439 288 427 299T415 328Q415 374 465 391Q454 404 425 404Q412 404 406 402Q368 386 350 336Q290 115 290 78Q290 50 306 38T341 26Q378 26 414 59T463 140Q466 150 469 151T485 153H489Q504 153 504 145Q504 144 502 134Q486 77 440 33T333 -11Q263 -11 227 52Q186 -10 133 -10H127Q78 -10 57 16T35 71Q35 103 54 123T99 143Q142 143 142 101Q142 81 130 66T107 46T94 41L91 40Q91 39 97 36T113 29T132 26Q168 26 194 71Q203 87 217 139T245 247T261 313Q266 340 266 352Q266 380 251 392T217 404Q177 404 142 372T93 290Q91 281 88 280T72 278H58Q52 284 52 289Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-S3-5D" d="M11 1388V1450H280V-949H11V-887H218V1388H11Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(633,0)"><use data-c="1D463" xlink:href="#MJX-1-TEX-I-1D463"></use></g><g data-mml-node="mo" transform="translate(1340.2,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(2340.4,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(3047.2,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4103,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(4603,0)"></g><g data-mml-node="mrow" transform="translate(4769.7,0)"><g data-mml-node="mo"><use data-c="5B" xlink:href="#MJX-1-TEX-N-5B"></use></g><g data-mml-node="mtable" transform="translate(278,0)"><g data-mml-node="mtr" transform="translate(0,3)"><g data-mml-node="mtd"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="TeXAtom" transform="translate(588,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g></g></g><g data-mml-node="mtd" transform="translate(2358.9,0)"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="TeXAtom" transform="translate(588,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="32" xlink:href="#MJX-1-TEX-N-32"></use></g></g></g></g></g></g></g><g data-mml-node="mo" transform="translate(3995.9,0)"><use data-c="5D" xlink:href="#MJX-1-TEX-N-5D"></use></g></g><g data-mml-node="mrow" transform="translate(9210.2,0)"><g data-mml-node="mo" transform="translate(0 -0.5)"><use data-c="5B" xlink:href="#MJX-1-TEX-S3-5B"></use></g><g data-mml-node="mtable" transform="translate(528,0)"><g data-mml-node="mtr" transform="translate(0,722.5)"><g data-mml-node="mtd"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D465" xlink:href="#MJX-1-TEX-I-1D465"></use></g></g></g></g><g data-mml-node="mtr" transform="translate(0,-677.5)"><g data-mml-node="mtd" transform="translate(29,0)"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g></g></g></g><g data-mml-node="mo" transform="translate(1598.5,0) translate(0 -0.5)"><use data-c="5D" xlink:href="#MJX-1-TEX-S3-5D"></use></g></g><g data-mml-node="mo" transform="translate(11558.9,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(12559.1,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(13265.9,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(14321.7,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(14821.7,0)"></g></g></g></svg></mjx-container><p>其中J是Jacobian矩陣，V是速度矩陣，b是偏誤(bias)</p><h2 id="Lagrange-Multiplier"><a href="#Lagrange-Multiplier" class="headerlink" title="Lagrange Multiplier"></a>Lagrange Multiplier</h2><p>先從約束的力開始推導：</p><p><img data-src="/img/forceExample.png" alt="example"></p><p>如上圖：<br>可以直觀的發現約束力的作用方向是與約束平面的法向量平行的。</p><p>而Lagrange Multiplier的定義是<br><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -0.357ex;" xmlns="http://www.w3.org/2000/svg" width="9.539ex" height="2.261ex" role="img" focusable="false" viewBox="0 -841.7 4216.4 999.5" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D439" d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z"></path><path id="MJX-1-TEX-I-1D450" d="M34 159Q34 268 120 355T306 442Q362 442 394 418T427 355Q427 326 408 306T360 285Q341 285 330 295T319 325T330 359T352 380T366 386H367Q367 388 361 392T340 400T306 404Q276 404 249 390Q228 381 206 359Q162 315 142 235T121 119Q121 73 147 50Q169 26 205 26H209Q321 26 394 111Q403 121 406 121Q410 121 419 112T429 98T420 83T391 55T346 25T282 0T202 -11Q127 -11 81 37T34 159Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D447" d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z"></path><path id="MJX-1-TEX-I-1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="msub"><g data-mml-node="mi"><use data-c="1D439" xlink:href="#MJX-1-TEX-I-1D439"></use></g><g data-mml-node="mi" transform="translate(676,-150) scale(0.707)"><use data-c="1D450" xlink:href="#MJX-1-TEX-I-1D450"></use></g></g><g data-mml-node="mo" transform="translate(1310,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msup" transform="translate(2365.7,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(3633.4,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g></g></g></svg></mjx-container></p><p>所以可以用前面的通式與牛頓第二運動定律，解出Lagrange Multiplier</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -1.266ex;" xmlns="http://www.w3.org/2000/svg" width="140.823ex" height="3.635ex" role="img" focusable="false" viewBox="0 -1047.1 62243.7 1606.7" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D439" d="M48 1Q31 1 31 11Q31 13 34 25Q38 41 42 43T65 46Q92 46 125 49Q139 52 144 61Q146 66 215 342T285 622Q285 629 281 629Q273 632 228 634H197Q191 640 191 642T193 659Q197 676 203 680H742Q749 676 749 669Q749 664 736 557T722 447Q720 440 702 440H690Q683 445 683 453Q683 454 686 477T689 530Q689 560 682 579T663 610T626 626T575 633T503 634H480Q398 633 393 631Q388 629 386 623Q385 622 352 492L320 363H375Q378 363 398 363T426 364T448 367T472 374T489 386Q502 398 511 419T524 457T529 475Q532 480 548 480H560Q567 475 567 470Q567 467 536 339T502 207Q500 200 482 200H470Q463 206 463 212Q463 215 468 234T473 274Q473 303 453 310T364 317H309L277 190Q245 66 245 60Q245 46 334 46H359Q365 40 365 39T363 19Q359 6 353 0H336Q295 2 185 2Q120 2 86 2T48 1Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-I-1D45A" d="M21 287Q22 293 24 303T36 341T56 388T88 425T132 442T175 435T205 417T221 395T229 376L231 369Q231 367 232 367L243 378Q303 442 384 442Q401 442 415 440T441 433T460 423T475 411T485 398T493 385T497 373T500 364T502 357L510 367Q573 442 659 442Q713 442 746 415T780 336Q780 285 742 178T704 50Q705 36 709 31T724 26Q752 26 776 56T815 138Q818 149 821 151T837 153Q857 153 857 145Q857 144 853 130Q845 101 831 73T785 17T716 -10Q669 -10 648 17T627 73Q627 92 663 193T700 345Q700 404 656 404H651Q565 404 506 303L499 291L466 157Q433 26 428 16Q415 -11 385 -11Q372 -11 364 -4T353 8T350 18Q350 29 384 161L420 307Q423 322 423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 181Q151 335 151 342Q154 357 154 369Q154 405 129 405Q107 405 92 377T69 316T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-I-1D44E" d="M33 157Q33 258 109 349T280 441Q331 441 370 392Q386 422 416 422Q429 422 439 414T449 394Q449 381 412 234T374 68Q374 43 381 35T402 26Q411 27 422 35Q443 55 463 131Q469 151 473 152Q475 153 483 153H487Q506 153 506 144Q506 138 501 117T481 63T449 13Q436 0 417 -8Q409 -10 393 -10Q359 -10 336 5T306 36L300 51Q299 52 296 50Q294 48 292 46Q233 -10 172 -10Q117 -10 75 30T33 157ZM351 328Q351 334 346 350T323 385T277 405Q242 405 210 374T160 293Q131 214 119 129Q119 126 119 118T118 106Q118 61 136 44T179 26Q217 26 254 59T298 110Q300 114 325 217T351 328Z"></path><path id="MJX-1-TEX-N-3E" d="M84 520Q84 528 88 533T96 539L99 540Q106 540 253 471T544 334L687 265Q694 260 694 250T687 235Q685 233 395 96L107 -40H101Q83 -38 83 -20Q83 -19 83 -17Q82 -10 98 -1Q117 9 248 71Q326 108 378 132L626 250L378 368Q90 504 86 509Q84 513 84 520Z"></path><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D447" d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z"></path><path id="MJX-1-TEX-I-1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z"></path><path id="MJX-1-TEX-I-1D440" d="M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z"></path><path id="MJX-1-TEX-N-28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-N-32" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"></path><path id="MJX-1-TEX-N-2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path><path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path id="MJX-1-TEX-N-29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path><path id="MJX-1-TEX-N-2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"></path><path id="MJX-1-TEX-I-1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path><path id="MJX-1-TEX-MI-1D6E5" d="M574 715L582 716Q589 716 595 716Q612 716 616 714Q621 712 621 709Q622 707 705 359T788 8Q786 5 785 3L781 0H416Q52 0 50 2T48 6Q48 9 305 358T567 711Q572 712 574 715ZM599 346L538 602L442 474Q347 345 252 217T157 87T409 86T661 88L654 120Q646 151 629 220T599 346Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><use data-c="1D439" xlink:href="#MJX-1-TEX-I-1D439"></use></g><g data-mml-node="mo" transform="translate(1026.8,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mi" transform="translate(2082.6,0)"><use data-c="1D45A" xlink:href="#MJX-1-TEX-I-1D45A"></use></g><g data-mml-node="mi" transform="translate(2960.6,0)"><use data-c="1D44E" xlink:href="#MJX-1-TEX-I-1D44E"></use></g><g data-mml-node="mo" transform="translate(3767.3,0)"><g data-mml-node="text"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="text" transform="translate(778,0)"><use data-c="3E" xlink:href="#MJX-1-TEX-N-3E"></use></g></g><g data-mml-node="mspace" transform="translate(5323.3,0)"></g><g data-mml-node="msup" transform="translate(5601.1,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(6868.8,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(7729.6,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mi" transform="translate(8785.4,0)"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="mo" transform="translate(9836.4,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="msub" transform="translate(10225.4,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="32" xlink:href="#MJX-1-TEX-N-32"></use></g></g><g data-mml-node="mo" transform="translate(11467.1,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="msub" transform="translate(12467.4,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(13486.9,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g><g data-mml-node="mspace" transform="translate(13875.9,0)"></g><g data-mml-node="msub" transform="translate(13875.9,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="32" xlink:href="#MJX-1-TEX-N-32"></use></g></g><g data-mml-node="mo" transform="translate(15173.3,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msub" transform="translate(16229,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(17470.8,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="msup" transform="translate(18471,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(20562.8,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(21830.5,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mspace" transform="translate(22413.5,0)"></g><g data-mml-node="mi" transform="translate(22413.5,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mo" transform="translate(23046.5,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="msub" transform="translate(23435.5,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(24677.2,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="msup" transform="translate(25677.5,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(27769.2,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(29036.9,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(29619.9,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g><g data-mml-node="mo" transform="translate(30231.1,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(31231.3,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(31938.1,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(32993.9,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(33493.9,0)"></g><g data-mml-node="mo" transform="translate(33493.9,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(33882.9,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msup" transform="translate(34515.9,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(36607.6,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mo" transform="translate(37875.3,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g><g data-mml-node="mi" transform="translate(38264.3,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(39125.1,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mo" transform="translate(40180.9,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mo" transform="translate(40958.9,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(41347.9,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msub" transform="translate(41980.9,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(43222.7,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(44222.9,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(44651.9,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g><g data-mml-node="mspace" transform="translate(45040.9,0)"></g><g data-mml-node="mi" transform="translate(45040.9,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(45901.7,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mfrac" transform="translate(46957.4,0)"><g data-mml-node="mrow" transform="translate(345.5,516.8) scale(0.707)"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mo" transform="translate(778,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(1167,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msub" transform="translate(1800,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(2819.6,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(3597.6,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(4026.6,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g></g><g data-mml-node="mrow" transform="translate(220,-382.9) scale(0.707)"><g data-mml-node="mo"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(389,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msup" transform="translate(1022,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,289) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(3113.7,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,289) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mo" transform="translate(4381.4,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g></g><rect width="3573.2" height="60" x="120" y="220"></rect></g><g data-mml-node="mspace" transform="translate(50770.6,0)"></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(50770.6,0)"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><use data-c="1D6E5" xlink:href="#MJX-1-TEX-MI-1D6E5"></use></g></g></g><g data-mml-node="mi" transform="translate(51603.6,0)"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mo" transform="translate(52650.4,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msub" transform="translate(53706.2,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="32" xlink:href="#MJX-1-TEX-N-32"></use></g></g><g data-mml-node="mo" transform="translate(54948,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="msub" transform="translate(55948.2,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(57245.5,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msup" transform="translate(58301.3,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(60393,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(61660.7,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mspace" transform="translate(62243.7,0)"></g></g></g></svg></mjx-container><p>以前面的地面約束為例，可以用這個方式推導，解出速度變化的通式：</p><mjx-container class="MathJax" jax="SVG"><svg style="vertical-align: -1.266ex;" xmlns="http://www.w3.org/2000/svg" width="82.073ex" height="3.635ex" role="img" focusable="false" viewBox="0 -1047.1 36276.3 1606.7" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="MJX-1-TEX-I-1D43D" d="M447 625Q447 637 354 637H329Q323 642 323 645T325 664Q329 677 335 683H352Q393 681 498 681Q541 681 568 681T605 682T619 682Q633 682 633 672Q633 670 630 658Q626 642 623 640T604 637Q552 637 545 623Q541 610 483 376Q420 128 419 127Q397 64 333 21T195 -22Q137 -22 97 8T57 88Q57 130 80 152T132 174Q177 174 182 130Q182 98 164 80T123 56Q115 54 115 53T122 44Q148 15 197 15Q235 15 271 47T324 130Q328 142 387 380T447 625Z"></path><path id="MJX-1-TEX-I-1D463" d="M173 380Q173 405 154 405Q130 405 104 376T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Q21 294 29 316T53 368T97 419T160 441Q202 441 225 417T249 361Q249 344 246 335Q246 329 231 291T200 202T182 113Q182 86 187 69Q200 26 250 26Q287 26 319 60T369 139T398 222T409 277Q409 300 401 317T383 343T365 361T357 383Q357 405 376 424T417 443Q436 443 451 425T467 367Q467 340 455 284T418 159T347 40T241 -11Q177 -11 139 22Q102 54 102 117Q102 148 110 181T151 298Q173 362 173 380Z"></path><path id="MJX-1-TEX-N-2B" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"></path><path id="MJX-1-TEX-I-1D44F" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"></path><path id="MJX-1-TEX-N-3D" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"></path><path id="MJX-1-TEX-N-30" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"></path><path id="MJX-1-TEX-I-1D449" d="M52 648Q52 670 65 683H76Q118 680 181 680Q299 680 320 683H330Q336 677 336 674T334 656Q329 641 325 637H304Q282 635 274 635Q245 630 242 620Q242 618 271 369T301 118L374 235Q447 352 520 471T595 594Q599 601 599 609Q599 633 555 637Q537 637 537 648Q537 649 539 661Q542 675 545 679T558 683Q560 683 570 683T604 682T668 681Q737 681 755 683H762Q769 676 769 672Q769 655 760 640Q757 637 743 637Q730 636 719 635T698 630T682 623T670 615T660 608T652 599T645 592L452 282Q272 -9 266 -16Q263 -18 259 -21L241 -22H234Q216 -22 216 -15Q213 -9 177 305Q139 623 138 626Q133 637 76 637H59Q52 642 52 648Z"></path><path id="MJX-1-TEX-I-1D466" d="M21 287Q21 301 36 335T84 406T158 442Q199 442 224 419T250 355Q248 336 247 334Q247 331 231 288T198 191T182 105Q182 62 196 45T238 27Q261 27 281 38T312 61T339 94Q339 95 344 114T358 173T377 247Q415 397 419 404Q432 431 462 431Q475 431 483 424T494 412T496 403Q496 390 447 193T391 -23Q363 -106 294 -155T156 -205Q111 -205 77 -183T43 -117Q43 -95 50 -80T69 -58T89 -48T106 -45Q150 -45 150 -87Q150 -107 138 -122T115 -142T102 -147L99 -148Q101 -153 118 -160T152 -167H160Q177 -167 186 -165Q219 -156 247 -127T290 -65T313 -9T321 21L315 17Q309 13 296 6T270 -6Q250 -11 231 -11Q185 -11 150 11T104 82Q103 89 103 113Q103 170 138 262T173 379Q173 380 173 381Q173 390 173 393T169 400T158 404H154Q131 404 112 385T82 344T65 302T57 280Q55 278 41 278H27Q21 284 21 287Z"></path><path id="MJX-1-TEX-I-1D6FD" d="M29 -194Q23 -188 23 -186Q23 -183 102 134T186 465Q208 533 243 584T309 658Q365 705 429 705H431Q493 705 533 667T573 570Q573 465 469 396L482 383Q533 332 533 252Q533 139 448 65T257 -10Q227 -10 203 -2T165 17T143 40T131 59T126 65L62 -188Q60 -194 42 -194H29ZM353 431Q392 431 427 419L432 422Q436 426 439 429T449 439T461 453T472 471T484 495T493 524T501 560Q503 569 503 593Q503 611 502 616Q487 667 426 667Q384 667 347 643T286 582T247 514T224 455Q219 439 186 308T152 168Q151 163 151 147Q151 99 173 68Q204 26 260 26Q302 26 349 51T425 137Q441 171 449 214T457 279Q457 337 422 372Q380 358 347 358H337Q258 358 258 389Q258 396 261 403Q275 431 353 431Z"></path><path id="MJX-1-TEX-I-210E" d="M137 683Q138 683 209 688T282 694Q294 694 294 685Q294 674 258 534Q220 386 220 383Q220 381 227 388Q288 442 357 442Q411 442 444 415T478 336Q478 285 440 178T402 50Q403 36 407 31T422 26Q450 26 474 56T513 138Q516 149 519 151T535 153Q555 153 555 145Q555 144 551 130Q535 71 500 33Q466 -10 419 -10H414Q367 -10 346 17T325 74Q325 90 361 192T398 345Q398 404 354 404H349Q266 404 205 306L198 293L164 158Q132 28 127 16Q114 -11 83 -11Q69 -11 59 -2T48 16Q48 30 121 320L195 616Q195 629 188 632T149 637H128Q122 643 122 645T124 664Q129 683 137 683Z"></path><path id="MJX-1-TEX-N-5B" d="M118 -250V750H255V710H158V-210H255V-250H118Z"></path><path id="MJX-1-TEX-N-31" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"></path><path id="MJX-1-TEX-N-5D" d="M22 710V750H159V-250H22V-210H119V710H22Z"></path><path id="MJX-1-TEX-I-1D706" d="M166 673Q166 685 183 694H202Q292 691 316 644Q322 629 373 486T474 207T524 67Q531 47 537 34T546 15T551 6T555 2T556 -2T550 -11H482Q457 3 450 18T399 152L354 277L340 262Q327 246 293 207T236 141Q211 112 174 69Q123 9 111 -1T83 -12Q47 -12 47 20Q47 37 61 52T199 187Q229 216 266 252T321 306L338 322Q338 323 288 462T234 612Q214 657 183 657Q166 657 166 673Z"></path><path id="MJX-1-TEX-N-2212" d="M84 237T84 250T98 270H679Q694 262 694 250T679 230H98Q84 237 84 250Z"></path><path id="MJX-1-TEX-N-28" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"></path><path id="MJX-1-TEX-N-29" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"></path><path id="MJX-1-TEX-I-1D440" d="M289 629Q289 635 232 637Q208 637 201 638T194 648Q194 649 196 659Q197 662 198 666T199 671T201 676T203 679T207 681T212 683T220 683T232 684Q238 684 262 684T307 683Q386 683 398 683T414 678Q415 674 451 396L487 117L510 154Q534 190 574 254T662 394Q837 673 839 675Q840 676 842 678T846 681L852 683H948Q965 683 988 683T1017 684Q1051 684 1051 673Q1051 668 1048 656T1045 643Q1041 637 1008 637Q968 636 957 634T939 623Q936 618 867 340T797 59Q797 55 798 54T805 50T822 48T855 46H886Q892 37 892 35Q892 19 885 5Q880 0 869 0Q864 0 828 1T736 2Q675 2 644 2T609 1Q592 1 592 11Q592 13 594 25Q598 41 602 43T625 46Q652 46 685 49Q699 52 704 61Q706 65 742 207T813 490T848 631L654 322Q458 10 453 5Q451 4 449 3Q444 0 433 0Q418 0 415 7Q413 11 374 317L335 624L267 354Q200 88 200 79Q206 46 272 46H282Q288 41 289 37T286 19Q282 3 278 1Q274 0 267 0Q265 0 255 0T221 1T157 2Q127 2 95 1T58 0Q43 0 39 2T35 11Q35 13 38 25T43 40Q45 46 65 46Q135 46 154 86Q158 92 223 354T289 629Z"></path><path id="MJX-1-TEX-I-1D447" d="M40 437Q21 437 21 445Q21 450 37 501T71 602L88 651Q93 669 101 677H569H659Q691 677 697 676T704 667Q704 661 687 553T668 444Q668 437 649 437Q640 437 637 437T631 442L629 445Q629 451 635 490T641 551Q641 586 628 604T573 629Q568 630 515 631Q469 631 457 630T439 622Q438 621 368 343T298 60Q298 48 386 46Q418 46 427 45T436 36Q436 31 433 22Q429 4 424 1L422 0Q419 0 415 0Q410 0 363 1T228 2Q99 2 64 0H49Q43 6 43 9T45 27Q49 40 55 46H83H94Q174 46 189 55Q190 56 191 56Q196 59 201 76T241 233Q258 301 269 344Q339 619 339 625Q339 630 310 630H279Q212 630 191 624Q146 614 121 583T67 467Q60 445 57 441T43 437H40Z"></path><path id="MJX-1-TEX-MI-1D6E5" d="M574 715L582 716Q589 716 595 716Q612 716 616 714Q621 712 621 709Q622 707 705 359T788 8Q786 5 785 3L781 0H416Q52 0 50 2T48 6Q48 9 305 358T567 711Q572 712 574 715ZM599 346L538 602L442 474Q347 345 252 217T157 87T409 86T661 88L654 120Q646 151 629 220T599 346Z"></path></defs><g stroke="currentColor" fill="currentColor" stroke-width="0" transform="scale(1,-1)"><g data-mml-node="math"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(633,0)"><use data-c="1D463" xlink:href="#MJX-1-TEX-I-1D463"></use></g><g data-mml-node="mo" transform="translate(1340.2,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(2340.4,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(3047.2,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(4103,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(4603,0)"></g><g data-mml-node="msub" transform="translate(4603,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mi" transform="translate(616,-150) scale(0.707)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g></g><g data-mml-node="mo" transform="translate(5837.7,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mfrac" transform="translate(6837.9,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(7685.2,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mo" transform="translate(8453,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mn" transform="translate(9508.8,0)"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g><g data-mml-node="mspace" transform="translate(10008.8,0)"></g><g data-mml-node="mi" transform="translate(10008.8,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mo" transform="translate(10919.6,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mrow" transform="translate(11975.3,0)"><g data-mml-node="mo"><use data-c="5B" xlink:href="#MJX-1-TEX-N-5B"></use></g><g data-mml-node="mtable" transform="translate(278,0)"><g data-mml-node="mtr"><g data-mml-node="mtd"><g data-mml-node="mn"><use data-c="30" xlink:href="#MJX-1-TEX-N-30"></use></g></g><g data-mml-node="mtd" transform="translate(1500,0)"><g data-mml-node="mn"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g></g><g data-mml-node="mo" transform="translate(2278,0)"><use data-c="5D" xlink:href="#MJX-1-TEX-N-5D"></use></g></g><g data-mml-node="mspace" transform="translate(14531.3,0)"></g><g data-mml-node="mi" transform="translate(14531.3,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(15238.1,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mfrac" transform="translate(16293.9,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(17141.2,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mspace" transform="translate(17631.2,0)"></g><g data-mml-node="mi" transform="translate(17631.2,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(18492,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mfrac" transform="translate(19547.7,0)"><g data-mml-node="mrow" transform="translate(345.5,516.8) scale(0.707)"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mo" transform="translate(778,0)"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(1167,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msub" transform="translate(1800,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mn" transform="translate(616,-150) scale(0.707)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g><g data-mml-node="mo" transform="translate(2819.6,0)"><use data-c="2B" xlink:href="#MJX-1-TEX-N-2B"></use></g><g data-mml-node="mi" transform="translate(3597.6,0)"><use data-c="1D44F" xlink:href="#MJX-1-TEX-I-1D44F"></use></g><g data-mml-node="mo" transform="translate(4026.6,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g></g><g data-mml-node="mrow" transform="translate(220,-382.9) scale(0.707)"><g data-mml-node="mo"><use data-c="28" xlink:href="#MJX-1-TEX-N-28"></use></g><g data-mml-node="mi" transform="translate(389,0)"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="msup" transform="translate(1022,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,289) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(3113.7,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,289) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mo" transform="translate(4381.4,0)"><use data-c="29" xlink:href="#MJX-1-TEX-N-29"></use></g></g><rect width="3573.2" height="60" x="120" y="220"></rect></g><g data-mml-node="mspace" transform="translate(23360.9,0)"></g><g data-mml-node="TeXAtom" data-mjx-texclass="ORD" transform="translate(23360.9,0)"><g data-mml-node="TeXAtom" data-mjx-texclass="ORD"><g data-mml-node="mi"><use data-c="1D6E5" xlink:href="#MJX-1-TEX-MI-1D6E5"></use></g></g></g><g data-mml-node="mi" transform="translate(24193.9,0)"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="mo" transform="translate(25240.7,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="msup" transform="translate(26296.5,0)"><g data-mml-node="mi"><use data-c="1D440" xlink:href="#MJX-1-TEX-I-1D440"></use></g><g data-mml-node="TeXAtom" transform="translate(1138,363) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mo"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mn" transform="translate(778,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="msup" transform="translate(28388.2,0)"><g data-mml-node="mi"><use data-c="1D43D" xlink:href="#MJX-1-TEX-I-1D43D"></use></g><g data-mml-node="mi" transform="translate(719.9,363) scale(0.707)"><use data-c="1D447" xlink:href="#MJX-1-TEX-I-1D447"></use></g></g><g data-mml-node="mi" transform="translate(29655.9,0)"><use data-c="1D706" xlink:href="#MJX-1-TEX-I-1D706"></use></g><g data-mml-node="mo" transform="translate(30516.7,0)"><use data-c="3D" xlink:href="#MJX-1-TEX-N-3D"></use></g><g data-mml-node="mo" transform="translate(31572.5,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="msub" transform="translate(32350.5,0)"><g data-mml-node="mi"><use data-c="1D449" xlink:href="#MJX-1-TEX-I-1D449"></use></g><g data-mml-node="TeXAtom" transform="translate(616,-150) scale(0.707)" data-mjx-texclass="ORD"><g data-mml-node="mi"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mn" transform="translate(490,0)"><use data-c="31" xlink:href="#MJX-1-TEX-N-31"></use></g></g></g><g data-mml-node="mo" transform="translate(33938.7,0)"><use data-c="2212" xlink:href="#MJX-1-TEX-N-2212"></use></g><g data-mml-node="mfrac" transform="translate(34939,0)"><g data-mml-node="mi" transform="translate(223.5,477.2) scale(0.707)"><use data-c="1D6FD" xlink:href="#MJX-1-TEX-I-1D6FD"></use></g><g data-mml-node="mi" transform="translate(220,-345) scale(0.707)"><use data-c="210E" xlink:href="#MJX-1-TEX-I-210E"></use></g><rect width="607.3" height="60" x="120" y="220"></rect></g><g data-mml-node="mi" transform="translate(35786.3,0)"><use data-c="1D466" xlink:href="#MJX-1-TEX-I-1D466"></use></g><g data-mml-node="mspace" transform="translate(36276.3,0)"></g></g></g></svg></mjx-container><p>而最後的速度變化就可以寫成程式進行約束模擬。</p><h2 id="Reference"><a href="#Reference" class="headerlink" title="Reference"></a>Reference</h2><p>Allen Chou - Physic Constraints<br><a href="https://github.com/TheAllenChou/unity-physics-constraints">https://github.com/TheAllenChou/unity-physics-constraints</a></p><p>Erin Catto - Box2D<br><a href="https://box2d.org/">https://box2d.org/</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;img data-src=&quot;/img/pexels-photo-2017868.jpeg&quot; alt=&quot;首頁用圖&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;Preface&quot;&gt;&lt;a href=&quot;#Preface&quot; class=&quot;headerlink&quot; title=&quot;Preface&quot;&gt;&lt;/a&gt;Preface&lt;/h2&gt;&lt;p&gt;先前2月參加了Unity應用領域舉辦的CJ貓大大的講座，&lt;/p&gt;
&lt;p&gt;非常感謝CJ大大的分享跟連大辛苦尋找場地，&lt;/p&gt;
&lt;p&gt;想說也將自己吸收學習到的內容整理成文章，與各位的開發者大大們一起參考學習。&lt;/p&gt;
&lt;p&gt;文章的內容是參考CJ大大的專案內容與Box2D作者ErinCatto大大的GDC演講所整理，&lt;br&gt;這兩份資料都在文章最下方的reference中&lt;/p&gt;</summary>
    
    
    
    <category term="Game Physics" scheme="https://blog.harrison-chen.dev/categories/Game-Physics/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Game Physics" scheme="https://blog.harrison-chen.dev/tags/Game-Physics/"/>
    
  </entry>
  
  <entry>
    <title>UniAvatar - 簡易Unity對話系統 (操作篇)</title>
    <link href="https://blog.harrison-chen.dev/2020/04/18/Game%20Implementations/UniAvatar_Intro/"/>
    <id>https://blog.harrison-chen.dev/2020/04/18/Game%20Implementations/UniAvatar_Intro/</id>
    <published>2020-04-18T14:00:00.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>Demo畫面鎮樓<br><img data-src="/img/UniAvatar/Result.png" alt="Result"></p><h2 id="簡介"><a href="#簡介" class="headerlink" title="簡介"></a>簡介</h2><p>UniAvatar是一個使用Unity製作的簡易對話系統，與文字冒險遊戲的範例。</p><p>專案所撰寫的程式碼均開放原始碼，且遵守MIT Lincense，但專案中的ADV實作部分有參考使用其他專案，使用時請參考各自的開放協議。</p><p>感謝<a href="https://www.facebook.com/ArmeIllust">ArmeCyan</a>提供立繪與UI的支援，如果喜歡他的畫風請去粉專支持。</p><p>Repository連結：<a href="https://github.com/Harrison-Dev/UniAvatar">https://github.com/Harrison-Dev/UniAvatar</a></p><p>範例連結: <a href="#example">點我</a></p><p>如果有任何希望追加的功能，歡迎在repo中發issue或是PR協助專案變得更完整！</p><span id="more"></span><h2 id="操作說明"><a href="#操作說明" class="headerlink" title="操作說明"></a>操作說明</h2><p>目前Repo上的版本是以Text mesh pro為主進行設定的，所以這次的操作步驟也會是以TMPro為主。</p><p>如果想使用一般UGUI Text，可以在Player Setting中，將TMP_SUPPORT Define拿掉即可。</p><p><img data-src="/img/UniAvatar/TMPConfig.png" alt="TMPCONFIG"></p><h3 id="場景架構"><a href="#場景架構" class="headerlink" title="場景架構"></a>場景架構</h3><p>打開專案後，首先要打開範例場景<strong>TextMeshProExample</strong>。</p><p>打開範例場景<strong>TextMeshProExample</strong>之後，可以看到場景是由一個Canvas作為主要組成，<br>在Canvas最底下的是Controller們，這部分會在之後的實作細節文章中再仔細提到。</p><p><img data-src="/img/UniAvatar/Hierarchy.png" alt="Hierarchy"></p><p>稍微簡單介紹UGUI中的架構，主要分為背景(背景圖片與物件)、中景(人物與相對應互動)、前景(對話框等UI物件)，最前方是操作時會點選的Panel物件與選項框物件。</p><p>可以透過調整下方的人物圖片、UI圖片等，來製作屬於自己的ADV遊戲。</p><p><strong>注意：</strong>如果調整名字時，記得在Animation Manager中調整Animation Target對應的Key，以免動畫沒辦法正確對應</p><p><img data-src="/img/UniAvatar/AnimationManager.png" alt="AnimationManager"></p><p>關於動畫等系統詳細的介紹，會在之後的文章中慢慢補上。</p><p>介紹完外觀上的架構後，讓我先來介紹一下對話內容的設定吧。</p><h3 id="對話設定"><a href="#對話設定" class="headerlink" title="對話設定"></a>對話設定</h3><p>這個專案參考了許多的文字冒險遊戲設定方法，最後決定以試算表作為文本設定的方式進行編輯。</p><p>可以參考 <a href="https://docs.google.com/spreadsheets/d/12jt6i-AYNEEpmP4Ztsfl6Bu7DbvRMB3_hHdfH_TdSyQ/edit#gid=216373703">範例所使用的文本</a> 中所使用的格式。</p><p>也可以自由將這份文件自己複製一份，方便自己編輯劇情文本。</p><p>第一頁列出目前所實作的Action的種類，以及其對應的參數，這個設定檔算是紀錄目前的功能以及與企劃同步資訊用的，不會實際讀進遊戲中。</p><p><img data-src="/img/UniAvatar/sheet1.png" alt="Sheet1"></p><p>可以看到目前實作了對話、動畫、選項、分支四大類別。</p><p>在第二頁中，可以看到透過前述的這些分類設定了範例的對話內容：</p><p><img data-src="/img/UniAvatar/sheet2.png" alt="Sheet2"></p><p>其中的參數意義，請參考第一頁所列出的內容。</p><p>大家可能注意到了，其中第一頁不管是名字，或是對話內容都有個<strong>Key</strong>在結尾出現。</p><p>這是因為這個系統也製作了簡單的翻譯用文字表格：</p><p><img data-src="/img/UniAvatar/sheet3.png" alt="Sheet3"></p><p>目前只是使用Google Spreadsheet的內建Google Translate，請大家不要太在意翻譯品質。</p><p>第一行的Key為了在劇情表中可以一眼看出對話內容，目前暫時使用整句中文語句作為主要key，可以依照實際翻譯所需進行調整。</p><p><img data-src="/img/UniAvatar/sheet4.png" alt="Sheet4"></p><p>最後一個列表是遊戲中的變數們，實際使用的時候只會用到第一列的值，後面只是方便記錄這個變數實際上的作用。</p><h2 id="將對話設定匯入引擎的步驟"><a href="#將對話設定匯入引擎的步驟" class="headerlink" title="將對話設定匯入引擎的步驟"></a>將對話設定匯入引擎的步驟</h2><p>這一個段落會敘述如何將上述的劇情與文本等文件，匯入到Unity引擎中使用。</p><p>首先將前面的試算表點選 檔案 [→] 下載 [→] 逗號分隔值檔案</p><p>將ActionSetting, Words, Flag 三個檔案都下載下來</p><p><img data-src="/img/UniAvatar/Download.png" alt="DL"></p><p>將下載出來的檔案覆蓋下面資料夾中的三個檔案</p><p><img data-src="/img/UniAvatar/SettingPath.png" alt="SettingPath"></p><p>檔案覆蓋後，回到上一層的目錄</p><p><img data-src="/img/UniAvatar/SettingAssetPath.png" alt="SettingAssetPath"></p><p>將三個目錄最上面的按鈕都點選重新讀檔，就可以將新的文本覆蓋了！</p><p><img data-src="/img/UniAvatar/ApplySetting.png" alt="ApplySetting"></p><p>最後，因為這個範例是使用Text Mesh Pro進行製作，所以要更新Text Atlas</p><p>首先點選這個資料夾中的SDF檔案<br><img data-src="/img/UniAvatar/FontPath.png" alt="FontPath"></p><p>在Inspector中點選Update Atlas<br><img data-src="/img/UniAvatar/UpdateAtlas.png" alt="UpdateAtlas"></p><p>跳出Text Mesh Pro視窗後，接著將選單選擇到From File<br><img data-src="/img/UniAvatar/FromFile.png" alt="FromFile"></p><p>最後按下Generate，最後按下Save就可以將Text Atlas更新了<br><img data-src="/img/UniAvatar/GenerateAndSave.png" alt="GenerateAndSave"></p><p>接下來回到場景執行，就是更新後的文本了！<br><img data-src="/img/UniAvatar/Result.png" alt="Result"></p><p><a name="example"></a></p><h2 id="遊戲範例"><a href="#遊戲範例" class="headerlink" title="遊戲範例"></a>遊戲範例</h2><p><a href="https://docs.google.com/spreadsheets/d/12jt6i-AYNEEpmP4Ztsfl6Bu7DbvRMB3_hHdfH_TdSyQ/edit#gid=216373703">範例所使用的文本</a></p><p>※這個範例與試算表的文本是直接同步的，但是目前公開的Repo並沒有包含下載功能。</p><div id="wrap"><iframe id="bi_iframe" src="https://harrison-dev.github.io/demos/UniAvatarDemo/"  frameborder="0" scrolling="no" allowfullscreen height=480 width=800> </iframe></div><!-- <script>    function adjustIFrame()    {        var ifm = document.getElementById("bi_iframe");        ifm.height = document.documentElement.clientHeight;        ifm.width = document.documentElement.clientWidth;    }</script> --><h2 id="相關文章-陸續更新"><a href="#相關文章-陸續更新" class="headerlink" title="相關文章 (陸續更新)"></a>相關文章 (陸續更新)</h2><ol><li>操作介紹</li><li>故事主控器介紹</li><li>動畫主控器介紹</li><li>多語言實作介紹</li><li>讀取設定檔介紹</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;Demo畫面鎮樓&lt;br&gt;&lt;img data-src=&quot;/img/UniAvatar/Result.png&quot; alt=&quot;Result&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;簡介&quot;&gt;&lt;a href=&quot;#簡介&quot; class=&quot;headerlink&quot; title=&quot;簡介&quot;&gt;&lt;/a&gt;簡介&lt;/h2&gt;&lt;p&gt;UniAvatar是一個使用Unity製作的簡易對話系統，與文字冒險遊戲的範例。&lt;/p&gt;
&lt;p&gt;專案所撰寫的程式碼均開放原始碼，且遵守MIT Lincense，但專案中的ADV實作部分有參考使用其他專案，使用時請參考各自的開放協議。&lt;/p&gt;
&lt;p&gt;感謝&lt;a href=&quot;https://www.facebook.com/ArmeIllust&quot;&gt;ArmeCyan&lt;/a&gt;提供立繪與UI的支援，如果喜歡他的畫風請去粉專支持。&lt;/p&gt;
&lt;p&gt;Repository連結：&lt;a href=&quot;https://github.com/Harrison-Dev/UniAvatar&quot;&gt;https://github.com/Harrison-Dev/UniAvatar&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;範例連結: &lt;a href=&quot;#example&quot;&gt;點我&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果有任何希望追加的功能，歡迎在repo中發issue或是PR協助專案變得更完整！&lt;/p&gt;</summary>
    
    
    
    <category term="Game Implementations" scheme="https://blog.harrison-chen.dev/categories/Game-Implementations/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Fun" scheme="https://blog.harrison-chen.dev/tags/Fun/"/>
    
    <category term="Camera" scheme="https://blog.harrison-chen.dev/tags/Camera/"/>
    
  </entry>
  
  <entry>
    <title>2D Collision Study</title>
    <link href="https://blog.harrison-chen.dev/2020/02/25/Game%20Physics/2D%20Collision%20Detection/"/>
    <id>https://blog.harrison-chen.dev/2020/02/25/Game%20Physics/2D%20Collision%20Detection/</id>
    <published>2020-02-25T04:00:00.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<!-- You can also check [my slide](https://docs.google.com/presentation/d/1UWPEWsAxNpu8nPuYT0IlYQL3WuFwkzCV8B4DjsTunoo/edit?usp=sharing) for more infomation. --><h2 id="Circle-Rectangle-Collision"><a href="#Circle-Rectangle-Collision" class="headerlink" title="Circle / Rectangle Collision"></a>Circle / Rectangle Collision</h2><h3 id="Circle-Collision"><a href="#Circle-Collision" class="headerlink" title="Circle Collision"></a>Circle Collision</h3><p>Circle collision is much easier, only need to determine distance between centers &gt; sum of radius.</p><script type="math/tex; mode=display">distance = \sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}</script><p><img data-src="https://i.imgur.com/UVqamK4.png" alt="circle"></p><span id="more"></span><h3 id="Axis-Aligned-Bounding-Box"><a href="#Axis-Aligned-Bounding-Box" class="headerlink" title="Axis-Aligned Bounding Box"></a>Axis-Aligned Bounding Box</h3><p>Determine 2 rectangles without rotation is collided or not.</p><p>Check the bounds of each rectangle with width &amp; height<br>That is check :</p><script type="math/tex; mode=display">rect1.x < rect2.x + rect2.width \\rect1.x + rect1.width > rect2.x \\rect1.y < rect2.y + rect2.height \\rect1.height + rect1.y > rect2.y</script><p>All of above conditions are satisfied.</p><p><img data-src="https://i.imgur.com/ygKAp8J.png" alt="AABB"></p><h3 id="AABB-in-Unity"><a href="#AABB-in-Unity" class="headerlink" title="AABB in Unity"></a>AABB in Unity</h3><p><a href="https://docs.unity3d.com/ScriptReference/Bounds.html"><strong>Bounds</strong></a></p><p>Represents an axis aligned bounding box.<br>An axis-aligned bounding box, or AABB for short, is a box aligned with coordinate axes and fully enclosing some object. Because the box is never rotated with respect to the axes, it can be defined by just its center and extents, or alternatively by min and max points.</p><h2 id="Separate-Axis-Theorem-SAT"><a href="#Separate-Axis-Theorem-SAT" class="headerlink" title="Separate Axis Theorem (SAT)"></a>Separate Axis Theorem (SAT)</h2><p>Separating Axis Theorem (SAT for short) states if you are able to draw a line to separate two polygons, then they do not collide.</p><p><strong>SAT :</strong></p><p>If we can find out separate axis,<br>two polygons doesn’t collide each other.</p><p><strong>Algorithm:</strong></p><p>Find out separate axis of 2 polygons.</p><p><strong>How to find SAT?</strong></p><p>Just like Axis-Aligned Bounding Box,<br>project each vertice onto each edge.</p><p>(AABB method use x-y axes to detect)</p><h3 id="Finding-SAT"><a href="#Finding-SAT" class="headerlink" title="Finding SAT"></a><strong>Finding SAT</strong></h3><ul><li>It’s not reasonable to search all axes for finding a SAT.</li><li>Select the candidate axes for finding SAT!</li><li>The axes must test are the normals of each edges from shapes.</li></ul><h3 id="Finding-SAT-Algorithm"><a href="#Finding-SAT-Algorithm" class="headerlink" title="Finding SAT Algorithm"></a>Finding SAT Algorithm</h3><ol><li>Find all normals from each shape</li><li>Find all project point for all vertices on each normal</li><li>Find if there is at least 1 separate axis or not.<br>(projection1.max &gt; projection2.min &amp;&amp; project2.max &gt; projection.min)</li></ol><h3 id="Find-Minimum-Translation-Vector"><a href="#Find-Minimum-Translation-Vector" class="headerlink" title="Find Minimum Translation Vector"></a>Find Minimum Translation Vector</h3><p>Tracking the the minimum overlap and axis when we finding SAT.<br>Use this vector to separate shapes.<br><img data-src="https://i.imgur.com/K35Yt6a.png" alt="from internet"></p><h2 id="Still-some-problem…"><a href="#Still-some-problem…" class="headerlink" title="Still some problem…"></a><strong>Still some problem…</strong></h2><h3 id="Tunneling"><a href="#Tunneling" class="headerlink" title="Tunneling"></a>Tunneling</h3><p>Discrete simulation can lead to missed collisions and tunneling. In this case the ball falls out of the world.</p><p>Some of CCD resources:  </p><p><a href="https://docs.unity3d.com/Manual/ContinuousCollisionDetection.html">Unity : Continous Collison</a></p><p><a href="https://www.youtube.com/watch?v=7_nKOET6zwI">Erin Catto : Continous Collision</a></p>]]></content>
    
    
    <summary type="html">&lt;!-- You can also check [my slide](https://docs.google.com/presentation/d/1UWPEWsAxNpu8nPuYT0IlYQL3WuFwkzCV8B4DjsTunoo/edit?usp=sharing) for more infomation. --&gt;
&lt;h2 id=&quot;Circle-Rectangle-Collision&quot;&gt;&lt;a href=&quot;#Circle-Rectangle-Collision&quot; class=&quot;headerlink&quot; title=&quot;Circle / Rectangle Collision&quot;&gt;&lt;/a&gt;Circle / Rectangle Collision&lt;/h2&gt;&lt;h3 id=&quot;Circle-Collision&quot;&gt;&lt;a href=&quot;#Circle-Collision&quot; class=&quot;headerlink&quot; title=&quot;Circle Collision&quot;&gt;&lt;/a&gt;Circle Collision&lt;/h3&gt;&lt;p&gt;Circle collision is much easier, only need to determine distance between centers &amp;gt; sum of radius.&lt;/p&gt;
&lt;script type=&quot;math/tex; mode=display&quot;&gt;
distance = &#92;sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}&lt;/script&gt;&lt;p&gt;&lt;img data-src=&quot;https://i.imgur.com/UVqamK4.png&quot; alt=&quot;circle&quot;&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Game Physics" scheme="https://blog.harrison-chen.dev/categories/Game-Physics/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Game Physics" scheme="https://blog.harrison-chen.dev/tags/Game-Physics/"/>
    
  </entry>
  
  <entry>
    <title>Introduction to Game Rotation</title>
    <link href="https://blog.harrison-chen.dev/2019/11/01/Game%20Mathematics/Introduction%20to%20Game%20Rotation/"/>
    <id>https://blog.harrison-chen.dev/2019/11/01/Game%20Mathematics/Introduction%20to%20Game%20Rotation/</id>
    <published>2019-11-01T04:00:00.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>You can also see this article in <a href="https://medium.com/akatsuki-taiwan-technology/introduction-to-game-rotation-2d1b671216c0">my medium post</a>.</p><p><img data-src="https://miro.medium.com/max/882/1*uLpwHWbnENJxOgrbTAbdAg.png" alt="Title"></p><p>我在接觸3D遊戲引擎時，一開始對旋轉這件事感到很困擾，</p><p>在Unity的編輯器中，旋轉的表現形式看起來像三個顏色的球狀旋轉。在Transform裡面又是有著3個數字的向量形式，到了程式碼裡面，又變成Quaternion這種資料形式，讓人一時之間很難搞懂。<br>這篇文章會記錄一些我對於旋轉的表示方法、各種表示方法的優缺點的理解，以及使用上的一些轉換方式。最後再用一個範例，在Unity中藉由滑鼠拖拉旋轉攝影機來表示如何用程式簡單控制旋轉。</p><span id="more"></span><h2 id="三維空間中的旋轉表示"><a href="#三維空間中的旋轉表示" class="headerlink" title="三維空間中的旋轉表示"></a>三維空間中的旋轉表示</h2><p>最為常見的用法有三種：矩陣、歐拉角以及四元數</p><h3 id="矩陣-Rotation-Matrix"><a href="#矩陣-Rotation-Matrix" class="headerlink" title="矩陣(Rotation Matrix)"></a>矩陣(Rotation Matrix)</h3><p>矩陣方式就是我們所熟知的旋轉矩陣，利用一個3×3矩陣，表示從一個基準的座標，旋轉到目標的座標所使用的旋轉矩陣，換言之，矩陣形式就是將旋轉表示(orientation)轉換成旋轉表示的數學形式。</p><p><img data-src="https://miro.medium.com/max/341/1*yA-e4zQUaMjBoDiIPc4ggg.png" alt="RotationMatrix"></p><p>利用矩陣形式的最大優點，就是對於三維空間座標的向量旋轉是可以立刻使用的，並且可以簡單取得相對的角位移(angular displacement)。<br>而缺點部分就是相對於其他旋轉的表示方法，需要花到9個數字的儲存空間，並且經常會造成浪費，因為時常我們可能只需要相對某個轉軸的旋轉。</p><h3 id="歐拉角-Euler-Angle"><a href="#歐拉角-Euler-Angle" class="headerlink" title="歐拉角(Euler Angle)"></a>歐拉角(Euler Angle)</h3><p>歐拉角是將旋轉的定義，從用數字一次定義出來，改變為依照順序對不同軸向進行旋轉，依照heading-pitch-bank定義三個旋轉為heading angle, pitch angle以及bank angle。Heading rotation是沿著y軸進行旋轉，Pitch rotation沿著x軸進行旋轉，Bank rotation則是沿著z軸進行旋轉，字面上定義依照這個順序進行歐拉角的旋轉。<br>值得注意的是，歐拉角的旋轉不只有heading-pitch-bank方式，還有roll-pitch-yaw等不同的旋轉方式以及順序，像在Unity中，就是以這種方式旋轉，Unity的歐拉角的旋轉順序是沿著Z軸旋轉(roll)，再來沿著X軸旋轉(pitch)，最後沿著Y軸旋轉(yaw)。</p><p><img data-src="https://miro.medium.com/max/1060/1*io6SlYVWUsRtcONiYWpwMA.png" alt="Euler Angle"></p><p>歐拉角的最大的優點，就是歐拉角對於閱讀起來十分直觀，是人類可以直接判別的旋轉方法。此外，歐拉角也是對於旋轉最為簡潔的表達方法，只需要3個數字就可以表達出一個旋轉，是最為節省記憶體的方法。<br>但是，看似如此方便的歐拉角，卻存在著兩個非常嚴重的缺點：</p><h3 id="1-表示同樣旋轉的歐拉角並不唯一"><a href="#1-表示同樣旋轉的歐拉角並不唯一" class="headerlink" title="1. 表示同樣旋轉的歐拉角並不唯一"></a>1. 表示同樣旋轉的歐拉角並不唯一</h3><p>也被稱作別名(aliasing)問題，例如在角度上加上360度，就是一種最單純的別名問題，因為對角度加上360度並不會改變他的角度。但是這類別名問題只要限制角度範圍就可以解決，並不會造成太大的困擾。<br>真正麻煩的是第二種，因為三個角度並不互相獨立的造成的問題，例如pitch 135度與 heading 180度加上pitch 45度(向下旋轉)是等價的旋轉表示。對於這種別名問題，常見的做法是限制他的旋轉角度，例如限制heading/bank在 －180 ~ +180之間，將pitch限制在－90 ~ +90之間。<br>然而，就算限制了上面所說的角度之後，仍然會存在一個問題，被稱為萬向鎖(Gimbal Lock)，最為著名的舉例就是先head 45度再pitch 90度，與先pitch 90度再banking 45度是相同的，其最根本的原因就是pitch ±90度之後，使得另外兩個轉軸重疊，此時兩個轉軸旋轉任意角度都會造成別名問題。</p><p><img data-src="https://miro.medium.com/max/1256/1*IvRdP5jY-Elhi9SRkau_2Q.png" alt="Gimbal Lock" title="from Wikipedia"></p><p>為了消除萬向鎖造成的別名問題，可以規定萬向鎖發生時，只交由某一個軸去完成旋轉，假如約定以heading完成全部旋轉，bank在萬向鎖發生時就會永遠為0。</p><h3 id="2-對於兩個旋轉表示的內插-Lerp-的問題"><a href="#2-對於兩個旋轉表示的內插-Lerp-的問題" class="headerlink" title="2. 對於兩個旋轉表示的內插(Lerp)的問題"></a>2. 對於兩個旋轉表示的內插(Lerp)的問題</h3><p>角度的內差第一個會面對的問題，是歐拉角旋轉的週期性所產生的，例如要從heading -150旋轉到heading 150，就存在著60度的短弧與300度的長弧之分，解決這類問題就是將插值的差角限制到正負180度內，確保旋轉在最短弧上。<br>而在旋轉角度內插上，歐拉角會遇到最大的問題，還是前面提的萬向鎖問題。在單純地將歐拉角進行差值運算時，如果遇到萬向鎖問題，大多情況會導致錯誤的路徑，抖動等等問題，在萬向鎖情況旋轉歐拉角，需要將兩個角度分開旋轉，但是以攝影機的轉向操作為例，在球面上光滑旋轉才是最舒適的表現方式。而歐拉角在旋轉上所遇到的萬向鎖問題，很不幸的目前並沒有任何好的數學解法，這也是歐拉角沒辦法作為最主要旋轉表示的主要原因。</p><p>More information : <a href="https://www.youtube.com/watch?v=zc8b2Jo7mno">https://www.youtube.com/watch?v=zc8b2Jo7mno</a></p><h2 id="四元數-Quaternion"><a href="#四元數-Quaternion" class="headerlink" title="四元數(Quaternion)"></a>四元數(Quaternion)</h2><h3 id="四元數的定義"><a href="#四元數的定義" class="headerlink" title="四元數的定義"></a>四元數的定義</h3><p>四元數原先是一個四維的複數空間的表示方法，在幾何上的應用，可以作為一種旋轉的表示方式。數值上，存在一個定標器(scaler)w以及一組三維向量v或是直接拆分成x,y,z(Unity中，可以直接取得w,x,y,z四個數值)。<br>四元數可以代表一個複數空間中的座標，其中[w, (x, y ,z)]被定義成w+xi+yj+zk。其中的i,j,k有如同二維複數空間的性質：</p><script type="math/tex; mode=display">    i^2 = j^2 = k^2 = -1</script><script type="math/tex; mode=display">    ij = k, ji = -k, jk = i, kj = -i, ki = j, ik = -j</script><p>如同二維空間的複數座標可以旋轉二維向量，四元數也可以拿來旋轉三維向量。<br>而四元數中的四個數字究竟是什麼意思呢？從歐拉角我們可以得知，一個三維的旋轉表示可以被表述成一個旋轉軸加上一個旋轉角度，四元數也是用這個概念表示的，假設有一個旋轉軸n加上旋轉角度θ，整個四元數可以被表示成：</p><script type="math/tex; mode=display">    [w,v] = [cos(θ/2), sin(θ/2)\hat{n}]</script><script type="math/tex; mode=display">    [w,x,y,z]  =  [ cos(θ/2), sin(θ/2) n_x,  sin(θ/2) n_y , sin(θ/2) n_z]</script><h3 id="四元數的性質們"><a href="#四元數的性質們" class="headerlink" title="四元數的性質們"></a>四元數的性質們</h3><ul><li><p>完全沒有旋轉的四元數被稱為identity，數值為[1,0]和[-1,0]，其中的0表示零向量。</p></li><li><p>在旋轉表示的用途中，我們只使用單位四元數(Unit Quaternion)，即模數為1的四元數。</p></li></ul><script type="math/tex; mode=display">    ||q || = [w,v] = \sqrt{w^2 + ||v||^2} = 1</script><ul><li>四元數的運算<ul><li>四元數的乘法沒有交換律，q1q2 ≠ q2q1。</li><li>四元數的乘法存在結合律， (q1q2)q3 = q1(q2q3)</li><li>四元數的乘積的模數等於模數的乘積(||q1|| <em>||q2|| = ||q1</em>q2||)</li><li>四元數的乘法可以表示兩個旋轉的結合，進行q1再進行q2，可以合併成q3 = q2q1(旋轉順序由右向左)</li><li>四元數的旋轉差為反四元數，q1到q2的旋轉量為：d = (q1^-1) q2</li></ul></li></ul><p>還有許多未提到的四元數運算如點積、Quaternion Interpolation(Slerp)等，在基礎篇裡面就先省略，如果有下一篇再補上相關資訊&lt;(<em> </em>)&gt;。<br>四元數的優點是可以平滑插值計算，並且可以快速計算角位移以及轉換成旋轉矩陣，而且只用到四個數字進行存取，記憶體消耗較低。<br>四元數的缺點則是跟矩陣類似，相較歐拉角更大的記憶體用量，並且比旋轉矩陣更難直接讓人類判讀。</p><h2 id="轉換成四元數"><a href="#轉換成四元數" class="headerlink" title="轉換成四元數"></a>轉換成四元數</h2><p>在Unity引擎裡面，Transform所顯示的旋轉角度是歐拉角，腳本上取得的Rotation則是四元數，理解兩者之間的轉換方式可以讓使用上更為方便。<br>為了更符合Unity內的使用，在這個段落中，歐拉角的表示方式將使用roll-pitch-yaw來表示。</p><h3 id="將歐拉角轉換成四元數"><a href="#將歐拉角轉換成四元數" class="headerlink" title="將歐拉角轉換成四元數"></a>將歐拉角轉換成四元數</h3><p>在前面我們了解到，四元數可以藉由相乘來完成連續旋轉，所以我們將把rolling, pitching, yawing分為三個四元數進行旋轉，最後再將它們串成同一個四元數。<br>根據四元數的定義，可以轉換如下：</p><p><img data-src="https://miro.medium.com/max/1284/1*403W_CTHQcSLWwk_oI6EVg.png" alt="eulerToQ" title="Image from wikipedia"></p><p>Reference<br>Wikipedia:<br><a href="https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles">https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles</a><br><a href="https://en.wikipedia.org/wiki/Quaternion">https://en.wikipedia.org/wiki/Quaternion</a></p><p>3D Math Primer For Graphics and Game Development:<br>Amazon : <a href="https://www.amazon.com/Math-Primer-Graphics-Game-Development-ebook/dp/B008KZU548">https://www.amazon.com/Math-Primer-Graphics-Game-Development-ebook/dp/B008KZU548</a></p><p>Unity Rotation Guide:<br><a href="https://docs.unity3d.com/Manual/QuaternionAndEulerRotationsInUnity.html">https://docs.unity3d.com/Manual/QuaternionAndEulerRotationsInUnity.html</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;You can also see this article in &lt;a href=&quot;https://medium.com/akatsuki-taiwan-technology/introduction-to-game-rotation-2d1b671216c0&quot;&gt;my medium post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img data-src=&quot;https://miro.medium.com/max/882/1*uLpwHWbnENJxOgrbTAbdAg.png&quot; alt=&quot;Title&quot;&gt;&lt;/p&gt;
&lt;p&gt;我在接觸3D遊戲引擎時，一開始對旋轉這件事感到很困擾，&lt;/p&gt;
&lt;p&gt;在Unity的編輯器中，旋轉的表現形式看起來像三個顏色的球狀旋轉。在Transform裡面又是有著3個數字的向量形式，到了程式碼裡面，又變成Quaternion這種資料形式，讓人一時之間很難搞懂。&lt;br&gt;這篇文章會記錄一些我對於旋轉的表示方法、各種表示方法的優缺點的理解，以及使用上的一些轉換方式。最後再用一個範例，在Unity中藉由滑鼠拖拉旋轉攝影機來表示如何用程式簡單控制旋轉。&lt;/p&gt;</summary>
    
    
    
    <category term="Game Mathematics" scheme="https://blog.harrison-chen.dev/categories/Game-Mathematics/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Game Math" scheme="https://blog.harrison-chen.dev/tags/Game-Math/"/>
    
  </entry>
  
  <entry>
    <title>關於C#記憶體管理那些事。</title>
    <link href="https://blog.harrison-chen.dev/2019/07/27/Game%20Programming/Memory%20Management%20in%20Game/"/>
    <id>https://blog.harrison-chen.dev/2019/07/27/Game%20Programming/Memory%20Management%20in%20Game/</id>
    <published>2019-07-27T17:51:53.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>You can also see my post in <a href="https://home.gamer.com.tw/creationDetail.php?sn=4475189">Bahamut</a>.</p><p>使用Unity製作遊戲也好一陣子，</p><p>途中踩過不少坑都是對於Unity預設值與C#程式語言的設計上的不熟悉，</p><p>關於Unity預設值的部分，<a href="https://www.slideshare.net/KelvinLo5/2019-unity-iii-tgdf">達哥在今年的TGDF上的簡報</a>讓我獲益良多，大家都該去看看。</p><p>這次想探討的是關於C#程式語言的設計方面，</p><p>特別是相對於C/C++這些低階語言來說，C#/Java的記憶體分配像是一個巨大的黑盒子，</p><p>運作起來還蠻順利的，但是時不時就會像樂高一樣踩到腳(而且很痛)，</p><p>這篇就來記錄一下自己學到的東西，順便討論裝箱(Boxing)跟C#的記憶體運作吧！</p><span id="more"></span><h2 id="一、C-的記憶體分配"><a href="#一、C-的記憶體分配" class="headerlink" title="一、C#的記憶體分配"></a><strong>一、C#的記憶體分配</strong></h2><p>由於看到文章的朋友，可能不一定對程式語言的一些處理非常孰悉，</p><p>所以在這邊先簡單整理關於C#記憶體分配的一些規則。</p><p>對C#來說，一個Class分成三種類型：</p><ol><li>Value Type 2. Reference Type 3. Pointer Type</li></ol><p>其中第三項要開啟unsafe才能夠使用，而Unity的預設值是關閉的，所以可以先不理它。</p><p>前兩項Value Type跟Reference Type，在MSDN的官方說明上是這樣的：</p><p>Value types are either stack-allocated or allocated inline in a structure.<br>Reference types are heap-allocated</p><p>可以了解到，</p><p>對於Value Type來說，一般是存放在STACK段，做為區域變數使用。</p><p>對於Reference Type來說，一般是存放在HEAP段，由C#的Garbage Collection控管。</p><p>(當然這樣簡單的分類未必完全正確，因為他們其實存在<a href="https://blogs.msdn.microsoft.com/ericlippert/2009/04/27/the-stack-is-an-implementation-detail-part-one/">一些實作細節的不同</a>)</p><p>簡單來說：</p><p><strong>Value Type</strong>就是一般常用的int, float, char, struct, enum這種簡單的資料型態，</p><p>他們在一般情況通常是區域變數，也就是用完就丟的，對記憶體的消耗也不會太大。</p><p><strong>Reference Type</strong>就是利用class包裝起來的資料了，他們會被整包放到動態記憶體裡面，</p><p>如果不特別處理，就會持續占用記憶體，當相關的程式使用完這些變數，</p><p>C#就會利用<strong>Garbage Collection</strong>的方法，回收這些用不到的記憶體，</p><p>在Collect的當下會消耗較多CPU資源，甚至在手機上有可能會導致掉幀的情況，</p><p>所以我們一般會希望迴避這種動態記憶體的分配能夠有所節制，</p><p>也是前幾篇文章所提到的物件池存在的一部份原因。</p><h2 id="二、萬惡的Boxing跟Unboxing"><a href="#二、萬惡的Boxing跟Unboxing" class="headerlink" title="二、萬惡的Boxing跟Unboxing"></a><strong>二、萬惡的Boxing跟Unboxing</strong></h2><p>介紹完兩種C#的記憶體分配方式之後，再回頭討論標題的Boxing究竟是什麼意思吧。</p><p>在寫遊戲程式的時候，常常會遇到一種狀況：</p><p>「需要把現在的數值記錄下來，做為某種用途」</p><p>這種情況，我們常常會宣告一個class，像是下面這種存檔用的資訊：</p><p><img data-src="https://i.imgur.com/aWNJodO.png" alt="sd"></p><p>在使用上，我們通常會寫成：</p><p><img data-src="https://i.imgur.com/oPD7LRT.png" alt="sd"></p><p>這種形式，此時原本存在區域變數的level跟health，就需要複製一份到動態變數區，</p><p>並且包裝成SaveFile的形式一直存在於動態變數區，直到它被使用完畢，被GC給回收去。</p><p>這樣<strong>從區域變數(Value Type)</strong>被打包到<strong>動態變數區段(HEAP段)</strong>，就被稱為<strong>Boxing(裝箱)</strong>。</p><p>反過來從<strong>動態變數區段</strong>擷取成<strong>區域變數(Value Type)</strong>就被稱為<strong>Unboxing(拆箱)</strong>。</p><h2 id="三、總結"><a href="#三、總結" class="headerlink" title="三、總結"></a>三、總結</h2><p>其實Boxing跟Unboxing在寫程式的時候幾乎是難以完全避免的，</p><p>我們只要記得盡量少使用裝拆箱，以及在使用ArrayList, HashTable這種</p><p>一放進去就會被轉型成object type的自動裝箱結構時，要務必小心使用。</p><p>另外就是盡量在不忙碌的時候(打開UI選單、暫停遊戲、或讀取關卡時)，</p><p>手動呼叫System.GC.Collect()進行手動GC，勢必可以稍微減少GC回收對效能造成的影響囉！</p><p>參考資料：<br><a href="https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing">https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing</a><br><a href="https://docs.microsoft.com/zh-tw/dotnet/standard/garbage-collection/fundamentals">https://docs.microsoft.com/zh-tw/dotnet/standard/garbage-collection/fundamentals</a><br><a href="https://docs.microsoft.com/zh-tw/dotnet/api/system.valuetype?view=netframework-4.8">https://docs.microsoft.com/zh-tw/dotnet/api/system.valuetype?view=netframework-4.8</a><br><a href="http://dev.yesky.com/msdn/359/3486359.shtml">http://dev.yesky.com/msdn/359/3486359.shtml</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;You can also see my post in &lt;a href=&quot;https://home.gamer.com.tw/creationDetail.php?sn=4475189&quot;&gt;Bahamut&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;使用Unity製作遊戲也好一陣子，&lt;/p&gt;
&lt;p&gt;途中踩過不少坑都是對於Unity預設值與C#程式語言的設計上的不熟悉，&lt;/p&gt;
&lt;p&gt;關於Unity預設值的部分，&lt;a href=&quot;https://www.slideshare.net/KelvinLo5/2019-unity-iii-tgdf&quot;&gt;達哥在今年的TGDF上的簡報&lt;/a&gt;讓我獲益良多，大家都該去看看。&lt;/p&gt;
&lt;p&gt;這次想探討的是關於C#程式語言的設計方面，&lt;/p&gt;
&lt;p&gt;特別是相對於C/C++這些低階語言來說，C#/Java的記憶體分配像是一個巨大的黑盒子，&lt;/p&gt;
&lt;p&gt;運作起來還蠻順利的，但是時不時就會像樂高一樣踩到腳(而且很痛)，&lt;/p&gt;
&lt;p&gt;這篇就來記錄一下自己學到的東西，順便討論裝箱(Boxing)跟C#的記憶體運作吧！&lt;/p&gt;</summary>
    
    
    
    <category term="Game Programming" scheme="https://blog.harrison-chen.dev/categories/Game-Programming/"/>
    
    
    <category term="Computer Orgnization" scheme="https://blog.harrison-chen.dev/tags/Computer-Orgnization/"/>
    
    <category term="Memory Management" scheme="https://blog.harrison-chen.dev/tags/Memory-Management/"/>
    
    <category term="C# Programming Language" scheme="https://blog.harrison-chen.dev/tags/C-Programming-Language/"/>
    
  </entry>
  
  <entry>
    <title>實作分享 - 攝影機捕捉多角色</title>
    <link href="https://blog.harrison-chen.dev/2019/02/08/Game%20Implementations/Multiplayer%20Camera/"/>
    <id>https://blog.harrison-chen.dev/2019/02/08/Game%20Implementations/Multiplayer%20Camera/</id>
    <published>2019-02-08T18:30:45.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>You can also see my post in <a href="https://home.gamer.com.tw/creationDetail.php?sn=4287854">Bahamut</a>.</p><p>最近在開發2D遊戲攝影機的時候，參考到一篇2D攝影機設計經典文章</p><p>就是2015年的這篇 <a href="https://igdshare.org/content/gdc2015-2d-scrolling-itay-keren">Scroll Back - 2D 捲軸遊戲的攝影機理論與實務</a> </p><p>其中有提到，在多人操作的時候，會希望攝影機能照到所有角色，這篇就將討論如何實做這件事。</p><p><img data-src="https://imgur.com/ltrEyc8.gif" alt="Smash is best"></p><span id="more"></span><h2 id="分析"><a href="#分析" class="headerlink" title="分析"></a><strong>分析</strong></h2><p>在開始製作之前，我們先試著簡化遇到的問題</p><p><img data-src="https://i.imgur.com/NZVef9F.png" alt="smash bounding box"></p><p>從上面這張圖來看，四個紅圈是我們的目標(角色)，我們希望的是將他們都顯示在畫面中。<br>那也就是說，我們希望能夠用一個長方形(螢幕)來塞下他們全部。</p><p>如下圖</p><p><img data-src="https://i.imgur.com/cUsZVJn.png" alt="Smash box"></p><p><del>我當初看到這個問題的時候，馬上想到演算法學到的convex-hull問題，<br>找出最小凸包之後，就可以沿著凸包求得最小的方形。</del></p><p>但是在我們攝影機不會旋轉的情況，我們不需要那麼麻煩，因為軸是固定的，<br>我們只要找到這些點之中最大和最小的x,y值即可<br>如下圖</p><p>![Smash] (<a href="https://i.imgur.com/wEs8HUp.png">https://i.imgur.com/wEs8HUp.png</a>)</p><p>判斷的程式碼如下</p><p><img data-src="https://i.imgur.com/1xmFkAA.png" alt="unity"></p><p>接著我們就可以利用判斷出來的這四個點做延伸，找出目標的長方形</p><p><img data-src="https://i.imgur.com/V32E8zZ.png" alt="unity"></p><p>此時將<strong>攝影機放在這個長方形的中心點，再將攝影機縮放到比長方形大小還要大</strong>，<br>就可以拍到所有角色囉！</p><h2 id="實作"><a href="#實作" class="headerlink" title="實作"></a>實作</h2><p>接下來實作長方形大小的計算，以及攝影機的縮放部分</p><p>這邊我的攝影機縮放以orthographic的攝影機為例(因為直接size乘上去就好)，<br>使用投影的情況就再額外計算Z軸距離吧！</p><p>以下是我實作的程式碼：<br><img data-src="https://i.imgur.com/Z27MqQs.png" alt="code"></p><p>使用前面說的方法獲得整個長方形的四個點之後，可以簡單地算出他們的中心點(第15行)<br>接著算出畫面長寬相對於長方形的長寬比例，將較大的一方回傳給攝影機設定就可以了！(17~20行以及22行所做)</p><p>執行結果大致如下影片</p><iframe width="560" height="315" src="https://www.youtube.com/embed/FnZb6DC56kg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe><p>整個專案的repo在這，如果有興趣也歡迎參考使用喔XD<br><a href="https://github.com/HaoxDev/UnityPractices">https://github.com/HaoxDev/UnityPractices</a></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;You can also see my post in &lt;a href=&quot;https://home.gamer.com.tw/creationDetail.php?sn=4287854&quot;&gt;Bahamut&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;最近在開發2D遊戲攝影機的時候，參考到一篇2D攝影機設計經典文章&lt;/p&gt;
&lt;p&gt;就是2015年的這篇 &lt;a href=&quot;https://igdshare.org/content/gdc2015-2d-scrolling-itay-keren&quot;&gt;Scroll Back - 2D 捲軸遊戲的攝影機理論與實務&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;其中有提到，在多人操作的時候，會希望攝影機能照到所有角色，這篇就將討論如何實做這件事。&lt;/p&gt;
&lt;p&gt;&lt;img data-src=&quot;https://imgur.com/ltrEyc8.gif&quot; alt=&quot;Smash is best&quot;&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Game Implementations" scheme="https://blog.harrison-chen.dev/categories/Game-Implementations/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Fun" scheme="https://blog.harrison-chen.dev/tags/Fun/"/>
    
    <category term="Camera" scheme="https://blog.harrison-chen.dev/tags/Camera/"/>
    
  </entry>
  
  <entry>
    <title>Object pooling - 基本物件池與應用</title>
    <link href="https://blog.harrison-chen.dev/2018/08/17/Game%20Programming/Object%20pooling/"/>
    <id>https://blog.harrison-chen.dev/2018/08/17/Game%20Programming/Object%20pooling/</id>
    <published>2018-08-17T09:22:00.000Z</published>
    <updated>2026-02-25T00:47:12.003Z</updated>
    
    <content type="html"><![CDATA[<p>You can also see my post in <a href="https://home.gamer.com.tw/creationDetail.php?sn=4097428">Bahamut</a>.</p><h2 id="什麼是Object-pooling"><a href="#什麼是Object-pooling" class="headerlink" title="什麼是Object pooling"></a><strong>什麼是Object pooling</strong></h2><p>在我們製作一些遊戲的時候，常常需要使用到一些重複且相同的物件，</p><p>如果我們照著一般物件產生以及消除的方法：Instantiate 以及 Destroy，</p><p>會使許多GameObject(object)用完慘遭系統GC，如果像是子彈或者音樂遊戲的object被大量GC，</p><p>很可能造成遊戲卡頓，對於音樂遊戲或者是捲軸射擊遊戲都是相當致命的傷害，</p><p>為了避免這種問題，我們使用Object pool來儲存可以使用的object們，來免於上述的問題。</p><p>那麼Object pool該如何在C#中實作呢？</p><span id="more"></span><p>以下是一個Object pool 的簡單範例：</p><p><img data-src="https://i.imgur.com/gtOHKt7.png" alt="ObjectPool"></p><p>可以看到，我使用Queue作為最基本的element存放結構，</p><p>在這邊稍微補充Queue的作用給沒有聽過的人：</p><p>Queue 是一個first in first out(先進先出)的資料結構，可以用來存放需要順序性的資料，例如網路</p><p>傳送的封包等，Queue有幾個基本的操作：Enqueue可以將物件存放到Queue的尾端，Dequeue</p><p>可以從Queue的開頭來拿取物件，對於我們這個object pool的實作並不是唯一的選擇，只是筆者</p><p>習慣上所做的選擇而已。</p><p>另外，在這個class中，可以看到建構子需要傳入創建object的創建方式，對於一般c#的物件來</p><p>說，通常是以new運算子開頭的建構函數，而對於unity的GameObject來說，便是Instantiate方法</p><p>了。</p><p>使用上，只需要呼叫GetObject就可以接收到object pool內儲存的物件，如果物件池中已經沒有物</p><p>件了，我們就會使用一開始指定的方法出創建新的物件來回傳。</p><p>另外，當我們使用完這個物件之後，我們可以呼叫Recycle方法，將這個物件回收起來，這樣如果</p><p>下次需要呼叫object pool裡頭的物件，我們就可以重複利用這個物件了！</p><h2 id="如何將物件池應用於Unity中"><a href="#如何將物件池應用於Unity中" class="headerlink" title="如何將物件池應用於Unity中"></a><strong>如何將物件池應用於Unity中</strong></h2><p>我們目前實作的物件池，其實只能將物件這個reference記錄起來，避免它被系統給GC，但如果</p><p>要真的在Unity裡面重複使用，還必須將物件本身藏起來才行，例如下面這個子彈發射的例子：</p><p><img data-src="https://i.imgur.com/uqWybrF.png" alt="Bullet Example"></p><p>在回收子彈時，同時將它設為Inactive。</p><p><img data-src="https://i.imgur.com/i5DlB77.png" alt="Bullet Example"></p><p>如果我們從pool中拿取子彈拿來使用，就必須將它Active，否則他是無法運作的。</p><p>當然，在Unity的Object pool實作上面，除了將他Inactive拿掉以外，也可以將該GameObject移出</p><p>遊戲畫面外，如果有較為耗效能的component再利用腳本關閉，這樣會比active該GameObject</p><p>能獲得更好的效能，大家有興趣的話，也可以自己實作看看喔！</p><p>這是上面的子彈範例專案檔，大家也可以下載下來試試看：Google雲端</p><p>＊本文章提及所有code以及專案中所有code都可以任意修改使用，不需進行告知！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;You can also see my post in &lt;a href=&quot;https://home.gamer.com.tw/creationDetail.php?sn=4097428&quot;&gt;Bahamut&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;什麼是Object-pooling&quot;&gt;&lt;a href=&quot;#什麼是Object-pooling&quot; class=&quot;headerlink&quot; title=&quot;什麼是Object pooling&quot;&gt;&lt;/a&gt;&lt;strong&gt;什麼是Object pooling&lt;/strong&gt;&lt;/h2&gt;&lt;p&gt;在我們製作一些遊戲的時候，常常需要使用到一些重複且相同的物件，&lt;/p&gt;
&lt;p&gt;如果我們照著一般物件產生以及消除的方法：Instantiate 以及 Destroy，&lt;/p&gt;
&lt;p&gt;會使許多GameObject(object)用完慘遭系統GC，如果像是子彈或者音樂遊戲的object被大量GC，&lt;/p&gt;
&lt;p&gt;很可能造成遊戲卡頓，對於音樂遊戲或者是捲軸射擊遊戲都是相當致命的傷害，&lt;/p&gt;
&lt;p&gt;為了避免這種問題，我們使用Object pool來儲存可以使用的object們，來免於上述的問題。&lt;/p&gt;
&lt;p&gt;那麼Object pool該如何在C#中實作呢？&lt;/p&gt;</summary>
    
    
    
    <category term="Game Programming" scheme="https://blog.harrison-chen.dev/categories/Game-Programming/"/>
    
    
    <category term="Basic" scheme="https://blog.harrison-chen.dev/tags/Basic/"/>
    
    <category term="Data Structure" scheme="https://blog.harrison-chen.dev/tags/Data-Structure/"/>
    
  </entry>
  
</feed>
