<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4380486110383106325</atom:id><lastBuildDate>Sat, 11 Apr 2026 00:53:48 +0000</lastBuildDate><category>Game</category><category>good</category><category>C/C++</category><category>Editor</category><category>Design</category><category>Android</category><category>Porting</category><category>HTML5</category><category>smallworld2</category><category>Lua</category><category>javascript</category><category>Debugger</category><category>Sample</category><category>Win32</category><category>Algorithm</category><category>Windows</category><category>EBNF</category><category>Emscripten</category><category>Parser</category><category>Sudoku</category><category>stge</category><category>OpenGL</category><category>PSP</category><category>VM</category><category>iPhone</category><category>Boost</category><category>Graphics</category><category>Java</category><category>Spirit</category><category>Test</category><category>WTL</category><category>Windows Mobile</category><category>jaja</category><category>API</category><category>Ini</category><category>Interface</category><category>MMOG</category><category>Objective-C</category><category>Python</category><category>SDK</category><category>SDL</category><category>3D</category><category>AI</category><category>Browser</category><category>C#</category><category>DotNet</category><category>Fun</category><category>LLM</category><category>Mac</category><category>OASYS</category><category>Ollama</category><category>OpenCV</category><category>QRCode</category><category>STL</category><category>UEFI</category><category>UnitTest</category><category>VS.Net</category><category>WebM</category><category>WebSocket</category><category>Xcode</category><category>ZXing</category><category>joke</category><category>port</category><category>yardparser</category><category>zlib</category><title>很讚的遊戲編輯器</title><description>很讚的遊戲編輯器 Good Game Editor 1.6.4</description><link>http://good-ed.blogspot.com/</link><managingEditor>noreply@blogger.com (Waync Cheng)</managingEditor><generator>Blogger</generator><openSearch:totalResults>122</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-4078850661067183810</guid><pubDate>Tue, 03 Feb 2026 13:34:00 +0000</pubDate><atom:updated>2026-02-03T21:34:02.760+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">AI</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">OpenCV</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>窮人的 AI：自動漫畫分鏡切割</title><description>&lt;p&gt;&amp;nbsp;&lt;span style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px;&quot;&gt;(&lt;/span&gt;&lt;a href=&quot;https://smallworld.idv.tw/misc/mangacut/&quot; style=&quot;color: #4183c4; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 0px; padding: 0px; text-decoration-line: none;&quot;&gt;試試看&lt;/a&gt;&lt;span style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px;&quot;&gt;)&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在手機上看漫畫時，有一個體驗上的問題：&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;漫畫原本是「整頁設計」&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;手機最適合的是「一格一格往下滑」&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;與其強迫使用者縮放、拖曳、放大，更直覺的做法是：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 5px solid rgb(221, 221, 221); color: #555555; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px; padding: 0px 0px 0px 0.6em;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;直接把一頁漫畫自動切成多個分鏡，轉成瀑布流閱讀。&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這篇文章分享一個不靠深度學習、完全在前端完成的實作方式：&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;使用 OpenCV.js 做分鏡偵測&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;輸出 rect list&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;再用 全畫面 Canvas 把每個分鏡當成一個「閱讀單位」&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;整個系統可以拆成三層：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;漫畫圖片
   ↓
影像處理（找出 rects）
   ↓
排序後的 rect list
   ↓
全畫面 Canvas 逐格呈現（瀑布流）&lt;/code&gt;&lt;/pre&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-1：灰階化&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 1：灰階化&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;漫畫的資訊 90% 都在線條上，顏色反而是干擾。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;cv.cvtColor(src, grayImage, cv.COLOR_RGBA2GRAY);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;灰階化的好處：&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;降低維度&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;對邊緣偵測更穩定&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;對黑白漫畫特別有效&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYDOcFJjmeH_HXdAiLxI1QdsoiLvOx0iPHi8VRxlVKWJM4Xr1l-TJRoMa27VGpmZMZBxPMab4BjIbuS_3EQEwO5lvDufxS-5c6LJmwVPh66h8NEtkM78V1B_t1D7XDQjQZ7E5dJs-5aTjrCG1QbnNKl1NMdHuJC0VZ0AnK5vYzzKz0onEACB1yNJJcVWkp/s599/Figure_2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;599&quot; data-original-width=&quot;455&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYDOcFJjmeH_HXdAiLxI1QdsoiLvOx0iPHi8VRxlVKWJM4Xr1l-TJRoMa27VGpmZMZBxPMab4BjIbuS_3EQEwO5lvDufxS-5c6LJmwVPh66h8NEtkM78V1B_t1D7XDQjQZ7E5dJs-5aTjrCG1QbnNKl1NMdHuJC0VZ0AnK5vYzzKz0onEACB1yNJJcVWkp/w304-h400/Figure_2.png&quot; width=&quot;304&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style=&quot;font-size: 13.34px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-2：邊緣偵測，抓出「分鏡的邊」&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 2：邊緣偵測，抓出「分鏡的邊」&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;接下來用最經典、也最夠用的 Canny Edge Detection：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;cv.Canny(grayImage, edges, 50, 150);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在漫畫中，分鏡外框通常就是最明顯的邊界。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitsJmtCiZTJD6gHTEvnnUEf5bc595FpCUA0iSpYK_AwXvbv86spaTibJOdpPlcAsCaEL2OkXzq_DMgLVWcaCfG1wVg7bQC_MlAJB-af4oj7NW5XvfZvpMcL0tEKLSgE__om4YU1O0-Vm1EPfihAp3KcJpt1iO6YhlrmLV_ZDhnABo1Fl0-ngw9R-nRjA7I/s601/Figure_3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;601&quot; data-original-width=&quot;434&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitsJmtCiZTJD6gHTEvnnUEf5bc595FpCUA0iSpYK_AwXvbv86spaTibJOdpPlcAsCaEL2OkXzq_DMgLVWcaCfG1wVg7bQC_MlAJB-af4oj7NW5XvfZvpMcL0tEKLSgE__om4YU1O0-Vm1EPfihAp3KcJpt1iO6YhlrmLV_ZDhnABo1Fl0-ngw9R-nRjA7I/w289-h400/Figure_3.png&quot; width=&quot;289&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-3：形態學操作，把破碎邊框「補起來」&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 3：形態學操作，把破碎邊框「補起來」&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;真實漫畫的線條並不完美，常常有斷線、陰影、留白。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;所以要做一個很重要的步驟：膨脹（Dilation）&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; kernel = cv.Mat.ones(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;, cv.CV_8U);
cv.dilate(edges, dilatedEdges, kernel);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;直覺理解就是：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 5px solid rgb(221, 221, 221); color: #555555; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px; padding: 0px 0px 0px 0.6em;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;把細線「抹粗一點」， 讓本來斷掉的邊界連成封閉區域。&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這一步直接決定後面能不能成功抓到「一整格分鏡」。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR8xLYOZ9r7kFUUczNb2aoDm5JFNy5EtxMMYB1EcUuRcXDCkbz7isU2LKT2KbC5OTRgboSXspt_IoP85AvK6occRm3Egns_myWFg09IepyQjY3jZ5J-CI85zNlI_75l5cJ3VcJehpgN08xJ0qBV-B-2CRGy_AQv1jh8Cq7bk_jusCmy8lxbsFJJwzWnBIv/s602/Figure_4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;602&quot; data-original-width=&quot;449&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR8xLYOZ9r7kFUUczNb2aoDm5JFNy5EtxMMYB1EcUuRcXDCkbz7isU2LKT2KbC5OTRgboSXspt_IoP85AvK6occRm3Egns_myWFg09IepyQjY3jZ5J-CI85zNlI_75l5cJ3VcJehpgN08xJ0qBV-B-2CRGy_AQv1jh8Cq7bk_jusCmy8lxbsFJJwzWnBIv/w299-h400/Figure_4.png&quot; width=&quot;299&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-4：找輪廓，轉成矩形框（rect）&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 4：找輪廓，轉成矩形框（rect）&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;有了封閉區域之後，就可以找輪廓：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;cv.findContours(
  dilatedEdges,
  contours,
  hierarchy,
  cv.RETR_EXTERNAL,
  cv.CHAIN_APPROX_SIMPLE
);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每一個 contour，代表一個「可能的分鏡區塊」。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;接著轉成矩形：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; rect = cv.boundingRect(contour);
rects.push([rect.x, rect.y, rect.width, rect.height]);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;並用面積過濾掉雜訊：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;if (cv.contourArea(contour) &amp;gt; 5000) { ... }
&lt;/code&gt;&lt;/pre&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-5：移除「被完全包住」的多餘-rect&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 5：移除「被完全包住」的多餘 rect&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;實務上你一定會遇到這種情況：同一格分鏡，被抓出「一個大框 + 一個小框」。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這時不需要聰明演算法，只要幾何判斷：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;isFullyOverlapped&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;small, large&lt;/span&gt;) &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; (
    x1 &amp;gt;= x2 &amp;amp;&amp;amp;
    y1 &amp;gt;= y2 &amp;amp;&amp;amp;
    x1 + w1 &amp;lt;= x2 + w2 &amp;amp;&amp;amp;
    y1 + h1 &amp;lt;= y2 + h2
  );
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;完全被包住的，直接丟掉。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZ_xzgNo3NbBtU6s18R06G1zK1ACOUXxeMF1VfVnOCMq8CAKjAE3f7gyeUHshg63MdH8cPrUhHXVkJzpI0RtpRhKQQS8KMhkhfJVg5vgPQpG8g8SsIb732Vjg9VDQm7NxsckwsarvDTQrBXm_UZ6-vlhBzwATw4vR66I3J9FWmEtrav4rckSLgAJHk3RT/s604/Figure_7.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;604&quot; data-original-width=&quot;436&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRZ_xzgNo3NbBtU6s18R06G1zK1ACOUXxeMF1VfVnOCMq8CAKjAE3f7gyeUHshg63MdH8cPrUhHXVkJzpI0RtpRhKQQS8KMhkhfJVg5vgPQpG8g8SsIb732Vjg9VDQm7NxsckwsarvDTQrBXm_UZ6-vlhBzwATw4vR66I3J9FWmEtrav4rckSLgAJHk3RT/w289-h400/Figure_7.png&quot; width=&quot;289&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;h2 id=&quot;step-6：排序-rect，讓它「像是在看漫畫」&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;Step 6：排序 rect，讓它「像是在看漫畫」&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這一步非常關鍵，也非常不完美，但夠用。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;rects.sort(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;a, b&lt;/span&gt;) =&amp;gt;&lt;/span&gt; a[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;] - b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;] || b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;] - a[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;]);&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;意思是：&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;先由上到下&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;同一排由右到左&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;⚠️ 這不一定符合所有漫畫的分鏡語法，但在手機瀑布流閱讀中：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 5px solid rgb(221, 221, 221); color: #555555; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px; padding: 0px 0px 0px 0.6em;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;「大致合理」比「絕對正確」重要得多&lt;/p&gt;&lt;/blockquote&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFSS865eGRFNDZycYymftivMh7Uh-GBRje392Xo_6O26r3iWZjYJpNrox4-SiRLD2SdymwV2YpAVIF_ea8bS3Hgi5qtAz9DhD6XvgB_dkQRMc5R2Ed-VmqPNSrJHmC96uFo8KHmRQpVTtYkZoE6EIKFryhPJwXXZP9rFe36kLBKc4p6pCUDNNYh1JODPrC/s597/Figure_8.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;597&quot; data-original-width=&quot;436&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFSS865eGRFNDZycYymftivMh7Uh-GBRje392Xo_6O26r3iWZjYJpNrox4-SiRLD2SdymwV2YpAVIF_ea8bS3Hgi5qtAz9DhD6XvgB_dkQRMc5R2Ed-VmqPNSrJHmC96uFo8KHmRQpVTtYkZoE6EIKFryhPJwXXZP9rFe36kLBKc4p6pCUDNNYh1JODPrC/w293-h400/Figure_8.png&quot; width=&quot;293&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;到這一步，我們已經有：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-language-override: normal; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;[
  [x, y, w, h],
  [x, y, w, h],
  ...
]&lt;/code&gt;&lt;/pre&gt;&lt;blockquote style=&quot;border-left: 5px solid rgb(221, 221, 221); color: #555555; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px; padding: 0px 0px 0px 0.6em;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每一個 rect，本質上就是一個「閱讀單位」&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;現在可以拿來作顯示了。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNB9vaeoq7UApIc7xeEQuIp-dfH3d_atoOUUTjBBpnq9J2tHNAcB2PmzZGjxrEWp6iJcyb5V7WPd6DNiME6CUA9j6sRVZdwuLaR796MvDuQs6uxdP4dp73HemLn8w6d69LKKi-VXg5diFT986vY27sDvwjkSL2enL-ySw5iq6Y35ctTYAoNgssvM9ggLcx/s933/Figure_9.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;933&quot; data-original-width=&quot;227&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNB9vaeoq7UApIc7xeEQuIp-dfH3d_atoOUUTjBBpnq9J2tHNAcB2PmzZGjxrEWp6iJcyb5V7WPd6DNiME6CUA9j6sRVZdwuLaR796MvDuQs6uxdP4dp73HemLn8w6d69LKKi-VXg5diFT986vY27sDvwjkSL2enL-ySw5iq6Y35ctTYAoNgssvM9ggLcx/w98-h400/Figure_9.png&quot; width=&quot;98&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;全畫面 Canvas 的好處，如果你把每個 rect：&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;裁切成獨立圖片&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;或在 Canvas 中單獨 render&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;一個 rect = 一個 viewport&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;你會得到幾個好處：&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 天然支援瀑布流：使用者只需要滑，不需要縮放。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 對不同螢幕尺寸友善Canvas：可以等比縮放到全寬。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 分鏡順序錯一點也沒關係：因為使用者是「連續閱讀」，不是在解析作者構圖。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 非常適合手機：這點真的差很多。&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這套方法有一個很重要的前提：&lt;/p&gt;&lt;blockquote style=&quot;border-left: 5px solid rgb(221, 221, 221); color: #555555; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px; padding: 0px 0px 0px 0.6em;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;我們只試圖改善呈現方式。&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;所以它：&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;❌ 不用深度學習&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;❌ 不用標註資料&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;❌ 不追求 100% 正確分鏡語法&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 快&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 可解釋&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;✅ 前端即可跑&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;對很多產品來說，這其實是更好的工程解法。&lt;/p&gt;&lt;hr style=&quot;background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 4px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; height: 0px; margin: 15px 0px; padding: 0px;&quot; /&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;很多人一提到「漫畫分析」，就直覺想到 AI / Model / Training。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;但實際上，只要簡單的影像處理就能作到90分，讓手機看漫畫更舒服。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這就是低科技，窮人的 AI 應用 &amp;gt;&amp;lt;&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;(&lt;a href=&quot;https://smallworld.idv.tw/misc/mangacut/&quot; style=&quot;color: #4183c4; margin: 0px; padding: 0px; text-decoration-line: none;&quot;&gt;試試看&lt;/a&gt;)&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2026/02/ai.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYDOcFJjmeH_HXdAiLxI1QdsoiLvOx0iPHi8VRxlVKWJM4Xr1l-TJRoMa27VGpmZMZBxPMab4BjIbuS_3EQEwO5lvDufxS-5c6LJmwVPh66h8NEtkM78V1B_t1D7XDQjQZ7E5dJs-5aTjrCG1QbnNKl1NMdHuJC0VZ0AnK5vYzzKz0onEACB1yNJJcVWkp/s72-w304-h400-c/Figure_2.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-6883611381266620459</guid><pubDate>Mon, 20 Oct 2025 03:10:00 +0000</pubDate><atom:updated>2025-10-20T11:10:21.223+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Python的Package和Module</title><description>&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最近有時會使用Python作些簡單的後端或工具的開發，這對許多人來說可能很熟悉了，不過在此就讓我這個不熟的新手作些基本觀念的記錄。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在Python中，Package(包)和Module(模組)是用來管理程式碼的結構。&lt;/p&gt;&lt;h2 id=&quot;1-模組-module&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1. 模組 Module&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Module是包含Python程式碼的檔案，簡單來說就是一個.py的Source Code檔案，裡面可以包含函數、變數、類別等等。或者是一個己經編譯過的.pyc檔案也是一個Module。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下定義一個a.py的模組。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-python&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# a.py&lt;/span&gt;
a=&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在其它的Python程式碼檔案裡面可以使用import語句來使用a.py這個模組內定義的函數、變數、類別等等。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下測試引用a.py裡定義的a。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;D:\temp\test&amp;gt;python
Python 3.12.3 (tags/v3.12.3:f6650f9, Apr  9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;]
&amp;gt;&amp;gt;&amp;gt; import a
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;]
&amp;gt;&amp;gt;&amp;gt; a
&amp;lt;module &#39;a&#39; from &#39;D:\\temp\\test\\a.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; a.a
1
&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;注意：一個Module被import的時候，如果存在.pyc就會載入它。如果.py比較新就會先編譯成.pyc再載入。&lt;/code&gt;&lt;/p&gt;&lt;h1 id=&quot;2-包-package&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;2. 包 Package&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Package其實就是一個目錄，裡面可以包含多個.py也就是多個Module。前提是這個目錄裡面必須有一個&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;__init__.py&lt;/code&gt;檔案，這個目錄才會被Python視為一個Package。(不過Python3.3以後這個限制就不在了，&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;__init__.py&lt;/code&gt;變成可有可無，但如果要作Package初始化還是需要它。)&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;因為是目錄，所以也能夠作巢狀管理。如a.b.c，就是目錄[a]下面的目錄[b]下面的c模組。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;現在建立一個目錄[b]，在目錄[b]裡面建立一個c.py。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-python&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# b/c.py&lt;/span&gt;
c=&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;ccc&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;D:\temp\test&amp;gt;python
Python 3.12.3 (tags/v3.12.3:f6650f9, Apr  9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;]
&amp;gt;&amp;gt;&amp;gt; import b
&amp;gt;&amp;gt;&amp;gt; b
&amp;lt;module &#39;b&#39; (namespace) from [&#39;D:\\temp\\test\\b&#39;]&amp;gt;
&amp;gt;&amp;gt;&amp;gt; b.c
Traceback (most recent call last):
  File &quot;&amp;lt;stdin&amp;gt;&quot;, line 1, in &amp;lt;module&amp;gt;
AttributeError: module &#39;b&#39; has no attribute &#39;c&#39;
&amp;gt;&amp;gt;&amp;gt; import b.c
&amp;gt;&amp;gt;&amp;gt; b.c
&amp;lt;module &#39;b.c&#39; from &#39;D:\\temp\\test\\b\\c.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; b.c.c
&#39;ccc&#39;
&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;3-導入模組或包-import&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;3. 導入模組或包 import&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Python的import語句有幾種用法。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-python&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;#直接import Module a&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;import&lt;/span&gt; a

&lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;#import Package b裡面的Module c&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;import&lt;/span&gt; b.c

&lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;#從Package b裡面import Module c&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;from&lt;/span&gt; b &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;import&lt;/span&gt; c&lt;/code&gt;&lt;/pre&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;D:\temp\test&amp;gt;python
Python 3.12.3 (tags/v3.12.3:f6650f9, Apr  9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;]
&amp;gt;&amp;gt;&amp;gt; import a
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;]
&amp;gt;&amp;gt;&amp;gt; a
&amp;lt;module &#39;a&#39; from &#39;D:\\temp\\test\\a.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; import b.c
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;, &#39;b&#39;]
&amp;gt;&amp;gt;&amp;gt; b
&amp;lt;module &#39;b&#39; (namespace) from [&#39;D:\\temp\\test\\b&#39;]&amp;gt;
&amp;gt;&amp;gt;&amp;gt; b.c
&amp;lt;module &#39;b.c&#39; from &#39;D:\\temp\\test\\b\\c.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; from b import c
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
&amp;gt;&amp;gt;&amp;gt; c
&amp;lt;module &#39;b.c&#39; from &#39;D:\\temp\\test\\b\\c.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; c.c
&#39;ccc&#39;
&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;4-別名-as&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;4. 別名 as&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;import as的用法是在導入模組時給它一個別名，可以使程式碼更簡潔易讀。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下是常見的範例，用np或pd来替代numpy或pandas。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-python&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;import&lt;/span&gt; numpy &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; np                      &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# 導入 numpy 模組並給它起别名 np&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;import&lt;/span&gt; pandas &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;as&lt;/span&gt; pd                     &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;# 導入 pandas 模組並給它起别名 pd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;結合from import as可以替模組內的特定部份取別名。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下面的範例，from a import a as aaa用a裡面的a取了一個aaa的別名。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;D:\temp\test&amp;gt;python
Python 3.12.3 (tags/v3.12.3:f6650f9, Apr  9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)] on win32
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;]
&amp;gt;&amp;gt;&amp;gt; import a
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;]
&amp;gt;&amp;gt;&amp;gt; a
&amp;lt;module &#39;a&#39; from &#39;D:\\temp\\test\\a.py&#39;&amp;gt;
&amp;gt;&amp;gt;&amp;gt; a.a
1
&amp;gt;&amp;gt;&amp;gt; from a import a as aaa
&amp;gt;&amp;gt;&amp;gt; dir()
[&#39;__annotations__&#39;, &#39;__builtins__&#39;, &#39;__doc__&#39;, &#39;__loader__&#39;, &#39;__name__&#39;, &#39;__package__&#39;, &#39;__spec__&#39;, &#39;a&#39;, &#39;aaa&#39;]
&amp;gt;&amp;gt;&amp;gt; aaa
1
&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;</description><link>http://good-ed.blogspot.com/2025/10/pythonpackagemodule.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-8227799282574109063</guid><pubDate>Thu, 28 Aug 2025 14:28:00 +0000</pubDate><atom:updated>2025-09-28T14:56:38.227+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Browser</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">WebM</category><title>照片轉Pixel Art動畫影片 PixAnim</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjIchNc4Jdkduuew93J-UBKqAXuFpp2pbNeKa80fyLrnP9ZpAzNv-YYdIBptNA0yLXOB0-wz-XDmrzpK2-0CrSqizrnI8eDvHoHAHTTiJbveSbtt9pRrz4z5312_FVH9UjlXEMKuu8SbxyleymW_dzuW02JG_oDnPGRePeufQIcYYebbHNo3fUCeRJw3LlN&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;931&quot; data-original-width=&quot;794&quot; height=&quot;640&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjIchNc4Jdkduuew93J-UBKqAXuFpp2pbNeKa80fyLrnP9ZpAzNv-YYdIBptNA0yLXOB0-wz-XDmrzpK2-0CrSqizrnI8eDvHoHAHTTiJbveSbtt9pRrz4z5312_FVH9UjlXEMKuu8SbxyleymW_dzuW02JG_oDnPGRePeufQIcYYebbHNo3fUCeRJw3LlN=w547-h640&quot; width=&quot;547&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;[&lt;a href=&quot;https://smallworld.idv.tw/misc/pixanim/&quot; target=&quot;_blank&quot;&gt;試試&lt;/a&gt;]&lt;/p&gt;&lt;p&gt;某天突然想到，我也可以利用之前作過的&lt;a href=&quot;https://good-ed.blogspot.com/2021/12/emoji-paint.html&quot;&gt;繪文字填圖EmojiPaint&lt;/a&gt;的演算法，作一個簡單的像素風動畫，然後可以存成GIF或者影片方便分享。&lt;/p&gt;&lt;p&gt;EmojiPaint裡面己經有一個叫作pixelart的函式，可以把一個己經畫好圖的canvas的內容，轉成像素風格。每一個像素根據指定tile大小(cw*ch)，它的顏色就是這塊tile裡所有pixel的顏色平均值。這就是pixelart的原理，最簡單的作法。&lt;/p&gt;&lt;p&gt;現在，要作成動畫，只要從最大的tile開始，也就是整張圖的大小(縮放調整至400*400)，不斷的呼叫pixelart。作完後再把tile縮小一半，也就是200*200，再作一次pixelart。一直持續這個過程，直到tile為1*1之前停止，因為1*1太多點要畫了。&lt;/p&gt;&lt;p&gt;經過修改的pixelart，會先把此次所有tile都計算好顏色和位置，儲存在一個陣列。接著才是畫圖階段，一個一個把tile畫出來。但是tile愈小的時候，數量就愈多，畫一個tile的時間也要跟著縮短，才不會讓人覺得過程太過冗長。其實，除了隨著tile縮小，畫tile的時間跟著縮短之外。每一個draw處理中畫的tile數量也會跟著增加，這都是為了減少動畫過程太冗長，提高觀看的人的體驗。&lt;/p&gt;&lt;p&gt;底下是關鍵的pixelart和drawblock函式。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;pixelart&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;id, cw, ch&lt;/span&gt;) &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; imgData = ctx.getImageData(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, canvas.width, canvas.height);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; col = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;Math&lt;/span&gt;.floor(canvas.width / cw);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; row = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;Math&lt;/span&gt;.floor(canvas.height / ch);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; blocks = [];
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; col; i++) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; j &amp;lt; row; j++) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; x = cw * i;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; y = ch * j;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; rgb = calcRgbSum(imgData.data, x, y, cw, ch);
      blocks.push([x, y, rgb]);
    }
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; canvas2 = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;document&lt;/span&gt;.getElementById(id);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;var&lt;/span&gt; ctx2 = canvas2.getContext(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;2d&#39;&lt;/span&gt;);
  displayBlocks(ctx2, blocks, cw, ch);
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;displayBlock&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;ctx, blocks, index, cw, ch&lt;/span&gt;) &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (blocks.length &amp;lt;= index) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; b = blocks[index];
  ctx.fillStyle = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;rgb(&#39;&lt;/span&gt; + b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;,&#39;&lt;/span&gt; + b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;,&#39;&lt;/span&gt; + b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;] + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;)&#39;&lt;/span&gt;;
  ctx.fillRect(b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;], b[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;], cw, ch);
  progress += &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;;
  ctx.fillStyle = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;blue&#39;&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; px = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;Math&lt;/span&gt;.floor(canvas.width * (progress / total_progress));
  ctx.fillRect(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, canvas.height - &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, px, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再來是如何把動畫過程製作影片？&lt;/p&gt;&lt;p&gt;非常簡單！我們可以利用瀏覽器內建的MediaRecorder撘配canvas.captureStream就能作到把canvas的變化內容作為串流輸入一個錄製器，輸出成WebM格式的影片。&lt;/p&gt;&lt;p&gt;底下為主要的相關程式碼。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;startRecAnim&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;/span&gt;) &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; canvas2 = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;document&lt;/span&gt;.getElementById(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;canvas2&#39;&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; stream = canvas2.captureStream(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;25&lt;/span&gt;); &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 25 FPS&lt;/span&gt;
  recorder = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; MediaRecorder(stream);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;let&lt;/span&gt; chunks = [];
  recorder.ondataavailable = &lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;e&lt;/span&gt; =&amp;gt;&lt;/span&gt; chunks.push(e.data);
  recorder.onstop = &lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;e&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; blob = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; Blob(chunks, {&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;type&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;video/webm&quot;&lt;/span&gt;});
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; url = URL.createObjectURL(blob);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; a = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;document&lt;/span&gt;.createElement(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;a&#39;&lt;/span&gt;);
    a.href = url;
    a.download = getWebmFileName();
    a.click();
    recorder = &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;null&lt;/span&gt;;
  }
  recorder.start();
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;另外，錄製結束時，只要呼叫recorder.stop()即可停止，並觸發onstop事件。在此事件中，將錄製完成的影片存檔。&lt;/p&gt;&lt;p&gt;最後再利用AI作些畫面美化，就完成了。前後大概只花不到一天。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;iframe allowfullscreen=&quot;&quot; class=&quot;BLOG_video_class&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/GXr96ZXhZSc&quot; width=&quot;320&quot; youtube-src-id=&quot;GXr96ZXhZSc&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2025/08/pixel-art-pixanim.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjIchNc4Jdkduuew93J-UBKqAXuFpp2pbNeKa80fyLrnP9ZpAzNv-YYdIBptNA0yLXOB0-wz-XDmrzpK2-0CrSqizrnI8eDvHoHAHTTiJbveSbtt9pRrz4z5312_FVH9UjlXEMKuu8SbxyleymW_dzuW02JG_oDnPGRePeufQIcYYebbHNo3fUCeRJw3LlN=s72-w547-h640-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-8527332101106907464</guid><pubDate>Fri, 13 Jun 2025 10:56:00 +0000</pubDate><atom:updated>2025-06-13T20:36:17.709+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">API</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">LLM</category><category domain="http://www.blogger.com/atom/ns#">Ollama</category><title>生成小鎮1010 - 用 Ollama 製作一個在本機執行的生成式文字冒險小遊戲</title><description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDgJ57gGFqRLzQASlKh1E3YyS1QaBtAZQSNjpsnZJLtP9jPAn2BxPG7e8IGHS2jxOc2d6fkypuZv44AD3LWhpcIStcb0sjlX2nJwFCtsj9m276Olgz3wOcNYkWd-KzLgKnEyKobzHuf-NqoNgRkdeMtRvikZFv0JdDEXE5aSY0K1PgKMYnryw53bouyKx8/s1920/town1010.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1128&quot; data-original-width=&quot;1920&quot; height=&quot;376&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDgJ57gGFqRLzQASlKh1E3YyS1QaBtAZQSNjpsnZJLtP9jPAn2BxPG7e8IGHS2jxOc2d6fkypuZv44AD3LWhpcIStcb0sjlX2nJwFCtsj9m276Olgz3wOcNYkWd-KzLgKnEyKobzHuf-NqoNgRkdeMtRvikZFv0JdDEXE5aSY0K1PgKMYnryw53bouyKx8/w640-h376/town1010.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;生成小鎮 1010&lt;/code&gt;是一個利用在本機執行的大語言模型，動態的生成遊戲地圖及根據玩家互動生成故事劇情及任務內容的文字冒險小遊戲。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;完成環境建置後，就可以到&amp;nbsp;&lt;a href=&quot;https://ollama.com/&quot; style=&quot;color: #4183c4; margin: 0px; padding: 0px;&quot;&gt;Ollama 官網&lt;/a&gt;&amp;nbsp;下載模型，在本機開始測試遊戲。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;處理器(CPU) 13th Gen Intel(R) Core(TM) i5-13500H 2.60 GHz
記憶體(RAM) 40.0 GB
顯示卡 Intel(R) Iris(R) Xe Graphics 128 M
系統 Windows 11 家用版 24H2&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這是我的筆電規格。在我的筆電上跑&amp;nbsp;&lt;a href=&quot;https://ollama.com/library/gemma3&quot; style=&quot;color: #4183c4; margin: 0px; padding: 0px; text-decoration-line: none;&quot;&gt;gemma3:4b-it-q4_K_M&lt;/a&gt;&amp;nbsp;模型，勉強可以玩。如果你有更強的硬體，就能夠利用更大的模型，得到更好的遊戲內容體驗。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;gemma 是 Google 的開放的整合了視覺理解能力多模態大語言模型。4b: 是模型參數大小，表示 40 憶個參數。q4_K_M: 是一種減少模型大小和提高效率的技術，它涉及到將模型中的數值精度降低，並減少了對記憶體和計算資源的需求。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;你也可以根據自己的需要或喜好，選擇下載不同模型。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;[&lt;a href=&quot;https://github.com/cnyaw/town1010&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt;]&lt;/p&gt;&lt;h2 id=&quot;1-準備工作&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1. 準備工作&lt;/h2&gt;&lt;h3 id=&quot;11-什麼是-ollama&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.1 什麼是 Ollama&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Ollama 是一個可以在本機運行大型語言模型（LLM）如 LLaMA、Mistral、Gemma 等的開源工具。它的目的是讓開發者和使用者可以更輕鬆地在自己的電腦上執行和使用這些 AI 模型，而不需要依賴雲端服務。Ollama 的特點是：&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;本地運行模型&lt;/strong&gt;&amp;nbsp;你可以直接在 Windows、macOS 或 Linux 上下載並運行語言模型，無需連網使用 API。&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;簡單的 CLI 工具&lt;/strong&gt;&amp;nbsp;安裝後只需要輸入像 ollama run llama3 這樣的指令就可以開始對話。&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;支援多種模型&lt;/strong&gt;&amp;nbsp;包含 Meta 的 LLaMA、Mistral、Gemma、Deepseek 等模型，也可以自訂模型。&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;開發整合容易&lt;/strong&gt;&amp;nbsp;提供簡單的 API（RESTful），方便整合到你自己的應用程式、網頁或手機 App 中。&lt;/p&gt;&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;p style=&quot;line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;節省成本與提高隱私&lt;/strong&gt;&amp;nbsp;不用連接 OpenAI、Anthropic 或其他雲端 LLM，降低使用成本，也不會洩漏資料。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;12-安裝-ollama&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.2 安裝 Ollama&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;訪問&amp;nbsp;&lt;a href=&quot;https://ollama.com/&quot; style=&quot;color: #4183c4; margin: 0px; padding: 0px; text-decoration-line: none;&quot;&gt;Ollama 官網&lt;/a&gt;，根據你的作業系統作安裝。安裝完成後，您可以使用以下命令來驗證 Ollama 是否安裝成功：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;ollama --version&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;13-cli-基本操作&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3 CLI 基本操作&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Ollama 的 CLI 提供了一些基本操作，讓用戶能夠輕鬆管理模型。以下是一些常用的命令：&lt;/p&gt;&lt;h4 id=&quot;131-下載模型&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 0px; padding: 0px;&quot;&gt;1.3.1 下載模型&lt;/h4&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;ollama pull &amp;lt;model_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個命令會從 Ollama 的模型庫中下載指定的模型。&lt;/p&gt;&lt;h4 id=&quot;132-運行模型&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 0px; padding: 0px;&quot;&gt;1.3.2 運行模型&lt;/h4&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;ollama run &amp;lt;model_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;使用此命令可以啟動指定的模型並開始進行推理。&lt;/p&gt;&lt;h4 id=&quot;133-列出已安裝的模型&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 0px; padding: 0px;&quot;&gt;1.3.3 列出已安裝的模型&lt;/h4&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;ollama list&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;此命令會顯示您系統中已安裝的所有模型。&lt;/p&gt;&lt;h4 id=&quot;134-刪除模型&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 0px; padding: 0px;&quot;&gt;1.3.4 刪除模型&lt;/h4&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;ollama rm &amp;lt;model_name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;使用此命令可以刪除不再需要的模型。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;其餘的命令可以由 ollama help 得到。&lt;/p&gt;&lt;h2 id=&quot;2-串接-api-簡介&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2. 串接 API 簡介&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Ollama 提供了一個 RESTful API，讓開發者能夠輕鬆地與模型進行互動。以下是一些常用的 API 請求範例。&lt;/p&gt;&lt;h3 id=&quot;21-獲取版本&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;2.1 獲取版本&lt;/h3&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;curl http://localhost:11434/api/version&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個請求將返回 API 的版本號，幫助您確認正在使用的 Ollama 版本。這個請求也可以用來確認本機上的 Ollama 正確安裝並在執行中。&lt;/p&gt;&lt;h2 id=&quot;22-生成聊天（串流）&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.2 生成聊天（串流）&lt;/h2&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;curl http://localhost:11434/api/chat -d &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;{
  &quot;model&quot;: &quot;llama3.2&quot;,
  &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;why is the sky blue?&quot;
    }
  ]
}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個請求將使用指定的模型生成對於提示 &quot;Why is the sky blue?&quot; 的回應，並以串流的方式返回結果。沒有特別指定的話，串流模式是預設模式。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;串流和非串流的差別是串流模式會把模型生成的內容逐步輸出給你，就像我們在網頁或 APP 上使用 ChatGPT 時，它的回答是逐字逐句跳出來的，這有助於提高使用者體驗。而不必像非串流模式要等待較長時間，等到全部結果生成後再一次整個跳出來。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;我們在遊戲中生成對話內容時，會使用串流模式。&lt;/p&gt;&lt;h2 id=&quot;23-生成聊天（非串流）&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.3 生成聊天（非串流）&lt;/h2&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;curl http://localhost:11434/api/chat -d &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;{
  &quot;model&quot;: &quot;llama3.2&quot;,
  &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;why is the sky blue?&quot;
    }
  ],
  &quot;stream&quot;: false
}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個請求將返回完整的生成結果，而不是逐步輸出。我們在遊戲中生成初始化地圖時，會使用非串流模式。&lt;/p&gt;&lt;h2 id=&quot;24-生成有前後文的聊天&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.4 生成有前後文的聊天&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;你可以將多輪的歷史聊天訊息一起輸入，產生帶有前後文的聊天訊息。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;curl http://localhost:11434/api/chat -d &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;{
  &quot;model&quot;: &quot;llama3.2&quot;,
  &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;why is the sky blue?&quot;
    },
    {
      &quot;role&quot;: &quot;assistant&quot;,
      &quot;content&quot;: &quot;due to rayleigh scattering.&quot;
    },
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;how is that different than mie scattering?&quot;
    }
  ]
}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;後面我們會利用這個功能，把遊戲歷史記錄餵給 AI 作為輸入資料。&lt;/p&gt;&lt;h2 id=&quot;25-生成結構化輸出&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.5 生成結構化輸出&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;為了有效控制模型的輸出資料格式，便於讓我們可以在程式裡面作後續的串接和處理，有必要控制生成資料的結構。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;我們在網頁或 APP 上使用 ChatGPT 時，如果只靠提示來指令模型生成結構化資料的話，通常結果是不能保證的。而如果模型最後生出不符合我們需要的格式的資料的話，最終程式就會出錯。好在我們現在是直接串接 API，可以用更直接的方式控制輸出格式。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下需要生成結構化的輸出，可以使用以下命令：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-bash&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;curl -X POST http://localhost:11434/api/chat -H &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Content-Type: application/json&quot;&lt;/span&gt; -d &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;{
  &quot;model&quot;: &quot;llama3.1&quot;,
  &quot;messages&quot;: [
    {
      &quot;role&quot;: &quot;user&quot;,
      &quot;content&quot;: &quot;Ollama is 22 years old and busy saving the world. Return a JSON object with the age and availability.&quot;
    }
  ],
  &quot;stream&quot;: false,
  &quot;format&quot;: {
    &quot;type&quot;: &quot;object&quot;,
    &quot;properties&quot;: {
      &quot;age&quot;: {
        &quot;type&quot;: &quot;integer&quot;
      },
      &quot;available&quot;: {
        &quot;type&quot;: &quot;boolean&quot;
      }
    },
    &quot;required&quot;: [
      &quot;age&quot;,
      &quot;available&quot;
    ]
  },
  &quot;options&quot;: {
    &quot;temperature&quot;: 0
  }
}&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個請求將生成一個包含年齡和可用性狀態的 JSON 物件，並確保返回的結果符合指定的結構。&lt;/p&gt;&lt;h1 id=&quot;3-關於角色-role-的定位及作用&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;3. 關於角色 role 的定位及作用&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在串接 API 時，&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;role&lt;/code&gt;&amp;nbsp;指的是訊息在對話中扮演的角色，它決定了 AI 如何理解並回應你的提示。 理解&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;role&lt;/code&gt;&amp;nbsp;的定位和作用對於構建有效的對話至關重要。&lt;/p&gt;&lt;h2 id=&quot;31-system-系統角色&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.1 System (系統角色)&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;System&lt;/code&gt;&amp;nbsp;角色是整個對話的起始點，定義了 AI 的行為、風格、知識範圍和任務目標。 你可以把它看作是「指令稿」。&lt;/p&gt;&lt;h3 id=&quot;311-作用&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.1.1 作用&lt;/h3&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;設定 AI 的行為:&lt;/strong&gt;&amp;nbsp;你可以在&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;System&lt;/code&gt;&amp;nbsp;角色中明確告知 AI 要扮演的角色，例如「你是一個友善的客戶服務代表」、「你是一個專業的編程助手」、「你是一個精通歷史的老師」。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;設定 AI 的風格:&lt;/strong&gt;&amp;nbsp;你可以規定 AI 的回答應該是正式的、非正式的、幽默的、簡潔的等等。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;設定知識範圍:&lt;/strong&gt;&amp;nbsp;你可以限制 AI 的知識範圍，例如「你只知道 2021 年之前的資訊」、「你只知道關於 Python 程式設計的知識」。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;設定任務目標:&lt;/strong&gt;&amp;nbsp;你可以明確告訴 AI 要完成的任務，例如「你的任務是幫我整理一份旅遊行程」、「你的任務是幫我撰寫一篇產品描述」。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;提示的初始設定:&lt;/strong&gt;&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;System&lt;/code&gt;&amp;nbsp;角色通常是整個對話的初始提示，它為後續的&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;和&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色奠定基礎。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;312-範例&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.1.2 範例&lt;/h3&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-json&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;{
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;system&quot;&lt;/span&gt;,
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;你是一個優秀的程式設計師，專注於 Python。請用簡潔明瞭的方式回答問題。&quot;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;32-user-使用者角色&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.2 User (使用者角色)&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;角色代表你的提問、指令或輸入。&lt;/p&gt;&lt;h3 id=&quot;321-作用&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.2.1 作用&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這是你與 AI 互動的直接方式。 你的&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;訊息會觸發 AI 生成&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色中的回應。&lt;/p&gt;&lt;h3 id=&quot;322-範例&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.2.2 範例&lt;/h3&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-json&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;{
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;user&quot;&lt;/span&gt;,
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;如何用 Python 讀取 CSV 檔案？&quot;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;33-assistant-助理角色&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.3 Assistant (助理角色)&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色代表 AI 生成的回應。&lt;/p&gt;&lt;h3 id=&quot;331-作用&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.3.1 作用&lt;/h3&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;AI 的回應:&lt;/strong&gt;&amp;nbsp;AI 會根據&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;System&lt;/code&gt;&amp;nbsp;和&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;角色中的訊息，生成&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色中的回應。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;strong style=&quot;margin: 0px; padding: 0px;&quot;&gt;對話流程:&lt;/strong&gt;&amp;nbsp;透過交替的&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;和&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色，AI 能夠模擬自然的對話流程。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;332-範例&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;3.3.2 範例&lt;/h3&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-json&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;{
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;,
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;你可以使用 `csv` 模組來讀取 CSV 檔案。以下是一個範例：\n\nimport csv\n\nwith open(&#39;your_file.csv&#39;, &#39;r&#39;) as file:\n    reader = csv.reader(file)\n    for row in reader:\n        print(row)\n&quot;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;34-要點總結&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.4 要點總結&lt;/h2&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;System&lt;/code&gt;&amp;nbsp;角色設定 AI 的背景和行為。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;User&lt;/code&gt;&amp;nbsp;角色代表你的輸入。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;Assistant&lt;/code&gt;&amp;nbsp;角色代表 AI 的輸出。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;正確使用&amp;nbsp;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;role&lt;/code&gt;&amp;nbsp;能夠更好地控制 AI 的行為，提高對話的品質。&lt;/li&gt;&lt;/ul&gt;&lt;h1 id=&quot;4-生成地圖&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;4. 生成地圖&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;現在我們要開始利用 AI 來生成遊戲地圖。基本概念是：我們要利用提示工程對 AI 下指令，讓它輸出我所期望的資料，也就是遊戲地圖。格式是一定要按照我的要求，至於內容則由 AI 自由發揮。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;要生成地圖可以使用 generate 指令也能用 chat 指令，這裡我們使用的是 chat 指令，指定了兩條訊息。一條訊息的角色是 System，用來作模型角色定位。另一條訊息角色是 User，用來指示模型怎麼生成地圖。&lt;/p&gt;&lt;h2 id=&quot;41-生成地圖的提示工程&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;4.1 生成地圖的提示工程&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最初的提示如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_system_prompt = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`你是一個專業的遊戲設計師,你的任務是設計一個10x10的遊戲村莊.`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_prompt =
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`生成一個遊戲小鎮初始的建築物列表.村莊包含如下資料:
- name 村莊名稱
- description 村莊的說明
- buildings 建物列表

村莊裡有如下的建物:
- 一家旅店
- 一家雜貨店
- 可有可無的武器防具店
- 2、3家民房

每一個建物包含如下屬性:
- id 一個唯一數字
- name 建物的名稱
- description 一個簡介說明
- emoji 代表此建物的emoji
- x 建物的水平座標(0&amp;lt;=x&amp;lt;10)
- y 建物的垂直座標(0&amp;lt;=y&amp;lt;10)
`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_messages = [
  {&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;system&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: create_town_system_prompt},
  {&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;user&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: create_town_prompt}
];&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;為了控制模型輸出資料格式，需要設定指令回應 format。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_format = {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;: {
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt;
        },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;: {
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt;
        },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;buildings&quot;&lt;/span&gt;: {
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;array&quot;&lt;/span&gt;,
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;building&quot;&lt;/span&gt;: {
                &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
                &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;id&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; },
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;emoji&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;x&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; },
                    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;y&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; }
                },
                &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;id&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;emoji&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;x&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;y&quot;&lt;/span&gt;]
            }
        }
    },
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;buildings&quot;&lt;/span&gt;]
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後再整個串接起來，就可以生出地圖來。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; input_data = {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;: model,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;messages&quot;&lt;/span&gt;: create_town_messages,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;format&quot;&lt;/span&gt;: create_town_format,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;stream&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;
};

fetch(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`&lt;span class=&quot;hljs-subst&quot; style=&quot;color: #333333; margin: 0px; padding: 0px;&quot;&gt;${api_base}&lt;/span&gt;/api/chat`&lt;/span&gt;, {
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;method&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;POST&#39;&lt;/span&gt;,
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;headers&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;application/json&#39;&lt;/span&gt; },
  &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;body&lt;/span&gt;: &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;JSON&lt;/span&gt;.stringify(input_data)
})
.then(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;response&lt;/span&gt; =&amp;gt;&lt;/span&gt; response.json())
.then(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Draw village.&lt;/span&gt;
})
.catch(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;error&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Handle error.&lt;/span&gt;
});&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;注意這裡不用串流模式，所以 fetch 會等到模型一次把完整的資料傳來。得到的其中一個地圖資料如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; villageData = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`{
  &quot;name&quot;: &quot;橡木谷村 (Oakwood Hollow)&quot;,
  &quot;description&quot;: &quot;橡木谷村是位於繁茂森林邊緣的一個寧靜村莊，居民以農業和簡單的生活為生。在這裡，你可以品嚐到新鮮的農產品，感受淳樸的民風，但也要小心潛伏在森林中的危險。&quot;,
  &quot;buildings&quot;: [
    {
      &quot;id&quot;: 1,
      &quot;name&quot;: &quot;橡木旅店 (The Oakwood Inn)&quot;,
      &quot;description&quot;: &quot;村莊唯一的旅店，提供舒適的客房和美味的食物。老闆娘艾米莉亞是一位熱情好客的女士。&quot;,
      &quot;emoji&quot;: &quot;🏠&quot;,
      &quot;x&quot;: 2,
      &quot;y&quot;: 5
    },
    {
      &quot;id&quot;: 2,
      &quot;name&quot;: &quot;好運雜貨店 (Lucky&#39;s General Goods)&quot;,
      &quot;description&quot;: &quot;村莊的雜貨店，出售各種必需品和一些稀有物品。老闆老約翰知道很多關於森林的故事。&quot;,
      &quot;emoji&quot;: &quot;🛒&quot;,
      &quot;x&quot;: 7,
      &quot;y&quot;: 2
    },
    {
      &quot;id&quot;: 3,
      &quot;name&quot;: &quot;鐵匠鋪 (Blacksmith&#39;s Forge)&quot;,
      &quot;description&quot;: &quot;村裡的鐵匠巴克正在努力打造武器和防具，但資源匱乏，需要玩家協助。&quot;,
      &quot;emoji&quot;: &quot;🔨&quot;,
      &quot;x&quot;: 9,
      &quot;y&quot;: 7
    },
    {
      &quot;id&quot;: 4,
      &quot;name&quot;: &quot;民房 - 艾倫一家 (Allen&#39;s Home)&quot;,
      &quot;description&quot;: &quot;艾倫一家是橡木谷村的居民，以種植蔬菜維生。他們友善而勤勞。&quot;,
      &quot;emoji&quot;: &quot;🏡&quot;,
      &quot;x&quot;: 1,
      &quot;y&quot;: 1
    },
    {
      &quot;id&quot;: 5,
      &quot;name&quot;: &quot;民房 - 貝克一家 (Baker&#39;s Home)&quot;,
      &quot;description&quot;: &quot;貝克一家以烘焙美味的麵包和糕點而聞名。他們的香氣經常瀰漫在村莊的上空。&quot;,
      &quot;emoji&quot;: &quot;🏡&quot;,
      &quot;x&quot;: 4,
      &quot;y&quot;: 3
    },
    {
      &quot;id&quot;: 6,
      &quot;name&quot;: &quot;民房 - 蓋洛德一家 (Gallord&#39;s Home)&quot;,
      &quot;description&quot;: &quot;蓋洛德一家是一群木匠，擅長製作家具和工具。他們在村莊中十分受人尊敬。&quot;,
      &quot;emoji&quot;: &quot;🏡&quot;,
      &quot;x&quot;: 6,
      &quot;y&quot;: 8
    },
    {
      &quot;id&quot;: 7,
      &quot;name&quot;: &quot;民房 - 霍普金斯一家 (Hopkins&#39; Home)&quot;,
      &quot;description&quot;: &quot;霍普金斯一家是村裡唯一的奶酪製造者，他們的奶酪在周圍地區都非常有名。&quot;,
      &quot;emoji&quot;: &quot;🏡&quot;,
      &quot;x&quot;: 3,
      &quot;y&quot;: 8
    },
    {
      &quot;id&quot;: 8,
      &quot;name&quot;: &quot;民房 - 羅伯斯一家 (Roberts&#39; Home)&quot;,
      &quot;description&quot;: &quot;羅伯斯一家是新搬到村裡的一家人，似乎在隱瞞著什麼...&quot;,
      &quot;emoji&quot;: &quot;🏡&quot;,
      &quot;x&quot;: 8,
      &quot;y&quot;: 4
    }
  ]
}`&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;存起來後，就可以根據這個資料畫地圖了。&lt;/p&gt;&lt;h2 id=&quot;42-讓-ai-幫忙完善生成地圖的提示&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;4.2 讓 AI 幫忙完善生成地圖的提示&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;雖然第一版的提示己經可以生成地圖了，但是還有改進空間。怎麼改進？這種事情就讓 AI 來作。再加上一些手動微調，最後得到的結果如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_system_prompt = 
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`你是一位經驗豐富的遊戲世界設計師，專長於創建引人入勝的 2D 遊戲地圖。
你的任務是設計一個 10x10 的遊戲村莊，它是一個&quot;奇幻&quot;風格的村莊。
地圖應考慮地形的變化和視覺層次的變化，使玩家在探索時有新鮮感。`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_prompt = 
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`根據系統指示，生成一個 10x10 遊戲村莊的初始建築物列表。
村莊包含以下資料：

- **村莊名稱:** （例如：晨曦村莊）
- **村莊說明:** （簡要描述村莊的背景和特色）
- **建物列表:** 至少包含一家旅店、一家雜貨店、1-3 家民房和一個武器店等等。

請確保：
- 所有建物不得重疊。
- 民房應分散在村莊的不同區域。
- 武器店應靠近村莊的入口。
- 旅店和雜貨店應位於村莊的中心。

每個建物包含以下屬性：
- **id:** 一個唯一的數字 (從 1 開始)
- **name:** 建物的名稱
- **description:** 一個簡要的說明, 可能包含裡面人物的簡介
- **emoji:** 代表此建物的 emoji (例如: 🏠, ⚔️, 🍺, 🕳)
- **x:** 建物的水平座標 (0 &amp;lt;= x &amp;lt; 10)
- **y:** 建物的垂直座標 (0 &amp;lt;= y &amp;lt; 10)

請注意，部分建物可能直接建造在山或山洞中。

**請確保：**
- 所有建物不得重疊。
- 民房應分散在村莊的不同區域。
- 武器店應靠近村莊的入口。
- 旅店和雜貨店應位於村莊的中心。
`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; create_town_format = {
  &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
  &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;buildings&quot;&lt;/span&gt;: {
      &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;array&quot;&lt;/span&gt;,
      &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;items&quot;&lt;/span&gt;: {
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;id&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; },
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;emoji&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;x&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; },
          &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;y&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;integer&quot;&lt;/span&gt; }
        },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;id&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;emoji&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;x&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;y&quot;&lt;/span&gt;]
      }
    }
  },
  &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;description&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;buildings&quot;&lt;/span&gt;]
};&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這裡面有個重點，用到一個叫作 In-context 的學習方式。這是一種提示工程的方法，即在提示中加入足夠多的背景知識或任務描述，以便進行預測。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;通過提供上下文信息，模型可以更好地理解問題的內容，並生成更加合適的答案。這種方法能夠提高模型在特定任務上的表現，並減少誤差。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;Zero-shot：沒有給出任何範例參考，直接進行詢問。
user&amp;gt;翻譯以下文字成英文: 蘋果 =&amp;gt;

One-shot：提供一個範例。
user&amp;gt;翻譯以下文字成英文: 香蕉 =&amp;gt; banana, 蘋果 =&amp;gt;

Few-shot：提供多個範例。
user&amp;gt;翻譯以下文字成英文: 香蕉 =&amp;gt; banana, 橘子 =&amp;gt; orange, 蘋果 =&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;透過這種引導方式，我們可以在大型模型上獲得驚人的效果（小型模型則無法達到這種效果）。&lt;/p&gt;&lt;h1 id=&quot;5-遊戲互動&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;5. 遊戲互動&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;處理玩家和遊戲互動推進遊戲的基本概念是：當玩家點擊地圖上的某建物時，就產生一條&quot;拜訪某某某&quot;的聊天訊息，串接在遊戲互動的系統提示及前面己進行的遊戲歷史記錄之下，讓 AI 接著生成回應。&lt;/p&gt;&lt;h2 id=&quot;51-遊戲互動的提示工程&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.1 遊戲互動的提示工程&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;第一個版本的提示工程如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; game_system_prompt =
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`你是一個專業的遊戲設計師,你的任務是設計在一個10x10的遊戲村莊裡的遊戲劇情及任務:
- 你會根據遊戲歷史記錄動態創造新的劇情及任務
- 你會根據遊戲小鎮裡的風土人物創造合適的劇情及任務
`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; play_game_prompt = 
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`遊戲進行方式是:
- user要求跟某人對話,你產生對應的結果.說明當前故事、劇情、任務或提示user下一步該怎麼作,應該找誰.
- 如果user要求跟某人對話,此人是下一個正確的人則推進劇情,否則繼續下一個故事、劇情、任務或提示user下一步該怎麼作.
`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; play_game_format = {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;response&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; }
    },
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;name&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;response&quot;&lt;/span&gt;]
};

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;constructPlayGameInputData&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;npc&lt;/span&gt;) &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; play_game_messages = [
    {&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;system&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: game_system_prompt},
    {&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;: play_game_prompt}
  ];
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;: model,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;messages&quot;&lt;/span&gt;: play_game_messages.concat(game_history),
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;format&quot;&lt;/span&gt;: play_game_format,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;stream&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;};
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;點擊地圖上的建物時，呼叫 talkToNpc 就能根據目前遊戲狀態讓模型產生合適的回應推進遊戲。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;talkToNpc&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;npc&lt;/span&gt;) &lt;/span&gt;{
  appendHistoryItem({&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`talkToNpc:&lt;span class=&quot;hljs-subst&quot; style=&quot;color: #333333; margin: 0px; padding: 0px;&quot;&gt;${npc}&lt;/span&gt;`&lt;/span&gt;});
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; inputData = constructPlayGameInputData(npc);
  fetch(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`&lt;span class=&quot;hljs-subst&quot; style=&quot;color: #333333; margin: 0px; padding: 0px;&quot;&gt;${api_base}&lt;/span&gt;/api/chat`&lt;/span&gt;, {
    &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;method&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;POST&#39;&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;headers&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;application/json&#39;&lt;/span&gt; },
    &lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;body&lt;/span&gt;: &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;JSON&lt;/span&gt;.stringify(inputData)
  })
  .then(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;response&lt;/span&gt; =&amp;gt;&lt;/span&gt; response.json())
  .then(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;data&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
    appendHistoryItem({&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;assistant&#39;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;:data.message.content});
  })
  .catch(&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;error&lt;/span&gt; =&amp;gt;&lt;/span&gt; {
    &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Handle error.&lt;/span&gt;
  });
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;52-改良模型回應&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.2 改良模型回應&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;回應裡面應包含關於&quot;拜訪某某某&quot;所產生的反應結果，以及一組建議玩家的下一步行作或操作。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;第一步先把 talkToNpc 改為 performAction，預留為以後作為更通用的執行動作。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;performAction&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;action&lt;/span&gt;) &lt;/span&gt;{
  appendHistoryItem({&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;role&#39;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;user&#39;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;content&#39;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`Your action: &lt;span class=&quot;hljs-subst&quot; style=&quot;color: #333333; margin: 0px; padding: 0px;&quot;&gt;${action}&lt;/span&gt;`&lt;/span&gt;});
  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 以下同上面的 talkToNpc 內容.&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;遊戲互動的模型回傳格式改成如下，新增 next_actions。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; play_game_format = {
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;object&quot;&lt;/span&gt;,
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;properties&quot;&lt;/span&gt;: {
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;action&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;result&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; },
        &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;next_actions&quot;&lt;/span&gt;: {
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;array&quot;&lt;/span&gt;,
            &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;next_action&quot;&lt;/span&gt;: { &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;string&quot;&lt;/span&gt; }
        }
    },
    &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;required&quot;&lt;/span&gt;: [&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;action&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;result&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;next_actions&quot;&lt;/span&gt;]
}
};&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;next_actions 是一個陣列，所以模型可能傳回多個下一步操作。收到回應後，就能把 next_actions 作為一個選單選項都顯示出來，讓玩家作選擇。當玩家選取某一選項時，則呼叫 performAction 推進模型產生下一步回應。&lt;/p&gt;&lt;h2 id=&quot;53-處理串流回應提高使用者體驗&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.3 處理串流回應提高使用者體驗&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如果串 API 是為了作在背景執行的工具或服務，那麼就不必管使用者體驗的問題。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;但若作為一個有使用者介面的應用的背景服務，如果每次使用者下個指令，就要等待一段較長時間後整個結果才跳出來。跟每次下完指令後等待一段較短時間後，結果就不斷的一個一個跳出來。這兩種處理方式，帶給使用者的體驗就完全不同。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;所以接下來，我們要作的是把遊戲互動的回應改為串流模式，以增加使用者體驗。要作到這件事，有兩個地方要修改。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;第一個很簡單，把 constructPlayGameInputData 裡面的 &quot;stream&quot;: false 拿掉即可變為串流模式。第二個修改較麻煩，要修改 performAction 為可以處理串流回應。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;串流模式回傳的資料結果可能如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-json&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;gemma3:4b-it-q4_K_M&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;created_at&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;2025-06-13T01:01:46.2135619Z&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;message&quot;&lt;/span&gt;:{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Okay&quot;&lt;/span&gt;},&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;done&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;}
{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;gemma3:4b-it-q4_K_M&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;created_at&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;2025-06-13T01:01:46.3280286Z&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;message&quot;&lt;/span&gt;:{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;,&quot;&lt;/span&gt;},&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;done&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;}
{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;gemma3:4b-it-q4_K_M&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;created_at&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;2025-06-13T01:01:46.4407359Z&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;message&quot;&lt;/span&gt;:{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;role&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;assistant&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot; let&quot;&lt;/span&gt;},&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;done&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;}
{&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;model&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;gemma3:4b-it-q4_K_M&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&quot;create&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;他是由許多個小塊的回應組成，每一小塊回應都是一個 JSON 格式的資料，我要需要把裡面的 content 都抓出來組成一個大塊的完整資料。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每處理一小塊的 content 時，就可以同時把這一小塊的 content 顯示到畫面上，這樣就能讓使用者不斷的看到畫面變化，減少長時間等待的不適感。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; reader = response.body.getReader();
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; decoder = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;new&lt;/span&gt; TextDecoder();
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;let&lt;/span&gt; done = &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;let&lt;/span&gt; textChunk = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (!done) {

  ...

  textChunk += decoder.decode(value);

  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 假設各別的 JSON 物件是以 &#39;\n&#39; 分隔.&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; matches = textChunk.split(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;\n&#39;&lt;/span&gt;);

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;let&lt;/span&gt; part_content = &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;&#39;&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;let&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; matches.length; i++) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;try&lt;/span&gt; {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; json_response = &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;JSON&lt;/span&gt;.parse(matches[i]);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; this_content = json_response.message.content;
      part_content += this_content;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (json_response.done) {
        done = &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
      }
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;catch&lt;/span&gt; (error) {
      &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Handle error.&lt;/span&gt;
    }
  }

  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Output part_content.&lt;/span&gt;

  ...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;上面的處理作了一個假設，它假設回傳的許多個各別的 JSON 物件是以 &#39;\n&#39; 分隔開的。因為作了這個假設的處理比較簡單，目前這樣的處理是可以的。正確的作法是要解析 textChunk 並找出每一塊 JSON 物件來，才能保證未來不會出錯。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;另一個作法是，把整塊 textChunk 丟給模型去分塊，充分利用模型的文字解析能力。當然，這會有額外開銷。&lt;/p&gt;&lt;h2 id=&quot;54-讓-ai-幫忙完善遊戲互動的提示&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.4 讓 AI 幫忙完善遊戲互動的提示&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後一樣讓 AI 幫忙完善一下遊戲互動的提示。加上一些手動微調後的結果如下:&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin: 1em 0px; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-javascript&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; game_system_prompt =
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`你是一位經驗豐富的遊戲劇情設計師，專注於創建引人入勝的 2D 遊戲劇情。
你的任務是動態創造新的劇情及任務，確保劇情與歷史記錄和村莊資訊相符。
請注重劇情的可玩性和沉浸感。
`&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; play_game_prompt = 
&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;`遊戲進行方式是:
- User 要求與某人對話。
- 你必須根據當前的遊戲歷史、村莊資訊和對話目標，產生合適的回應。
- 回應內容應包含當前故事、劇情、任務或提示 User 下一步該怎麼作，應該找誰。
- 如果 User 要求與某人對話，且此人是推進劇情所必需，則推進劇情；否則，繼續設計新的故事、劇情、任務或提示 User 下一步該怎麼作。

你的回應 JSON 格式應該如下：
{&quot;result&quot;: &quot;你的回應&quot;, &quot;next_actions&quot;: [&quot;下一個動作1&quot;, ...]}
`&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;6-總結&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;6. 總結&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這是一個利用大語言模型的生成能力作出來的小遊戲，還有很多改進空間。 例如:&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;完善建築物及 NPC 的屬性，加上&#39;角色定位&#39;、&#39;目前任務&#39;、&#39;關係屬性&#39;等等，會讓模型的生成結果有更微妙的不同。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;加入背包系統，可以讓遊戲更多互動變化。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;前面提到的 performAction 的串流處理的改進。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;經由這個小遊戲，對於怎麼串接大語言模型 API 來製作應用，相信對大家有一個更明確的概念。&lt;/p&gt;</description><link>http://good-ed.blogspot.com/2025/06/1010-ollama.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDgJ57gGFqRLzQASlKh1E3YyS1QaBtAZQSNjpsnZJLtP9jPAn2BxPG7e8IGHS2jxOc2d6fkypuZv44AD3LWhpcIStcb0sjlX2nJwFCtsj9m276Olgz3wOcNYkWd-KzLgKnEyKobzHuf-NqoNgRkdeMtRvikZFv0JdDEXE5aSY0K1PgKMYnryw53bouyKx8/s72-w640-h376-c/town1010.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-6166512450365046242</guid><pubDate>Sun, 09 Feb 2025 15:50:00 +0000</pubDate><atom:updated>2025-02-09T23:56:20.609+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">C/C++</category><category domain="http://www.blogger.com/atom/ns#">Debugger</category><category domain="http://www.blogger.com/atom/ns#">Win32</category><category domain="http://www.blogger.com/atom/ns#">Windows</category><title>從頭實作一個 WIN32 Source Level 除錯器</title><description>&lt;p&gt;&lt;a href=&quot;https://good-ed.blogspot.com/2011/11/how-to-debugger-1.html&quot;&gt;很久以前&lt;/a&gt;寫過一篇關於debugger的文，但只起個頭就沒有繼續了，現在才把這件事再拿起來作。&lt;/p&gt;&lt;p&gt;&amp;lt;&lt;a href=&quot;https://github.com/cnyaw/mydbg&quot;&gt;GitHub&lt;/a&gt;&amp;gt;&lt;/p&gt;&lt;h1 id=&quot;從頭實作一個-win32-source-level-除錯器&quot; style=&quot;border-bottom: 0px; border-image: initial; border-left: 0px; border-right: 0px; border-top: none; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 0px; padding: 0.25em 0px 0px;&quot;&gt;1. WIN32 除錯事件及迴圈&lt;/h1&gt;&lt;h2 id=&quot;11-最小的-win32-除錯器&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1.1 最小的 WIN32 除錯器&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Windows 提供 WIN32 API 支援除錯器 (Debugger) 的實作，以下是一個最小的 WIN32 環境底下的除錯器。主要分為兩個部份。一、啟動被除錯的程式 (Debuggee)，二、除錯事件迴圈 (Debug Event Loop)。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;#&lt;span class=&quot;hljs-meta-keyword&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-meta-string&quot; style=&quot;color: #4d99bf; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  CreateProcess(..., DEBUG_ONLY_THIS_PROCESS ,...);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (WaitForDebugEvent(...)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXIT_PROCESS) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
    }
    ContinueDebugEvent(...);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以上幾行程式碼雖然不能作什麼事，但已經是一個最小的 WIN32 除錯器了。接下來我們會一步一步建立出一個 Source Level Debugger 的各個主要功能。&lt;/p&gt;&lt;h2 id=&quot;12-啟動被除錯的程式&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1.2 啟動被除錯的程式&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;使用 CreateProcess 啟動被除錯程式，被除錯程式會作為除錯器的子行程。當除錯器關閉時，被除錯程式的行程也會隨之終止。除錯器呼叫的 CreateProcess 必須加上 DEBUG_ONLY_THIS_PROCESS 參數，才能對子行程除錯。加上 CREATE_NEW_CONSOLE 參數開啟新的文字視窗，以避免被除錯程式和除錯器的輸出混雜在一起。若被除錯程式或除錯器是有 GUI 的視窗程式，則此參數是否有加上則無影響。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;STARTUPINFO si = { &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; };
si.cb = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(si);

&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!CreateProcess(DEBUGEE_FILE_NAME, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, FALSE, DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &amp;amp;si, &amp;amp;g_piDbgee)) {
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;CreateProcess failed: %u\n&quot;&lt;/span&gt;, GetLastError());
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;-1&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;13-debug_event-結構&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1.3 DEBUG_EVENT 結構&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除錯事件 (Debug Event) 和除錯主迴圈 (Debug Main Loop) 依靠一個 DEBUG_EVENT 結構作中介，DEBUG_EVENT 結構定義在 WinBase.h，如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;hljs-class&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;struct&lt;/span&gt; _&lt;span class=&quot;hljs-title&quot; style=&quot;color: #445588; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DEBUG_EVENT&lt;/span&gt; {&lt;/span&gt;
  DWORD dwDebugEventCode;
  DWORD dwProcessId;
  DWORD dwThreadId;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;union&lt;/span&gt; {
    EXCEPTION_DEBUG_INFO Exception;
    CREATE_THREAD_DEBUG_INFO CreateThread;
    CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
    EXIT_THREAD_DEBUG_INFO ExitThread;
    EXIT_PROCESS_DEBUG_INFO ExitProcess;
    LOAD_DLL_DEBUG_INFO LoadDll;
    UNLOAD_DLL_DEBUG_INFO UnloadDll;
    OUTPUT_DEBUG_STRING_INFO DebugString;
    RIP_INFO RipInfo;
  } u;
} DEBUG_EVENT&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;根據 DEBUG_EVENT 結構的 dwDebugEventCode 欄位的不同值，再對應 union 結構 u 裡的相應子結構可得到更詳盡的事件訊息。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;dwDebugEventCode 欄位的可能值如下：&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CREATE_PROCESS_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;被除程式行程建立時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CREATE_THREAD_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;新建一執行緒時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;異常發生時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXIT_PROCESS_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;被除錯程式行程結束時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXIT_THREAD_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;執行緒結束時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;LOAD_DLL_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;載入一DLL時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;OUTPUT_DEBUG_STRING_EVENT&lt;/code&gt;&amp;nbsp;呼叫 OutputDebugString 輸出除錯訊息時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;RIP_EVENT&lt;/code&gt;&amp;nbsp;系統發生錯誤時。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;UNLOAD_DLL_DEBUG_EVENT&lt;/code&gt;&amp;nbsp;卸載一 DLL 時。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;131-create_process_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.1 CREATE_PROCESS_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;當被除錯程式以 CreateProcess 啟動後，即收到此事件。因為行程只會被建立一次，因此此事件也只會產生一次。這是行程建立後觸發的事件，因此可在此事件中作必要的初始化動作。比如載入模組除錯資訊、設定初始中斷點等。&lt;/p&gt;&lt;h3 id=&quot;132-exit_process_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.2 EXIT_PROCESS_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;當被除錯程式的行程結束時，即收到此事件。此事件對應 CREATE_PROCESS_DEBUG_EVENT 事件，且只會觸發一次。可在此事件中處理釋放資源等動作，比如釋放在除錯過程中所配置的資源等。&lt;/p&gt;&lt;h3 id=&quot;133-load_dll_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.3 LOAD_DLL_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;動態載入的 DLL，每載入一個 DLL 就會產生一個 LOAD_DLL_DEBUG_EVENT 事件。&lt;/p&gt;&lt;h3 id=&quot;134-unload_dll_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.4 UNLOAD_DLL_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;對應於 LOAD_DLL_DEBUG_EVENT 事件，動態載入的 DLL 卸載時產生一個 UNLOAD_DLL_DEBUG_EVENT 事件。&lt;/p&gt;&lt;h3 id=&quot;135-create_thread_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.5 CREATE_THREAD_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每創建一個執行緒時，會產生一個 CREATE_THREAD_DEBUG_EVENT 事件。除錯器以 CreateProcess 啟動創建一個被除錯程式子行程，並且由系統創建一個主執行緒，但並不會產生一個對應的 CREATE_THREAD_DEBUG_EVENT 事件。&lt;/p&gt;&lt;h3 id=&quot;136-exit_thread_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.6 EXIT_THREAD_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;對應於 CREATE_THREAD_DEBUG_EVENT 事件，執行緒結束時時會產生一個 EXIT_THREAD_DEBUG_EVENT 事件。&lt;/p&gt;&lt;h3 id=&quot;137-output_debug_string_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.7 OUTPUT_DEBUG_STRING_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在程式中使用 OutputDebugString 輸出的訊息會觸發此事件。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;有一點要注意的是，OutputDebugStringW 是 Windows 提供的寬字元版本，其內部實作會依照當前編碼環境將字串轉換為 ASCII 格式，並呼叫 OutputDebugStringA 進行處理。然而，這僅在某些環境或編碼設置下會發生，具體情況依賴系統的字串處理設定。所以底下我們在實作 OUTPUT_DEBUG_STRING_EVENT 事件處理時，都是以 ASCII 字串處理。如果除錯器想要取得 UNICODE 字串，除錯器事件迴圈必需以 WaitForDebugEventEx 來等待並處理除錯事件。&lt;/p&gt;&lt;h3 id=&quot;138-rip_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.8 RIP_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;系統發生錯誤時，產生此事件。&lt;/p&gt;&lt;h3 id=&quot;139-exception_debug_event&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;1.3.9 EXCEPTION_DEBUG_EVENT&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;程式發生異常時，會觸發此事件。中斷異常，也就是程式裡的中斷點 (Break Point) 就是以此事件處理。中斷異常有兩類，一、程式斷點造成的異常，二、CPU 單步 (Single Step) 執行造成的異常。&lt;/p&gt;&lt;h2 id=&quot;14-除錯事件迴圈&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;1.4 除錯事件迴圈&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除錯事件迴圈就好比是視窗訊息迴圈，是用來驅動除錯器核心功能。主要透過 WaitForDebugEvent 等待除錯事件發生的迴圈，事件發生時再依據 DEBUG_EVENT 結構的 dwDebugEventCode 欄位的值作分發處理。正常情況下，每處理完一個除錯事件後，再呼叫 ContinueDebugEvent 傳入 DBG_CONTINUE 參數表示己處理完畢此除錯事件，讓程式繼續執行，並等待下一個除錯事件的發生。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;DEBUG_EVENT debugEvent;
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (WaitForDebugEvent(&amp;amp;debugEvent, INFINITE)) {
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (DispatchDebugEvent(debugEvent)) {
    ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;2-dispatch-debug-event&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;2. Dispatch Debug Event&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是簡單的 DispatchDebugEvent 實作，依據 DEBUG_EVENT 結構的 dwDebugEventCode 欄位的值，分發到不同事件處理函式作進一步處理。此函數若回傳 false，則會終止當前事件處理並結束當前事件循環，但並不會直接結束整個除錯過程，除非程式內部有額外邏輯處理來停止整體除錯器的運行。否則會呼叫 ContinueDebugEvent 以 DBG_CONTINUE 參數，讓被除錯程式繼續執行，並等待下一個除錯事件。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DispatchDebugEvent&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; DEBUG_EVENT &amp;amp;debugEvent)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (debugEvent.dwDebugEventCode) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; CREATE_PROCESS_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnProcessCreated(debugEvent.u.CreateProcessInfo);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; CREATE_THREAD_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnThreadCreated(debugEvent.u.CreateThread);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; EXCEPTION_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnException(debugEvent.u.Exception);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; EXIT_PROCESS_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnProcessExited(debugEvent.u.ExitProcess);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; EXIT_THREAD_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnThreadExited(debugEvent.u.ExitThread);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; LOAD_DLL_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnDllLoaded(debugEvent.u.LoadDll);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; UNLOAD_DLL_DEBUG_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnDllUnloaded(debugEvent.u.UnloadDll);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; OUTPUT_DEBUG_STRING_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnOutputDebugString(debugEvent.u.DebugString);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; RIP_EVENT:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnRipEvent(debugEvent.u.RipInfo);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;default&lt;/span&gt;:
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Unknown debug event.\n&quot;&lt;/span&gt;);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下就主要幾個除錯事件作出處理器的骨架，後面會持續完善功能。&lt;/p&gt;&lt;h2 id=&quot;21-onprocesscreated&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.1 OnProcessCreated&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;被除錯程式行建立時觸發此事件。後面講到中斷時，會再此加入除錯資訊的相關初始化，以及建立初始軟體中斷。目前只把沒有使用到的 HANDLE 都關閉。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnProcessCreated&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; CREATE_PROCESS_DEBUG_INFO* pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;CREATE_PROCESS_DEBUG_EVENT\n&quot;&lt;/span&gt;);
  CloseHandle(pi-&amp;gt;hFile);
  CloseHandle(pi-&amp;gt;hThread);
  CloseHandle(pi-&amp;gt;hProcess);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;22-onprocessexited&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.2 OnProcessExited&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;被除錯程式行程結束時，關閉 CreateProcess 記錄的 HANDLE。OnProcessExited 回傳 false 的原因是，此回傳值一直往上層傳遞到達除錯事件迴圈時，會讓除錯事件迴圈跳出並最終結束除錯器的執行。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnProcessExited&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXIT_PROCESS_DEBUG_INFO*)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;EXIT_PROCESS_DEBUG_EVENT\n&quot;&lt;/span&gt;);
  CloseHandle(g_piDbgee.hThread);
  CloseHandle(g_piDbgee.hProcess);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;memset&lt;/span&gt;(&amp;amp;g_piDbgee, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(g_piDbgee));
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;23-onthreadcreated&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.3 OnThreadCreated&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;關閉沒有使用到的 HANDLE。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnThreadCreated&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; CREATE_THREAD_DEBUG_INFO* pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;CREATE_THREAD_DEBUG_EVENT\n&quot;&lt;/span&gt;);
  CloseHandle(pi-&amp;gt;hThread);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;24-ondllloaded&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.4 OnDllLoaded&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;此處只關閉沒有使用到的 HANDLE，之後會添加除錯資訊的載入。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnDllLoaded&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; LOAD_DLL_DEBUG_INFO* pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;LOAD_DLL_DEBUG_EVENT\n&quot;&lt;/span&gt;);
  CloseHandle(pi-&amp;gt;hFile);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;25-onoutputdebugstring&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;2.5 OnOutputDebugString&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;因為很簡單，在這裡直接實作 OnOutputDebugString 事件處理器，顯示 OutputDebugString 的輸入字串。因為除錯器行程是被除錯程式行程的父行程，所以可以合法的透過 ReadProcessMemory 從被除錯程式行程讀取放在記憶體中的 OutputDebugString 的字串資料。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnOutputDebugString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; OUTPUT_DEBUG_STRING_INFO* pi)&lt;/span&gt;
&lt;/span&gt;{
  BYTE* pBuffer = (BYTE*)&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;malloc&lt;/span&gt;(pi-&amp;gt;nDebugStringLength);
  ReadProcessMemory(g_piDbgee.hProcess, pi-&amp;gt;lpDebugStringData, pBuffer, pi-&amp;gt;nDebugStringLength, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;OUTPUT_DEBUG_STRING_EVENT: &#39;%s&#39;\n&quot;&lt;/span&gt;, pBuffer);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;free&lt;/span&gt;(pBuffer);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;3-使用者指令交互模式&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;3. 使用者指令交互模式&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;當被除錯程式執行過程中，遇到一個中斷點而停下來時，除錯器進入與使用者的指令交互模式，等待使用者輸入除錯指令。&lt;/p&gt;&lt;h2 id=&quot;31-debugger-event-loop&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.1 Debugger Event Loop&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;首先稍微重整一下程式，新增一個 DebugEventLoop。DebugEventLoop 是除錯事件迴圈的包裝。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DebugEventLoop&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  DEBUG_EVENT debugEvent;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (WaitForDebugEvent(&amp;amp;debugEvent, INFINITE)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (DispatchDebugEvent(debugEvent)) {
      ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;32-除錯器狀態機&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.2 除錯器狀態機&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;建立一個簡單的除錯器狀態機，用來表示當前除錯器狀態。底下定義 DEBUGGER_STATE：&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; DEBUGGER_STATE {
  DBGS_NONE = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;,
  DBGS_BREAK,
  DBGS_EXIT_PROCESS = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;100&lt;/span&gt;
};&lt;/code&gt;&lt;/pre&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;DBGS_BREAK&lt;/code&gt;&amp;nbsp;表示中斷狀態，可以接收使用者指令。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;DBGS_EXIT_PROCESS&lt;/code&gt;&amp;nbsp;OnProcessExited 事件發生時進入此狀態，跳出並結束除錯事件迴圈。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以後陸續添加其它狀態。&lt;/p&gt;&lt;h2 id=&quot;33-debugger-main-loop&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.3 Debugger Main Loop&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這個除錯器主迴圈很單純，當進入中斷模式時，允許使用者輸入指令作交互，例如顯示暫存器內容、檢視記憶體內容、設定軟體中斷或繼續執行等。如果是 DBGS_EXIT_PROCESS 狀態，則表示被除錯程式己結束，所以直接跳出並結束除錯器程式執行。其它的狀態都是進入除錯事件迴圈 DebugEventLoop，等待並處理除錯事件。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DebuggerMainLoop&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (g_dbgState) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; DBGS_BREAK:
        HandleUserCommand();
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; DBGS_EXIT_PROCESS:
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;default&lt;/span&gt;:
        DebugEventLoop();
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;34-handle-user-command&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.4 Handle User Command&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;處理使用者輸入，並執行輸入的指令。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;-&quot;&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; buff[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;256&lt;/span&gt;];
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!fgets(buff , &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(buff), &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;stdin&lt;/span&gt;)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;;
  }

  &lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(buff)&lt;/span&gt;&lt;/span&gt;;
  str.erase(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, str.find_first_not_of(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot; \t\r\n&quot;&lt;/span&gt;)); &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Trim space.&lt;/span&gt;
  str.erase(str.find_last_not_of(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot; \t\r\n&quot;&lt;/span&gt;) + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (str.empty()) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt;;
  }

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (str[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;]) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;g&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;G&#39;&lt;/span&gt;:
      Go();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;目前只簡單加一個繼續執行的 Go 的指令，以後再陸續添加其它指令。&lt;/p&gt;&lt;h2 id=&quot;35-go&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.5 Go&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Go 很簡單，就是將除錯器狀態回復為 DBGS_NONE，並且呼叫 ContinueDebugEvent 讓被除錯程式可以繼續往下執行，並等待下一個除錯事件發生。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;將除錯器狀態設為 DBGS_NONE 的原因是，這樣下一輪 DebuggerMainLoop 執行時，才能再進入除錯器事件迴圈，讓 DebugEventLoop 處理相關事件。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;Go&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  g_dbgState = DBGS_NONE;
  ContinueDebugEvent(g_debugEvent.dwProcessId, g_debugEvent.dwThreadId, DBG_CONTINUE);
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;36-onexception&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;3.6 OnException&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 OnException 裡判斷 ExceptionRecord.ExceptionCode 是否為一個 EXCEPTION_BREAKPOINT 造成的中斷，若是則進入 DBGS_BREAK 模式，等待使用者輸入指令。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除錯器狀態設為 DBGS_BREAK 並且回傳 false 的原因是，如此 DebugEventLoop 才能跳出，並在 DebuggerMainLoop 裡進入等待使用者輸入交互指令的循環。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;EXCEPTION_DEBUG_EVENT. Code: 0x%x, Addr: 0x%x &quot;&lt;/span&gt;, pi.ExceptionRecord.ExceptionCode, pi.ExceptionRecord.ExceptionAddress);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode) {
    g_dbgState = DBGS_BREAK;
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;4-測試用的被除錯程式&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;4. 測試用的被除錯程式&lt;/h1&gt;&lt;h2 id=&quot;41-測試程式&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;4.1 測試程式&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這是一個很簡單的用來測試用的被除錯程式，檔名叫作 test.c，是一個 WIN32 Console 程式。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;#&lt;span class=&quot;hljs-meta-keyword&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-meta-string&quot; style=&quot;color: #4d99bf; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;#&lt;span class=&quot;hljs-meta-keyword&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-meta-string&quot; style=&quot;color: #4d99bf; margin: 0px; padding: 0px;&quot;&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; a, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; b)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; c = a + b;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; c;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Hello world!\n&quot;&lt;/span&gt;);
  OutputDebugStringA(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;hello world!&quot;&lt;/span&gt;);
  __debugbreak();
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; sum = add(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;, sum);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;因為我們還沒有實作動態設置軟體中斷點的處理，這裡先使用 __debugbreak 的呼叫。等到實作了軟體中斷之後，就可以把這個 __debugbreak 拿掉。在使用者交互模式中，可以透過除錯器動態增減中斷點，這樣可以在程式執行時根據需要來控制程式的執行流程。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;__debugbreak 是 Visual Studio 提供的一個函數，用於在程式中插入中斷點。當執行到此函數時，會觸發中斷並暫停程式的執行。需要注意的是，這個方法主要在 Microsoft 編譯器中有效，其他編譯器可能會使用不同的方法來觸發斷點。除了以 __debugbreak 在程式內插入一個中斷點外，也能用內嵌組合語言 __asm {int 3} 的方式插入一個int 3，也就是 0xcc 的指令。&lt;/p&gt;&lt;h2 id=&quot;42-除錯測試程式&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;4.2 除錯測試程式&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改除錯器的 CreateProcess，直接寫死測試用被除錯程式的路徑檔名。以後功能更完善後，則可將要被除錯的程式作為參數導入除錯器。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;...
&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!CreateProcess(TEXT(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;D:\\testc\\bin\\Debug\\testc.exe&quot;&lt;/span&gt;), ...)) {
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;CreateProcess failed: %u\n&quot;&lt;/span&gt;, GetLastError());
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;-1&lt;/span&gt;;
}
...&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;43-執行除錯器測試&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;4.3 執行除錯器測試&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;重新編譯除錯器及測試程式後，執行除錯器，可以看到如下結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;CREATE_PROCESS_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
LOAD_DLL_DEBUG_EVENT
EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x77b157f8 (First chance)
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;g&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x406d1388, Addr: 0x76f99e14 (First chance)
OUTPUT_DEBUG_STRING_EVENT: &#39;hello world!&#39;
EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d7c (First chance)
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;g&lt;/span&gt;
EXIT_PROCESS_DEBUG_EVENT. Code: 0&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;第一個 EXCEPTION_DEBUG_EVENT 是 WIN32 自動替被除錯程式加上的中斷點。第二個 EXCEPTION_DEBUG_EVENT 是 OutputDebugString 內部實作產生的事件，緊接其後可看到 OUTPUT_DEBUG_STRING_EVENT 事件及其輸出。第三個 EXCEPTION_DEBUG_EVENT 才是我們測試程式裡加上的 __debugbreak 呼叫所產生的中斷點。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每次遇到一個 EXCEPTION_DEBUG_EVENT 中斷下來時，我們就按一下 &#39;g&#39; 讓程式繼續執行下去。&lt;/p&gt;&lt;h1 id=&quot;5-異常&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;5. 異常&lt;/h1&gt;&lt;h2 id=&quot;51-異常種類&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.1 異常種類&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;錯誤異常恢復執行時是從發生異常的那條指令繼續執行，而陷阱異常恢復執行時是從發生異常的那條指令的下一條指令繼續執行。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以下是 WinBase.h 中的定義。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_ACCESS_VIOLATION&lt;/code&gt;&amp;nbsp;0xC0000005&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_ARRAY_BOUNDS_EXCEEDED&lt;/code&gt;&amp;nbsp;0xC000008C&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_BREAKPOINT&lt;/code&gt;&amp;nbsp;0x80000003&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_DATATYPE_MISALIGNMENT&lt;/code&gt;&amp;nbsp;0x80000002&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_DENORMAL_OPERAND&lt;/code&gt;&amp;nbsp;0xC000008D&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_DIVIDE_BY_ZERO&lt;/code&gt;&amp;nbsp;0xC000008E&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_INEXACT_RESULT&lt;/code&gt;&amp;nbsp;0xC000008F&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_INVALID_OPERATION&lt;/code&gt;&amp;nbsp;0xC0000090&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_OVERFLOW&lt;/code&gt;&amp;nbsp;0xC0000091&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_STACK_CHECK&lt;/code&gt;&amp;nbsp;0xC0000092&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_FLT_UNDERFLOW&lt;/code&gt;&amp;nbsp;0xC0000093&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_ILLEGAL_INSTRUCTION&lt;/code&gt;&amp;nbsp;0xC000001D&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_IN_PAGE_ERROR&lt;/code&gt;&amp;nbsp;0xC0000006&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_INT_DIVIDE_BY_ZERO&lt;/code&gt;&amp;nbsp;0xC0000094&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_INT_OVERFLOW&lt;/code&gt;&amp;nbsp;0xC0000095&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_INVALID_DISPOSITION&lt;/code&gt;&amp;nbsp;0xC0000026&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_NONCONTINUABLE_EXCEPTION&lt;/code&gt;&amp;nbsp;0xC0000025&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_PRIV_INSTRUCTION&lt;/code&gt;&amp;nbsp;0xC0000096&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_SINGLE_STEP&lt;/code&gt;&amp;nbsp;0x80000004&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;EXCEPTION_STACK_OVERFLOW&lt;/code&gt;&amp;nbsp;0xC00000FD&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;前面處理的 EXCEPTION_DEBUG_EVENT 除錯事件，其實就是因為觸發了一個 EXCEPTION_BREAKPOINT 異常，以及之後實作單步執行等功能時的 EXCEPTION_SINGLE_STEP 異常。當然還有其它種類異常可能發生，但是除錯器主要關心的就是這二種。&lt;/p&gt;&lt;h2 id=&quot;52-異常的處理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.2 異常的處理&lt;/h2&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;程式發生異常時，被 Windows 捕獲進入內核態。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;Windows 檢查此程式是否正被除錯中，若是則發出一個 EXCEPTION_DEBUG_EVENT 事件給除錯器，否則到 4。這是除錯器第一次收到該事件 (First Chance)。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;除錯器收到 EXCEPTION_DEBUG_EVENT 事件，最後如果以 DBG_CONTINUE 參數呼叫 ContinueDebugEvent，表示除錯器己處理此異常，程式繼續執行。如果是以 DBG_EXCEPTION_NOT_HANDLED 參數呼叫 ContinueDebugEvent，表示沒有處理此異常。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;Windows 回到用戶態，尋找可處理該異常的處理器。如果找到了並處理完畢，則程式繼續執行，否則到 5。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;Windows 回到內核態，檢查此程式是否正被除錯中，若是再發出一個 EXCEPTION_DEBUG_EVENT 事件給除錯器，否則到 7。這是除錯器第二次收到該事件 (Second Chance)。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;除錯器收到 EXCEPTION_DEBUG_EVENT 事件，最後如果以 DBG_CONTINUE 參數呼叫 ContinueDebugEvent，表示除錯器己處理此異常，程式繼續執行。如果是以 DBG_EXCEPTION_NOT_HANDLED 參數呼叫 ContinueDebugEvent，表示沒有處理此異常。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;異常沒有被處理，程式以應用程式錯誤結束執行。&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;First Chance 例外是指程式首次遇到異常時，除錯器有機會介入進行處理。如果除錯器選擇不處理，則該異常會被視為 Second Chance 例外，並觸發進一步的錯誤處理或終止程式。&lt;/p&gt;&lt;h2 id=&quot;53-outputdebugstring&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;5.3 OutputDebugString&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;前面&#39;執行除錯器測試&#39;一節的執行結果中，總共看到三個 EXCEPTION_DEBUG_EVENT。第一個是 Windows 送給除錯器的第一個初始化 EXCEPTION_DEBUG_EVENT 事件，第三個是我們在測試程式中加上的 __debugbreak 所產生的 EXCEPTION_DEBUG_EVENT 事件。而第二個 EXCEPTION_DEBUG_EVENT 事件則是 OutputDebugString 底層利用異常機制來實作 OUTPUT_DEBUG_STRING_EVENT 事件所產生出來的。&lt;/p&gt;&lt;h1 id=&quot;6-除錯符號資訊&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;6. 除錯符號資訊&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除錯器在除錯程式時，要顯示程式中斷處的程式碼、顯示變數型別及內容值等功能及操作，都需要除錯符號資訊的支援才能作到。&lt;/p&gt;&lt;h2 id=&quot;61-pdb-格式&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;6.1 PDB 格式&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除錯符號資訊有很多種格式，Visual Studio 預設使用PDB格式。&lt;/p&gt;&lt;h2 id=&quot;62-使用除錯資訊&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;6.2 使用除錯資訊&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Windows 提供 DbgHelp (Debug Help Library) 及 DIA (Debug Interface Access) 用來讀取除錯資訊。DIA 是基於 COM 的 API，DbgHelp 則像是一般 WIN32 API 的形式。底下所有內容都是以 DbgHelp 的 API 的方式讀取除錯資訊。&lt;/p&gt;&lt;h2 id=&quot;63-載入除錯資訊&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;6.3 載入除錯資訊&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;每一個被除錯的程式行程都對應一個DbgHelp符號處理器，在使用前使用 SymInitialize 初始化。如下，修改前面定義的 OnProcessCreated 函數，添加載入行程模組的除錯資訊。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnProcessCreated&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; CREATE_PROCESS_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymInitialize(g_piDbgee.hProcess, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, FALSE)) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymInitialize ok.\n&quot;&lt;/span&gt;);
    DWORD64 moduleAddress = SymLoadModule64(g_piDbgee.hProcess, pi.hFile, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, (DWORD64)pi.lpBaseOfImage, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; != moduleAddress) {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymLoadModule64 0x%x ok.\n&quot;&lt;/span&gt;, pi.lpBaseOfImage);
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymLoadModule64 failed.\n&quot;&lt;/span&gt;);
    }
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymInitialize failed.\n&quot;&lt;/span&gt;);
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;SymInitialize 第一個參數 hProcess 是 CreateProcess 時儲存的被除錯程式行程的 HANDLE。第三個參數 fInvadeProcess 為 FALSE 時，表示 hProcess 不一定要是一個有效的 HANDLE，只要是能表示一個唯一的數即可。第二個參數 UserSearchPath 為 NULL，表示下面我們會自己以 SymLoadModule64 載入需要的模組除錯資訊。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 OnProcessCreated 中，SymInitialize 初始化後，即以 SymLoadModule64 載入行程除錯資訊。底下在 OnDllLoaded 中，再各別載入 DLL 模組的除錯資訊。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnDllLoaded&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; LOAD_DLL_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  DWORD64 moduleAddress = SymLoadModule64(g_piDbgee.hProcess, pi.hFile, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, (DWORD64)pi.lpBaseOfDll, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; != moduleAddress) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymLoadModule64 0x%0x ok.\n&quot;&lt;/span&gt;, pi.lpBaseOfDll);
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tSymLoadModule64 failed.\n&quot;&lt;/span&gt;);
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;7-顯示中斷點原始碼&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;7. 顯示中斷點原始碼&lt;/h1&gt;&lt;h2 id=&quot;71-以中斷點位址取得原始碼檔名及行號&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;7.1 以中斷點位址取得原始碼檔名及行號&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 OnException 中，如果異常是一個軟體中斷點 (EXCEPTION_BREAKPOINT) 或是單步執行中斷 (EXCEPTION_SINGLE_STEP)，則我們就嘗試以中斷點位址取得對應的原始碼檔名及行號。這樣每次程式中斷時，就能把中斷位置的程式碼顯示出來。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以中斷點位址取得原始碼檔名及行號是透過 SymGetLineFromAddr64 這個 API 作到。第一個參數是被除錯程式的行程 HANDLE，第二個參數是中斷點位址。第三個參數是徧移量，如果成功取得指定位址的原始碼檔名及行號，此欄位回傳此行程式碼從指定位址開始共佔多少 BYTE 指令。第四個參數是 IMAGEHLP_LINE64 結構，用來接收 API 回傳的資訊。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如果呼叫失敗，以 GetLastError 的回傳值用來判斷失敗原因。如果 GetLastError 回傳 126，表示目前模組的除錯資訊並沒有載入。如果 GetLastError 回傳 487，表示找不到指定的除錯資訊。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode || EXCEPTION_SINGLE_STEP == pi.ExceptionRecord.ExceptionCode) {
    IMAGEHLP_LINE64 lineInfo = { &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; };
    lineInfo.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(lineInfo);
    DWORD displacement = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymGetLineFromAddr64(g_piDbgee.hProcess, (DWORD64)pi.ExceptionRecord.ExceptionAddress, &amp;amp;displacement, &amp;amp;lineInfo)) {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot; at %s:%d\n&quot;&lt;/span&gt;, lineInfo.FileName, lineInfo.LineNumber);
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
      DWORD ec = GetLastError();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (ec) {
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;126&lt;/span&gt;:
          &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Debug info in current module has not loaded.\n&quot;&lt;/span&gt;);
          &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;487&lt;/span&gt;:
          &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;No debug info in current module.\n&quot;&lt;/span&gt;);
          &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;default&lt;/span&gt;:
          &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;SymGetLineFromAddr64 failed. LastError: %d\n&quot;&lt;/span&gt;, ec);
          &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
      }
    }
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;72-顯示中斷點前後幾行程式碼&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;7.2 顯示中斷點前後幾行程式碼&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;有了上一節以中斷點位址取得原始碼檔名及行號的資訊，就能夠把中斷點前後幾行的程式碼都顯示出來，增加除錯的便利性。每一行程式碼除了顯示原始碼文字外，再加上行號以及位址，便於後續要切換軟體中斷點之用。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d7c (First chance)
        EXCEPTION_BREAKPOINT.
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     __debugbreak();
0x443d7d *15     int sum = add(2, 3);
0x443d8c  16     printf(&quot;%d\n&quot;, sum);
0x443d9d  17     return 0;
0x443d9f  18 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;8-顯示暫存器狀態&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;8. 顯示暫存器狀態&lt;/h1&gt;&lt;h2 id=&quot;81-取得並顯示暫存器狀態&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;8.1 取得並顯示暫存器狀態&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;取得目前執行緒的暫存器的狀態是使用 GetThreadContext 這個 API，傳入的執行緒 HANDLE 是 CreateProcess 時儲存下來的。在使用 GetThreadContext 函數獲取執行緒的暫存器狀態時，請注意該執行緒必須處於暫停狀態 (例如被除錯器中斷)。若執行緒處於執行狀態，則無法獲取其暫存器狀態。為了正確使用此函數，需先確保執行緒已經停止執行。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;GetThreadContext 傳入的參數除了指定要讀取暫存器狀態的執行緒 HANDLE，第二個參數 CONTEXT 的 ContextFlags 欄位必須事先指定要讀取的暫存器類型。根據 winnt.h 的註釋內容，ContextFlags 有如下幾種定義在 WinNT.h 中的旗標。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_FULL&lt;/code&gt;&amp;nbsp;所有暫存器。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_CONTROL&lt;/code&gt;&amp;nbsp;SegSs, Rsp, SegCs, Rip, and EFlags。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_INTEGER&lt;/code&gt;&amp;nbsp;Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_SEGMENTS&lt;/code&gt;&amp;nbsp;SegDs, SegEs, SegFs, and SegGs。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_DEBUG_REGISTERS&lt;/code&gt;&amp;nbsp;Dr0-Dr3 and Dr6-Dr7。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;CONTEXT_MMX_REGISTERS&lt;/code&gt;&amp;nbsp;Mm0/St0-Mm7/St7 and Xmm0-Xmm15。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;DumpRegisters 實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DumpRegisters&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  CONTEXT ctx;
  ctx.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
  GetThreadContext(g_piDbgee.hThread, &amp;amp;ctx);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;EAX = 0x%08x, EBX = 0x%08x, ECX = 0x%08x, EDX = 0x%08x, ESI = 0x%08x, EDI = 0x%08x\n&quot;&lt;/span&gt;, ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx, ctx.Esi, ctx.Edi);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;EIP = 0x%08x, EBP = 0x%08x, ESP = 0x%08x, EFlags = 0x%08x\n&quot;&lt;/span&gt;, ctx.Eip, ctx.Ebp, ctx.Esp, ctx.EFlags);
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;82-修改-handleusercommand-支援-dump-registers&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;8.2 修改 HandleUserCommand 支援 Dump Registers&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;把 DumpRegisters 添加入 HandleUserCommand，修改如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;r&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;R&#39;&lt;/span&gt;:
      DumpRegisters();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;根據顯示的中斷點的原始程式碼，再配合顯示目前暫存器狀態，已經可以讓我們觀察中斷時的程式狀態。底下是一個測試的結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d7c (First chance)
        EXCEPTION_BREAKPOINT.
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     __debugbreak();
0x443d7d *15     int sum = add(2, 3);
0x443d8c  16     printf(&quot;%d\n&quot;, sum);
0x443d9d  17     return 0;
0x443d9f  18 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;r&lt;/span&gt;
EAX = 0x00000000, EBX = 0x00223000, ECX = 0xe4b5bfcd, EDX = 0x00000000, ESI = 0x004012c0, EDI = 0x004012c0
EIP = 0x00443d7d, EBP = 0x0019ff08, ESP = 0x0019ff04, EFlags = 0x00000246
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;9-step-into&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;9. Step Into&lt;/h1&gt;&lt;h2 id=&quot;91-step-into-原理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;9.1 Step Into 原理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Source Level Debugger 必備的三大程式追蹤功能中，Step Into 是最簡單的。實作 Step Into 並不需要擁有軟體中斷的功能，只需要用到目前為止我們所知道的知識及己實作的功能就夠了。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Step Info 就是從目前的原始程式碼行號執行到下一行號，如果目前這一行的程式碼是一個函式呼叫，則執行進入此函式內部。簡單講就是直接執行，直到目前的原始碼檔名或行號不同為止。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;整理如下。&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;把目前的原始碼檔名及行號記錄下來。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;開啟 CPU 單步執行旗標。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;繼續執行。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;觸發單步執行中斷 (EXCEPTION_SINGLE_STEP) 時，檢查目前原始碼檔名及行號是否和 1 不同。若是則結束 Step Into，等待使用者下一個指令，否則到 2。&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;因為每次單步執行中斷後，CPU 會自己清除單步執行旗標，所以才會每次跳到 2 再重開旗標，之後再繼續執行 Step Into 流程。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;StepInto&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  SaveCurrSourceLine();
  SetCpuSingleStepFlag();
  Continue();
  g_dbgState = DBGS_STEP_INTO;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;新增一個除錯器狀態 DBGS_STEP_INTO。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; DEBUGGER_STATE {
  DBGS_NONE = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;,
  DBGS_BREAK,
  DBGS_STEP_INTO,
  ...
};&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;92-在-onexception-中處理-step-into-單步執行&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;9.2 在 OnException 中處理 Step Into 單步執行&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改在 OnException 裡關於 EXCEPTION_SINGLE_STEP 的中斷情況。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_SINGLE_STEP == pi.ExceptionRecord.ExceptionCode &amp;amp;&amp;amp; DBGS_STEP_INTO == g_dbgState &amp;amp;&amp;amp; HandleStepIntoSingleStep()) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;HandleStepIntoSingleStep 實作也很簡單。如果目前的原始碼檔名或行號沒變化，就再作一次 Step Into。持續這個動作，直到目前的原始碼檔名或行號變化為止。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleStepIntoSingleStep&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; fn;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!IsCurrSourceLineChanged(fn, LineNumber)) {
    StepInto();
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;93-修改-handleusercommand-支援-step-into&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;9.3 修改 HandleUserCommand 支援 Step Into&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後修改 HandleUserCommand，加入 Step Into 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;t&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;T&#39;&lt;/span&gt;:
      StepInto();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;測試結果如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d7c (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:15
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     __debugbreak();
0x443d7d *15     int sum = add(2, 3);
0x443d8c  16     printf(&quot;%d\n&quot;, sum);
0x443d9d  17     return 0;
0x443d9f  18 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;t&lt;/span&gt;
No debug info in current module.
EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x443d40 (First chance)
        EXCEPTION_SINGLE_STEP. at d:\vs.net\testc2\main.cpp:5
0x443d40   1 #include &amp;lt;stdio.h&amp;gt;
0x443d40   2 #include &amp;lt;windows.h&amp;gt;
0x443d40   3
0x443d40   4 int add(int a, int b)
0x443d40 * 5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12     printf(&quot;Hello world!\n&quot;);
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;10-顯示記憶體內容&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;10. 顯示記憶體內容&lt;/h1&gt;&lt;h2 id=&quot;101-dump-memory&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;10.1 Dump Memory&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;顯示記憶體內容是將使用 ReadProcessMemeory 讀取到的被除錯程式的記錄體內容呈現出來，協助除錯程式。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DumpMemory&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; addr, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; count)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 略&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;102-修改-handleusercommand-支援-dump-memory&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;10.2 修改 HandleUserCommand 支援 Dump Memory&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改 HandleUserCommand，加入 Dump Memory 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;d&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;D&#39;&lt;/span&gt;:                 &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Dump memory.&lt;/span&gt;
      {
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; addr = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, count = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;128&lt;/span&gt;;
        &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str() + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%x %d&quot;&lt;/span&gt;, &amp;amp;addr, &amp;amp;count);
        DumpMemory(addr, count);
      }
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;測試結果如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;d 400000&lt;/span&gt;
00400000  4D 5A 90 00 03 00 00 00-04 00 00 00 FF FF 00 00  MZ..............
00400010  B8 00 00 00 00 00 00 00-40 00 00 00 00 00 00 00  ........@.......
00400020  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
00400030  00 00 00 00 00 00 00 00-00 00 00 00 D8 00 00 00  ................
00400040  0E 1F BA 0E 00 B4 09 CD-21 B8 01 4C CD 21 54 68  ........!..L.!Th
00400050  69 73 20 70 72 6F 67 72-61 6D 20 63 61 6E 6E 6F  is program canno
00400060  74 20 62 65 20 72 75 6E-20 69 6E 20 44 4F 53 20  t be run in DOS
00400070  6D 6F 64 65 2E 0D 0D 0A-24 00 00 00 00 00 00 00  mode....$.......&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;11-設置軟體中斷&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;11. 設置軟體中斷&lt;/h1&gt;&lt;h2 id=&quot;111-新增軟體中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.1 新增軟體中斷&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下定義一個軟體中斷結構，以及用來儲存所有軟體中斷的列表。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-class&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #445588; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;BREAK_POINT&lt;/span&gt;
{&lt;/span&gt;
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; fn;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber;                       &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 1-based.&lt;/span&gt;
  DWORD64 address;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; saveCode;
};

&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;vector&lt;/span&gt;&amp;lt;BREAK_POINT&amp;gt; g_bp;          &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Save all break points.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;前面在講測試程式時提到在程式裡呼叫 __debugbreak，也就是插入一個 0xcc，也就是插入一個軟體中斷 int 3。新增一個軟體中斷就是動態在一個指定原始碼檔案及行號的位置 (位址) 填入一個 0xcc。問題是如果直接在指定位址填入一個 0xcc 把原來的那個 BYTE 蓋掉，那麼當程式中斷下來執行完這條 0xcc 指令之後再繼續執行時，就有可能造成後續的程式全都產生嚴重錯誤。因為原來被蓋掉的那個 BYTE 也是一個需要被執行的指令或較長指令的一部份，少執行了這個 BYTE 就會發生問題。所以在寫入 0xcc 之前，要先把原來的那個 BYTE 存起來，以備後續恢復執行。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;新增一個軟體中斷是以指定的原始碼檔名加行號，內部透過 SymGetLineFromName64 取得此原始碼檔名加行號的位址，並從此位址把原指令 BYTE 備份起來後再寫入一個 0xcc 去替換原指令 BYTE，即完成一個軟體中斷的設置。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;AddBreakPoint&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;fn, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber)&lt;/span&gt;
&lt;/span&gt;{
  LONG displacement;
  IMAGEHLP_LINE64 li = { &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; };
  li.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(li);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymGetLineFromName64(g_piDbgee.hProcess, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, (PSTR)fn.c_str(), LineNumber, &amp;amp;displacement, &amp;amp;li)) {
    BREAK_POINT bp;
    bp.fn = fn;
    bp.LineNumber = LineNumber;
    bp.address = li.Address;
    ReadProcessMemory(g_piDbgee.hProcess, (LPVOID)li.Address, &amp;amp;bp.saveCode, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
    g_bp.push_back(bp);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; cc = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xcc&lt;/span&gt;;
    WriteProcessMemory(g_piDbgee.hProcess, (LPVOID)li.Address, &amp;amp;cc, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;); &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Write 0xcc to bp address.&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Add breakpoint at %s:%d(%x)\n&quot;&lt;/span&gt;, fn.c_str(), LineNumber, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)li.Address);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;112-移除軟體中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.2 移除軟體中斷&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;移除一個軟體中斷的動作只需和新增的動作相反，而且更簡單，只要把事先記錄的指令 BYTE 寫回原來的位址，再把此軟體中斷的記錄清除即可。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;RemoveBreakPoint&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;fn, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;size_t&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; g_bp.size(); i++) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT &amp;amp;bp = g_bp[i];
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (bp.LineNumber == LineNumber &amp;amp;&amp;amp; bp.fn == fn) {
      WriteProcessMemory(g_piDbgee.hProcess, (LPVOID)bp.address, &amp;amp;bp.saveCode, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;); &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Write back saved OP code.&lt;/span&gt;
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Remove breakpoint at %s:%d(%x)\n&quot;&lt;/span&gt;, fn.c_str(), LineNumber, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)bp.address);
      g_bp.erase(g_bp.begin() + i);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
    }
  }
 &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;113-exception_breakpoint-中斷處理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.3 EXCEPTION_BREAKPOINT 中斷處理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;軟體中斷 (int 3) 的處理分為兩部份。一、當 OnException 以 EXCEPTION_BREAKPOINT 中斷時的處理，二、當 OnException 以 EXCEPTION_SINGLE_STEP 中斷時的處理。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;當 OnException 以 EXCEPTION_BREAKPOINT 中斷時，表示 CPU 執行到一個 0xcc，也就是 int 3 指令。我們要先判斷這個軟體中斷是我們動態以上面的 AddBreakPoint 加入的，還是使用者在程式裡以 __debugbreak 或 __asm {int 3} 內嵌等方式插入的。如果是後者，我們就不作特別處理。如果是前者，也就是這個中斷是我們動態加入的，就必需要作額外的處理。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;整理如下。&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;首先要把事先記錄的指令 BYTE 寫回原位址。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;IP 要減 1。因為 CPU 執行了 0xcc 這條指令後 IP 就自動加 1 了，若要再執行 1 所寫回的原始指令 BYTE，IP 要退回。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;設定 CPU 單步執行旗標。這樣，下次單步執行中斷後，我們才有機會作第二部份的處理。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;繼續執行。&lt;/li&gt;&lt;/ol&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleSoftBreak&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT* bp)&lt;/span&gt;
&lt;/span&gt;{
  WriteProcessMemory(g_piDbgee.hProcess, (LPVOID)bp-&amp;gt;address, &amp;amp;bp-&amp;gt;saveCode, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  SetCurrIp(GetCurrIp() - &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;);
  SetCpuSingleStepFlag();

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;SetCurrIp 的實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SetCurrIp&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(DWORD64 ip)&lt;/span&gt;
&lt;/span&gt;{
  CONTEXT ctx;
  ctx.ContextFlags = CONTEXT_CONTROL;
  GetThreadContext(g_piDbgee.hThread, &amp;amp;ctx);
  ctx.Eip = ip;
  SetThreadContext(g_piDbgee.hThread, &amp;amp;ctx);
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;114-exception_single_step-中斷處理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.4 EXCEPTION_SINGLE_STEP 中斷處理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;單步執行中斷時，我們一樣要先判斷目前是否是上一步驟處理我們動態加入的軟體中斷後所觸發的單步執行，或者是因為 Step Into 或其它情況觸發的單步執行中斷。如果是後者，則不作額外的處理。如果是前者，也就是這個中斷是我們動態加入的，就必需要作額外的處理。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;處理其實很簡單，就是再把 0xcc 寫到軟體中斷位址。因為在上一步驟，事先記錄的指令 BYTE 的寫回去後已經執行過了。再把 0xcc 寫到軟體中斷位址一次，這樣當下次程式再執行到這此處時，才可以再中斷一次。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleSoftBreakSingleStep&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT* bp)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; cc = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xcc&lt;/span&gt;;
  WriteProcessMemory(g_piDbgee.hProcess, (LPVOID)bp-&amp;gt;address, &amp;amp;cc, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;115-修改-onexception-支援軟體中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.5 修改 OnException 支援軟體中斷&lt;/h2&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode || EXCEPTION_SINGLE_STEP == pi.ExceptionRecord.ExceptionCode) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode) {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tEXCEPTION_BREAKPOINT. &quot;&lt;/span&gt;);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp = FindBreakPoint((DWORD64)pi.ExceptionRecord.ExceptionAddress);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (bp &amp;amp;&amp;amp; HandleSoftBreak(bp)) {
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnBreakPoint();
      }
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;\tEXCEPTION_SINGLE_STEP. &quot;&lt;/span&gt;);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp = FindBreakPoint((DWORD64)pi.ExceptionRecord.ExceptionAddress);
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (bp) {
        HandleSoftBreakSingleStep(bp);
      }
    }
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; OnBreakPoint();
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;OnBreakPoint 是把顯示原始碼等操作的一個重整包裝。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnBreakPoint&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; fn;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  DWORD displacement = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (GetSourceLineByAddr(GetCurrIp(), fn, LineNumber, displacement)) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;at %s:%d\n&quot;&lt;/span&gt;, fn.c_str(), LineNumber);
    DisplaySourceLines(fn, LineNumber);
    g_dbgState = DBGS_BREAK;
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;116-修改-handleusercommand-支援軟體中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;11.6 修改 HandleUserCommand 支援軟體中斷&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改 HandleUserCommand，加入切換軟體中斷的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;b&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;B&#39;&lt;/span&gt;:                 &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Toggle break point.&lt;/span&gt;
      {
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; fn[MAX_PATH];
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; lineno = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;-1&lt;/span&gt;;
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %99s %d&quot;&lt;/span&gt;, key, fn, &amp;amp;addr)) {
          ToggleBreakPoint(fn, addr);
        } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %x&quot;&lt;/span&gt;, key, &amp;amp;addr)) {
          ToggleBreakPoint(addr);
        } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %99s&quot;&lt;/span&gt;, key, fn)) {
          ToggleBreakPoint(fn);
        }
      }
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這裡支援三種方式設置軟體中斷。一、以原始碼檔名及行號，二、以指定位址，三、以函數名稱。另外使用 ToggleBreakPoint 的方式切換軟體中斷設置，如果指定位置沒有設置軟體中斷就以 AddBreakPoint 新增一個，否則就以 RemoveBreakPoint 移除它。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;ToggleBreakPoint&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;fn, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (FindBreakPoint(fn, LineNumber)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; RemoveBreakPoint(fn, LineNumber);
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; AddBreakPoint(fn, LineNumber);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下為測試結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d60 (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:11
0x443d40   3
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60 *11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
0x443d71  13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;b 443d7c&lt;/span&gt;
Add breakpoint at d:\vs.net\testc2\main.cpp:14(443d7c)
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;g&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x406d1388, Addr: 0x76f99e14 (First chance)
OUTPUT_DEBUG_STRING_EVENT: &#39;hello world!&#39;
EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d7c (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:14
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
0x443d71  13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c *14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;b 443d7c&lt;/span&gt;
Remove breakpoint at d:\vs.net\testc2\main.cpp:14(443d7c)
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;12-程式啟動時在-main-中斷&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;12. 程式啟動時在 main 中斷&lt;/h1&gt;&lt;h2 id=&quot;121-程式啟動時在-main-中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;12.1 程式啟動時在 main 中斷&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;現在我們已經實作了可以隨時切換軟體中斷的功能，因此測試程式裡的 __debugbreak 可以移除了。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;但是現在又有個問題。如果把測試程式裡的 __debugbreak 拿掉後，程式一開始執行就會停不下來，直到程式結束。所以這裡要作個小修改，讓被除錯程式啟動時，自動斷在進入點 main。這樣我們就有機會在這個時候設置其它中斷點。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 Windows 之下的程式的進入點總共有四種名稱，分別是：&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;main&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;wmain&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;WinMain&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;wWinMain&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;ToggleBreakPointAtEntryPoint 以 SymFromName 一個一個檢查是否能找到符號，若是則在此符號的位址設置一個軟體中斷。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;ToggleBreakPointAtEntryPoint&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt;* names[] = {&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;main&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;wmain&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;WinMain&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;wWinMain&quot;&lt;/span&gt;};
  SYMBOL_INFO sym = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
  sym.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(sym);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;size_t&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(names)/&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(names[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;]); i++) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymFromName(g_piDbgee.hProcess, (LPSTR)names[i], &amp;amp;sym)) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; ToggleBreakPoint(sym.Address);
    }
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;122-修改-onprocesscreate-在程式進入點插入中斷&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;12.2 修改 OnProcessCreate 在程式進入點插入中斷&lt;/h2&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnProcessCreated&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; CREATE_PROCESS_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymInitialize(g_piDbgee.hProcess, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, FALSE)) {
    ...
    ToggleBreakPointAtEntryPoint();
    ...
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是執行結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;CREATE_PROCESS_DEBUG_EVENT
        SymInitialize ok.
        SymLoadModule64 0x400000 ok.
Add breakpoint at d:\vs.net\testc2\main.cpp:11(443d60)
LOAD_DLL_DEBUG_EVENT
        SymLoadModule64 0x77a00000 ok.
LOAD_DLL_DEBUG_EVENT
        SymLoadModule64 0x767d0000 ok.
LOAD_DLL_DEBUG_EVENT
        SymLoadModule64 0x76e40000 ok.
EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x77b157f8 (First chance)
        EXCEPTION_BREAKPOINT. No debug info in current module.
EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d60 (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:11
0x443d40   3
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60 *11 {
0x443d64  12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     int sum = add(2, 3);
0x443d8b  15     printf(&quot;%d\n&quot;, sum);
0x443d9c  16     return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;13-step-out&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;13. Step Out&lt;/h1&gt;&lt;h2 id=&quot;131-step-out-原理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;13.1 Step Out 原理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Step Out 可以結合軟體中斷和 Step Into 作出來。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;原理如下。&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;以當前 IP 找到目前所在 FUNCTION。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;設置一個暫時的軟體中斷在 FUNCTION 尾巴，也就是 RET 指令的位置。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;繼續執行。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;觸發 EXCEPTION_BREAKPOINT 中斷時，照原來的方式處理。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;移除暫時的軟體中斷。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;作一次 Step Into，執行到下一行。&lt;/li&gt;&lt;/ol&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;StepOut&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  SYMBOL_INFO si = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
  si.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(si);

  DWORD64 displacement = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!SymFromAddr(g_piDbgee.hProcess, GetCurrIp(), &amp;amp;displacement, &amp;amp;si)) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;StepOut: SymFromAddr failed. LastError %d\n&quot;&lt;/span&gt;, GetLastError());
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
  }

  g_tmpBpAddr = si.Address + si.Size - &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!AddTempBreakPoint(g_tmpBpAddr)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
  }

  Go();
  g_dbgState = DBGS_STEP_OUT;

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;注意這裡用一個變數 g_tmpBpAddr，把暫時的軟體中斷位址記錄下來，以便觸發暫時的軟體中斷並處理完畢後，再把它移除。&lt;/p&gt;&lt;h2 id=&quot;132-修改-onexception-支援-step-out&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;13.2 修改 OnException 支援 Step Out&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;如下修改，在開頭檢查是否是 DBGS_STEP_OUT 狀態，若是則以 HandleStepOut 處理。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp = FindBreakPoint((DWORD64)pi.ExceptionRecord.ExceptionAddress);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (DBGS_STEP_OUT == g_dbgState &amp;amp;&amp;amp; HandleStepOutBreak(bp)) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
    }
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;HandleStepOutBreak 的前半部如軟體中斷的處理相同，完成後再把暫時的軟體中斷移除，並作一次 Step Into。實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleStepOutBreak&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (bp &amp;amp;&amp;amp; HandleSoftBreak(bp)) {
    RemoveTempBreakPoint(g_tmpBpAddr);
    StepInto();
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;133-修改-handleusercommand-支援-step-out&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;13.3 修改 HandleUserCommand 支援 Step Out&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改 HandleUserCommand，加入 Step Out 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;o&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;O&#39;&lt;/span&gt;:
      StepOut();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;測試結果如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;t&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x443d64 (First chance)
        EXCEPTION_SINGLE_STEP. at d:\vs.net\testc2\main.cpp:12
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64 *12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     int sum = add(2, 3);
0x443d8b  15     printf(&quot;%d\n&quot;, sum);
0x443d9c  16     return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;t&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x401040 (First chance)
        EXCEPTION_SINGLE_STEP. at f:\rtm\vctools\crt_bld\self_x86\crt\src\printf.c:49
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;o&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x406d1388, Addr: 0x76f99e14 (First chance)
EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x443d6e (First chance)
        EXCEPTION_SINGLE_STEP. at d:\vs.net\testc2\main.cpp:12
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64 *12     printf(&quot;Hello world!\n&quot;);
0x443d71  13     OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14     int sum = add(2, 3);
0x443d8b  15     printf(&quot;%d\n&quot;, sum);
0x443d9c  16     return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;14-step-over&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;14. Step Over&lt;/h1&gt;&lt;h2 id=&quot;141-step-over-原理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;14.1 Step Over 原理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Step Over 一次執行一行程式碼，和 Step Into 很像，只在遇到一個函式呼叫時的處理不同。Step Into 遇到一個函式呼叫時進入函式執行，Step Over 遇到函式時不會進入執行，而是把函式當成一條語句執行過去，不管這一行的程式碼有多少個函式呼叫。這也是 Step Over 會比 Step Into 及 Step Out 稍微複雜的原因。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以下是 Step Over 的原理。&lt;/p&gt;&lt;ol style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;把目前的原始碼檔名及行號記錄下來。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;如果當前指令是一個函式呼叫，則在函式呼叫指令的最後插入一個暫時的軟體中斷，跳到 4。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;設定 CPU 單步執行旗標。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;繼續執行。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;觸發 EXCEPTION_BREAKPOINT 中斷時，照原來的方式處理。移除暫時的軟體中斷。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;觸發單步執行中斷 (EXCEPTION_SINGLE_STEP) 時，檢查目前原始碼檔名及行號是否和1不同。若是則結束 Step Over，等待使用者下一個指令。否則到 2。&lt;/li&gt;&lt;/ol&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;StepOver&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  SaveCurrSourceLine();
  DoStepOver();
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;DoStepOver 實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DoStepOver&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; Length = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;                       &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Length of the call instructions.&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (IsCallInstruction(GetCurrIp(), Length)) {
    g_tmpBpAddr = GetCurrIp() + Length;
    AddTempBreakPoint(g_tmpBpAddr);
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    SetCpuSingleStepFlag();
  }

  Continue();
  g_dbgState = DBGS_STEP_OVER;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;此處新增一個除錯器狀態 DBGS_STEP_OVER。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; DEBUGGER_STATE {
  ...
  DBGS_STEP_OUT,
  DBGS_STEP_OVER,
  ...
};&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;142-檢查-call-指令&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;14.2 檢查 CALL 指令&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;檢查指令是否為一個函式呼叫，就是在檢查是否為一個 CALL 指令。CALL 指令有很多種形式，我們把所有可能的呼叫形式都找出來建表。用笨方法只要一個一個比對檢查，就能判斷當前指令是否為一個函式呼叫。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;IsCallInstruction&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(DWORD64 addr, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &amp;amp;Length)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; CALL_INST[] = {
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x9A&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x00&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;7&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL FAR seg16:abs32&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xE8&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x00&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;5&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL rel32&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x10&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EAX]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x11&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ECX]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x12&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDX]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x13&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EBX]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x14&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [REG * SCALE + BASE]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x15&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [abs32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x16&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ESI]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x17&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDI]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x50&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EAX + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x51&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ECX + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x52&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDX + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x53&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EBX + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x54&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;4&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [REG * SCALE + BASE + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x55&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EBP + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x56&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ESI + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x57&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDI + off8]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x90&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EAX + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x91&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ECX + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x92&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDX + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x93&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EBX + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x94&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;7&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [REG * SCALE + BASE + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x95&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EBP + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x96&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [ESI + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0x97&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL dword ptr [EDI + off32]&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL EAX&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL ECX&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL EDX&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD3&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL EBX&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL ESP&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD5&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL EBP&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD6&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL ESI&lt;/span&gt;
    &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xFF&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0xD7&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// CALL EDI&lt;/span&gt;
  };

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; code[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;];
  ReadProcessMemory(g_piDbgee.hProcess, (LPVOID)addr, code, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(CALL_INST) / &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;; i++) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; OP1 = CALL_INST[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt; * i + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;];
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; OP2 = CALL_INST[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt; * i + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;];
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (OP1 == code[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;] &amp;amp;&amp;amp; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; == OP2 || OP2 == code[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;])) {
      Length = CALL_INST[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt; * i + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;];
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
    }
  }

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;143-修改-onexception-支援-step-over&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;14.3 修改 OnException 支援 Step Over&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Step Over 有用到暫時的軟體中斷及以單步執行中斷，所以必須針對兩種不同中斷處理。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;OnException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; EXCEPTION_DEBUG_INFO &amp;amp;pi)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_SINGLE_STEP == pi.ExceptionRecord.ExceptionCode) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (DBGS_STEP_OVER == g_dbgState &amp;amp;&amp;amp; HandleStepOverSingleStep()) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
    }
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (EXCEPTION_BREAKPOINT == pi.ExceptionRecord.ExceptionCode) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp = FindBreakPoint((DWORD64)pi.ExceptionRecord.ExceptionAddress);
    ...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (DBGS_STEP_OVER == g_dbgState &amp;amp;&amp;amp; HandleStepOverBreak(bp)) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
    }
  }
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;單步中斷的處理如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleStepOverSingleStep&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; fn;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!IsCurrSourceLineChanged(fn, LineNumber)) {
    DoStepOver();
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;                        &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Return true to continue.&lt;/span&gt;
  }

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;軟體中斷的處理如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleStepOverBreak&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; BREAK_POINT *bp)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (bp &amp;amp;&amp;amp; HandleSoftBreak(bp)) {
    RemoveTempBreakPoint(g_tmpBpAddr);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; HandleStepOverSingleStep();
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;144-修改-handleusercommand-支援-step-over&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;14.4 修改 HandleUserCommand 支援 Step Over&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後修改 HandleUserCommand，加入 Step Over 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;p&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;P&#39;&lt;/span&gt;:
      StepOver();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下為測試結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x443d64 (First chance)
        EXCEPTION_SINGLE_STEP. at d:\vs.net\testc2\main.cpp:12
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64 *12   printf(&quot;Hello world!\n&quot;);
0x443d71  13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;p&lt;/span&gt;
EXCEPTION_DEBUG_EVENT. Code: 0x406d1388, Addr: 0x76f99e14 (First chance)
EXCEPTION_DEBUG_EVENT. Code: 0x80000004, Addr: 0x443d71 (First chance)
        EXCEPTION_SINGLE_STEP. at d:\vs.net\testc2\main.cpp:13
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
0x443d71 *13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;15-set-next-statement&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;15. Set Next Statement&lt;/h1&gt;&lt;h2 id=&quot;151-set-next-statement-原理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;15.1 Set Next Statement 原理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;除了 Step Into、Step Out 及 Step Over 之外，Set Next Statement 也是一個好用的除錯指令。Set Next Statement 的使用方法和設置一個軟體中斷完全一樣，差別在於 Set Next Statement 是直接把程式 IP 強制設定為指定的位址。因此 Set Next Statement 是一個有副作用的指令，因為它直接跳過所有中間過程，直接把 IP 改成指定的位址。所以在使用時你必須知道你自己正在作什麼，因為強制改變 IP，很有可能造成程式狀態錯誤。雖然如此，有時候 Set Next Statement 還是一個有用的指令。因為可以讓你很暴力的改變程式流程，直接跳到你想要的地方繼續執行。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;Set Next Statement 的實作排常直接，找到目的位址後，以 SetCurrIp 把 IP 設為此位址即可。最後再把此位址的程式碼檔案行號顯示出來。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SetNextStatement&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(DWORD64 addr)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; fn;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  DWORD displacement = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (GetSourceLineByAddr(addr, fn, LineNumber, displacement)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; SetNextStatement(fn, LineNumber);
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SetNextStatement&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;func)&lt;/span&gt;
&lt;/span&gt;{
  SYMBOL_INFO sym = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
  sym.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(sym);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymFromName(g_piDbgee.hProcess, (LPSTR)func.c_str(), &amp;amp;sym)) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; SetNextStatement(sym.Address);
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SetNextStatement&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;fn, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; LineNumber)&lt;/span&gt;
&lt;/span&gt;{
  LONG displacement;
  IMAGEHLP_LINE64 li = { &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; };
  li.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(li);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymGetLineFromName64(g_piDbgee.hProcess, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, (PSTR)fn.c_str(), LineNumber, &amp;amp;displacement, &amp;amp;li)) {
    SetCurrIp(li.Address);
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;Set next statement at %s:%d(%x)\n&quot;&lt;/span&gt;, fn.c_str(), LineNumber, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)li.Address);
    DisplaySourceLines(fn, LineNumber);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;false&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;152-修改-handleusercommand-支援-set-next-statement&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;15.2 修改 HandleUserCommand 支援 Set Next Statement&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改 HandleUserCommand，加入 Set Next Statement 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;s&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;S&#39;&lt;/span&gt;:                 &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// Set next statement.&lt;/span&gt;
      {
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; key[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;];
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; fn[MAX_PATH];
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; addr;
        &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %99s %d&quot;&lt;/span&gt;, key, fn, &amp;amp;addr)) {
          SetNextStatement(fn, addr);
        } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %x&quot;&lt;/span&gt;, key, &amp;amp;addr)) {
          SetNextStatement(addr);
        } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sscanf&lt;/span&gt;(str.c_str(), &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%1s %99s&quot;&lt;/span&gt;, key, fn)) {
          SetNextStatement(fn);
        } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
          &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;invalid s cmd\n&quot;&lt;/span&gt;);
        }
      }
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是執行結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x443d60 (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:11
0x443d40   3
0x443d40   4 int add(int a, int b)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60 *11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
0x443d71  13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;s 443d71&lt;/span&gt;
Set next statement at d:\vs.net\testc2\main.cpp:13(443d71)
0x443d40   5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
0x443d71 *13   OutputDebugStringA(&quot;hello world!&quot;);
0x443d7c  14   int sum = add(2, 3);
0x443d8b  15   printf(&quot;%d\n&quot;, sum);
0x443d9c  16   return 0;
0x443d9e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;s d:\vs.net\testc2\main.cpp 5&lt;/span&gt;
Set next statement at d:\vs.net\testc2\main.cpp:5(443d40)
0x443d40   1 #include &amp;lt;stdio.h&amp;gt;
0x443d40   2 #include &amp;lt;windows.h&amp;gt;
0x443d40   3
0x443d40   4 int add(int a, int b)
0x443d40 * 5 {
0x443d44   6   int c = a + b;
0x443d4d   7   return c;
0x443d50   8 }
0x443d50   9
0x443d50  10 int main()
0x443d60  11 {
0x443d64  12   printf(&quot;Hello world!\n&quot;);
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;s &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;&lt;/span&gt;
Set next statement at f:\rtm\vctools\crt_bld\self_x86\crt\src\printf.c:49(401040)
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;16-顯示函式呼叫堆疊&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;16. 顯示函式呼叫堆疊&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;程式在斷點停下來時，若可以知道程式呼叫函式的執行過程，有時對於除錯過程會很有幫助。&lt;/p&gt;&lt;h2 id=&quot;161-堆疊&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;16.1 堆疊&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;堆疊 (Stack) 是一種先進後出 (First In Last Out) 的資料結構，在組合語言程式裡是用來作為資料暫存、函式的參數傳遞及作為函式區域變數等用途。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;主要有二個操作：&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;PUSH&lt;/code&gt;&amp;nbsp;ESP 減少，將資料壓入堆疊。若 ESP 為 0，當資料要寫入位址為 0 的記憶體時，會觸發異常。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;POP&lt;/code&gt;&amp;nbsp;將資料從堆疊彈出，ESP 增加。同樣的，若 ESP 為 0，執行 POP 指令會引發錯誤，導致程序異常結束。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是個簡單的例子。一開始堆疊為空，接著推入 2，再推入 3。接著彈出 3 至 EAX，再彈出 2 到 EBX。最後堆疊又回到空的狀態。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;+---+   初始狀態
|   |

+---+   PUSH 2
| 2 |

+---+   PUSH 3
| 2 |
| 3 |

+---+   POP EAX
| 2 |

+---+   POP EBX
|   |&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;162-函式呼叫的過程&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;16.2 函式呼叫的過程&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;要了解如何解析 Call Stacks，需先了解 C/C++ 的函式呼叫是怎麼作。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是一個簡單的 C 語言程式。定義一個簡單的函式 add，以呼叫 add 的語句。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; a, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; b)&lt;/span&gt; &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; c = a + b;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; c;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{
  ...
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; sum = add(&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;);
  ...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;呼叫 add 的程式碼初編譯成如下組合語言。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-asm&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;push 3
push 2
call _add
add esp, 8&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;可以看到 3 和 2 這兩個參數初推入堆疊，再以 CALL 指令呼叫 _add。請注意參數是從右往左推入堆疊，所以是先 PUSH 3，再 PUSH 2。函式呼叫完成後，下一條指令給 ESP 加 8，回復回狀。這裡加 8 是假設資料是 32 位元，所以作了兩次 PUSH，共佔 64 位元，也就是 8 個 BYTES。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;編譯成組合語言後，函式 add 的樣子大概如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-asm&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;_add:
  push ebp
  move ebp, esp
  sub esp, 4
  ...
  mov esp, ebp
  pop ebp
  ret&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;一開頭先作一個把當前 EBP 推入堆疊儲存起來的動作，因為接下來就要把當前的 ESP 的值賦給 EBP 的動作。為什麼這麼作？因為我們的函式參數及區域變數都放在堆疊裡面，需要靠 EBP 來存取。為什麼不透過 ESP 存取參數及區域變數呢？因為函式執行過程中還是有可能對堆疊作任意操作而改變了 ESP 的值。而 EBP 的值一直到函式呼叫結束都不會再變化了，所以我們可以放心的以 EBP (也就是當初進入函式時的 ESP 的值) 來存取參數及區域變數。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;下一條指令作了 ESP 減 4 的動作。這 4 個 BYTES 是保留變區域變數 c 的。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後一點補充。當以 CALL 指令呼叫 add 時，CPU 會自動把 CALL 指令的下一條指令的位址 push 到堆疊。這樣當 add 執行到最後的 RET 要返回時，CPU 就可以再從堆疊裡把這個返回位址取出，賦給 EIP 後繼續執行。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-text&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;高位址
+-----+
|  3  | b
|  2  | a
| ret |
| ebp | &amp;lt;--- ebp 
|  c  | &amp;lt;--- esp
低位址&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以上的堆疊狀態就是從傳遞參數，到呼叫 add，進入 add 後完成 Stack Frame 的整個初始化後的狀態。&lt;/p&gt;&lt;h2 id=&quot;163-stack-frame&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;16.3 Stack Frame&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;上面根據從傳遞參數，到呼叫 add，進入 add 後完成的 Stack Frame，只要透過 EBP 就能存取參數及區域變數。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;例如要把參數 a 的值取出賦給 eax。因為參數 a 在 EBP 之上的兩個單位，所以以 EBP 加 8 為索引，即可從堆疊取出參數 a 的值。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-asm&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;mov eax, [ebp + 8]  ; Read a&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;例如要把區域參數 c 的值取出賦給 EBX。因為區域參數 c 在 EBP 之下的一個單位，所以以 EBP 減 4 為索引，即可從堆疊取出區域參數 c 的值。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-asm&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;mov ebx, [ebp - 4]  ; Read c&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;164-dump-call-stacks-的原理&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;16.4 Dump Call Stacks 的原理&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;根據前面的了解，如果進入呼叫的函式裡後，能夠取得 EBP 的值，就能夠存取到函式的參數及區域變數。同樣的，假如可以取得上一層被呼叫函式的 EBP，也就能存取到上一層被呼叫函式的參數及區域變數。事實上這些都能作到，因為一進入函式，第一條指令作的就是把 EBP 存起來。也就是說，只要順著這條路徑回朔，就能作到Dump Call Stacks，以及能夠存取到每一層呼叫函式的參數及區域變數。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 WIN32 之下可以透過 dbghelp 的 StackWalk 來實作此功能。只需要事先填好 STACKFRAME 結構中的 EIP、ESP 及 EBP，接著以一個迴圈不斷的呼叫 StackWalk 即可一路回朔 Call Stacks。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;實作如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DumpCallStacks&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  CONTEXT ctx;
  ctx.ContextFlags = CONTEXT_FULL;
  GetThreadContext(g_piDbgee.hThread, &amp;amp;ctx);

  STACKFRAME sf = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
  sf.AddrPC.Offset = ctx.Eip;
  sf.AddrPC.Mode = AddrModeFlat;
  sf.AddrStack.Offset = ctx.Esp;
  sf.AddrStack.Mode = AddrModeFlat;
  sf.AddrFrame.Offset = ctx.Ebp;
  sf.AddrFrame.Mode = AddrModeFlat;

  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;true&lt;/span&gt;) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!StackWalk(IMAGE_FILE_MACHINE_I386, g_piDbgee.hProcess, g_piDbgee.hThread, &amp;amp;sf, &amp;amp;ctx, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, SymFunctionTableAccess, SymGetModuleBase, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;)) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
    }

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt; == sf.AddrFrame.Offset) {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
    }

    DWORD displacement;
    IMAGEHLP_LINE64 li = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
    li.SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(li);

    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!SymGetLineFromAddr64(g_piDbgee.hProcess, sf.AddrPC.Offset, &amp;amp;displacement, &amp;amp;li)) {
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;0x%x\n&quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)sf.AddrPC.Offset);
    } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; buff[&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(SYMBOL_INFO) + &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;256&lt;/span&gt;] = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
      SYMBOL_INFO *psi = (SYMBOL_INFO*)buff;
      psi-&amp;gt;SizeOfStruct = &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;sizeof&lt;/span&gt;(SYMBOL_INFO);
      psi-&amp;gt;MaxNameLen = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;256&lt;/span&gt;;
      DWORD64 displacement2 = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;;
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (!SymFromAddr(g_piDbgee.hProcess, sf.AddrPC.Offset, &amp;amp;displacement2, psi)) {
        &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%s:%d\n&quot;&lt;/span&gt;, li.FileName, li.LineNumber);
      } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
        &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%s:%d!%s\n&quot;&lt;/span&gt;, li.FileName, li.LineNumber, psi-&amp;gt;Name);
      }
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;165-修改-handleusercommand-支援-dump-call-stacks&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;16.5 修改 HandleUserCommand 支援 Dump Call Stacks&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;修改 HandleUserCommand，加入 Dump Call Stacks 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;c&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;C&#39;&lt;/span&gt;:
      DumpCallStacks();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;測試結果如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;EXCEPTION_DEBUG_EVENT. Code: 0x80000003, Addr: 0x401040 (First chance)
        EXCEPTION_BREAKPOINT. at d:\vs.net\testc2\main.cpp:11
0x401020   3
0x401020   4 int add(int a, int b)
0x401020   5 {
0x401024   6   int c = a + b;
0x40102d   7   return c;
0x401030   8 }
0x401030   9
0x401030  10 int main()
0x401040 *11 {
0x401044  12   printf(&quot;Hello world!\n&quot;);
0x401051  13   OutputDebugStringA(&quot;hello world!&quot;);
0x40105c  14   int sum = add(2, 3);
0x40106b  15   printf(&quot;%d\n&quot;, sum);
0x40107c  16   return 0;
0x40107e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;c&lt;/span&gt;
d:\vs.net\testc2\main.cpp:11!main
f:\rtm\vctools\crt_bld\self_x86\crt\src\crt0.c:318!__tmainCRTStartup
f:\rtm\vctools\crt_bld\self_x86\crt\src\crt0.c:187!mainCRTStartup
0x76325d49
0x777acdeb
0x777acd71
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;17-顯示區域變數型別及內容&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;17. 顯示區域變數型別及內容&lt;/h1&gt;&lt;h2 id=&quot;171-symbol_info-結構&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.1 SYMBOL_INFO 結構&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在除錯器裡要顯示區域變數及全域變數的型別及其內容等，必須要有除錯符號資訊才行，除錯符號資訊記錄了這些變數的名稱、型別、位址、長度等資訊。透過這些資料就可以在除錯程式時，動態顯示當前變數的狀態。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;符號資訊是由定義在 dbghelp.h 中的 SYMBOL_INFO 結構得到。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;hljs-class&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;struct&lt;/span&gt; _&lt;span class=&quot;hljs-title&quot; style=&quot;color: #445588; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SYMBOL_INFO&lt;/span&gt; {&lt;/span&gt;
  ULONG   SizeOfStruct;
  ULONG   TypeIndex;
  ULONG64 Reserved[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;];
  ULONG   Index;
  ULONG   Size;
  ULONG64 ModBase;
  ULONG   Flags;
  ULONG64 Value;
  ULONG64 Address;
  ULONG   Register;
  ULONG   Scope;
  ULONG   Tag;
  ULONG   NameLen;
  ULONG   MaxNameLen;
  CHAR    Name[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;];
} SYMBOL_INFO, *PSYMBOL_INFO;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;172-列出區域變數&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.2 列出區域變數&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;透過 API SymEnumSymbols 的幫助，可以找到目前可見的區域變數。呼叫時傳入一個 EnumSymbolsCallback，SymEnumSymbols 會把區域變數一個一個透過這個 Callback 函式通知我們 。因為 SymEnumSymbols 會連函式都一起找出來，所以在 StaticEnumLocals 裡面，我們多作一個檢查，檢查此符號是否為一個資料類別，以此過濾掉其它的符號。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;static&lt;/span&gt; BOOL CALLBACK &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;StaticEnumLocals&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymTagData == pSymInfo-&amp;gt;Tag) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%08x %4u %s\n&quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)pSymInfo-&amp;gt;Address, SymbolSize, pSymInfo-&amp;gt;Name);
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; TRUE;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DumpLocals&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  IMAGEHLP_STACK_FRAME sf = {&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;};
  sf.InstructionOffset = GetCurrIp();
  SymSetContext(g_piDbgee.hProcess, &amp;amp;sf, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  SymEnumSymbols(g_piDbgee.hProcess, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, StaticEnumLocals, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;173-讀取區域變數記憶體內容&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.3 讀取區域變數記憶體內容&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;在 StaticEnumLocals 裡，我們可以透過 pSymInfo 傳遞來的資訊取得區域變數的位址資訊。得到位址後，就能透過 ReadProcessMemeory 讀取區域變數的記憶體內容。&lt;/p&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;前面說明過，函式參數及區域變數都是存放在堆疊中，且都是相對於 EBP。其實這句話只對了一半，正確來講是在 32-bits 模式下，函式參數及區域變數都是存放在堆疊中，且都是相對於 EBP。如果是在 64-bits 模式下，函式參數及區域變數還是存放在堆疊中，只不過不是相對於 EBP，而是要看 pSymInfo-&amp;gt;Register 這個欄位告訴我們是那個暫存器。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;ULONG64 &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetVariableAddress&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(PSYMBOL_INFO pSymInfo)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (pSymInfo-&amp;gt;Flags &amp;amp; SYMFLAG_REGREL) {
    CONTEXT ctx;
    ctx.ContextFlags = CONTEXT_CONTROL;
    GetThreadContext(g_piDbgee.hThread, &amp;amp;ctx);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; ctx.Ebp + pSymInfo-&amp;gt;Address; &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// In 32-bits mode, variable address is related to EBP.&lt;/span&gt;
  } &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;else&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; pSymInfo-&amp;gt;Address;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;174-取得區域變數資料型別&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.4 取得區域變數資料型別&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;要取得區域變數資料型別是一件很瑣碎複雜的工作，主要透過 SymGetTypeInfo 這個 API，函式原型如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;BOOL
IMAGEAPI
&lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;SymGetTypeInfo&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(
    IN  HANDLE          hProcess,
    IN  DWORD64         ModBase,
    IN  ULONG           TypeId,
    IN  IMAGEHLP_SYMBOL_TYPE_INFO GetType,
    OUT PVOID           pInfo
    )&lt;/span&gt;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;hProcess 同上面一樣是被除錯程式的 HANDLE。ModeBase 使用 pSymInfo-&amp;gt;ModeBase 欄位，TypeId 使用 pSymInfo-&amp;gt;TypeIndex 欄位。GetType 參數可以是如下定義的數值之一。不同的 GetType 參數，可以讀取不同的符號資訊。pInfo 的返回值及返回值的型別會根據我們傳入的 GetType 不同而不同。IMAGEHLP_SYMBOL_TYPE_INFO 定義於 dbghelp.h，如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; _IMAGEHLP_SYMBOL_TYPE_INFO {
    TI_GET_SYMTAG,
    TI_GET_SYMNAME,
    TI_GET_LENGTH,
    TI_GET_TYPE,
    TI_GET_TYPEID,
    TI_GET_BASETYPE,
    TI_GET_ARRAYINDEXTYPEID,
    TI_FINDCHILDREN,
    TI_GET_DATAKIND,
    TI_GET_ADDRESSOFFSET,
    TI_GET_OFFSET,
    TI_GET_VALUE,
    TI_GET_COUNT,
    TI_GET_CHILDRENCOUNT,
    TI_GET_BITPOSITION,
    TI_GET_VIRTUALBASECLASS,
    TI_GET_VIRTUALTABLESHAPEID,
    TI_GET_VIRTUALBASEPOINTEROFFSET,
    TI_GET_CLASSPARENTID,
    TI_GET_NESTED,
    TI_GET_SYMINDEX,
    TI_GET_LEXICALPARENT,
    TI_GET_ADDRESS,
    TI_GET_THISADJUST,
    TI_GET_UDTKIND,
    TI_IS_EQUIV_TO,
    TI_GET_CALLING_CONVENTION,
} IMAGEHLP_SYMBOL_TYPE_INFO;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;這裡我們只會使用到下面這幾種，後面使用到時會再陸續說明。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_SYMTAG&lt;/code&gt;&amp;nbsp;符號 Tag，回傳資料型別 DWORD。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_SYMNAME&lt;/code&gt;&amp;nbsp;符號名稱，回傳資料型別 WCHAR*。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_BASETYPE&lt;/code&gt;&amp;nbsp;符號基礎型別，回傳資料型別 DWORD。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_LENGTH&lt;/code&gt;&amp;nbsp;符號長度，回傳資料型別 ULONG64。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_TYPEID&lt;/code&gt;&amp;nbsp;符號 Type Index，回傳資料型別 DWORD。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;TI_GET_COUNT&lt;/code&gt;&amp;nbsp;Array 的元素個數，回傳資料型別 DWORD。&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;175-ti_get_symtag&quot; style=&quot;border: 0px; font-family: helvetica, arial, freesans, clean, sans-serif; margin: 1em 0px; padding: 0px;&quot;&gt;17.5 TI_GET_SYMTAG&lt;/h3&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;首先以 TI_GET_SYMTAG 取得變數的符號的 Tag，得到符號 Tag 後我們就能得知變數的類型。同樣的符號的 Tag 種類也非常多，由以下於 cvconst.h 中的 SymTagEnum 定義。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; SymTagEnum {
    SymTagNull,
    SymTagExe,
    SymTagCompiland,
    SymTagCompilandDetails,
    SymTagCompilandEnv,
    SymTagFunction,
    SymTagBlock,
    SymTagData,
    SymTagAnnotation,
    SymTagLabel,
    SymTagPublicSymbol,
    SymTagUDT,
    SymTagEnum,
    SymTagFunctionType,
    SymTagPointerType,
    SymTagArrayType,
    SymTagBaseType,
    SymTagTypedef,
    SymTagBaseClass,
    SymTagFriend,
    SymTagFunctionArgType,
    SymTagFuncDebugStart,
    SymTagFuncDebugEnd,
    SymTagUsingNamespace,
    SymTagVTableShape,
    SymTagVTable,
    SymTagCustom,
    SymTagThunk,
    SymTagCustomType,
    SymTagManagedType,
    SymTagDimension,
    SymTagCallSite,
    SymTagInlineSite,
    SymTagBaseInterface,
    SymTagVectorType,
    SymTagMatrixType,
    SymTagHLSLType,
    SymTagCaller,
    SymTagCallee,
    SymTagExport,
    SymTagHeapAllocationSite,
    SymTagCoffGroup,
    SymTagInlinee,
    SymTagTaggedUnionCase,
};&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;同樣的我們也只會使用到下面這幾種，其餘的我們都當作 unknown 型別不于處理。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagBaseType&lt;/code&gt;&amp;nbsp;基礎型別，如 int、long、float 等。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagFunctionType&lt;/code&gt;&amp;nbsp;函數型別。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagPointerType&lt;/code&gt;&amp;nbsp;指標型別。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagArrayType&lt;/code&gt;&amp;nbsp;陣列型別。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagUDT&lt;/code&gt;&amp;nbsp;使用者自訂義型別 (User Defined Type)。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;SymTagEnum&lt;/code&gt;&amp;nbsp;Enum 型別。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下我們定義 GetVariableTypeName 以一指定變數的 typeIndex 取得其對應的 C/C++ 型別名稱。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetVariableTypeName&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo)&lt;/span&gt;
&lt;/span&gt;{
  DWORD symTag;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_SYMTAG, &amp;amp;symTag);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (symTag) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagUDT:
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagEnum:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; GetUdtTypeName(typeIndex, pSymInfo);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagFunctionType:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;&amp;lt;func&amp;gt;&quot;&lt;/span&gt;;
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagPointerType:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; GetPointTypeName(typeIndex, pSymInfo);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagArrayType:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; GetArrayTypeName(typeIndex, pSymInfo);
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagBaseType:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; GetBaseTypeName(typeIndex, pSymInfo);
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;&amp;lt;unknown&amp;gt;&quot;&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;SymTagFunctionType 類型的變數型別名稱我們簡單的顯示 &amp;lt;func&amp;gt;，其它的以下進一步說明。&lt;/p&gt;&lt;h2 id=&quot;176-讀取-symtagbasetype-型別名稱&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.6 讀取 SymTagBaseType 型別名稱&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;讀取 SymTagBaseType 的型別名稱是透用使用 TI_GET_BASETYPE 參數呼叫 SymGetTypeInfo，回傳的內容由 cvconst.h 中的 BasicType 定義。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;enum&lt;/span&gt; BasicType {
    btNoType   = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;,
    btVoid     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;1&lt;/span&gt;,
    btChar     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;2&lt;/span&gt;,
    btWChar    = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;3&lt;/span&gt;,
    btInt      = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;6&lt;/span&gt;,
    btUInt     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;7&lt;/span&gt;,
    btFloat    = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;8&lt;/span&gt;,
    btBCD      = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;9&lt;/span&gt;,
    btBool     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;10&lt;/span&gt;,
    btLong     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;13&lt;/span&gt;,
    btULong    = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;14&lt;/span&gt;,
    btCurrency = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;25&lt;/span&gt;,
    btDate     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;26&lt;/span&gt;,
    btVariant  = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;27&lt;/span&gt;,
    btComplex  = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;28&lt;/span&gt;,
    btBit      = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;29&lt;/span&gt;,
    btBSTR     = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;30&lt;/span&gt;,
    btHresult  = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;31&lt;/span&gt;,
    btChar16   = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;32&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// char16_t&lt;/span&gt;
    btChar32   = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;33&lt;/span&gt;,  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// char32_t&lt;/span&gt;
    btChar8    = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;34&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// char8_t&lt;/span&gt;
};&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;同樣的我們只處理一般 C/C++ 程式會出現的型別類型。底下列出我們有處理的類型及 C/C++ 對應的型別。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btVoid&lt;/code&gt;&amp;nbsp;void。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btChar&lt;/code&gt;&amp;nbsp;char。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btWChar&lt;/code&gt;&amp;nbsp;wchar_t。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btBool&lt;/code&gt;&amp;nbsp;bool。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btLong&lt;/code&gt;&amp;nbsp;long。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btULong&lt;/code&gt;&amp;nbsp;unsigned long。&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;下面三個型別類型需再配合變數的長度資訊才能作正確判斷。變數資料長度由 TI_GET_LENGTH 參數呼叫 SymGetTypeInfo 取得。&lt;/p&gt;&lt;ul style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; margin: 1em 0px 1em 2em; padding: 0px;&quot;&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btInt&lt;/code&gt;&amp;nbsp;長度 2 時為 short，長度 4 時為 int，長度 8 時為 long long。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btUInt&lt;/code&gt;&amp;nbsp;長度 1 時為 unsigned char，長度 2 時為 unsigned short，長度 4 時為 unsigned int，長度 8 時為 unsigned long long。&lt;/li&gt;&lt;li style=&quot;margin: 0.5em 0px; padding: 0px;&quot;&gt;&lt;code style=&quot;background-color: ghostwhite; border: 1px solid rgb(222, 222, 222); color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px 0.2em;&quot;&gt;btFloat&lt;/code&gt;&amp;nbsp;長度 4 時為 float，長度 8 時為 double。&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;177-讀取-symtagpointertype-型別名稱&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.7 讀取 SymTagPointerType 型別名稱&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;SymTagPointerType 類型的指標型別變數，需要再以 TI_GET_TYPEID 參數取得指標內含的真正的資料型別 typeIndex，再以這個 typeIndex 呼叫 GetVariableTypeName 並在最後加上一個 * 號，表示此是一個指標型別變數。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetPointTypeName&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo)&lt;/span&gt;
&lt;/span&gt;{
  DWORD containTypeIndex;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_TYPEID, &amp;amp;containTypeIndex);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; typeName = GetVariableTypeName(containTypeIndex, pSymInfo);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; typeName + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;*&quot;&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;178-讀取-symtagarraytype-型別名稱&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.8 讀取 SymTagArrayType 型別名稱&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;同樣的 SymTagArrayType 類型的陣列型別變數，也需要以 TI_GET_TYPEID 參數取得陣列元素的真正型別，以及以 TI_GET_COUNT 參數取得陣列素個數。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetArrayTypeName&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo)&lt;/span&gt;
&lt;/span&gt;{
  DWORD containTypeIndex;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_TYPEID, &amp;amp;containTypeIndex);
  DWORD count;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_COUNT, &amp;amp;count);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; typeName = GetVariableTypeName(containTypeIndex, pSymInfo);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; buff[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;64&lt;/span&gt;];
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sprintf&lt;/span&gt;(buff, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%u&quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)count);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; typeName + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;[&quot;&lt;/span&gt; + buff + &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;]&quot;&lt;/span&gt;;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;179-讀取-symtagudt-及-symtagenum-型別名稱&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.9 讀取 SymTagUDT 及 SymTagEnum 型別名稱&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;SymTagUDT 及 SymTagEnum 類型的變數，都是以 TI_GET_SYMNAME 取得符號名稱。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetUdtTypeName&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo)&lt;/span&gt;
&lt;/span&gt;{
  WCHAR *pName;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_SYMNAME, &amp;amp;pName);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt; NeedLen = WideCharToMultiByte(CP_ACP, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, pName, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;-1&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; buff;
  buff.resize(NeedLen);
  WideCharToMultiByte(CP_ACP, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;, pName, &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;-1&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt;*)buff.c_str(), NeedLen, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
  LocalFree(pName);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; buff;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;1710-顯示變數內容&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.10 顯示變數內容&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;GetVariableValue 的實作很類似 GetVariableTypeName，差別在於回傳變數型別名稱的地方修改成根據變數型別格式化變數的記憶體內容。為簡化起見，這裡只處理 SymTagBaseType 類型的變數內容顯示，以及 SymTagPointerType 類型的變數內容只顯示指標指向的位址。其餘的類型，一律以 16 進制顯示。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetBaseTypeValue&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; *pData)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-comment&quot; style=&quot;color: #999988; font-style: italic; margin: 0px; padding: 0px;&quot;&gt;// 略&lt;/span&gt;
}

&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;GetVariableValue&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(ULONG typeIndex, PSYMBOL_INFO pSymInfo, &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; &amp;amp;data)&lt;/span&gt;
&lt;/span&gt;{
  DWORD symTag;
  SymGetTypeInfo(g_piDbgee.hProcess, pSymInfo-&amp;gt;ModBase, typeIndex, TI_GET_SYMTAG, &amp;amp;symTag);
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt; buff[&lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;32&lt;/span&gt;];
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;switch&lt;/span&gt; (symTag) {
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagBaseType:
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; GetBaseTypeValue(typeIndex, pSymInfo, data.data());
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; SymTagPointerType:
      &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sprintf&lt;/span&gt;(buff, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;0x%x&quot;&lt;/span&gt;, *(&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;*)data.data());
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; buff;
  }
  &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; value;
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;size_t&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;0&lt;/span&gt;; i &amp;lt; data.size(); i++) {
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;sprintf&lt;/span&gt;(buff, &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%02x &quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;char&lt;/span&gt;)data[i]);
    value += buff;
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; value;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;1711-修改-staticenumlocals&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.11 修改 StaticEnumLocals&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;StaticEnumLocals 修改如下。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;static&lt;/span&gt; BOOL CALLBACK &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;StaticEnumLocals&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)&lt;/span&gt;
&lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;if&lt;/span&gt; (SymTagData == pSymInfo-&amp;gt;Tag) {
    ULONG64 addr = GetVariableAddress(pSymInfo);
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; mem;
    mem.resize(SymbolSize);
    ReadProcessMemory(g_piDbgee.hProcess, (LPCVOID)addr, (LPVOID)mem.data(), SymbolSize, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; value = GetVariableValue(pSymInfo-&amp;gt;TypeIndex, pSymInfo, mem);
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;string&lt;/span&gt; type = GetVariableTypeName(pSymInfo-&amp;gt;TypeIndex, pSymInfo);
    &lt;span class=&quot;hljs-built_in&quot; style=&quot;color: #0086b3; margin: 0px; padding: 0px;&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&quot;%08x %s %s %s\n&quot;&lt;/span&gt;, (&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;int&lt;/span&gt;)addr, type.c_str(), pSymInfo-&amp;gt;Name, value.c_str());
  }
  &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;return&lt;/span&gt; TRUE;
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;1712-修改-handleusercommand-支援-dumplocals&quot; style=&quot;border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: initial; border-top-style: initial; border-width: 0px 0px 1px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 20.01px; margin: 1.5em 0px 1em; padding: 0px 0px 0.5em;&quot;&gt;17.12 修改 HandleUserCommand 支援 DumpLocals&lt;/h2&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;最後修改 HandleUserCommand，加入 DumpLocals 指令的支援。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;HandleUserCommand&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
...
    &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;l&#39;&lt;/span&gt;: &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot; style=&quot;color: #dd1144; margin: 0px; padding: 0px;&quot;&gt;&#39;L&#39;&lt;/span&gt;:
      DumpLocals();
      &lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;break&lt;/span&gt;;
...
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;底下是測試結果。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-shell&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;0x449010   4 int add(int a, int b)
0x449010   5 {
0x449014   6   int c = a + b;
0x44901d   7   return c;
0x449020   8 }
0x449020   9
0x449020  10 int main(int argc, char** argv)
0x449030  11 {
0x449034 *12   printf(&quot;Hello world!\n&quot;);
0x449041  13   OutputDebugStringA(&quot;hello world!&quot;);
0x44904c  14   int sum = add(2, 3);
0x44905b  15   printf(&quot;%d\n&quot;, sum);
0x44906c  16   return 0;
0x44906e  17 }
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;l&lt;/span&gt;
0019ff10 int argc 1
0019ff14 char** argv 0x9c18b0
0019ff04 int sum 10229936
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;bash&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;d 9c18b0&lt;/span&gt;
009C18B0  B8 18 9C 00 00 00 00 00-44 3A 5C 76 73 2E 6E 65  ........D:\vs.ne
009C18C0  74 5C 74 65 73 74 63 32-5C 62 69 6E 5C 44 65 62  t\testc2\bin\Deb
009C18D0  75 67 5C 74 65 73 74 63-32 2E 65 78 65 00 FD FD  ug\testc2.exe...
009C18E0  FD FD AB AB AB AB AB AB-AB AB EE FE EE FE EE FE  ................
009C18F0  00 00 00 00 00 00 00 00-D7 C9 74 E7 55 69 00 18  ..........t.Ui..
009C1900  90 18 9C 00 E8 19 9C 00-FC 01 46 00 75 00 00 00  ..........F.u...
009C1910  AC 00 00 00 02 00 00 00-0B 00 00 00 FD FD FD FD  ................
009C1920  08 1A 9C 00 68 1A 9C 00-D0 1A 9C 00 48 1B 9C 00  ....h.......H...
&lt;span class=&quot;hljs-meta&quot; style=&quot;color: #999999; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&quot;18-顯示全域變數型別及內容&quot; style=&quot;border-bottom-color: initial; border-bottom-style: initial; border-image: initial; border-left-color: initial; border-left-style: initial; border-right-color: initial; border-right-style: initial; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-width: 4px 0px 0px; font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 22.678px; margin: 1.5em 0px 0px; padding: 0.5em 0px 0px;&quot;&gt;18. 顯示全域變數型別及內容&lt;/h1&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;以前面完成的顯示區域變數型別及內容的功能為基礎，要顯示全域變數型別及內容，只需作一個小小的改動。這個改動就是：當呼叫 SymEnumSymbols 時，BaseOfDll 傳入模組的基底位址。而模組的基底位址，可以透過 SymGetModuleBase64 取得。&lt;/p&gt;&lt;pre style=&quot;background-color: #eeeeee; border-radius: 3px; border: 1px solid rgb(221, 221, 221); box-shadow: rgba(0, 0, 0, 0.07) 0px 1px 2px inset; color: #444444; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-size: 12px; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: 1.5em; margin-bottom: 1em; margin-top: 1em; overflow: auto; padding: 5px;&quot;&gt;&lt;code class=&quot;language-c++&quot; style=&quot;border: none; font-family: Monaco, &amp;quot;Courier New&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, monospace; font-feature-settings: normal; font-kerning: auto; font-optical-sizing: auto; font-size-adjust: none; font-stretch: normal; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-emoji: normal; font-variant-numeric: normal; font-variant-position: normal; font-variation-settings: normal; line-height: normal; margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-function&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;&lt;span class=&quot;hljs-keyword&quot; style=&quot;color: #333333; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot; style=&quot;color: #990000; font-weight: bold; margin: 0px; padding: 0px;&quot;&gt;DumpGlobals&lt;/span&gt;&lt;span class=&quot;hljs-params&quot; style=&quot;margin: 0px; padding: 0px;&quot;&gt;()&lt;/span&gt;
&lt;/span&gt;{
  DWORD64 BaseMod = SymGetModuleBase64(g_piDbgee.hProcess, GetCurrIp());
  SymEnumSymbols(g_piDbgee.hProcess, BaseMod, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;, StaticEnumLocals, &lt;span class=&quot;hljs-literal&quot; style=&quot;color: teal; margin: 0px; padding: 0px;&quot;&gt;NULL&lt;/span&gt;);
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: helvetica, arial, freesans, clean, sans-serif; font-size: 13.34px; line-height: 1.5em; margin: 1em 0px; padding: 0px;&quot;&gt;其餘部份的修改都和 DumpLocals 類似，這裡就不再贅述。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description><link>http://good-ed.blogspot.com/2025/02/win32-source-level.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-3006513913566212770</guid><pubDate>Thu, 04 Apr 2024 08:20:00 +0000</pubDate><atom:updated>2024-04-04T16:20:07.886+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">Game</category><title>任務檢測器</title><description>翻到一個古董，再把資料檔案翻出來，還可以執行！這是第一份工作時製作的小工具之一，功能是用來檢視及測試編輯好的任務。設計的這個Script實際上就好像是在寫組合語言一樣，只不過到後來企劃也訓練的會寫組合語言了...&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1x-scpRsSIJjA8ey2qON5jkE1AMpDp71bQq6p9RPHVBDAMzWzIzh9qDksog33RY4GHpRFuapeSG-iUP__Ag040AycDk06U9qFMjDF4curhcvifBS-f-juH3R_3zVtYpp-pUy_lke_9ndo/s1600/clip_1.jpg&quot; onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1x-scpRsSIJjA8ey2qON5jkE1AMpDp71bQq6p9RPHVBDAMzWzIzh9qDksog33RY4GHpRFuapeSG-iUP__Ag040AycDk06U9qFMjDF4curhcvifBS-f-juH3R_3zVtYpp-pUy_lke_9ndo/s400/clip_1.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5605137289059724786&quot; /&gt;&lt;/a&gt;(單步/執行結果)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHjXpJre9ocvD_sUaGIijGzPGOWhn_v6A3Sv25qR2rEGS9wqN7su9gYCzbUvYznzZyWNERpQoaW99JKA-eX_MqACnPsOwDmUr_rfuzMwqAhw3nf0cDQRoQZL017vzsjy32PyTKmZMs_nip/s1600/clip_2.jpg&quot; onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHjXpJre9ocvD_sUaGIijGzPGOWhn_v6A3Sv25qR2rEGS9wqN7su9gYCzbUvYznzZyWNERpQoaW99JKA-eX_MqACnPsOwDmUr_rfuzMwqAhw3nf0cDQRoQZL017vzsjy32PyTKmZMs_nip/s400/clip_2.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5605137294530278898&quot; /&gt;&lt;/a&gt;(玩家屬性)&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkaVOzRIy9mz6S2kkPjJKE-2J60PDEWxJ4H9Qsa8SvfKFvQjR0dqDv4VplagUUIEcvC_66g24RRRMqvGnvAixstQOxJtT82p3IbW9n1eUv7N_ZteAFnHskhF9tAA-KVjigjnxDZtORY2Xd/s1600/clip_3.jpg&quot; onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkaVOzRIy9mz6S2kkPjJKE-2J60PDEWxJ4H9Qsa8SvfKFvQjR0dqDv4VplagUUIEcvC_66g24RRRMqvGnvAixstQOxJtT82p3IbW9n1eUv7N_ZteAFnHskhF9tAA-KVjigjnxDZtORY2Xd/s400/clip_3.jpg&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5605137295305265762&quot; /&gt;&lt;/a&gt;(任務原始碼)&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmjZk5L9Zpp4jaO2Juz5apgtuld6zSHIRX5vSZRGg7Vzb3ey-HxnfUDbvJe-Mj1NarGe9hWi5VhvnaJ99ORVBziFB7nCffwpJCISqD8APcoPV9RKOUCx6nGl5TwjyVvoCqiH8IuhJc36Js/s1600/clip_4.jpg&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhmjZk5L9Zpp4jaO2Juz5apgtuld6zSHIRX5vSZRGg7Vzb3ey-HxnfUDbvJe-Mj1NarGe9hWi5VhvnaJ99ORVBziFB7nCffwpJCISqD8APcoPV9RKOUCx6nGl5TwjyVvoCqiH8IuhJc36Js/s400/clip_4.jpg&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5605141768005211282&quot; /&gt;&lt;/a&gt;(字串表)</description><link>http://good-ed.blogspot.com/2011/05/blog-post.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1x-scpRsSIJjA8ey2qON5jkE1AMpDp71bQq6p9RPHVBDAMzWzIzh9qDksog33RY4GHpRFuapeSG-iUP__Ag040AycDk06U9qFMjDF4curhcvifBS-f-juH3R_3zVtYpp-pUy_lke_9ndo/s72-c/clip_1.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-7074323328347993538</guid><pubDate>Thu, 04 Jan 2024 15:24:00 +0000</pubDate><atom:updated>2024-01-04T23:24:41.327+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">good</category><category domain="http://www.blogger.com/atom/ns#">Lua</category><category domain="http://www.blogger.com/atom/ns#">stge</category><title>千字文射擊 BreakShoot</title><description>&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;[&lt;a href=&quot;https://github.com/cnyaw/breakshoot&quot;&gt;GitHub&lt;/a&gt;][&lt;a href=&quot;https://smallworld.idv.tw/game/good/play.html?pkg=breakshoot.zip&quot;&gt;Play&lt;/a&gt;]&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;兒子小學低年級時，學校要求他們背弟子規，所以我想如果他們也能學習千字文應該很不錯。千字文總共一千個字，每個字都不同，是古代的兒童課本。學習千字文可以了解古代社會的規範、歷史常識和禮節禮儀等。平常只要有機會我就會想辨法引導他們去讀讀千字文，這也是製作這個小遊戲的用意。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx14vmLWsAXmnbbB1tm4FJ-QqZcpaGw0RDv8Wiud4ZTsXMyGxYeg-UDY_Qx903q0_9Cdg5MQaJnC14tUkqmXcA3W_GqDaB1STY13DbAS26t6BcPz83LGLh4v8wRhVtbui4NdemATppUp2Ew4kQby1FflloJn74Rg12NIQOeONddQPmPg0LI135C0U0UYe9/s482/1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;352&quot; data-original-width=&quot;482&quot; height=&quot;293&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx14vmLWsAXmnbbB1tm4FJ-QqZcpaGw0RDv8Wiud4ZTsXMyGxYeg-UDY_Qx903q0_9Cdg5MQaJnC14tUkqmXcA3W_GqDaB1STY13DbAS26t6BcPz83LGLh4v8wRhVtbui4NdemATppUp2Ew4kQby1FflloJn74Rg12NIQOeONddQPmPg0LI135C0U0UYe9/w400-h293/1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj71IhELVSuyj5Tqg3j40aRUUAws720Szpiw_s9vWyEaklejS6L87_D6d1CfyTkTXhKbiM6PnALtHPDx0lELHfXhHmRvFlGVn5PMXqvYoXkDKzt_746vtjm4q-8miWJIdjg3Bp_Ii2JWpe0tOrT4x5BR6n7g53n2O0Gwgp1YW9hIxl6Tq8BGjAPTSUMholR/s482/2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;352&quot; data-original-width=&quot;482&quot; height=&quot;293&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj71IhELVSuyj5Tqg3j40aRUUAws720Szpiw_s9vWyEaklejS6L87_D6d1CfyTkTXhKbiM6PnALtHPDx0lELHfXhHmRvFlGVn5PMXqvYoXkDKzt_746vtjm4q-8miWJIdjg3Bp_Ii2JWpe0tOrT4x5BR6n7g53n2O0Gwgp1YW9hIxl6Tq8BGjAPTSUMholR/w400-h293/2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNVWW42F_lpGEeOWpHT9tur9Ii-JPjAf-kCT9KahrFWik_fF18CfOuHOegYDEgNC6IEpXvKChxpm2ox7rst-3JvoA2y2nX0Mnnc9Rz0p3nlfjZbgSae-es7X_JEcVC4vXcpwHkR-8orbNCzTd1Reoxm8kSeM1IwjqMH_sWtZOQsHnSDy5n_s0X3xRBhXP2/s482/4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;352&quot; data-original-width=&quot;482&quot; height=&quot;293&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNVWW42F_lpGEeOWpHT9tur9Ii-JPjAf-kCT9KahrFWik_fF18CfOuHOegYDEgNC6IEpXvKChxpm2ox7rst-3JvoA2y2nX0Mnnc9Rz0p3nlfjZbgSae-es7X_JEcVC4vXcpwHkR-8orbNCzTd1Reoxm8kSeM1IwjqMH_sWtZOQsHnSDy5n_s0X3xRBhXP2/w400-h293/4.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzz3bpgLrDYN0E1k-m3cF7HIME1BZqN8qBydOsZgrIzQ2h-hnUjfWYR0jhyphenhyphenZeWNTAdvuL2bR9Nm8royyKSdEzSVhMl1qnzW1i-Nc6gOxqqnqVG8RY5LY23yE_HCL4XwjZvmVcOguFWJESjO12YcAGdcpIwIK4ctMkZSg4nZvtnXjAcAkCbfJ0vv1mj2DxN/s482/3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;352&quot; data-original-width=&quot;482&quot; height=&quot;293&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzz3bpgLrDYN0E1k-m3cF7HIME1BZqN8qBydOsZgrIzQ2h-hnUjfWYR0jhyphenhyphenZeWNTAdvuL2bR9Nm8royyKSdEzSVhMl1qnzW1i-Nc6gOxqqnqVG8RY5LY23yE_HCL4XwjZvmVcOguFWJESjO12YcAGdcpIwIK4ctMkZSg4nZvtnXjAcAkCbfJ0vv1mj2DxN/w400-h293/3.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;動態點陣字標題&lt;/h2&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;遊戲的標題是由&#39;BREAKSHOOT&#39;這幾個字元構成，每一個字元的畫素又以千字文裡的一個中文字取代。進入標題畫面時，可以看到有約1秒鐘的動畫，每一個點陣字的中文字畫素隨機打散至畫面四周，然後再飛入重組。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;點陣字的畫素取得是先透過Graphics.GenCanvas生成一個大小9x18的虛擬畫布，然後每次從&#39;BREAKSHOOT&#39;裡面取出一個個字元出來，以Graphics.DrawText畫到這個畫布上。之後再以Graphics.GetPixel取出畫布上的每個點，如果不是0就生一個中文字出來。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;點陣字的動畫則是把上面的步驟裡生出來的中文字由&lt;a href=&quot;https://smallworld.idv.tw/doc/stge/&quot; style=&quot;color: blue; text-decoration-line: none;&quot;&gt;STGE&lt;/a&gt;腳本來控制移動。為了實現這個功能，新增了一條API：Stge.LoadScript，可以在Runtime建立新的腳本。整個動作結合起來，如下面程式所示：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;local function LoadStgeCharScript(c, W, H, script_name, ch)
  Graphics.FillRect(c, 0, 0, W, H, 0)
  Graphics.DrawText(c, 0, 0, ch, 1)
  local script = &#39;script &#39; .. script_name
  for x= 0, W-1 do
    for y= 0, H-1 do
      local p = Graphics.GetPixel(c, x, y)
      if (0 ~= p) then
        script = script .. string.format(&#39; fire(title_char,$1+%d,$2+%d)&#39;, CW * x, CH * y)
      end
    end
  end
  script = script .. &#39; end&#39;
  Stge.LoadScript(script)
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;每次呼叫一次LoadStgeCharScript就可以動態產生一段STGE腳本對應到&#39;BREAKSHOOT&#39;裡面的一個字元，腳本的名稱是char_1~char_10。之後會再一個個呼叫它們，讓每個字元動起來，如下所示：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;local function LoadStgeTitleScript(c, W, H, script_name, text)
  for i = 1, #text do
    LoadStgeCharScript(c, W, H, &#39;char_&#39; .. i, string.sub(text,i,i))
  end
  local script = string.format(&#39;script %s sleep(0.2)&#39;, script_name)
  local offsetx = (SW - #text * W * CW) / 2 + CW/2
  for i = 1, #text do
    local x = math.floor(offsetx + (i - 1) * W * CW - SW/2)
    script = script .. string.format(&#39; fork(char_%d,%d,%d)&#39;, i, x, -100)
  end
  script = script .. &#39; sleep(1) userdata(1) fire(title_hint) end&#39;
  Stge.LoadScript(script)
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;每一個字元裡的畫素是以title_char來控制關聯中文字的位置，先是隨機飛到畫面周邊，然後再飛回它的定位。每一個點陣字的畫素的定位座標，是在LoadStgeCharScript裡面就己經事先指定好。title_char的定義如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;script title_char
  changex(rand(0.2,0.4),rand(-$w/2,$w/2))
  changey(rand(0.2,0.4),rand(-$h/2,$h/2))
  sleep(0.4)
  changex(rand(0.1,0.5),$1)
  changey(rand(0.1,0.5),$2)
  sleep(0.5)
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;標題畫面初始化時會以Stge.RunScript執行以上腳本來產生動態點陣字，若是無法執行則表示是第一次初始化需要動態產生腳本。如下所示：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;local script_name = &#39;title_text&#39;
if (-1 == Stge.RunScript(script_name)) then
  local CW5x8,CH5x8 = 5,8
  local c = Graphics.GenCanvas(CW5x8, CH5x8)
  Graphics.SetFont(Graphics.FIXED_FONT)
  LoadStgeTitleScript(c, CW5x8, CH5x8, script_name, &#39;BREAKSHOOT&#39;)
  Graphics.KillCanvas(c)
  Graphics.SetFont(Graphics.SYSTEM_FONT)
  Stge.RunScript(script_name)
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;最後再建立每一個畫素粒子和中文字的關聯就完成了。&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;多層星空的產生及捲動&lt;/h2&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;遊戲中每一個畫面都以簡單的星空作背景，在純黑色的背景疊上3層星星，點上2x2的小白點作為星星，越遠的星星顏色越淡，畫面捲動時也移動的越慢。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;3層星星是以STGE腳本生成的。如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;script star
  repeat(32)
    userdata(3,0.9,0.9,0.9)
    fire(star_a)
    userdata(2,0.5,0.5,0.5)
    fire(star_a)
    userdata(1,0.3,0.3,0.3)
    fire(star_a)
  end
end

script star_a
  changex(0,rand(-$w/2,$w/2))
  changey(0,rand(-$h/2,$h/2))
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;可以看到star裡的repeat迴圈在每一層星空裡共生出32個星星，userdata的第一個參數用來控制這是第幾層的星星，後面3個參數是用來指定星星的RGB值，至於star_a只是用來隨機設定星星的位置。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;當畫面捲動時，以Lua函式MoveStars來捲動3層星空。如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;function MoveStars(stars, x)
  local offset = (x - SCR_W/2) / SCR_W
  for i = 1, #stars do
    Good.SetPos(stars[i], 8 * i * offset, 0)
  end
end&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;stars是事先己經根據不同層(userdata第一個參數)儲存好的3層星星群的父物件。x是目前的畫面捲動位置，依據畫面的x座標相對於畫面中心計算出偏移值，再由這個偏移值去移動所有星星。迴圈的i就是第幾層的星空索引，x8可以讓不同層的星星移動速度有所區別。這樣就作到越遠的星星動的慢，越近的星星動的快。&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;顯示注音&lt;/h2&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;之前看到老婆在幫女兒作上小學前的注音預習，當時突然想到或許可以寫個小工具讓她使用，可以幫忙生出簡單的注音小測驗題。所以那時候利用&lt;a href=&quot;https://github.com/openvanilla/McBopomofo&quot; style=&quot;color: blue; text-decoration-line: none;&quot;&gt;小麥注音輸入法&lt;/a&gt;的國字和注音的對照表寫了一個國字轉注音的小測試程式，但後來就沒有繼續往下作。因為我沒有處理詞彙，所以會把一字多音都列出來。如下圖：&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7Q6v43R69G9hTnL3NU1Lrzz9iBFWx0GRZnf_lNCwh1zbZ7VwDYFN1zGWvsxJCImZ1cPgF1Ru5eAgMnnBCVzfTHFfIYbkS9X7TJd7WZ9_UhfJtskwY5fHR3mrZpnUCxd8IYEv5Whiedl1Z9PidJ4S9IeyLHLLe__r0sHEN39IrWp6kAfjxKWSGLIBFPXpj/s272/5.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;175&quot; data-original-width=&quot;272&quot; height=&quot;175&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7Q6v43R69G9hTnL3NU1Lrzz9iBFWx0GRZnf_lNCwh1zbZ7VwDYFN1zGWvsxJCImZ1cPgF1Ru5eAgMnnBCVzfTHFfIYbkS9X7TJd7WZ9_UhfJtskwY5fHR3mrZpnUCxd8IYEv5Whiedl1Z9PidJ4S9IeyLHLLe__r0sHEN39IrWp6kAfjxKWSGLIBFPXpj/s1600/5.png&quot; width=&quot;272&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;注音小工具的HTML網頁原始碼如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;
&amp;lt;style&amp;gt;
body {font-family:Helvetica, Arial, &quot;黑體-繁&quot;, &quot;微軟正黑體&quot;, sans-serif}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;input type=&quot;text&quot; id=&quot;inp&quot;&amp;gt;
&amp;lt;input type=&quot;button&quot; value=&quot;國字轉注音&quot; onclick=&quot;doParse()&quot;&amp;gt;
&amp;lt;div id=&quot;res&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
var dict = [];

fetch(&#39;BPMFBase.txt&#39;).then(function(response) {
  if (response.ok) {
    return response.text();
  } else {
    throw Error(response.statusText);
  }
}).then(function(text) {
  var lines = text.split(&quot;\n&quot;);
  lines.map(function(line) {
    var parts = line.split(&#39; &#39;);
    if (2 &amp;lt;= parts.length) {
      var c = parts[0], zhuyin = parts[1];
      var a = dict[c];
      if (null != a) {
        a.push(zhuyin);
      } else {
        dict[c] = [zhuyin];
      }
    }
  });
}).catch(function(error) {
  alert(error);
});

function doParse() {
  var s = document.getElementById(&#39;inp&#39;).value;
  var chars = s.split(&#39;&#39;);
  var html = &#39;&#39;;
  for (var i = 0; i &amp;lt; chars.length; i++) {
    var ch = chars[i];
    html += ch;
    var a = dict[ch];
    if (null != a) {
      html += &#39; &#39; + a;
    }
    html += &#39;&amp;lt;br&amp;gt;&#39;;
  }
  document.getElementById(&#39;res&#39;).innerHTML = html;
}
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;製作千字文射擊時利用這個小工具，把一千個字輸入，再把輸出結果存檔為zhuyin.txt。zhuyin.txt的內容是一行一個字和它的注音，如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;天 ㄊㄧㄢ
地 ㄉㄧˋ
玄 ㄒㄩㄢˊ
...&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;手工把一字多音的部份都處理好後，就可以把注音對照表輸入到Lua程式裡使用了。如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;local STR1000 = &#39;天地玄...&#39;
local STR1000_ZHUYIN = {[1]=&#39;ㄊㄧㄢ&#39;,[2]=&#39;ㄉㄧˋ&#39;,[3]=&#39;ㄒㄩㄢˊ&#39;,...&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;STR1000_ZHUYIN總共有一千組注音，當然不是用手工一個一個輸入，而是用一小段PHP來作，如下：&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-family: monospace, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1em; width: auto;&quot;&gt;&amp;lt;?php
$lines = explode(&quot;\r\n&quot;, file_get_contents(&#39;zhuyin.txt&#39;));
$no = 1;
foreach ($lines as $line) {
  echo &quot;[$no]=&#39;&quot;.explode(&#39; &#39;, $line)[1].&quot;&#39;,&quot;;
  $no += 1;
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif, &amp;quot;Microsoft JhengHei&amp;quot;, STHeiti; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;前置作業都準備好後，剩下的就是在遊戲裡面把注音畫出來，這裡就不再贅述了。&lt;/p&gt;</description><link>http://good-ed.blogspot.com/2024/01/breakshoot.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx14vmLWsAXmnbbB1tm4FJ-QqZcpaGw0RDv8Wiud4ZTsXMyGxYeg-UDY_Qx903q0_9Cdg5MQaJnC14tUkqmXcA3W_GqDaB1STY13DbAS26t6BcPz83LGLh4v8wRhVtbui4NdemATppUp2Ew4kQby1FflloJn74Rg12NIQOeONddQPmPg0LI135C0U0UYe9/s72-w400-h293-c/1.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-4181901219008148334</guid><pubDate>Tue, 27 Jun 2023 04:17:00 +0000</pubDate><atom:updated>2023-06-27T12:24:39.432+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Emscripten</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">OASYS</category><category domain="http://www.blogger.com/atom/ns#">Porting</category><title>Escape from Planet Delta by Russell Wallace 文字冒險遊戲</title><description>&lt;div id=&quot;title&quot; style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: left;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;Escape from Planet Delta是以OASYS系統製作的文字冒險遊戲，OASIS是一個用於製作文字冒險遊戲的物件導向的系統。最早Escape是在1980年代中期在Commodore64上以The Quill製作的，在1991年時移植至OASYS系統。Escape發佈於public domain，可以任意複制和散佈source和可執行檔。&lt;/span&gt;&lt;/div&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: left;&quot;&gt;OASYS是Object-Oriented Adventure System的縮寫，它的作者是Russell Wallace，在1992年於comp.binaries.ibm.pc發佈的，並且可以在各大FTP站取得。下載的zip包包含一個說明文件檔、二個範例(其中一個是escape)、反組譯器、編譯器及解譯器的C的source、以及MS-DOS的反組譯器、編譯器及解譯器的可執行檔。原始的zip包裡的source缺少include檔不過不難移植到非MS-DOS的平台。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: left;&quot;&gt;[&lt;a href=&quot;https://smallworld.idv.tw/game/escape/play.html&quot;&gt;Play&lt;/a&gt;] / [&lt;a href=&quot;https://github.com/cnyaw/oasys&quot;&gt;Github&lt;/a&gt;]&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;1. 編譯程式碼及執行&lt;/h2&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;OASYS製作的遊戲是先以OASYS程式語言撰寫好程式碼後，再以oac編譯器編譯為物件碼，再透過oai解譯器執行。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;1.1 OAC&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;首先你需要使用一個文字編輯器編輯你的遊戲原始碼，一般附屬檔名為s，例如test.s。接著使用oac編譯器把你的遊戲原始碼編譯為物件碼。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;請執行以下命令編譯原始碼&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;oac test.s&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;或者省略附屬檔名&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;oac test&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;編譯成功的話會輸出同檔名的物件檔，不包含附屬檔名。如編譯test.s成功後，產生名為test的物件檔。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;編譯過程如果有任何錯誤，則會輸出錯誤訊息。請再根據錯誤訊息，修正程式錯誤，並再重複以上的編譯命令及修正錯誤的流程，直到成功編譯出物件檔。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;1.2 OAI&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;編譯成功的物件檔，可透過oai解譯器執行。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;請執行以下命令執行物件檔&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;oai test&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;載入並成功啟動遊戲的話，可以看的遊戲輸出的訊息，以及接受文字命令的輸入提示符號。透過文字命令進行遊戲，quit離開。&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2. OASYS程式語言 Language&lt;/h2&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;底下介紹基本的OASYS程式語言語法規則，更詳細的說明請參數OASYS說明文件。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.1 大小寫 Case&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;雖然底下的範例都是以大寫字母作示範，但OASYS程式語言不區分大小寫英文字母。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.2 空白字元 Spaces&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;空白字元包含space、tab及換行字元。多個空白字元都會被合併視為一個單一空白字元。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.3 識別字 Identifiers&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;跟所有其他程式語言的識別字一樣，識別字由英文字母及數字組成，但必需以英文字母或底線字元作為開頭第一個字元。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如以下範例都是有效的識別字&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;ROOM
SATURNS
HYDRUGONBOMB&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;以下是不合法的識別字的例子&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;9TO5&lt;/pre&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.4 註解 Comments&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;註解有兩種形式，一是單行註解，另一是多行註解。&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;... // 這是單行註解

/* 這是一個
    多行註解  */&lt;/pre&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.5 宣告的次序 Order of definitions&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;基於效率的考量，OASYS在解析編譯程式碼的時候只會掃描一遍。這表示說，在程式碼中的任何參考都必須事先宣告。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.6 類別及物件 Classes and objects&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;OASYS是基於物件的系統，像是位置或玩家都是物件。當遊戲開始時並沒有任何物件，必須在開始時建立並初始化後才能使用。等到物件不再使用了，物件則被刪除。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;物件是基於類別來建立的，所以第一步就是定義類別。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;例如&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;CLASS PLAYER {{ME} {SELF} {MYSELF}}
CLASS ROOM {}
CLASS MACHINE_GUN {{GUN} {MACHINE GUN}}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;一個類別以關鍵字CLASS開頭，接著是空白字元，然後是類別名稱識別字，接著空白字元，然後是一對大刮號。大刮號裡面可以定義可有可無的用來存取以此類別生成的物件別名，每一個別名也用一對大括號刮起來。例如類別PLAYER的物件，可以以ME、SELF或MYSELF來存取。而像是ROOM類別的物件則無法讓玩家透過任何名字存取，只能作為內部使用。而MACHINE_GUN類別物件有兩個可以存取的別名，分別是GUN及MACHINE GUN。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.7 屬性 Properties&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;就像許多物件導向的程式語言一樣，OASYS的類別也有屬性，例如描述或重量。只是宣告的方式是以PROPERTY宣告一個屬性列表，這些屬性並不是特別專屬于那個類別，而是所有類別都能使用宣告的任何屬性。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;例如&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;PROPERTY INT WEIGHT
PROPERTY STRING DESCRIPTION
PROPERTY OBJECT IN&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如上面的例子，屬性以一個PROPERTY關鍵字開始，接著空白字元，然後是一個屬性類型關鍵字，接著是空白字元，最後是屬性名稱識別字。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;屬性類型總共有三種，INT、STRING或OBJECT。INT是整數型別，初始值為0，如上面的WEIGHT屬性。STRING是字串型別，初始值為&quot;NULL STRING&quot;，如上面的描述屬性。OBJECT則是一個指向其它物件的參考的屬性，初始值為OBJECT 0。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.8 方法 Methods&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;方法是OASYS裡面要作的事情怎麼完成的的動作。如下是一個簡單範例&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD INT SQUARE INT X
{
  RETURN X * X
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這是一個計算平方數的方法。一個方法以METHOD關鍵字開始，接著空白字元，可有可無的回傳值類型，接著是空白字元，然後是方法名稱識別字，此例中是SQUARE。再來是可有可無的參數列，此例中有一個類型為INT的叫作X的參數。接著是方法主體，以一對大括號括起來。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;底下是另一個例子&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD LOOK VERBS {{LOOK} {DESCRIBE LOCATION}}
{
  PRINT PLAYER IN DESCRIPTION
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這個方法叫作LOOK，它沒有回傳值所以沒有回傳值類型。另外關鍵字VERBS表示接下來的一對大括號裡面，是這個方法的別名列表，定義的方法類似CLASS的別名。定義方法的VERB別名後，就能在遊戲的過程中，使用此定義的別名作為操作命令輸入遊戲中。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;下面是比較複雜的例子&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD GIVE_TO OBJECT X IS_CARRIED OBJECT Y IS_VISIBLE
   VERBS {{GIVE X TO Y} {OFFER X TO Y} {GIVE Y X} {OFFER Y X}}
{
  ...
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這樣就能以如下的方法呼叫到GIVE_TO方法&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;GIVE FISH TO TIGER
OFFER FISH TO TIGER
GIVE THE TIGER THE FISH
OFFER THE TIGER THE FISH&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;注意到GIVE_TO方法的參數列的定義裡有IS_CARRIED及IS_VISIBLE，其實這是另外兩個定義的修飾方法，用來修飾X和Y參數，底下會再介紹。另外上面的例子裡面可以看到THE這個單字，這個特別的單字也是作為修飾用，會被系統自動忽略。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.9 變數 Variables&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;類似在定義PROPERTY一樣，你也可以定義GLOBAL變數，但只能有一個實體，如下所示&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;INT SCORE&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如果加上PROPERTY關鍵字，就變成了物件屬性，可以被多個物件擁有。另外在方法裡定義的變數則為LOCAL變數，可見範圍及生命周期只在方法內部有效。如下面的例子&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD INT SQUARE INT X
{
  INT RESULT

  RESULT = X * X
  RETURN RESULT
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;此外方法的參數的地位則相當於LOCAL變數。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.10 THIS&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;所有的方法都會假定為被指定為某個物件呼叫。例如，當你輸入指令時，就預設假定為指令是被PLAYER物件所呼叫。方法呼叫時，系統維護一個隱含的THIS物件參考，表示此方法是被此物件呼叫的。另外像上面的SQUARE方法的實作裡，並沒有使用到THIS物件，但系統還是一樣會指派一個THIS物件參考。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.11 INIT方法 METHOD INIT&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;每一個遊戲都需要一個INIT方法，INIT方法是遊戲程式的進入點，遊戲啟動時第一個被系統呼叫的方法就是INIT，可以在此作初始化。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.12 選擇器方法 Selector methods&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;上面的GIVE_TO方法裡定義的參數列中，我們看到IS_CARRIED及IS_VISIBLE。前面提到這是修飾方法，也就是選擇器方法。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這二個方法定義如下&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD INT IS_CARRIED
&quot;You haven&#39;t got that.\n&quot;
{
  RETURN THIS IN == PLAYER
}

METHOD INT IS_VISIBLE
&quot;That isn&#39;t here.\n&quot;
{
  RETURN THIS IS_CARRIED OR THIS IN == PLAYER IN
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;選擇器方法不帶參數，回傳值類型都是INT，也就是0或非0，即FALSE或TRUE。在左大括號前的字串，是定義為當選擇器方法回傳FALSE時，顯示給usr的提示訊息。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.13 SELECT_ADDRESSEE方法 METHOD SELECT_ADDRESSEE&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;在遊戲中，玩家可以和其它物件互動或交談。使用如下的語法&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;GUARD, DROP THE MACHINE GUN&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如果沒有前面的&quot;GUARD,&quot;，則表示玩家執行“DROP THE MACHINE GUN&quot;，加上前面的&quot;GUARD,&quot;後，這個動作則變為是由GUARD執行。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;一般來說，要把命令指派給物件，要先輸入物件的名字，接著一個逗號，然後是指令。至於那些物件能夠和玩家互動或交談呢？&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;有個特殊的選擇器方法叫作SELECT_ADDRESSEE就是用來做這個檢查的。如果你有定義一個SELECT_ADDRESSEE，則需要時它就會被呼叫，否則系統總是會顯示預設的訊息&quot;You can&#39;t talk to that&quot;。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;下面是一個範例&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;METHOD SELECT_ADDRESSEE
&quot;It doesn&#39;t understand you!\n&quot;
{
  RETURN (THIS IS GUARD OR THIS IS ROBOT) AND THIS IS_VISIBLE
}&lt;/pre&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;2.14 玩家 Player&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;PLAYER是需要預先定義的物件，在INIT方法裡需要被產生出來。如&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;PLAYER = CREATE PLAYER&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如上的例子PLAYER物件是以PLAYER類別產生出來的，當然這也不是必需這樣，你也能以其它類別的產生PLAYER物件。如&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;PLAYER = CREATE ROOM&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;上面的例子中，PLAYER物件是以ROOM類別建立的。這表示說，在遊戲過程中玩家可以在不同時間轉換為不同角色。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;例如在Commodore 64上的魔戒這個遊戲裡，4個哈比人Frodo、Sam、Merry和Pippin，可以用4個類別來表示這4個角色。玩家可以使用BECOME這個命令來操控這4個角色。遊戲開始時，玩家是先從FRODO這個角色開始，然後使用BECOME SAME切換為SAM。一個使用OASYS的可能實現方式如下&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;CLASS FRODO {{FRODO}}
CLASS SAM {{SAM}}
CLASS MERRY {{MERRY}}
CLASS PIPPIN {{PIPPIN}}

...

OBJECT FRODO
OBJECT SAM
OBJECT MERRY
OBJECT PIPPIN

...

METHOD INT IS_BECOMABLE
{
  RETURN THIS SELECT_ADDRESSEE AND (THIS IS FRODO OR
                                    THIS IS SAM OR
                                    THIS IS MERRY OR
                                    THIS IS PIPPIN)
}

METHOD BECOME OBJECT X IS_BECOMABLE VERBS {{BECOME X}}
{
  PLAYER = X
}

METHOD INIT
{
  ...
  FRODO = CREATE FRODO
  SAM = CREATE SAM
  MERRY = CREATE MERRY
  PIPPIN = CREATE PIPPIN

  PLAYER = FRODO      // Player starts off playing Frodo
  ...
}&lt;/pre&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;3. 攻略 Walkthrough&lt;/h2&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;Escape from Planet Delta by Russell Wallace

Originally written with The Quill on the Commodore 64 in the mid eighties and
ported to OASYS in January 1991. This game is public domain and source and
object code may be freely copied and used.

The plot is as follows: You were on a starship flying to the planet Betelgeuse
Delta, fourth planet of the Betelgeuse star system. On approaching the planet
for landing, the ship developed engine trouble and appeared to be about to
crash. Unfortunately there was not quite enough lifeboat space for everyone, so
your shipmates beat you up, threw you into the control room, locked the door,
grabbed the lifeboat, ejected and are probably on their way back to Earth by
now. The ship crash landed but amazingly is still mostly intact and you
survived the landing. However there is no chance of your being able to fly it
out of here, so you will have to look for the Starfleet base on the planet and
try to find some means of escape.

Commands can be multiple words, but words like ALL, IT and AND are not
supported. SAVE saves the game and LOAD reloads your position. VERBOSE, BRIEF
and NORMAL give you different lengths of location descriptions.

Good luck!&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;底下是一系列需要輸入的指令，括號裡的文字是一些關鍵訊息。&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;(Control Room)
open box
open box
open box
open box
open box
open box
open box
open box
open box
open box
open box
(以上總共11次open box)
(You open the box and remove an American Express credit card and an
oxy-acetylene torch.)
get card
get torch
open door with card
(You manage to unlock the door with the credit card.)
e
(Corridor)&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;以上的solution只是拋磚引玉起個頭，改天有什麼好心人士提供或我自己過關了再補上。&lt;/p&gt;&lt;h2 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;4. 移植雜記&lt;/h2&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;4.1 試移植&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如上面提到的，在網路上下載的v1版本oa_script.zip有缺檔案，另外找到v1.01版本oasys101.zip就完整了。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;一開始我先在emsc環境試下po，看看有沒有很多err。還好不多，也很快就修正可以編譯出目標檔。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;基本上以以下命令編譯&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;em++ OAI.C OALIB.C&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;然後試著用node執行看看，會有當掉的錯誤。原因是我先用下載的oac.exe編譯escape，但是下載下來的執行檔是古董程式，那時候的int是2個bytes。所以如果我用現在的編譯工具編譯oai.exe，新的oai會認為一個int是4個bytes。所以主要問題出在這裡。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;想辦法用硬幹的方式修正後，也可以成功在console下看到print的遊戲文字了。但是emsc不能直接移植scanf，所以試po到此為止。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;以以下命令執行編譯出來的程式&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;node a.out.js&lt;/pre&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;4.2 建立oac和oai專案作改版&lt;/h3&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;在Visual studio下建立oac和oai專案，之所有用vs建立專案只是方便移植，任何可以達到目的的方式或工具都可以。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;建立vs的oac和oai專案後，用類似試po時的改法，先改版一個可以執行的版本。接著就是針對這個可以執行的版本作更多的跨平台改版。這裡只要針對oai改版即可，先不用管oac，除非我們之後還要可以編譯並執行usr輸入的程式，否則現在只要改版oai並一律使用目前可執行的oac的版本。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;移植oai有兩個關鍵點。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;第一點是載入檔案的地方都改成從byte stream載入，這樣方便在上層一次載入檔案資料再一次解析再執行。第二個地方是usr輸入的處理，只要把原本無窮的REPL迴圈改成事件驅動即可。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;第一點沒有甚麼特別的，現在只說明一下第二個重點，其實很簡單。底下是原本的主REPL迴圈&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;LoadGame(argv[1]);
NewGame();
for (;;) {
  assert (sp == 0);
  if (!getinput ()) {
    continue;
  }
  command ();
  if (restart) {
    if (!getyn (&quot;Would you like to play again? (Y/N) &quot;))
      return 0;
    NewGame();
  }
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;現在只要改成當使用emsc編譯時，不要進入一個無窮的REPL迴圈，而時把這個迴圈打散，以事件趨動的方式每次從javascript那邊呼叫並傳遞進來作為usr輸入的字串時，再進行下一步的command解析處理。&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;#ifdef __EMSCRIPTEN__
LoadGameFromStream((char*)BIN);
NewGame();
getinput();
emscripten_exit_with_live_runtime();
#endif&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;BIN是將透過oac編譯好的escape遊戲的物件檔binary使用bin2c之類的工具轉成c程式碼裡的array，底下是ESCAPE.h的一個部份範例。&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;#ifndef ESCAPE_INC
#define ESCAPE_INC

const unsigned char BIN[] = {
0x6f,0x61,0x73,0x00,0x9f,0x01,0x00,0x00,0x0d,0x00,0x00,0x00,0x2a,0x4e,0x55,0x4c,
...
};

#endif // ESCAPE_INC&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;底下是對getinput的修改&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;void input (char *s)
{
  printx = printy = 0;
#ifdef __EMSCRIPTEN__
  // 不作事, 等待從javascript傳遞usr輸入字串.
#else
  gets (s);
#endif
}

int getinput_i(void)
{
  // 作原來的處理.
}

int getinput (void)
{
  print (&quot;&amp;gt; &quot;);
  input (buf);
#ifndef __EMSCRIPTEN__
  return getinput_i();
#else
  return FALSE;
#endif
}&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;至於提供給javascript的api，用來模擬usr輸入字串的cSendCmd如下&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;#ifdef __EMSCRIPTEN__
#include &lt;emscripten .h=&quot;&quot;&gt;
extern &quot;C&quot; {
int EMSCRIPTEN_KEEPALIVE cSendCmd(char *pBuff)
{
  strcpy(buf, pBuff);
  if (getinput_i()) {
    printf(&quot;%s\n&quot;, pBuff);
    command();
  }
  getinput();
  return 0;
}
} // extern &quot;C&quot;
#endif&lt;/emscripten&gt;&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;另外javascript的部份，底下只列出怎麼呼叫cSendCmd模擬usr輸入&lt;/p&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;&amp;lt;script&amp;gt;
function sendCommand(e) {
  if (13 === e.keyCode || 14 === e.keyCode) {
    sendCommand_i();
  }
}

function sendCommand_i() {
  var el = document.getElementById(&#39;cmd&#39;);
  var cmd = el.value;
  el.value = &#39;&#39;;
  if (&#39;&#39; == cmd) {
    return;
  }
  var ptr  = allocate(intArrayFromString(cmd), &#39;i8&#39;, ALLOC_NORMAL);
  Module.ccall(&#39;cSendCmd&#39;, &#39;number&#39;, [&#39;number&#39;], [ptr]);
  var resValue = Pointer_stringify(retPtr);
  _free(ptr);
}
&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這樣基本就完成了移植。&lt;/p&gt;</description><link>http://good-ed.blogspot.com/2023/06/escape-from-planet-delta-by-russell.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-4930411451859503953</guid><pubDate>Sat, 04 Mar 2023 13:17:00 +0000</pubDate><atom:updated>2023-03-04T21:17:53.857+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Algorithm</category><category domain="http://www.blogger.com/atom/ns#">Game</category><title>無限隨機地圖生成 Wang Tiles</title><description>&lt;div style=&quot;text-align: left;&quot;&gt;Wang Tiles&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;----------------&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;在研究關於可用於地圖生成的&lt;a href=&quot;https://github.com/mxgmn/WaveFunctionCollapse&quot;&gt;波函數坍縮&lt;/a&gt;演算法(Wave Function Collapse，底下簡寫WFC)的時候，又看到關於&lt;a href=&quot;https://en.wikipedia.org/wiki/Wang_tile&quot;&gt;王式磚&lt;/a&gt;的資料(Wang Tiles，底下簡寫WT)。跟WFC比起來，WT比較容易理解和實作，所以我就先根據WT的原理實作了一個無限隨機地圖生成的測試。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEit6CIkK9pGwn1tVkFiRGQ_w7aje4lgJ0xOqWPPEVNoYtEYywbluJATNseYi5S6m_7w8J0vUvoLHnrd_iijOuVb_d9soIP_sUTvkAtYyhHa9bpQZycRZTcEsDSHJ05dzyXkqD-ZJST-E2Xewl5N1E89i9cDfKUmvotJ1leS3C1YOXeZvfzP44nx_3UnBQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;518&quot; data-original-width=&quot;1011&quot; height=&quot;328&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEit6CIkK9pGwn1tVkFiRGQ_w7aje4lgJ0xOqWPPEVNoYtEYywbluJATNseYi5S6m_7w8J0vUvoLHnrd_iijOuVb_d9soIP_sUTvkAtYyhHa9bpQZycRZTcEsDSHJ05dzyXkqD-ZJST-E2Xewl5N1E89i9cDfKUmvotJ1leS3C1YOXeZvfzP44nx_3UnBQ=w640-h328&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;關於WT，這個&lt;a href=&quot;http://cr31.co.uk/stagecast/wang/intro.html&quot;&gt;網站&lt;/a&gt;有詳細的介紹，同時也有許多tilesets可以用來作為測試資源。WT是數學家發明的遊戲，主要概念是邊緣匹配的tile連通拚接。每一個矩形tile有4個邊和4個角，所以有2種拼法，一種是邊匹配的拼法，一種是角匹配的拼法。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;邊匹配 2Edge&lt;div&gt;---------------------&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;以邊匹配的拼法為例，每一個矩形tile的4個邊裡面，每個邊如果用0或1表示不同顏色，則總共有2x2x2x2共16種不同的tile。如下圖，生成tilemap時，如果一個tileA的上方的tileB的下邊是1，則tileA的上邊必須也是1，才能連通。同理，右方的tileC的左邊是1的話tileA的右邊也要是1，等等。整個tilemap的每一個tile都符合這個規則，就是一個符合WT的tilemap。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgfGiwrDzahe-_aCetF3PK3SBGt8Ey_Qj3vJSm2wdS4Z5a4DMPkV95QG6F7KmEEz4imdeWyQmIErRVooUqUNKtKbIsS32ca6crOj56Y39Fslsw9mzWZHiO1mUowYGTEnkOEO2DiD9pODiBUdU6HUDcP_L5qTFAuoMSfMYp5iOux-iFi8K368oz-4_L3cw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;165&quot; data-original-width=&quot;177&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgfGiwrDzahe-_aCetF3PK3SBGt8Ey_Qj3vJSm2wdS4Z5a4DMPkV95QG6F7KmEEz4imdeWyQmIErRVooUqUNKtKbIsS32ca6crOj56Y39Fslsw9mzWZHiO1mUowYGTEnkOEO2DiD9pODiBUdU6HUDcP_L5qTFAuoMSfMYp5iOux-iFi8K368oz-4_L3cw=s16000&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;生成隨機tilemap的方式不只一種，一個簡單的方法是從左到右從上到下，一個一個tile生成。每一個新tile生成時，針對它的上方及左方2個己生成的tile的邊建立連通狀態(上方tile的下邊是1則新tile的上邊也需為1，左方tile的右邊為1則新tile的左邊也需為1)，而新tile的右方及下方的邊則隨機選擇0或1。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如下圖，針對tileX的4個邊依序上右下左以2進制編碼為1,2,4,8，這樣在生成tilemap時可以使用bit運算操作方便判斷。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg64euiAQfaK9E6pAI6zted1UiyaSW_AgCyZ8kD97e4_zc6pAvdvqQrARwSFFwlbXEA4Tos8Px2S1dgpbAdAUdM35xI3UnRicUlfPReonO7iraPyCJkaoYR0TVsVLaoHwn1VwjoFgLEsy9nJ6MNHduiYtFEo3r-C6eJWH_ys_PB1NkwDSYx1SV5PP15pQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;87&quot; data-original-width=&quot;110&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg64euiAQfaK9E6pAI6zted1UiyaSW_AgCyZ8kD97e4_zc6pAvdvqQrARwSFFwlbXEA4Tos8Px2S1dgpbAdAUdM35xI3UnRicUlfPReonO7iraPyCJkaoYR0TVsVLaoHwn1VwjoFgLEsy9nJ6MNHduiYtFEo3r-C6eJWH_ys_PB1NkwDSYx1SV5PP15pQ=s16000&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;這樣16種tile的編號也同時是它的編碼。如tile0表示4個邊都是0，tile8表示左邊是1其餘3邊是0，tile13表示上左下邊是1右邊是0，等等。底下是生成邊匹配的tilemap的虛擬碼。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;void gen2EdgeWangTilesmap(cx, cy)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; foreach tile i of tilemap {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tile = 0;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (tilemap[upper] &amp;amp; 4) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// Match upper edge.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 1;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (tilemap[left] &amp;amp; 2) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Match left edge.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 8;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (rand) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// Random lower edge.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 4;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (rand) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// Random right edge.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 2;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tilemap[i] = tile;&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;下圖為以邊匹配拼法產生的隨機tilemap。(tileset來源http://cr31.co.uk/stagecast/wang/tiles_e.html)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjlJBqcxICwJD7krlHewgc82Hh4oPf04GOyfY7WmTBV31t9qrTs_7YxlaFb9zllEQqH5tEO6HumI1pYXvIvSXjKzu5JWYQDVAipKh9iQiVUBwx0LAoVv6ZkFOahMSfWYhzF_8GDFFgYM9iPbwEp4tYCwTG3OWCrnaPNCuuaT6DM7Wk-Zz8MtF6QzI766A&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;267&quot; data-original-width=&quot;791&quot; height=&quot;216&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjlJBqcxICwJD7krlHewgc82Hh4oPf04GOyfY7WmTBV31t9qrTs_7YxlaFb9zllEQqH5tEO6HumI1pYXvIvSXjKzu5JWYQDVAipKh9iQiVUBwx0LAoVv6ZkFOahMSfWYhzF_8GDFFgYM9iPbwEp4tYCwTG3OWCrnaPNCuuaT6DM7Wk-Zz8MtF6QzI766A=w640-h216&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;角匹配 2Corner&lt;/div&gt;&lt;div&gt;----------------------&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;邊匹配的拼法裡面，對每個tile的每個邊來說只需要跟另一個相隣的tile的一條邊作匹配即可，但是角匹配的拼法就複雜多了，角匹配的拼法裡面的每個tile的每個角需要和其它3個相隣的tile的角匹配。如下圖，和tileX的角x相隣的3個tile的角分別是tileA的角a、tileB的角b和tileC的角c。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEj9YDxKeBqDbw4szBjdq22lOyKUxbUMnmuAaxpH3xSoKauArEy4uSvbfqkmT8URHFmbYB1yUYvwypdCOcFOw-oBPrKdld45Zh8EnAeirklMYERLucJxmeop-VnXTYJPvcPCX6_WfUQcPQpPBjgbkA2-k526Qy2EbVbzj4vdDwBO7jwovFokMBnPP_yMzQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;112&quot; data-original-width=&quot;123&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEj9YDxKeBqDbw4szBjdq22lOyKUxbUMnmuAaxpH3xSoKauArEy4uSvbfqkmT8URHFmbYB1yUYvwypdCOcFOw-oBPrKdld45Zh8EnAeirklMYERLucJxmeop-VnXTYJPvcPCX6_WfUQcPQpPBjgbkA2-k526Qy2EbVbzj4vdDwBO7jwovFokMBnPP_yMzQ=s16000&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;同邊匹配的拼法一樣，在作角匹配的演算法我們一樣對每一個tile的4個角作編碼，方便使用bit運算作檢查，如下圖。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiWzkPr1XpJ4er_wIo9ki7mMdhpCh-2JZDlR_jKjQKOA3FyIHB6F-KxawUtQ88LgiIjNHf4A-Owl187UZ7MWAv-CIpU4L0KLRE-ojnl8Ux7zhGYmTm_mmu-vTahJJTpZ2Kjo41YlaqW7ZK4g2ZY3yeJ19AC4t4ZoSWMcxaf-oaTXrxs0Mjth6ZzLZIeqw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;76&quot; data-original-width=&quot;89&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEiWzkPr1XpJ4er_wIo9ki7mMdhpCh-2JZDlR_jKjQKOA3FyIHB6F-KxawUtQ88LgiIjNHf4A-Owl187UZ7MWAv-CIpU4L0KLRE-ojnl8Ux7zhGYmTm_mmu-vTahJJTpZ2Kjo41YlaqW7ZK4g2ZY3yeJ19AC4t4ZoSWMcxaf-oaTXrxs0Mjth6ZzLZIeqw=s16000&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;生成隨機tilemap時，在上圖中相隣的4個角xabc中只要一個是1，全都要是1才能連通。一個生成的方法也是同邊匹配的拼法一樣，從左到右從上到下，一個一個tile生成。每一個新tile生成時，針對新tile的左上、右上及左下角3個角要和己存在的tile的對應的相隣角匹配作連通，而剩下的右下角則使用隨機數0或1。底下是生成角匹配的隨機tilemap虛擬碼。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;void gen2CornerWangTilesmap(cx, cy)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; foreach tile i of tilemap {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tile = 0;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; // Match upper.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[up] &amp;amp; 4) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 8;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[up] &amp;amp; 2) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 1;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; // Match left.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[left] &amp;amp; 1) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 8;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[left] &amp;amp; 2) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 4;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; // Match lower.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[down] &amp;amp; 8) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 4;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; // Match right.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (mTilemap[right] &amp;amp; 8) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 1;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; // Random lower-right.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (rand()) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 2;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tilemap[i] = tile;&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;下圖為以角匹配拼法產生的隨機tilemap。(tileset來源http://cr31.co.uk/stagecast/wang/tiles_c.html)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhF7AsXcgTe96Ko3TEOy-kpbIRTChs6iu1FtjL_tU-O_veJDyegnK6AocIq4e66J5tDfWpqHctNkIEa8njj1pVV1wVTsJf2y4uXo6emH0m7Qs7gLFez4aItxWFjF4gOcZKltSUc07uoS3wBjdUU5YjU2onR4aMX9IrFV4-q7trkO0FHLiC2qERNQmMapw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;265&quot; data-original-width=&quot;783&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhF7AsXcgTe96Ko3TEOy-kpbIRTChs6iu1FtjL_tU-O_veJDyegnK6AocIq4e66J5tDfWpqHctNkIEa8njj1pVV1wVTsJf2y4uXo6emH0m7Qs7gLFez4aItxWFjF4gOcZKltSUc07uoS3wBjdUU5YjU2onR4aMX9IrFV4-q7trkO0FHLiC2qERNQmMapw=w640-h217&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;生成無限隨機地圖&lt;/div&gt;&lt;div&gt;---------------------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;動態生成無限隨機地圖的一個簡單方法是，把世界地圖切成許多小tilemap，每一個tilemap是8x8的tile組成。每一個tilemap使用WT的拼法隨機生成，同時每一個tilemap還要和相隣的tilemap連通。不只每一個tilemap內的每一個tile是連通的，相隣的tilemap之間也都是連通的，這樣整個世界地圖都會是無縫連接的。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如下圖，在畫世界地圖時，從左上角開始，計算出左上角的tilemap是那一個，然後依序從左到右從上到下，一個一個tilemap畫出來。每一個tilemap是8x8大小，每個tilemap區塊的左上角的數字是這個tilemap的座標(col,row)。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjBKhP9phEFWgysTFp8_cKXC_kfkvXLSQHDWPEsZtr3ZkSS13pKrVXWVn8B5k1H3FykNHA2zZ2drMWWmbY1uiFgA30wdYsLyRNFg4S4HPeIT_hyW0p2WxVZot3cmyE7SVP0fjgj06tgnn6sde4HgFrrFXzTgFOgWo0Ll39KtGbWx8GqoNXLBc-LuGKkDw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;518&quot; data-original-width=&quot;1011&quot; height=&quot;328&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjBKhP9phEFWgysTFp8_cKXC_kfkvXLSQHDWPEsZtr3ZkSS13pKrVXWVn8B5k1H3FykNHA2zZ2drMWWmbY1uiFgA30wdYsLyRNFg4S4HPeIT_hyW0p2WxVZot3cmyE7SVP0fjgj06tgnn6sde4HgFrrFXzTgFOgWo0Ll39KtGbWx8GqoNXLBc-LuGKkDw=w640-h328&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;tilemap生成的時機是，當畫面捲動要畫出其中一個tilemap區塊時(指定座標為col:row)，若這個tilemap原先不存在，則生成一個新的tilemap，並記錄下來。每一個tilemap以上面介紹的WT生成隨機內容，生成每一個tilemap內容後，還要作的就是處理相隣的tilemap怎麼作到連通相接。如下是生成世界地圖中指定座標的tilemap的虛擬碼。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;void genNewTilemap(col, row)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; //&lt;/div&gt;&lt;div&gt;&amp;nbsp; // Gen new tilemap.&lt;/div&gt;&lt;div&gt;&amp;nbsp; //&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; tilemaps[col,row].gen2CornerWangTilesmap();&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; //&lt;/div&gt;&lt;div&gt;&amp;nbsp; // Link tiles of edges to neighbor tilemaps.&lt;/div&gt;&lt;div&gt;&amp;nbsp; //&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (isTilemapExist(col - 1, row)) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; tilemaps[col,row].linkLeftEdge(tilemaps[col - 1, row]);&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (isTilemapExist(col, row - 1)) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; tilemaps[col,row].linkUpperEdge(tilemaps[col, row - 1]);&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (isTilemapExist(col + 1, row)) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; tilemaps[col,row].linkRightEdge(tilemaps[col + 1, row]);&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (isTilemapExist(col, row + 1)) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; tilemaps[col,row].linkLowerEdge(tilemaps[col, row + 1]);&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如上面的虛擬碼所示，生成一個指定座標的tilemap之後，還要再檢查此tilemap的上下左右4個方向是否也己經有tilemap存在，若是則需要再和它們作連通檢驗。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;底下只舉linkLeftEdge一例，其餘依此類推。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;void linkLeftEdge(leftTilemap)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;&amp;nbsp; // Link left col to right col of wt.&lt;/div&gt;&lt;div&gt;&amp;nbsp; foreach tile i of left col {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tileL = leftTilemap.tilemap[iL];&amp;nbsp; &amp;nbsp; // foreach tile iL of right col of leftTilemap.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tile = mTilemap[i] &amp;amp; ~(4 + 8);&amp;nbsp; &amp;nbsp; &amp;nbsp; // Clear top-left and bottom-left corner.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (tileL &amp;amp; 1) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Match top-right corner.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 8;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (tileL &amp;amp; 2) {&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Match bottom-right corner.&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; tile |= 4;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; tilemap[i] = tile;&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;下圖為以此方法生成的一個無限隨機地圖。(tileset來源為http://cr31.co.uk/stagecast/wang/tiles_c.html)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhSi7nDO2KALsPUY_aPtHET-ub2O7GbYibODOrs1T6O07fnW1sy25Mba1eKOYjBNEgoOrAV38Z-E8-unPA10zQ1atZXyMs09qzOFPNA4dsjivvcjE1Owb8YjdrU_kA0hLZKK3zCk9aE7WdNIH-vwVrLgWOcr4I0nFpGu5mxOlB4Cb2LnY412MWNX7GssQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhSi7nDO2KALsPUY_aPtHET-ub2O7GbYibODOrs1T6O07fnW1sy25Mba1eKOYjBNEgoOrAV38Z-E8-unPA10zQ1atZXyMs09qzOFPNA4dsjivvcjE1Owb8YjdrU_kA0hLZKK3zCk9aE7WdNIH-vwVrLgWOcr4I0nFpGu5mxOlB4Cb2LnY412MWNX7GssQ=w640-h342&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2023/03/wang-tiles.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEit6CIkK9pGwn1tVkFiRGQ_w7aje4lgJ0xOqWPPEVNoYtEYywbluJATNseYi5S6m_7w8J0vUvoLHnrd_iijOuVb_d9soIP_sUTvkAtYyhHa9bpQZycRZTcEsDSHJ05dzyXkqD-ZJST-E2Xewl5N1E89i9cDfKUmvotJ1leS3C1YOXeZvfzP44nx_3UnBQ=s72-w640-h328-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-5810845288694807621</guid><pubDate>Sun, 24 Jul 2022 08:47:00 +0000</pubDate><atom:updated>2022-11-02T11:09:53.007+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">Emscripten</category><category domain="http://www.blogger.com/atom/ns#">good</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">Porting</category><title>Good Game Editor HTML5 porting (resource browser)</title><description>&lt;p&gt;斷斷續續製作了一個HTML5版本的Good Game Editor，一方面是作為測試及學習web相關技術，一方面也是利用這個過程持續對good作點改良。雖然目的是想作一個HTML5版的編輯器，但實際上目前只作到resource browser，可以在web browser開啟good package作資源檢視。目前大部份的功能還是原來的C++ code直接以emscripten編譯成javascript，再加上少部份javascript，最後利用w3.css作排版。&lt;/p&gt;&lt;p&gt;&amp;lt;&lt;a href=&quot;https://smallworld.idv.tw/game/good/&quot;&gt;試試&lt;/a&gt;&amp;gt;&lt;/p&gt;&lt;p&gt;點擊連結會列出網站上good/uploads目錄下的所有good package，可以再點擊package的play來試玩或者是edit開啟編輯器(res browser)。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhIKQ9vTHIaejyzcqKxFpA3ByoYE83HPLpuUU3WTb1CeraktchtfvQQy1IXQJCFhByXOvQ6JIpBqMYbXXwchtqVZa77xfk9qR9a80PCa15pfPNmUa6-ocdnxDzutxewG3OzdYVsoEwO_z5j0XeXyK_vbrYbIZk0wZQFD8GGnNK8hY_iTgyEP2Cy1CsMlQ&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;303&quot; data-original-width=&quot;692&quot; height=&quot;140&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEhIKQ9vTHIaejyzcqKxFpA3ByoYE83HPLpuUU3WTb1CeraktchtfvQQy1IXQJCFhByXOvQ6JIpBqMYbXXwchtqVZa77xfk9qR9a80PCa15pfPNmUa6-ocdnxDzutxewG3OzdYVsoEwO_z5j0XeXyK_vbrYbIZk0wZQFD8GGnNK8hY_iTgyEP2Cy1CsMlQ&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;目前編輯器大致可以檢視所有類型的資源，包含聲音(audio)、貼圖(texture)、精靈(sprite)、地圖(tilemap)、關卡(level)、腳本(script)及粒子腳本(particle)。&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;如下圖，為點擊herobye.zip這個package的Edit時顯示的第一個畫面。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5Jt3lD1kUrYMz9w2QXqF74vMY5h_n2ZlQQEi-iYusNNezHKOecbH734xU-7ZuvEkx1iTgtrlDKSV5e7PD0AXrpgfGBtSTPv93PnOH1ewr-Aumzjp2w0dK2kLL0KXy0pN_eVV4pLVzwXO1meexX_MLICrqszqagcAzyUvf60AXu4uPgDIxogA8K3_3Wg/s1366/prj.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;341&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5Jt3lD1kUrYMz9w2QXqF74vMY5h_n2ZlQQEi-iYusNNezHKOecbH734xU-7ZuvEkx1iTgtrlDKSV5e7PD0AXrpgfGBtSTPv93PnOH1ewr-Aumzjp2w0dK2kLL0KXy0pN_eVV4pLVzwXO1meexX_MLICrqszqagcAzyUvf60AXu4uPgDIxogA8K3_3Wg/w640-h341/prj.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;編輯器畫面主要分為3個部份。左側依據不同類型資源，列出所有資源列表。右側是屬性顯示區，顯示選取的物件屬性資料。中間區域為編輯區，依據選取的不同類型物件作不同顯示。&lt;/p&gt;&lt;p&gt;下圖是選取了聲音(audio)類型的資源，編輯區顯示標準的播放聲音介面。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXRSaeS2o_IbM2OIN0EoHGlJ9nKpY_SO5orTZ4HkRRAAZ1LUHebNrplyU6yRr0kFlsgaTPeIJeBSiwzpijYL2U3sE-0XUNbfMSCPVxErIhXXYnDeTz_MOpwTJwyaM8b8uGWFEZCtiZbU1T9QPafRX-EZoUXBaS3uZG-RoXyLDLrm88hlrXD9Q7kT67pg/s1366/audio.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXRSaeS2o_IbM2OIN0EoHGlJ9nKpY_SO5orTZ4HkRRAAZ1LUHebNrplyU6yRr0kFlsgaTPeIJeBSiwzpijYL2U3sE-0XUNbfMSCPVxErIhXXYnDeTz_MOpwTJwyaM8b8uGWFEZCtiZbU1T9QPafRX-EZoUXBaS3uZG-RoXyLDLrm88hlrXD9Q7kT67pg/w640-h342/audio.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;下圖是選取了貼圖(texture)類型的資源。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZloNYkfW-8lR2Cm8uS-mYe4CauDAADOFVWl_ykg3_000N9hMIHSQUgUUHlb7OM-6vuQ1VwA8kypq_0eSEZSaIe0j1EZIDBIpT7zapCEQnHN4mjOuL-O2n4AVsuyp-xBkNLy5sJKhXRVGxC_5KmpHDu-Qsq1T_9782W6_ovlB6xBCbBIPk-Bq98_XRLw/s1366/tex.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZloNYkfW-8lR2Cm8uS-mYe4CauDAADOFVWl_ykg3_000N9hMIHSQUgUUHlb7OM-6vuQ1VwA8kypq_0eSEZSaIe0j1EZIDBIpT7zapCEQnHN4mjOuL-O2n4AVsuyp-xBkNLy5sJKhXRVGxC_5KmpHDu-Qsq1T_9782W6_ovlB6xBCbBIPk-Bq98_XRLw/w640-h342/tex.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;如下圖是選取了精靈(sprite)類型的資源，編輯區顯示此精靈每個frame的資訊及在上方播放精靈動畫。而右側屬性區也會顯示此精靈使用的貼圖物件。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCzNRvSNZcOvVlHlJejKvffnh39TbNK97vdhkzwWnjcpht2AYHXef2b157xQSpTy8E5w1sIuSlh7zS11UMLd96-yHOuavux3oe1ygshINwSVUruUYcdMgmCXByhlSfJ1XB7aBvvZTEbLIekqBi-iEb5aa1Af92c5tk8V0fK-FLQUBjBIum6VlWyZ1AoQ/s1366/sprite.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCzNRvSNZcOvVlHlJejKvffnh39TbNK97vdhkzwWnjcpht2AYHXef2b157xQSpTy8E5w1sIuSlh7zS11UMLd96-yHOuavux3oe1ygshINwSVUruUYcdMgmCXByhlSfJ1XB7aBvvZTEbLIekqBi-iEb5aa1Af92c5tk8V0fK-FLQUBjBIum6VlWyZ1AoQ/w640-h342/sprite.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;下圖是選取的地圖(tilemap)類型的資源，編輯區顯示己編輯的tilemap，右側屬性區也會顯示目前地圖使用的貼圖。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYtfFCLpeWbPQSbsyl0aLstsR4wMysWAwIC3_MRJD3hUjrG1OQKMEWfIGLQAVPlRfMTXC061dVWehE9wKegmoshrf1i-t0zk8U1bFTpho7FhZX_yjX2Vd-xLEDJAIQfwAHvmr9VVlBIlt8-lHjGG7ZzlxY7fH10eKY5R8hn8olcbF6f_yCQkutlhIFjg/s1366/map.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYtfFCLpeWbPQSbsyl0aLstsR4wMysWAwIC3_MRJD3hUjrG1OQKMEWfIGLQAVPlRfMTXC061dVWehE9wKegmoshrf1i-t0zk8U1bFTpho7FhZX_yjX2Vd-xLEDJAIQfwAHvmr9VVlBIlt8-lHjGG7ZzlxY7fH10eKY5R8hn8olcbF6f_yCQkutlhIFjg/w640-h342/map.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;下圖為選取關卡(level)類型的資源，編輯區顯示關卡內容，右側屬性區上方顯示關卡內物件的階層圖。點擊階層圖上的子物件時，右側屬性區下方會再顯示選取子物件的屬性資訊。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidkU55ZpQ4nSplxiAxvpbu9gNvKMmg8XgrD5U9GXjXOpLqWsvxfd4-yS0obMkjZMsSiaSW8TdXAVwfegVqKZdImmrbP37VavwJWuxiCladp1ALiLEEh7VpvOu7YNo-8IuZXfUa9eVi5rMs59tKxSFqG_ZguZDlOhqleF7nRFF6BrU8d8AjRoUV-DynPA/s1366/lvl.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidkU55ZpQ4nSplxiAxvpbu9gNvKMmg8XgrD5U9GXjXOpLqWsvxfd4-yS0obMkjZMsSiaSW8TdXAVwfegVqKZdImmrbP37VavwJWuxiCladp1ALiLEEh7VpvOu7YNo-8IuZXfUa9eVi5rMs59tKxSFqG_ZguZDlOhqleF7nRFF6BrU8d8AjRoUV-DynPA/w640-h342/lvl.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;下圖為選取腳本(script)類型的資源。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9IijX-gffZ4w2EjtTclY6o2OxEzCga53aaOG9FTxffKI4NpYuu6RRTmNb0PlzkHv4Ua0coRGWh9wTrJgp4v7CAUbnUCDk-4_oIUC0PWToOb9-JwBGqdizAXxYUHAKbO4jW2WneYx-WJ2o8wHf_AtHXd0ZUCrQ6dDbYv0rKRQwCF-pJnzkrPiSPO6c0w/s1366/script.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9IijX-gffZ4w2EjtTclY6o2OxEzCga53aaOG9FTxffKI4NpYuu6RRTmNb0PlzkHv4Ua0coRGWh9wTrJgp4v7CAUbnUCDk-4_oIUC0PWToOb9-JwBGqdizAXxYUHAKbO4jW2WneYx-WJ2o8wHf_AtHXd0ZUCrQ6dDbYv0rKRQwCF-pJnzkrPiSPO6c0w/w640-h342/script.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;下圖為選取粒子腳本(particle)類型資源。編輯區有二個分頁，左分頁Source同腳本一樣顯示script內容。右分頁Test為粒子執行preview畫面，同時右側屬性區上方也會列出所有可測試的particle script名稱，點擊時立即執行作preview。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzMJOhaTwaQ1dx6l2zUEr0DgqfBD5_6auEpzOp9hB1JcKr91kbytdMWVxl7GGymRPVbyxLukJD2zHRRQ5M2u2XxN_WFd3ZzaQ5VABQDTkXQU7ihkdlXX5XPsTSmKOsG40_YTcjTTDldfnPkipdetAvkXtf12kOpG7nFebWPjOgt_uXNx_pYpDG-3Tllw/s1366/stge.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;728&quot; data-original-width=&quot;1366&quot; height=&quot;342&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzMJOhaTwaQ1dx6l2zUEr0DgqfBD5_6auEpzOp9hB1JcKr91kbytdMWVxl7GGymRPVbyxLukJD2zHRRQ5M2u2XxN_WFd3ZzaQ5VABQDTkXQU7ihkdlXX5XPsTSmKOsG40_YTcjTTDldfnPkipdetAvkXtf12kOpG7nFebWPjOgt_uXNx_pYpDG-3Tllw/w640-h342/stge.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;以上是目前Good Game Editor HTML5的移植，還會持續update。&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description><link>http://good-ed.blogspot.com/2022/07/good-game-editor-html5-porting-resource.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEhIKQ9vTHIaejyzcqKxFpA3ByoYE83HPLpuUU3WTb1CeraktchtfvQQy1IXQJCFhByXOvQ6JIpBqMYbXXwchtqVZa77xfk9qR9a80PCa15pfPNmUa6-ocdnxDzutxewG3OzdYVsoEwO_z5j0XeXyK_vbrYbIZk0wZQFD8GGnNK8hY_iTgyEP2Cy1CsMlQ=s72-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-911872251545679881</guid><pubDate>Thu, 02 Jun 2022 08:32:00 +0000</pubDate><atom:updated>2022-11-02T11:10:21.861+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">C/C++</category><category domain="http://www.blogger.com/atom/ns#">Emscripten</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">Porting</category><category domain="http://www.blogger.com/atom/ns#">Win32</category><title>867的HTML5移植</title><description>&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;[&lt;a href=&quot;https://smallworld.idv.tw/game/867/&quot;&gt;PLAY&lt;/a&gt;]&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;這個遊戲是較早期的作品，所以使用的技術是以當時自己較熟悉的&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Win32_api&quot; style=&quot;color: blue; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify; text-decoration-line: none;&quot;&gt;Win32&lt;/a&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;相關技術製作。遊戲核心部份一開始就己分離出來，但還不是100%跨平台。畫面部份是以Win32 GDI呈現，以及透過Windows視窗機制處理輸入。本次目標是將遊戲移植到&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/HTML5&quot; style=&quot;color: blue; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify; text-decoration-line: none;&quot;&gt;HTML5&lt;/a&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;，主要的工作有三個部份。&lt;/span&gt;&lt;/p&gt;&lt;ol style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;li&gt;將遊戲核心Gameplay確實作到跨平台。&lt;/li&gt;&lt;li&gt;將畫圖及輸入部份抽離作到跨平台。&lt;/li&gt;&lt;li&gt;將遊戲移植為HTML5可以在Browser上執行。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;第一部份己幾乎完成了，只需再作點小修改就能達成。主要的移植工作在於第二和第三部份，以下是這部份工作的重點記錄。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;抽離繪圖層&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;因為867和Win32 GDI緊密結合，一時無法輕易的將繪圖層抽離出來。萬事起頭難，可以先從最簡單的改良開始，一次一小步逐步重整。首先增加一個Renderer類別，只包含一個很大略的一個render函數。而render函數的實作，是根據當前遊戲狀態透過renderTitle和renderGame二個函數實作遊戲的全部繪圖。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;class Renderer
{
public:
  void render(const Game &amp;amp;game, CDCHandle&amp;amp; dc)
  {
    switch (game.iStage)
    {
    case Game::STAGE_TITLE:
      renderTitle(dc);
      break;
    case Game::STAGE_GAME:
      renderGame(dc, Game::MENU_NONE);
      break;
    case Game::STAGE_MENU:
      renderGame(dc, Game::MENU_GAME);
      break;
    case Game::STAGE_DIE:
      renderGame(dc, Game::MENU_NONE);
      break;
    case Game::STAGE_OVER:
      renderGame(dc, Game::MENU_OVER);
      break;
    case Game::STAGE_WIN:
      renderGame(dc, Game::MENU_NONE);
      break;
    }
  }
  virtual void renderTitle(CDCHandle&amp;amp; dc) {...}
  virtual void renderGame(CDCHandle&amp;amp; dc, int menu) {...}
};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;Renderer的renderTitle及renderGame的內容，是整個從原來和Win32 GDI相依的程式完整的搬過來，現在先忽略它。定義Renderer後，原來在視窗裡的畫圖部份就可以以Renderer替換。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;// Render game.
CClientDC dc(m_hWnd);
RECT rc = {0, 0, SCREEN_W, SCREEN_H};
CMemoryDC memdc(dc, rc);
Renderer renderer;
renderer.render(game, memdc);&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;注意到上面呼叫Renderer::render時，傳入的第二個參數memdc目前還是一樣跟Win32平台相關。底下繼續對Renderer::renderTitle整理，抽出幾個子函數。這些子函數的參數裡還是有許多和Win32平台相依的部份，也暫時忽略。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;class Renderer
{
public:
  ...
  virtual void drawMenuStrings(CDCHandle&amp;amp; dc, int idsStart, int idsEnd, int xOffset, int yOffset, COLORREF clrNormal = RGB(0,0,0), COLORREF clrSelect = RGB(255,0,0)) const=0;
  virtual void drawMenuBar(CDCHandle&amp;amp; dc, int xOffset, int yOffset) const=0;
  virtual void drawMsgIcon(CDCHandle&amp;amp; dc, int offsetMsg, int w, int h, int xSrc, int ySrc) const=0;
  virtual void fillRect(CDCHandle&amp;amp; dc, LPCRECT lpRect, int brush) const=0;
};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;繼續對Renderer::renderGame作類似整理，抽出幾個子函數。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;class Renderer
{
public:
  ...
  virtual void drawAlphaRect(CDCHandle&amp;amp; dc, int brush, int x, int y, int w, int h, int step) const=0;
  virtual void drawFadeText(CDCHandle&amp;amp; dc, const char* str, int step, int x, int y) const=0;
  virtual void drawFireBall(CDCHandle&amp;amp; dc, int iBallImg, int xOffset, int yOffset, int shift) const=0;
  virtual void drawPlayer(CDCHandle&amp;amp; dc, int x, int y, int frame, int dir) const=0;
  virtual void drawPlane(CDCHandle&amp;amp; dc, int x, int y, int dir) const=0;
};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;接著定義一個Win32Renderer繼承自Renderer，並實作上面那些純虛擬的畫圖子函數，然後在遊戲繪圖部份以Win32Renderer替換。這樣就能逐步的把平台無關和平台相關的繪圖程式碼抽離。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;// Define Win32 Renderer.
class Win32Renderer : public Renderer
{
public:
  ...
  virtual void drawMenuStrings(CDCHandle&amp;amp; dc, int idsStart, int idsEnd, int xOffset, int yOffset, COLORREF clrNormal = RGB(0,0,0), COLORREF clrSelect = RGB(255,0,0)) const {...}
  virtual void drawMenuBar(CDCHandle&amp;amp; dc, int xOffset, int yOffset) const {...}
  virtual void drawMsgIcon(CDCHandle&amp;amp; dc, int offsetMsg, int w, int h, int xSrc, int ySrc) const {...}
  virtual void fillRect(CDCHandle&amp;amp; dc, LPCRECT lpRect, int brush) const {...}
};

// Render game.
...
Win32Renderer win32renderer;
win32renderer.render(game, memdc);&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;重複上面的步驟，將各個render子函數持續抽象化，盡可能的把更小的可能和平台有關的子函數抽出來，只保留和平台無關的部份。接下來開始逐步替換平台相依的部份，一次替換一個。首先把CDCHandle抽象化替換為void*，底下以Renderer::fillRect為例。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;// Renderer base.
class Renderer
{
public:
  ...
  virtual void fillRect(void *pCtx, LPCRECT lpRect, int brush) const=0;
};

// Render game.
...
Win32Renderer win32renderer;
win32renderer.render(game, (void*)(HDC)memdc);

// Win32 renderer.
class Win32Renderer : public Renderer
{
public:
  ...
  virtual void fillRect(void *pCtx, LPCRECT lpRect, int brush) const
  {
    CDCHandle dc((HDC)pCtx);
    ...
  }
};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如上所示，把Renderer::fillRect的HDC參數替換成void*後。在遊戲繪圖呼叫render，傳入第二個平台相依的參數memdc時，作一個將dc轉型抽象為和平台無關的型別void*。而在平台相依的Win32Renderer::fillRect實作裡，再作一次將void*轉型回平台相依的HDC型別，底下其它實作照舊不變。這個動作好像多此一舉，但這個處理就能把平台相關的東西全部從平台無關的Renderer裡搬到外面，而達到跨平台的目的。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;注意上面的兩個主要的操作：一、抽出平台相依的子函數及二、替換平台相依的參數，是可以交替進行的。持續以上操作，盡可能把平台相關和無關的部份以這種方式逐步抽離乾淨，直到可以很容易的作到跨平台移植。&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;遊戲移植到HTML5&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;HTML5的移植主要透過&lt;/span&gt;&lt;a href=&quot;https://emscripten.org/&quot; style=&quot;color: blue; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify; text-decoration-line: none;&quot;&gt;Emscripten&lt;/a&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;將跨平台的程式碼編譯成WebAssembly。跨平台的程式碼包含有二部份，一個是和平台無關的可以直接移植的程式碼，也就是像上面的Renderer的部份。另一部份是和平台相依的需要作移植的程式碼，像是上面的Win32Renderer的部份。這裡要作的是定義一個EmscRenderer繼承自Renderer，並實作所有需要跨平台到HTML5的子函數。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;class EmscRenderer : public _867::Renderer
{
public:

  virtual void drawAlphaRect(void *pCtx, int brush, int x, int y, int w, int h, int step) const;
  virtual void drawAlphaText(void *pCtx, const char* s, int step, int x, int y) const;
  virtual void drawFireBall(void *pCtx, int iBallImg, int xOffset, int yOffset, int shift) const;
  virtual void drawGameFinText(void *pCtx, const char *s, const sw2::IntRect &amp;amp;rc) const;
  virtual void drawGameScore(const _867::Game &amp;amp;game, void* pCtx, int x, int y) const;
  virtual void drawMenuStrings(void *pCtx, const char* str[], int xOffset, int yOffset, int clrNormal = COLOR_BLACK, int clrSelect = COLOR_RED) const;
  virtual void drawMenuBar(void *pCtx, int xOffset, int yOffset) const;
  virtual void drawMsgIcon(void *pCtx, int offsetMsg, int w, int h, int xSrc, int ySrc) const;
  virtual void drawPlayer(void *pCtx, int x, int y, int w, int h, int frame, int dir) const;
  virtual void drawPlane(void *pCtx, int x, int y, int w, int h, int dir) const;
  virtual void drawTitleBkgndText(void *pCtx, const char* s, const sw2::IntRect &amp;amp;rc) const;
  virtual void fillRect(void *pCtx, const sw2::IntRect &amp;amp;rc, int brush) const;
};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;實作的細節沒什麼特別的，這裡不特別說明。底下只針對幾個需要作特別的處理，作了記錄。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;轉換有Color Key的圖形為ARGB格式&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;早期要作簍空貼圖都是使用Color Key作法，也就是指定2D圖形裡某個顏色的RGB值作為Color Key，繪圖時只要是這張貼圖裡的像素的RGB是和Color Key相同，則這些像素就不會被繪出來。如下圖是遊戲裡使用的紙飛機的貼圖，大片的紫色色塊的紫色RGB(254,0,255)作為Color Key。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZv6ogNcd79yi3IvVW4gOx5N7J8Ri9JioNoDzzPSFNHUb9Ez3yg45F9krKOYSJm9E9v9f2XV6_B7yIyUfUJWzfr7nXIGdnuHDajhfuiFFSM_bu6KQv4PI56dQGq5Nld_4kID2nnTObfFzdnZ7iYZ8HWOlEOklHT1jeZMJe4lz0eHu3G-57x_qhAI9JfA/s64/plane.bmp&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;32&quot; data-original-width=&quot;64&quot; height=&quot;32&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZv6ogNcd79yi3IvVW4gOx5N7J8Ri9JioNoDzzPSFNHUb9Ez3yg45F9krKOYSJm9E9v9f2XV6_B7yIyUfUJWzfr7nXIGdnuHDajhfuiFFSM_bu6KQv4PI56dQGq5Nld_4kID2nnTObfFzdnZ7iYZ8HWOlEOklHT1jeZMJe4lz0eHu3G-57x_qhAI9JfA/s1600/plane.bmp&quot; width=&quot;64&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;因為不想要改變原始貼圖格式及繪圖方式，所以一個簡單的作法是HTML5版本中，把原來的使用Color Key的貼圖作一個轉換，轉換成ARGB格式，這樣在HTML5使用drawImage時就自然可以作簍空貼圖。&lt;/p&gt;&lt;p style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;轉換的方法很簡單，步驟如下。&lt;/p&gt;&lt;ol style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;li&gt;將原始貼圖畫到一個memory canvas。&lt;/li&gt;&lt;li&gt;將這個canvas裡的所有像素取出處理，如果像素的RGB值和Color Key相同，則把這個像素的alpha清0。&lt;/li&gt;&lt;li&gt;以處理過的memory canvas建立一個新的貼圖img，使用這個img作為新貼圖來源。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;如下所示，為轉換程式碼片斷。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;&amp;lt;img id=&quot;imgPlane&quot; src=&quot;plane.bmp&quot; alt=&quot;&quot; style=&quot;display:none;&quot;/&amp;gt;
&amp;lt;img id=&quot;imgRole&quot; src=&quot;role.bmp&quot; alt=&quot;&quot; style=&quot;display:none;&quot;/&amp;gt;

&amp;lt;script&amp;gt;
function convertColorKeyedImg(id) {
  var img = document.getElementById(id);
  var canvas = document.createElement(&#39;canvas&#39;);
  canvas.width = img.width;
  canvas.height = img.height;
  var ctx = canvas.getContext(&#39;2d&#39;);
  ctx.drawImage(img, 0, 0);
  var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imgData.data;
  var Color Key = [data[0], data[1], data[2]];
  for (var i = 0; i &amp;lt; data.length; i += 4) {
    if (data[i] == Color Key[0] &amp;amp;&amp;amp;
        data[i + 1] == Color Key[1] &amp;amp;&amp;amp;
        data[i + 2] == Color Key[2]) {
      data[i + 3] = 0;
    }
  }
  ctx.putImageData(imgData, 0, 0);
  img.src = canvas.toDataURL(&#39;image/png&#39;);
}

convertColorKeyedImg(&#39;imgRole&#39;);
convertColorKeyedImg(&#39;imgPlane&#39;);
&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;畫火球&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;畫火球主要有兩個步驟。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;li&gt;產生火焰圖。&lt;/li&gt;&lt;li&gt;以火焰圖作底圖，畫出彈性球形。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;產生火焰圖的部份這裡略過，網路上有許多產生火焰效果圖的資料。這裡說明怎麼利用事先建好的火焰圖作貼圖，畫出彈跳的球形。這裡的作法還是一樣利用一個memory canvas，步驟如下。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;li&gt;建立一個memory canvas。&lt;/li&gt;&lt;li&gt;在memory canvas上根據扁平需求畫一個紅色ellipse。&lt;/li&gt;&lt;li&gt;取出memory canvas所有像素，把所有紅色像素替換為火焰圖貼圖裡對應座標的像素。&lt;/li&gt;&lt;li&gt;將memory canvas的內容畫到指定畫面位置。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;程式片斷如下。&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style=&quot;border-left: 4px solid; font-size: 13px; letter-spacing: 1px; line-height: 18px; margin: 1em; overflow: auto; padding: 1.5em; width: auto;&quot;&gt;function drawFireBall(x, y, w, h, W, H, xSrc, data, len) {
  var canvas1 = document.createElement(&#39;canvas&#39;);
  canvas1.width = w;
  canvas1.height = h;
  var ctx1 = canvas1.getContext(&#39;2d&#39;);
  ctx1.fillStyle = &#39;red&#39;;
  ctx1.beginPath();
  ctx1.ellipse(w/2, h/2, w/2, h/2, 0, 0, 2 * Math.PI);
  ctx1.fill();
  var imgData1 = ctx1.getImageData(0, 0, w, h);
  var data1 = imgData1.data;
  for (var i = 0; i &amp;lt; w; i++) {
    for (var j = 0; j &amp;lt; h; j++) {
      var idx1 = 4 * (i + j * w);
      if (255 == data1[idx1 + 0] &amp;amp;&amp;amp; 0 == data1[idx1 + 1] &amp;amp;&amp;amp; 0 == data1[idx1 + 2]) { // red pixel.
        var idx = 2 * (xSrc + i + (h - j - 1) * W);
        var c16 = getValue(data + idx, &#39;i16&#39;);
        var r5 = (c16 &amp;gt;&amp;gt; 11) &amp;amp; 0x1f;
        var g6 = (c16 &amp;gt;&amp;gt; 5) &amp;amp; 0x3f;
        var b5 = c16 &amp;amp; 0x1f;
        data1[idx1 + 0] = Math.floor(r5 * 255 / 31.0 + 0.5);
        data1[idx1 + 1] = Math.floor(g6 * 255 / 63.0 + 0.5);
        data1[idx1 + 2] = Math.floor(b5 * 255 / 31.0 + 0.5);
      }
    }
  }
  ctx1.putImageData(imgData1, 0, 0);
  ctx.drawImage(canvas1, x, y);
}&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;其實中間那個判斷是否為RGB(255,0,0)的if是可有可無的，因為畫ellipse時，範圖外不屬於扁平球的部份的alpha為0，不會被畫出來。只是多了這個檢查可以少作些運算。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2022/06/867html5.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZv6ogNcd79yi3IvVW4gOx5N7J8Ri9JioNoDzzPSFNHUb9Ez3yg45F9krKOYSJm9E9v9f2XV6_B7yIyUfUJWzfr7nXIGdnuHDajhfuiFFSM_bu6KQv4PI56dQGq5Nld_4kID2nnTObfFzdnZ7iYZ8HWOlEOklHT1jeZMJe4lz0eHu3G-57x_qhAI9JfA/s72-c/plane.bmp" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-2726940263642209350</guid><pubDate>Sat, 19 Mar 2022 15:29:00 +0000</pubDate><atom:updated>2022-11-02T11:10:40.043+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Android</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><title>耐心烏龜 Patience</title><description>&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;有一次去看診的時候，因為等了好久等到有點快失去耐性，看完診花了不少時間。在回家的路上有感而發，想說不知道有沒有什麼可以訓練或培養耐性的方法。如果沒有的話，或者我自己可以作個APP來達到這個目的，最後就作了這個APP。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&amp;lt;&lt;a href=&quot;https://smallworld.idv.tw/game/patience&quot;&gt;玩&lt;/a&gt;&lt;a href=&quot;https://agile-hollows-18660.herokuapp.com/game/patience&quot;&gt;玩&lt;/a&gt;&amp;gt; &amp;lt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.weilican.patience&quot;&gt;Android&lt;/a&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgIEWpdiD5MohZm-Q2AnbWQ32U8LZv2-6I5vp2_2ot3BCAKwymcnVttCl5b-r1XsWhBPFKODtA5UdjeGvCssGV3FCuUvYK3qRfV7v9UC56qVPpHcI05un5YUmwFeTFywdSo5me3vdOCKBEEZPTOfjwK7wwyNHppGNszbp4pVVI4NGgkV_pfwT5QQYoW8A&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;480&quot; data-original-width=&quot;540&quot; height=&quot;356&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEgIEWpdiD5MohZm-Q2AnbWQ32U8LZv2-6I5vp2_2ot3BCAKwymcnVttCl5b-r1XsWhBPFKODtA5UdjeGvCssGV3FCuUvYK3qRfV7v9UC56qVPpHcI05un5YUmwFeTFywdSo5me3vdOCKBEEZPTOfjwK7wwyNHppGNszbp4pVVI4NGgkV_pfwT5QQYoW8A=w400-h356&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;一開始想到的不是烏龜，而是主畫面是一個泡泡。這個泡泡會愈來愈大，但很容易就破掉。比如不小心點了畫面、程式進入背景、有來電或收到訊息通知等等，都會讓泡泡破掉。程式的目的就是想辨法讓泡泡持續變大，也就是你愈有耐心的保護它，就愈成功。可能可以顯示一個存活時間，用來表示耐心度。&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;後來一邊考慮程式內容時，一邊把泡泡改成了烏龜。同時考慮到，如果這隻烏龜很容易就死掉，要用這種方式來訓練耐心似乎很難，甚至會有反效果。考慮到一次性的遊戲方式，以存活度來評價耐心度有難度，改變為養成性質的作法。現在不會死掉了，存活時間是累計制的。這樣子應該會比較容易讓人持續的去作這作事，長期下來應該就能提高點耐心吧。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;改成養成性質的作法後，其它的設計就能對應調整。首先除了存活度(存活時間)之外，再加上一個等級。這個等級的定義，只是簡單的每次烏龜從左走到右就升級一次。等級每升一級，烏龜就長大1個pixel。同時等級也對應烏龜移動速度，LV10表示每10秒烏龜走1個pixel。以上是核心功能，其它還設計了幾個裝飾畫面的功能。如上方背景日夜變化、月相變化及顯示12星座等。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;以下作重點說明。&lt;/span&gt;&lt;/p&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; letter-spacing: 2px; padding-bottom: 0.4em;&quot;&gt;背景連續山脈圖&lt;/h3&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;背景的山是先建好一個div元素，以CSS設定背景水平重複。&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;&amp;nbsp; // CSS.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; #mountains {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; background-repeat:repeat-x;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; background-position:bottom;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; text-align:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; right;font-size:48px;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; // HTML.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;lt;div style=&quot;mountains&quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px; text-align: justify;&quot;&gt;重複的圖片則以一記憶體canvas畫了一個山型emoji後產生。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var mountains = document.getElementById(&#39;mountains&#39;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var url = getCharImgUrl(32, &#39;⛰️&#39;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;mountains.style.backgroundImage = &#39;url(&quot;&#39; + url + &#39;&quot;)&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function drawCharCenter(ctx, size, s, x, y) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; ctx.font = size + &#39;px Arial&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; ctx.textBaseline = &#39;middle&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; ctx.textAlign = &#39;center&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; ctx.fillText(s, x, y);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function getCharImgUrl(size, s) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var canvas = document.createElement(&#39;canvas&#39;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; canvas.width = canvas.height = size;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var ctx = canvas.getContext(&#39;2d&#39;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; drawCharCenter(ctx, size, s, size/2, size/2);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return canvas.toDataURL();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; padding-bottom: 0.4em; text-align: left;&quot;&gt;背景日夜變化&lt;/h3&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;日夜變化是根據目前的時間來判斷是白天或黑夜，只是簡單的檢查目前小時來決定。&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function isNight() {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var now = new Date();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var hour = now.getHours();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return 6 &amp;gt; hour || 18 &amp;lt;= hour;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function getDayNightColor() {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; if (isNight()) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; return &#39;black&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; return &#39;skyblue&#39;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; padding-bottom: 0.4em; text-align: left;&quot;&gt;月相變化&lt;/h3&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;月相是根據取得目前年月日計算得到，公式是上網google得到。&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var now = new Date();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var phase = moonPhase(now.getFullYear(), now.getMonth() + 1, now.getDate());&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function moonPhase(year, month, day) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var lp = 2551443;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var now = new Date(year, month - 1, day, 20, 35,0);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var new_moon = new Date(1970, 0, 7, 20, 35, 0);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var phase = ((now.getTime() - new_moon.getTime())/1000) % lp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return Math.floor(phase / (24 * 3600)) + 1;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;月相圖則是根據計算得到的月相參數，再利用emoji內建的幾個月相圖作顯示。&lt;/div&gt;&lt;div&gt;&lt;blockquote style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;div&gt;function moonPhaseEmoji(day) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (1 &amp;lt;= day &amp;amp;&amp;amp; 30 &amp;gt;= day) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; var emoji = [&#39;🌑&#39;, &#39;🌒&#39;, &#39;🌒&#39;, &#39;🌒&#39;, &#39;🌒&#39;, &#39;🌓&#39;, &#39;🌓&#39;, &#39;🌓&#39;, &#39;🌓&#39;, &#39;🌔&#39;, &#39;🌔&#39;, &#39;🌔&#39;, &#39;🌔&#39;, &#39;🌕&#39;, &#39;🌕&#39;, &#39;🌕&#39;, &#39;🌖&#39;, &#39;🌖&#39;, &#39;🌖&#39;, &#39;🌖&#39;, &#39;🌗&#39;, &#39;🌗&#39;, &#39;🌗&#39;, &#39;🌗&#39;, &#39;🌘&#39;, &#39;🌘&#39;, &#39;🌘&#39;, &#39;🌘&#39;, &#39;🌘&#39;, &#39;🌑&#39;];&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; return emoji[day - 1];&lt;/div&gt;&lt;div&gt;&amp;nbsp; } else {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; return &#39; &#39;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/blockquote&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;h3 style=&quot;border-bottom: 1px solid black; padding-bottom: 0.4em; text-align: left;&quot;&gt;12星座&lt;/h3&gt;&lt;/div&gt;&lt;div style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;12星座是根據目前月日，作簡單判斷得到。&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var now = new Date();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var zodiac = getZodiacSign(now.getMonth() + 1, now.getDate());&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function getZodiacSign(month, day) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var astro_sign = &quot;&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; if (1 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 20)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Capricorn♑&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;aquarius♒&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (2 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 19)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Aquarius♒&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;pisces♓&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (3 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 21)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Pisces♓&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;aries♈&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (4 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 20)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Aries♈&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;taurus♉&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (5 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 21)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Taurus♉&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;gemini♊&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (6 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 21)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Gemini♊&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;cancer♋&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (7 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 23)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Cancer♋&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;leo♌&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if(8 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 23)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Leo♌&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;virgo♍&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (9 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 23)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Virgo♍&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;libra♎&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (10 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 23)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Libra♎&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;scorpio♏&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (11 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 22)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;scorpio♏&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;sagittarius♐&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; } else if (12 == month) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; if (day &amp;lt; 22)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign = &quot;Sagittarius♐&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; astro_sign =&quot;capricorn♑&quot;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return astro_sign;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2022/03/patience.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEgIEWpdiD5MohZm-Q2AnbWQ32U8LZv2-6I5vp2_2ot3BCAKwymcnVttCl5b-r1XsWhBPFKODtA5UdjeGvCssGV3FCuUvYK3qRfV7v9UC56qVPpHcI05un5YUmwFeTFywdSo5me3vdOCKBEEZPTOfjwK7wwyNHppGNszbp4pVVI4NGgkV_pfwT5QQYoW8A=s72-w400-h356-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-2071457039226792983</guid><pubDate>Thu, 23 Dec 2021 12:48:00 +0000</pubDate><atom:updated>2022-11-02T11:11:07.015+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>繪文字填圖 Emoji Paint</title><description>&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;這個遊戲的靈感是源自兒子的學校課本裡面，有個叫不插電程式課的書本裡面得到的。書裡面有一類型的題目就是把圖畫裡的數字填上對應的色塊，全部填滿後就能夠得到一張馬賽克風格的圖案。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;利用這個概念，再結合之前製作的&lt;/span&gt;&lt;a href=&quot;https://good-ed.blogspot.com/2020/12/emoji-scratch.html&quot; style=&quot;color: blue; font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px; text-decoration-line: none;&quot;&gt;繪文字刮刮樂&lt;/a&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;的分類資料，使用emoji製作了一個馬賽克像素風的填圖小遊戲。&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/emojipaint&quot;&gt;玩&lt;/a&gt; / &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.weilican.emojipaint&quot;&gt;Android&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg215B2iVTnuGVk81JO7ceIXD5ldCm2yZ-WwzuXHqStdEz22FMgKBOfjjenigZ_7UJ8sJbaf-LthIM3Ndoy4NArwdlPNkAeHNdLeJuPih-UCvhyWqNKC33H_WSX9CEZJVEN5nImm5zPiQtg7hAxk8IlS2EARH2YT1t8uTeLaK0i-q3wGT1RXFdmzzJ12A=s1350&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;480&quot; data-original-width=&quot;1350&quot; height=&quot;229&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEg215B2iVTnuGVk81JO7ceIXD5ldCm2yZ-WwzuXHqStdEz22FMgKBOfjjenigZ_7UJ8sJbaf-LthIM3Ndoy4NArwdlPNkAeHNdLeJuPih-UCvhyWqNKC33H_WSX9CEZJVEN5nImm5zPiQtg7hAxk8IlS2EARH2YT1t8uTeLaK0i-q3wGT1RXFdmzzJ12A=w640-h229&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;底下是這個小遊戲的製作技術重點。&lt;/span&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;b&gt;圖片馬賽克化&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;把圖片馬賽克化的原理很簡單，簡單的講就是：&lt;/span&gt;&lt;/p&gt;&lt;ol style=&quot;font-family: Arial, Helvetica, sans-serif; font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;li&gt;先把整張圖片根據馬賽克大小作切割。&lt;/li&gt;&lt;li&gt;對每一塊切割下來的馬賽克圖塊裡面的所有像素的顏色計算平均值。&lt;/li&gt;&lt;li&gt;使用計算出來的平均顏色填滿馬賽克圖塊。&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;對所有馬賽克圖塊作同樣處理，這樣就完成了把一張圖片馬賽克化了，接下來底下說明一些實作細節。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;1、繪文字填圖的馬賽克分為大中小三種尺寸，為了在手機上最後呈現的畫面尺寸大小適中，把canvas的大小設定為400x400px。為了方便計算，三種馬賽克方塊的大小分別為：16x16、25x25及40x40，16、25及40正好都可以整除400。在遊戲主選單最下方選擇馬賽克尺寸後，就會以這個大小對400x400尺寸的原圖作馬賽克化的切割。如果選擇最小尺寸的馬賽克，則原圖被切割成25x25個圖塊。如果選擇中等尺寸的馬賽克，則原圖被切割成16x16個圖塊。若選擇最大尺寸的馬賽克，則原圖被切割成10x10個圖塊。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;2、計算每個馬賽克圖塊的平均顏色的方法很直接，就是對圖塊中每一個Pixel加總後，再除以Pixel總數得到平均值。需注意的是，加總再求平均的計算是要對顏色的RGB值各別作。最後把得到的平均的RGB值，再組成一個新的顏色作為整個馬賽克圖塊的顏色。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function sumRgb(data, x, y, cw, ch) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; var rgb = [0, 0, 0];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; for (var i = 0; i &amp;lt; cw; i++) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; for (var j = 0; j &amp;lt; ch; j++) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; var idx = 4 * ((x + i) + (y + j) * canvas.width);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; rgb[0] += data[idx];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; rgb[1] += data[idx + 1];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; rgb[2] += data[idx + 2];&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; for (var i = 0; i &amp;lt; rgb.length; i++) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; &amp;nbsp; rgb[i] = clamp(rgb[i] / (cw * ch));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return rgb;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;data是透過canvas的context2d.getImageData得到的，而cw及ch是馬賽克尺寸，一般cw=ch為正方形。而x及y是馬賽克圖塊在原圖中的左上角座標。注意在sumRgb最後對各別RGB值求平均時還作了一個clamp的動作。這個clamp其實是一個類似四拾五入的動作，目的是為了要減少最後整個原圖馬賽克化的顏色數量，讓調色盤的顏色數不要那麼多。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var CLAMP_EMOJI = 32;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;var CLAMP_NUM = CLAMP_EMOJI;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;function clamp(n) {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&amp;nbsp; return CLAMP_NUM * Math.round(n / CLAMP_NUM);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot;&gt;&lt;span style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;3、整張原圖馬賽克化後，就可以根據所有馬賽克圖塊的顏色建立一個調色盤。再根據這個調色盤再把馬賽克化的原圖，轉換成數字謎題圖。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);&lt;/div&gt;&lt;div&gt;var col = canvas.width / cw;&lt;/div&gt;&lt;div&gt;var row = canvas.height / ch;&lt;/div&gt;&lt;div&gt;var colors = [];&lt;/div&gt;&lt;div&gt;for (var i = 0; i &amp;lt; col; i++) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; for (var j = 0; j &amp;lt; row; j++) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; var x = cw * i;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; var y = ch * j;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; var rgb = sumRgb(imgData.data, x, y, cw, ch);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx.fillStyle = &#39;rgb(&#39; + rgb[0] + &#39;,&#39; + rgb[1] + &#39;,&#39; + rgb[2] + &#39;)&#39;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; var index = colors.indexOf(ctx.fillStyle);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; if (-1 == index) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; colors.push(ctx.fillStyle);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; }&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2021/12/emoji-paint.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEg215B2iVTnuGVk81JO7ceIXD5ldCm2yZ-WwzuXHqStdEz22FMgKBOfjjenigZ_7UJ8sJbaf-LthIM3Ndoy4NArwdlPNkAeHNdLeJuPih-UCvhyWqNKC33H_WSX9CEZJVEN5nImm5zPiQtg7hAxk8IlS2EARH2YT1t8uTeLaK0i-q3wGT1RXFdmzzJ12A=s72-w640-h229-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-1590433210852016135</guid><pubDate>Sat, 21 Aug 2021 02:59:00 +0000</pubDate><atom:updated>2022-11-02T11:11:32.793+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>勇者小白</title><description>&lt;p&gt;勇者小白是一個簡單的冒險小遊戲，主要由三大系統構成：任務系統、對話系統和背包系統。由小遊戲和過場劇情對話把遊戲故事串連起來，目前小遊戲數量己經有30個，還在持續增加中。這些小遊戲和故事，大部份由我設計製作，有些是和兒子一起設計由我製作。&lt;/p&gt;&lt;p&gt;從我兒子幼兒園開始就就只會讓小孩玩勇者小白，後來女兒也開始玩了。其間也試著引導小孩幫忙設計內容，雖然效果還不明顯，不過多少也為生活增加點樂趣。遊戲裡面的資源儘量都是網路上的免費資料，而有些是自己簡單製作的，但也有些就是借用的，那天有問題時再作更換。&lt;/p&gt;&lt;p&gt;總之，勇者小白會持續不斷的增加內容。&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvBHxmOBTNxCgpdZB4cGVYAKwL89ide251iai5xH2UBGkPmYJXXKNrte5HSL4vQxMeBLbDSrq-U0-N_40hyZQC9ka0xWqtBgNDINHKD-SIqJjYnT-biMy_sgdE_ow9ZRp3tEI1RDKLH8Qq/s642/3470.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvBHxmOBTNxCgpdZB4cGVYAKwL89ide251iai5xH2UBGkPmYJXXKNrte5HSL4vQxMeBLbDSrq-U0-N_40hyZQC9ka0xWqtBgNDINHKD-SIqJjYnT-biMy_sgdE_ow9ZRp3tEI1RDKLH8Qq/w400-h259/3470.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/good/play.html?pkg=herobye.zip&quot;&gt;試玩&lt;/a&gt;&amp;nbsp;/ &lt;a href=&quot;https://github.com/cnyaw/herobye&quot;&gt;Source&lt;/a&gt;&lt;br /&gt;&lt;p&gt;;-----&lt;/p&gt;&lt;p&gt;很久之前我就想要製作一個冒險類的小遊戲，所以某天靈感來了很快的寫了幾頁的故事大綱。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;早上起床的時候發現小白不見了&lt;/li&gt;&lt;li&gt;一出門外星人巨大的太空船蓋住整個天空，廣播說要你們好看&lt;/li&gt;&lt;li&gt;跟爺爺說明，爺爺說出一段古老的傳說，需要3把神兵利器才能把外星人打跑，分別是(xx,yy,zz-要命名)&lt;/li&gt;&lt;li&gt;突然發現爺爺用來抓癢的手牌不求人是其中一把神兵(布)-獲得(布)&lt;/li&gt;&lt;li&gt;爺爺說張媽媽家有另一把神兵，於是去找張媽媽&lt;/li&gt;&lt;li&gt;張媽媽在她家門口曬衣服，她說她家的傳家之寶封印在洞穴內，被祖先保管著要通過考驗才能取得&lt;/li&gt;&lt;li&gt;到洞穴，用手牌不求人解開封印，進去後通過考驗(倉庫番)，和祖先對話取得寶箱，打開是空的...&lt;/li&gt;&lt;li&gt;回去找張媽媽說明-原來她把傳家之寶拿來當曬衣杆-獲得(石頭)&lt;/li&gt;&lt;li&gt;從張媽媽得知另一把神兵是由小香家保管的&lt;/li&gt;&lt;li&gt;小香正在作美勞作業，(取得布和石頭前她只會在門口玩)，發現她桌上有一把美勞用的剪刀，不過要拿棒棒糖來換&lt;/li&gt;&lt;li&gt;跑到雜貨店去，結果沒有錢，回去找爺爺要5塊再到雜貨店買棒棒糖(要今天的零用 錢)&lt;/li&gt;&lt;li&gt;拿著棒棒糖去和小香換到剪刀，但是沒有神力不能用&lt;/li&gt;&lt;li&gt;此時小香爸爸出現，他說他的傳家之寶是一段咒語，可以附與剪刀神力變成神之剪刀，不過還缺少桿子的部份&lt;/li&gt;&lt;li&gt;到搖滾阿凱家去，向他借打鼓棒，不過要先幫他找回偷跑的小烏龜&lt;/li&gt;&lt;li&gt;找小香爸爸但少了烏龜的眼淚才能施咒，回去找阿凱的小烏龜&lt;/li&gt;&lt;li&gt;需要一個瓶子到雜貨店玩轉蛋取得(找爺爺要但今天給過了，雜貨店老闆給一個 打工機會賺5塊)&lt;/li&gt;&lt;li&gt;親了小烏龜一下讓他大哭，趕快用瓶子裝獲得烏龜眼淚&lt;/li&gt;&lt;li&gt;再回去找小香爸爸,組合成神之剪刀-獲得(剪刀)&lt;/li&gt;&lt;li&gt;到飛碟處，用猜拳打倒魔王&lt;/li&gt;&lt;li&gt;警報響起,飛碟要爆了，趕快進到機艙，解除爆炸裝置(解謎)&lt;/li&gt;&lt;li&gt;魔王：謝謝你，小白。你真是個勇者！&lt;/li&gt;&lt;li&gt;過關&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;同時也對想像的gameplay作了幾個重點記錄。&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;室外地圖 – 地上地圖由3x3個畫面構成，每個畫面為640x480大小，但遊戲地圖會更小(包含其它UI部份)；走到地圖邊緣時會整個地圖捲到下一個畫面，而不使用
全地圖捲動方式&lt;/li&gt;&lt;li&gt;室內地圖 – 地圖會有建築物，有些可以進入，進入後就是室內地圖，室內地圖固定都為一個畫面大小&lt;/li&gt;&lt;li&gt;走路 – 勇者小白(你)，可以在全地圖上自由行走，即便相關任務還未達成；走路方式為4方向，以pixel為單位&lt;/li&gt;&lt;li&gt;和NPC說話 – 任務的執行必須利用和各個NPC對話來達成；應任務需求會有給NPC任務物品及獲得物品&lt;/li&gt;&lt;li&gt;猜拳 – 為本遊戲的攻擊方式，必須取得3把神兵後才能出對應的拳；敵人在地圖上行走時，身上會有不斷變換的猜拳屬性，進入攻擊範圍後出拳，如果是剋制屬性，對方不能動作，如果被剋，你不能動，同屬性則沒有反應；出不同拳會有不同動作&lt;/li&gt;&lt;li&gt;主角被敵人碰到會損血，血會隨著時間自動回復，最多3滴，死掉回到自己家後繼續遊戲&lt;/li&gt;&lt;li&gt;敵人血沒了會被從天空打下來的光束吸回太空船&lt;/li&gt;&lt;li&gt;魔王血沒了，全破&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;還有出場人物列表。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;勇者小白&lt;/li&gt;&lt;li&gt;爺爺&lt;/li&gt;&lt;li&gt;張媽媽 – 一直在門口曬衣&lt;/li&gt;&lt;li&gt;小香妹妹 – 在門口玩/在家作美勞作業&lt;/li&gt;&lt;li&gt;小香她爹&lt;/li&gt;&lt;li&gt;雜貨店老闆&lt;/li&gt;&lt;li&gt;搖滾阿凱 – 打鼓(搖頭)&lt;/li&gt;&lt;li&gt;小烏龜&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;以及建築物列表。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;教堂 – 裡面有壁畫，可觀賞片頭動畫&lt;/li&gt;&lt;li&gt;你家 - 門口旁有個狗屋，露出個狗頭..&lt;/li&gt;&lt;li&gt;張媽媽家&lt;/li&gt;&lt;li&gt;小香家&lt;/li&gt;&lt;li&gt;雜貨店&lt;/li&gt;&lt;li&gt;阿凱家&lt;/li&gt;&lt;li&gt;封印洞&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;span face=&quot;Arial, Helvetica, sans-serif&quot; style=&quot;font-size: 15px; letter-spacing: 2px;&quot;&gt;甚至還寫了幾段開場劇情設計。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;Title 很久很久以前，邪惡的外星人來到地球打算要征服世界，勇者村的三個勇者拿著傳說的神兵勇敢的去挑戰魔王，最後三位勇者終於打敗了魔王。 某年某月的某一天，邪惡的外星人搭著巨大的太空船來到勇者村上空，要勇者村的村民們把勇者交出來，因為邪惡的外星人們相信，要征服世界就必須先征服勇者村。&lt;/li&gt;&lt;li&gt;起床 小白：爺爺，為什麼我們村要叫作勇者村？ 爺爺：小白啊，總有一天你會了解的。 小白：什麼時候呢？ 爺爺：總有一天啊...先不談這個了，去把我的無敵不求人拿來給我抓抓癢。 小白：不求人就不求人，為什麼叫無敵不求人？ 爺爺：這是我們家的傳家之寶，以後我還會傳給你，總有一天你會了解的... 小白：...&lt;/li&gt;&lt;li&gt;外星人來到&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;不過寫了這幾頁的word文件之後，一方面對於實際如何表現後來一直沒什麼靈感，一方面也沒有美術和企劃的支援，所以就一直放著沒動。又過了幾年後才又心血來潮，請老婆幫我畫了幾張勇者小白和小狗小白，然後我自己也試著開如規畫了一下地圖的格局。總算有個開始，只不過開個頭後又拖了一陣子。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzzVIrC0b217-zaDeXoGBKe3dWpcSfHlQD17d4ZQqNtcCFRL9w_PQXfre5BwGgQfSssKiCVqnKpzmWF_ZeL-H2VGXfDAC0BLrAI7v7ng4sBngIgf151gtGsjGanfHq2C2I4nMxPp0gz_9E/s374/scratch.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;333&quot; data-original-width=&quot;374&quot; height=&quot;356&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzzVIrC0b217-zaDeXoGBKe3dWpcSfHlQD17d4ZQqNtcCFRL9w_PQXfre5BwGgQfSssKiCVqnKpzmWF_ZeL-H2VGXfDAC0BLrAI7v7ng4sBngIgf151gtGsjGanfHq2C2I4nMxPp0gz_9E/w400-h356/scratch.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdvXay0u_vSbkhnUvDHVotquNdx_sXJI_Fd4x5BiyAHOdFxkkrOb3cFZgX3toqFKfc_XohbjOxjqHsGUlj88-RJTr6Ttm0CXOzMTStWF5bV6yivcYTRNHdeTljncNcMcid2mx1HyEM-TsX/s720/map.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;432&quot; data-original-width=&quot;720&quot; height=&quot;384&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdvXay0u_vSbkhnUvDHVotquNdx_sXJI_Fd4x5BiyAHOdFxkkrOb3cFZgX3toqFKfc_XohbjOxjqHsGUlj88-RJTr6Ttm0CXOzMTStWF5bV6yivcYTRNHdeTljncNcMcid2mx1HyEM-TsX/w640-h384/map.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;最後終於用good編輯器開新專案，根據上面的地圖設計，首先編輯了一張大地圖。因為最一開始的想法是想要模仿薩爾達傳說的地圖gameplay，所以把大地圖用了6x4個640x384個畫面大小的地圖拼起來，總大小是3840x1536，作出來的地圖如下。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-2KjK7v6oBy5hV3vqaV2ylhPj_pOirXFHSKM5EgO23mscbgyFYYQ4FXG58iKdUgta0cQoMlh9M7tBPywg-9iYldKRVv7pTKp03ZmzFrXsI2DuTSwxG_smVeue-NRS00YBIVCksL7RiFX4/s2804/fullmap.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1122&quot; data-original-width=&quot;2804&quot; height=&quot;256&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-2KjK7v6oBy5hV3vqaV2ylhPj_pOirXFHSKM5EgO23mscbgyFYYQ4FXG58iKdUgta0cQoMlh9M7tBPywg-9iYldKRVv7pTKp03ZmzFrXsI2DuTSwxG_smVeue-NRS00YBIVCksL7RiFX4/w640-h256/fullmap.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;地圖編好後，也寫了簡單的script可以用滑鼠或鍵盤來捲動檢視地圖。不過一時想不到怎麼在上面簡單的進行遊戲，所以又再編了遊戲title和一張地圖，把這三個場景串起來體驗看看。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9ET6OmTkdIr1YyMc6Cd9QtjdvOoSIwghQCIH77ujyWSPU-SNzfcc1lcYfXL7QNCM9sApGv_7CZ4bQOwcVaM6bmgsfSKXjUMBlh7PZqa4UrnwmoKP6kzE_JixSIGn7FNXijghDqI6nV7D/s642/1905.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;432&quot; data-original-width=&quot;642&quot; height=&quot;269&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9ET6OmTkdIr1YyMc6Cd9QtjdvOoSIwghQCIH77ujyWSPU-SNzfcc1lcYfXL7QNCM9sApGv_7CZ4bQOwcVaM6bmgsfSKXjUMBlh7PZqa4UrnwmoKP6kzE_JixSIGn7FNXijghDqI6nV7D/w400-h269/1905.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJXdjN0CkY80kxwHq3naB8q_LNKQQ8vSe-6PxnWxsBfBscaU78RgrYYpY3lkq6llxNa1uVYx52a9vsl7sjz1LlR3Zcnn-u5Mp0yQtv-KWqQ6eof7czEmbRbVoyczn8Hqy1vf1HLRVcgPNq/s642/3125.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJXdjN0CkY80kxwHq3naB8q_LNKQQ8vSe-6PxnWxsBfBscaU78RgrYYpY3lkq6llxNa1uVYx52a9vsl7sjz1LlR3Zcnn-u5Mp0yQtv-KWqQ6eof7czEmbRbVoyczn8Hqy1vf1HLRVcgPNq/w400-h259/3125.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;試來試去想來想去，好像無論如何總是很難作出預想的效果，所以又卡關繼續放著。過一陣子後再拿出來看的時候，想說不如先全部化簡把作不到的都先去掉，不要在地圖走路先作遊戲故事過程，以後再看怎麼作改良。同時一方面也考慮到，這個遊戲或者可以作成以簡單的小遊戲來串連劇情。同時因為都是簡單的小遊戲，之後也可以給兒子玩。結果一開始就作了兩個很小的遊戲，一個是撿木頭另一個是敲木魚。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHz8kdKuo3H0dG1O2eEgj7-Y4qiMFY1XIJO-iji0R3iRrkLa-pXelV8MoCfYE4lYQ1ZHmy65B8o9G2nBAYxQ1n-YMpdPG3dRwnjUULkm8OvC76Y7tJKPcrol52-PxkbECAmpxrgF2u3Qv7/s642/3362-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHz8kdKuo3H0dG1O2eEgj7-Y4qiMFY1XIJO-iji0R3iRrkLa-pXelV8MoCfYE4lYQ1ZHmy65B8o9G2nBAYxQ1n-YMpdPG3dRwnjUULkm8OvC76Y7tJKPcrol52-PxkbECAmpxrgF2u3Qv7/w400-h259/3362-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK9PjdzosbDXgESpIOweVv-_XZov121oyqPajvunTWg1Ma6U-_XvIQh5RUvaw9Kt9a85A4x3-nztAaJn5carEsuXtKwbija97ahoFQsngbwJbMO7wVUmOPJ6_2XNDterbVFofCsm6vUwu9/s642/3362-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK9PjdzosbDXgESpIOweVv-_XZov121oyqPajvunTWg1Ma6U-_XvIQh5RUvaw9Kt9a85A4x3-nztAaJn5carEsuXtKwbija97ahoFQsngbwJbMO7wVUmOPJ6_2XNDterbVFofCsm6vUwu9/w400-h259/3362-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyXjWel2xBdnsr4Iv3sLTptYr5W4V-mzG1wgFweG5mIfIFcXdV-yA4xIifNQSf-vIiXFGDh6AuAV70sbySh8phvbZhQv5Cq2MrH4R44u9GCf5iQRJ3308eh1zoV8Q3UOqFlpl4bm0rOlyT/s642/3362-3.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyXjWel2xBdnsr4Iv3sLTptYr5W4V-mzG1wgFweG5mIfIFcXdV-yA4xIifNQSf-vIiXFGDh6AuAV70sbySh8phvbZhQv5Cq2MrH4R44u9GCf5iQRJ3308eh1zoV8Q3UOqFlpl4bm0rOlyT/w400-h259/3362-3.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;再來設計了一個簡單的對話系統，可以顯示圖片和文字，這樣就可以表現劇情了。所以在開頭插入了另一段劇情，用來銜接進入這兩個開頭的小遊戲。&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQYjtoi8skFelvDNi81VpvLRAAatbq-iLEGrTgyxCtOzV9DNezOx9EcCexl5UO946nJQA0-P2SCioqlduOMTjCYtok3MGnBT9V3KB5F-3y64DvwV8D7oDapbLDm7hyphenhyphenWqx6uiBtq5OmnYaw/s642/3369.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQYjtoi8skFelvDNi81VpvLRAAatbq-iLEGrTgyxCtOzV9DNezOx9EcCexl5UO946nJQA0-P2SCioqlduOMTjCYtok3MGnBT9V3KB5F-3y64DvwV8D7oDapbLDm7hyphenhyphenWqx6uiBtq5OmnYaw/w400-h259/3369.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;接著就是第一張小地圖，這是包含開頭小遊戲的勇者山地圖。勇者山地圖的模式，也確立了勇者小白的地圖形式。地圖上的物件原則上都是靜態物件，點擊它時會顯示對話過場或者是切換畫面。地圖上的物件點了要作什麼由任務系統控制，每個物件會有個狀態值其實就是狀態機的值，根據故事進行這個值會變化，點擊後不同狀態值就值行不同對話script或切換場景。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如圖一開始勇者山有3個場景物件，分別是勇者山、商店和村落。點擊村落可以玩化緣小遊戲賺點錢，點擊勇者山或商店則視情況會有不同劇情。另外這時也加了一個簡單的背包系統，用來顯示己獲得的物品，點擊時會顯示一個簡短的說明。地圖ui上也顯示了目前擁有的金錢數量。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYnSXsexCTCN9327KQmZFXh_0wONyFepthCXKuY5Jui3JnMP3TCyJV7KmGQtsDd4ciUQgs4TNFyA4dlbYRqT4VcLayn_xK2l3DWbrPG2IfbqvmjFdvWpzDTq0O1lYvoxmRJU0JFuuaEqUM/s642/3397-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYnSXsexCTCN9327KQmZFXh_0wONyFepthCXKuY5Jui3JnMP3TCyJV7KmGQtsDd4ciUQgs4TNFyA4dlbYRqT4VcLayn_xK2l3DWbrPG2IfbqvmjFdvWpzDTq0O1lYvoxmRJU0JFuuaEqUM/w400-h259/3397-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb2QJ0gMsY-zeX0Oq8zaBf_F2b7cC_snUXNPtE_z8xYR5UjODgSYk20pFgA7g1b1ArQGqe5vcNyDeVBNQ5tdbibLsb6Arwz6flzIeASCawQANmfg7suHpjj8ubhs9nhqkF0haSKPuDNVCA/s642/3397-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb2QJ0gMsY-zeX0Oq8zaBf_F2b7cC_snUXNPtE_z8xYR5UjODgSYk20pFgA7g1b1ArQGqe5vcNyDeVBNQ5tdbibLsb6Arwz6flzIeASCawQANmfg7suHpjj8ubhs9nhqkF0haSKPuDNVCA/w400-h259/3397-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Zaos63tbCY14eoenFx-kzv0Enw-qLyEPq4Tn-xCly_YEuJiVTW2rlbql8fbnJc4mrWtW97cyATjz5QIsCBwbOESsNZ64fWekp_L5v2cbeFL-YF9CcxtxxlyUCmsBE6PQy5vUYgOdcw82/s642/inv.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4Zaos63tbCY14eoenFx-kzv0Enw-qLyEPq4Tn-xCly_YEuJiVTW2rlbql8fbnJc4mrWtW97cyATjz5QIsCBwbOESsNZ64fWekp_L5v2cbeFL-YF9CcxtxxlyUCmsBE6PQy5vUYgOdcw82/w400-h259/inv.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkfsgg6foCkplEjJJEFNjTXMVO5oVHPMed_ds0DBwv1dK86CYiMAABfx9BniOEz3OE7okZpzKU4E5_GyKESEGkmSlmgV5kvZvgiQLOXGr9TFHWa1XQT73ccrdxG5rItpiojocRUaYgO-OM/s642/3382.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkfsgg6foCkplEjJJEFNjTXMVO5oVHPMed_ds0DBwv1dK86CYiMAABfx9BniOEz3OE7okZpzKU4E5_GyKESEGkmSlmgV5kvZvgiQLOXGr9TFHWa1XQT73ccrdxG5rItpiojocRUaYgO-OM/w400-h259/3382.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJau5AWOB7cy8WuvU2VKCp_N3vtAktpi17jrhett-h9QL293bB2_qy_ZSMiDrw4_EPi0AOxVaLuOr1-srxAXVKuCq9wVbteJh3fueNjPhc4dcIQg1gGLEByPlUFXR32LNNapIcFKXLhThJ/s642/3382-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJau5AWOB7cy8WuvU2VKCp_N3vtAktpi17jrhett-h9QL293bB2_qy_ZSMiDrw4_EPi0AOxVaLuOr1-srxAXVKuCq9wVbteJh3fueNjPhc4dcIQg1gGLEByPlUFXR32LNNapIcFKXLhThJ/w400-h259/3382-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;接著又加了二個場景物件，教堂和工地。教堂其實是吳神父的按摩店，是切換至夢中世界勇者村的入口，而工地是作為未來建廟的保留地。預計以後廟蓋起來後，在裡面可以玩各種可以賺大錢的小遊戲，比如說募功德款、廟會進香團等等。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaeQN8GOskqfSUDZXNQ7hANhBQjrWZiGVZ42lTp_Q5j3byRRHzwdsxgh4JWcHFGc1wBYudFt-hh4r6y_VAcLaDTFglUwxwP2hRbcKRfu5KtLAn3aP9uc8ptEeZS3RgW1wtx7YiNB-xMN_2/s642/3412.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaeQN8GOskqfSUDZXNQ7hANhBQjrWZiGVZ42lTp_Q5j3byRRHzwdsxgh4JWcHFGc1wBYudFt-hh4r6y_VAcLaDTFglUwxwP2hRbcKRfu5KtLAn3aP9uc8ptEeZS3RgW1wtx7YiNB-xMN_2/w400-h259/3412.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcqVjVu3Cj_jd-ZZBbE0g6zghYLzueeHwAoII7AevpyWno6SDcCprwGf79f7ZEdEjpp76XqJEsQePhFTXgp6OhRn8HHZ2MYusFlAq3zsn5_Oqre1cT2uq3UDUf-C7sW7kEE98GpZZj5qWC/s642/3399-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcqVjVu3Cj_jd-ZZBbE0g6zghYLzueeHwAoII7AevpyWno6SDcCprwGf79f7ZEdEjpp76XqJEsQePhFTXgp6OhRn8HHZ2MYusFlAq3zsn5_Oqre1cT2uq3UDUf-C7sW7kEE98GpZZj5qWC/w400-h259/3399-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;第一次進入夢中世界時，插入了一段劇情，把以前寫的一篇也叫作&lt;a href=&quot;https://hitechgodstick.blogspot.com/2011/04/blog-post.html&quot;&gt;勇者小白&lt;/a&gt;的極短篇小說的劇情整合了進來。在這裡加入了豬小妹的打小強小遊戲，以及小白的爺爺也登場了。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtCl1LQfPW_-vmFdNYEjsHIDb-WOcZhYNdwo6RfIe6LBFzKRgJNwa-7tdl9FOxC8B4NS13O4d_jTz-zFdghxgV9eDVN3ehRgnJ2hWQ64ohffNh1qg_IVg1KfcnpVTyQkWj0BgHDnP3ZjIm/s642/3420-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtCl1LQfPW_-vmFdNYEjsHIDb-WOcZhYNdwo6RfIe6LBFzKRgJNwa-7tdl9FOxC8B4NS13O4d_jTz-zFdghxgV9eDVN3ehRgnJ2hWQ64ohffNh1qg_IVg1KfcnpVTyQkWj0BgHDnP3ZjIm/w400-h259/3420-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrDeAYuqAX8i7Rbo7RhnqE_yyDrbtWZvgQgL3_cGxkS_SrOGVdgd8LMAfqMqhE_Bvvi_fctzuc0LI4scqM_Us2gD74S2TicSJGcjhQcJFvYLjqTS5rlyJCMUTNKS_FArawGcXubU1_8h9R/s642/3420-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrDeAYuqAX8i7Rbo7RhnqE_yyDrbtWZvgQgL3_cGxkS_SrOGVdgd8LMAfqMqhE_Bvvi_fctzuc0LI4scqM_Us2gD74S2TicSJGcjhQcJFvYLjqTS5rlyJCMUTNKS_FArawGcXubU1_8h9R/w400-h259/3420-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlgNXItfzrJZjspq5CTUwd9Vb-ZEiR8evt4-I6BDXHLy9GGnl0I8HA_fkz-UIhzwI0qTxZLVOkC010CgLpKyMVwg_wylnqTNDwn-4GE3OnjwWBDitnhWrQMcqpCmsIffSF4M633NrdWkF/s642/3430.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlgNXItfzrJZjspq5CTUwd9Vb-ZEiR8evt4-I6BDXHLy9GGnl0I8HA_fkz-UIhzwI0qTxZLVOkC010CgLpKyMVwg_wylnqTNDwn-4GE3OnjwWBDitnhWrQMcqpCmsIffSF4M633NrdWkF/w400-h259/3430.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;作到這裡，也把之前只作了起頭的小遊戲加進來。把勇者山的商店老闆沒東西可以賣了之後，改成賽魂場用來賭注比賽賽魂。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcmNdVVoOID9Fkx6hBw67QSCcV2fktkffYNBkRwigXZI_IYg4F6X1h-TKybbHiuuU7IjhCnRDyk5YcG2QUSCOaKGbKCVx3WlBin6vR7nhA5bPS_SoGTO8IaaMxojzXyvtVn18T0HPpdBWE/s642/saihoon.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcmNdVVoOID9Fkx6hBw67QSCcV2fktkffYNBkRwigXZI_IYg4F6X1h-TKybbHiuuU7IjhCnRDyk5YcG2QUSCOaKGbKCVx3WlBin6vR7nhA5bPS_SoGTO8IaaMxojzXyvtVn18T0HPpdBWE/w400-h259/saihoon.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqRMoY3xTCbGzoHykOczoCwU9nTKoLWMM5Pxciogq29k0IdS0H24SpSymCADRXAkE-Db1z64PHSBMYLiX1fuE74u2XcWWJvNuTvzRAJv74IMPDWyspvW-tT2wXHj0RqJ3sRXpYzmVHJqxO/s642/3458.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqRMoY3xTCbGzoHykOczoCwU9nTKoLWMM5Pxciogq29k0IdS0H24SpSymCADRXAkE-Db1z64PHSBMYLiX1fuE74u2XcWWJvNuTvzRAJv74IMPDWyspvW-tT2wXHj0RqJ3sRXpYzmVHJqxO/w400-h259/3458.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;第二次進入教堂吳神父按摩店，舒服到睡著後又進入夢鄉。初次進入勇者村場景時會有一段過場，用來表現原始設計的外星人降臨的情節。&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjelGl7cON0QFxKhUahsNyPFn3128SMAI-o-ATi8ShA2R7Mq8PzTu9TEPJn1KFy8jx74QTZm-vaLp5VRKx2-pOCIZ1k5FbuOPuY6bZgyTDu8nCiJykds2sZzmEig5TRxsufowiFjY_p_Wta/s642/3428.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjelGl7cON0QFxKhUahsNyPFn3128SMAI-o-ATi8ShA2R7Mq8PzTu9TEPJn1KFy8jx74QTZm-vaLp5VRKx2-pOCIZ1k5FbuOPuY6bZgyTDu8nCiJykds2sZzmEig5TRxsufowiFjY_p_Wta/w400-h259/3428.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAzgfBC0909U3DYtlTL9bYfyenU0sH8EcTjPblD8xG65v779dGmuKGdRve9bRJRqDBRELarSVPOSszRJK6Zz_Eeeq1AG3m1ibLO3IEWKWWBq5ycyupL6vIrpuFqTeeJAU9vgDbiUZ-CIs8/s642/3463-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAzgfBC0909U3DYtlTL9bYfyenU0sH8EcTjPblD8xG65v779dGmuKGdRve9bRJRqDBRELarSVPOSszRJK6Zz_Eeeq1AG3m1ibLO3IEWKWWBq5ycyupL6vIrpuFqTeeJAU9vgDbiUZ-CIs8/w400-h259/3463-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIsJQldx3NijZFzqXtocnOTaStza_7rgE-fiOKuDhFgjIQnyAqyxIF-1csS2RDhrqaowaNLGqbW7T4e_7923qcCttZvBhK8dg1XWhngIIeo-8vEtgSRRtWPoMqcpjrcuJ948Bsvn2haAJw/s642/3463-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIsJQldx3NijZFzqXtocnOTaStza_7rgE-fiOKuDhFgjIQnyAqyxIF-1csS2RDhrqaowaNLGqbW7T4e_7923qcCttZvBhK8dg1XWhngIIeo-8vEtgSRRtWPoMqcpjrcuJ948Bsvn2haAJw/w400-h259/3463-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;勇者村的教堂其實是另一張小地圖，裡面有小白的爺爺和教堂圖書館。教堂圖書館是背包系統的另一個表現，只不過只會顯示背包裡的書籍物件。點擊書籍的時候，會顯示比較長的說明文字，提供一些額外故事或過關訊息。同時小白爺爺的設計，是一個攻略提示的功能。在勇者村的世界裡，只要不知道下一步怎麼辨的時候就去找小白爺爺，小白爺爺就會給你提供簡單的提示。&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheU8RGSmC9wkVozKS4Ouy5IjRvyvDwzNiZw0ZJuhiEy7hSSKP-Q_-rHNrJD3Qjr1kqaGnSYNYZXMfGiFOWobEzV0Gx_J_mnBe9HjyXRfnr8K02snXY0foW_BaY_GfRYKX31oPmZyOy5ghq/s642/3674.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheU8RGSmC9wkVozKS4Ouy5IjRvyvDwzNiZw0ZJuhiEy7hSSKP-Q_-rHNrJD3Qjr1kqaGnSYNYZXMfGiFOWobEzV0Gx_J_mnBe9HjyXRfnr8K02snXY0foW_BaY_GfRYKX31oPmZyOy5ghq/w400-h259/3674.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4BU0N9oRFwR-Ev2G5Ey0_hlY7HoWLSAKwBcG4tOtGzpi_b-m-RANsTAqvjCeAk8Y1q8kVYqoQRaJHRIQ30cWD4Jfagrl2gggf-jUHe56AwSmertjyYCTJfj_9VFb-55SWo7b4U7x7rJIs/s642/library.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4BU0N9oRFwR-Ev2G5Ey0_hlY7HoWLSAKwBcG4tOtGzpi_b-m-RANsTAqvjCeAk8Y1q8kVYqoQRaJHRIQ30cWD4Jfagrl2gggf-jUHe56AwSmertjyYCTJfj_9VFb-55SWo7b4U7x7rJIs/w400-h259/library.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;在勇者村裡，隨時可以找張媽媽玩曬衣服小遊戲，賺點零用錢。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2S_bwSpt85afBMFK_LeS4Z4XPs4s0H_k8rxh5OYcn8geOR_VHSfdzsnnEqPwSlrHXiBu-APjHtqD3zD_NRTYDxu1VmSXpoXwkgw4hR2fuWm6RyQJ-jWbzYb_dREXWl4q-s6ce6FUMhTrg/s642/zhongmama.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2S_bwSpt85afBMFK_LeS4Z4XPs4s0H_k8rxh5OYcn8geOR_VHSfdzsnnEqPwSlrHXiBu-APjHtqD3zD_NRTYDxu1VmSXpoXwkgw4hR2fuWm6RyQJ-jWbzYb_dREXWl4q-s6ce6FUMhTrg/w400-h259/zhongmama.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrWd5oiAg0Kp8SL_UVDIIanEgoFnojkjJUBYgV9ZlfjFfMrsiZ7XQC4Busgn6YmH6lGG5eHQAOyo6XpTK6PaDyBiEtm397PoCxC5igzIZrxxyvU3gJ2H1KItD1Uyq0voPblHDH8-bCt6CP/s642/dryclose.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrWd5oiAg0Kp8SL_UVDIIanEgoFnojkjJUBYgV9ZlfjFfMrsiZ7XQC4Busgn6YmH6lGG5eHQAOyo6XpTK6PaDyBiEtm397PoCxC5igzIZrxxyvU3gJ2H1KItD1Uyq0voPblHDH8-bCt6CP/w400-h259/dryclose.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;勇者村左邊地圖是一個猜拳小遊戲，必須收集三種猜拳武器才能過關進入下一個場景。右邊地圖是搖滾阿凱的家和池塘，再右邊是洞穴入口地圖。&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_ecTbjjLNFZjT_9fY0fVu9Ir6VUMY1bWgqfWYVn0WmMMneC-X9zdPHoSGCfrX3B_nCYP_ZDrkTwUyhwPRIuWg4OaXRMX3VmMwhI2LGVlsGm046D6EEUqN1dFLrtIJFztPml8JAdFfi8ik/s642/alienpath.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_ecTbjjLNFZjT_9fY0fVu9Ir6VUMY1bWgqfWYVn0WmMMneC-X9zdPHoSGCfrX3B_nCYP_ZDrkTwUyhwPRIuWg4OaXRMX3VmMwhI2LGVlsGm046D6EEUqN1dFLrtIJFztPml8JAdFfi8ik/w400-h259/alienpath.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOwsjI_x0ZKj_Kq_vZ-neFRGiP87qHKG66hx_OvYPOuiMtYnccRnlRVytTvyPulvYJMAEW9oBDAoOTjLpPHRgars0CIk5YscLs4iCEAUb_1EYHyobGTOQxhc4IKiClYNjaxDchmGxicHg8/s642/country.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOwsjI_x0ZKj_Kq_vZ-neFRGiP87qHKG66hx_OvYPOuiMtYnccRnlRVytTvyPulvYJMAEW9oBDAoOTjLpPHRgars0CIk5YscLs4iCEAUb_1EYHyobGTOQxhc4IKiClYNjaxDchmGxicHg8/w400-h259/country.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6FwSmBryoxEEamQ-J6BL072_Y_Nb0pm1gMVGXtVRy-vzEtrNR_bAAd09xHxkK3KMjdJQLNfo-Q2S8ATX41M9hDpdlifdxbbZolnLUCfe_BGdXKyA6ll5Bf1SdM97Vzz32dUPrviqFBb8/s642/cavefield.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6FwSmBryoxEEamQ-J6BL072_Y_Nb0pm1gMVGXtVRy-vzEtrNR_bAAd09xHxkK3KMjdJQLNfo-Q2S8ATX41M9hDpdlifdxbbZolnLUCfe_BGdXKyA6ll5Bf1SdM97Vzz32dUPrviqFBb8/w400-h259/cavefield.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;洞穴入口一開始無法進入，必須先取得過關道具手電筒才能前進。進去之後還會遇到一道有密碼保護的門，必須知道通關密碼才能進入。解決了一些簡單的問題後，最後可以獲得猜拳武器。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsdwx5dG-Mb9lAC9VOG_Cbnq1cTtjghY3x9zAMjKuKqSoQ65g9nlmRs3tv-7enLA1P2bFm4mYxrrU1k81QSfyEX95TYNf0NMZPJLz9HxJfA0ZiVWu2oeIDJ4Pa4YIo-fBOKtDDBVXOzpbz/s642/cave.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsdwx5dG-Mb9lAC9VOG_Cbnq1cTtjghY3x9zAMjKuKqSoQ65g9nlmRs3tv-7enLA1P2bFm4mYxrrU1k81QSfyEX95TYNf0NMZPJLz9HxJfA0ZiVWu2oeIDJ4Pa4YIo-fBOKtDDBVXOzpbz/w400-h259/cave.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiul6p9qtQk97rv5i8sqBIRB7NvnnDK6ILkVy4Bsiy2mg1zeYIRR8dHWA7TrS1AQH6l3JbvQhOVZUJQ3sk48INhm8VcrSe5Cts57ag3jlgEOCeyuxuCrfYT4lMuHKuBiaD4cZfiWHLXMfW8/s642/flashlight.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiul6p9qtQk97rv5i8sqBIRB7NvnnDK6ILkVy4Bsiy2mg1zeYIRR8dHWA7TrS1AQH6l3JbvQhOVZUJQ3sk48INhm8VcrSe5Cts57ag3jlgEOCeyuxuCrfYT4lMuHKuBiaD4cZfiWHLXMfW8/w400-h259/flashlight.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWDb2TFeYyJ3rUyGAG5P48p4bv-EspSpJOW3oHz9e8sk0rrXfesXYX9QY_tFSesfCNuWk95-BizBFR7xZ7nWWKqK4KIH04TdG9NAaLPs-HQ2-cBXMnSkxxbZcIIqWtp_iRuD5ymlhY8l5L/s642/cavedoor-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWDb2TFeYyJ3rUyGAG5P48p4bv-EspSpJOW3oHz9e8sk0rrXfesXYX9QY_tFSesfCNuWk95-BizBFR7xZ7nWWKqK4KIH04TdG9NAaLPs-HQ2-cBXMnSkxxbZcIIqWtp_iRuD5ymlhY8l5L/w400-h259/cavedoor-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIGm10x4pwkPMB_rJGvgGEGEdTcuJOZcnTY1A7bbcROhOapCchMcd4uiNu3rM6SRUYHfvDZpDkX_DJpju8H6e3lQ__2URuXjTC_aQyY-sbunAyq68P9cvZN8jEu_8-DfpuFb1RD2ZTUjQ1/s642/cavedoor-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIGm10x4pwkPMB_rJGvgGEGEdTcuJOZcnTY1A7bbcROhOapCchMcd4uiNu3rM6SRUYHfvDZpDkX_DJpju8H6e3lQ__2URuXjTC_aQyY-sbunAyq68P9cvZN8jEu_8-DfpuFb1RD2ZTUjQ1/w400-h259/cavedoor-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div&gt;池塘小遊戲是一個找小青蛙的簡單遊戲，那時候作出來這個小遊戲，正好給在念幼兒園的兒子還有更小的女兒玩，讓他們練習一下點擊的操作。其實上面的猜拳小遊戲也是同樣的目的，都是很簡單的設計，很適合給小孩玩。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsF3aYduqmU0lrYt9RJV8y1gkXuXtyEfuLdfndoM0-QFLYNbg94_UCZM_5ckgt37My0-LTTjn1dhhyqa3gAWRP9RkBxKp2Toyb8KN2vf-66u006c8YkYbMyRbN4YKfprDebkx1GokSVQFn/s642/frog-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsF3aYduqmU0lrYt9RJV8y1gkXuXtyEfuLdfndoM0-QFLYNbg94_UCZM_5ckgt37My0-LTTjn1dhhyqa3gAWRP9RkBxKp2Toyb8KN2vf-66u006c8YkYbMyRbN4YKfprDebkx1GokSVQFn/w400-h259/frog-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg17XkLJjLiL5T65JhebctPttwNI63F8lXYMoxQw2FYGQCAV7mjl8bW7VvaB-tff6FUw_7x3NQaFLrrKoHzNxiTmV_Dw5-3xRju8ftG1jk5Jq1c0nzU47IF3P1zKzVfyfPqKkSgLYMX0SKG/s642/frog-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg17XkLJjLiL5T65JhebctPttwNI63F8lXYMoxQw2FYGQCAV7mjl8bW7VvaB-tff6FUw_7x3NQaFLrrKoHzNxiTmV_Dw5-3xRju8ftG1jk5Jq1c0nzU47IF3P1zKzVfyfPqKkSgLYMX0SKG/w400-h259/frog-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;不過搖滾阿凱的小遊戲我一直沒有靈感，直到有一天我看到兒子的塗鴉，是一個機械設計圖，題目就叫作超級老鼠拍打器。內容是這樣子的：&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;按下紅色按鈕 拍打器跑出來&lt;/li&gt;&lt;li&gt;按下綠色按鈕 球跑出來&lt;/li&gt;&lt;li&gt;按下黃色按鈕 起士跑出來&lt;/li&gt;&lt;li&gt;老鼠跑來吃起士&lt;/li&gt;&lt;li&gt;老鼠踩到球跌倒&lt;/li&gt;&lt;li&gt;拍打器打下來打死老鼠&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;我一看立刻稱讚兒子幹的好，正好適合拿來作成搖滾阿凱的小遊戲，我立刻就以此構想設計了一個小遊戲，另外還特別作了一本書放在勇者村教堂圖書館作為紀念。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcaHXzLbEtn38i3p8-EA26anxU2IHSzg8rh2vWTLIzq9yveizV6AZHfZsoPZi9iqG9lwxpi4SBAD6q9SVtGf9-EHSjciVqupnSS_3uZXRw6td36C316bRz45tdWEqmE4iKSwLpqLkwa0uI/s642/slapmouse-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcaHXzLbEtn38i3p8-EA26anxU2IHSzg8rh2vWTLIzq9yveizV6AZHfZsoPZi9iqG9lwxpi4SBAD6q9SVtGf9-EHSjciVqupnSS_3uZXRw6td36C316bRz45tdWEqmE4iKSwLpqLkwa0uI/w400-h259/slapmouse-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6ThLe1eL36dR4nnLmA-XI_6V95lOlMRTNRKD-0j_Lq9-YTwwu1OPVjQG7NIeMKoWmgxoP28hh_LrpNcaqKnJ7fVPbVmz8Z6VGJ36QKi9LbeJh3lvSZFEQikVH4V1FJTlRjy48fI_0y6EP/s642/slapmouse-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6ThLe1eL36dR4nnLmA-XI_6V95lOlMRTNRKD-0j_Lq9-YTwwu1OPVjQG7NIeMKoWmgxoP28hh_LrpNcaqKnJ7fVPbVmz8Z6VGJ36QKi9LbeJh3lvSZFEQikVH4V1FJTlRjy48fI_0y6EP/w400-h259/slapmouse-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;集滿三種猜拳武器之後，就可以通過猜拳小遊戲去和外星人用猜拳作戰鬥。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhurSoVSGkutjEE0cywTXSv4HGapb-uJorEnJe9CtuX1qrZ2ryNyEkDVsL0bw26UPyPiPv9UAjegCv8AI0Wce1sixrrYAMdaPxxqAdAOiGjoy9dCTruAR_FlpmEcYkTCeafDdxZtZ21xd5F/s642/alien-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhurSoVSGkutjEE0cywTXSv4HGapb-uJorEnJe9CtuX1qrZ2ryNyEkDVsL0bw26UPyPiPv9UAjegCv8AI0Wce1sixrrYAMdaPxxqAdAOiGjoy9dCTruAR_FlpmEcYkTCeafDdxZtZ21xd5F/w400-h259/alien-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYUVu7Yp9aRflXXziKj06tDROLt2UF1ee5DoOMmrWbcq0Lxk_siPhyiMqIaAIfIdTga682KLIGtwlHPxb8NYKQCltLgR7zszQGU4zUZmUicq5M3mQVMOV75HP-RkkreRzh_RokiNkgapt5/s642/alien-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYUVu7Yp9aRflXXziKj06tDROLt2UF1ee5DoOMmrWbcq0Lxk_siPhyiMqIaAIfIdTga682KLIGtwlHPxb8NYKQCltLgR7zszQGU4zUZmUicq5M3mQVMOV75HP-RkkreRzh_RokiNkgapt5/w400-h259/alien-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;打敗外星人之後，這時候如果回到勇者山，就可以開啟財神廟的功能了。原本打算進入廟後可以玩各種賺錢的遊戲，不過一時想不到好點子，所以簡化成類似小瑪利的小遊戲。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm9iBNYDssKWYlyqu7fUUtsnLx8i1kl1337ul9-Aeucz8iNWxba_nm8FINrVNWfrYFg9cZYRHAKJM2CPIoS4oj_RJaDjWXYvv_8WczoS14Dl0UbZNIukFQESnh1ez8kePOaNBH7E0TRvlw/s642/temple-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm9iBNYDssKWYlyqu7fUUtsnLx8i1kl1337ul9-Aeucz8iNWxba_nm8FINrVNWfrYFg9cZYRHAKJM2CPIoS4oj_RJaDjWXYvv_8WczoS14Dl0UbZNIukFQESnh1ez8kePOaNBH7E0TRvlw/w400-h259/temple-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipXjDwADLxn-2nlNyxHPsZ1Usyklk8AEtjQzgt7uY0EhdEwnC67NoPz-_zr4jFw07MMRI5Y1fylmgdOqEUKJSCm-LvXgEpaio31gCH9GJjZzGvstcUfQkaESasBtNpsXMiy4snYZwug23h/s642/temple-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipXjDwADLxn-2nlNyxHPsZ1Usyklk8AEtjQzgt7uY0EhdEwnC67NoPz-_zr4jFw07MMRI5Y1fylmgdOqEUKJSCm-LvXgEpaio31gCH9GJjZzGvstcUfQkaESasBtNpsXMiy4snYZwug23h/w400-h259/temple-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaaKFy7g_Iw2iSQItubKp2_cig-VSFCjDOvUdy4x7PdNttxdU2ipKEdxjhzLJ21nAJVg1H875vPhub73JLAkHPUd0-TCabkxXoEEfl93k5Um6rPB9UEzYbL1t8pva6iWyco1ef_vzgwCCD/s642/temple-3.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaaKFy7g_Iw2iSQItubKp2_cig-VSFCjDOvUdy4x7PdNttxdU2ipKEdxjhzLJ21nAJVg1H875vPhub73JLAkHPUd0-TCabkxXoEEfl93k5Um6rPB9UEzYbL1t8pva6iWyco1ef_vzgwCCD/w400-h259/temple-3.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;作到這裡，故事內容大致和原始的設計走向差不多。雖然製作過程也是花了些時間，但遊戲內容實在太短了，一下子就玩完了。所以接著又增加了地底世界的設計，入口一樣從洞穴入口進入。&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;一進入地底洞穴會先經過一個地底迷宮，這是為了向&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E8%96%A9%E7%88%BE%E9%81%94%E5%82%B3%E8%AA%AA_%E7%B9%94%E5%A4%A2%E5%B3%B6&quot;&gt;薩爾達夢見島&lt;/a&gt;致敬，所以迷宮的過關路徑也和gb版夢見島蛋迷宮路徑一樣。過關後會進入地底王國的世界，這裡面就放了7個小遊戲。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn5WspPDsjGJxHCmTH1mhnmZmfe6Zun2_CPQtaQtcilYlow-uDdth8b0xSw0K6ggGcNul9cp1sOMSvsbI5z2gt12XHDHnGI8LAtX_PL-HTzcXBJ61p2NkjlBw8JmIAiP2Vi1kgiaceah1Z/s642/cavemaze.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjn5WspPDsjGJxHCmTH1mhnmZmfe6Zun2_CPQtaQtcilYlow-uDdth8b0xSw0K6ggGcNul9cp1sOMSvsbI5z2gt12XHDHnGI8LAtX_PL-HTzcXBJ61p2NkjlBw8JmIAiP2Vi1kgiaceah1Z/w400-h259/cavemaze.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7pd99-m43CZwJeGknoAwUTVpo7VNqLR_tqsIoJxtGaD-L-Uqgv4X77FSBDZuqVvQMfYEEgTlI9Nr6ndF9WsowTy5sW80o-ZHAnv30KYWz6msD425i8APxMGf84Y_5lPXWzzBjNwcS2Iuv/s1926/underworld.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;832&quot; data-original-width=&quot;1926&quot; height=&quot;276&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7pd99-m43CZwJeGknoAwUTVpo7VNqLR_tqsIoJxtGaD-L-Uqgv4X77FSBDZuqVvQMfYEEgTlI9Nr6ndF9WsowTy5sW80o-ZHAnv30KYWz6msD425i8APxMGf84Y_5lPXWzzBjNwcS2Iuv/w640-h276/underworld.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFI7eU8m0bcAmq0jsqAjYj7-dxo6Wgw1Xy1pWWt_8WxIyJsm9htcc6RcoAGfgAaX7-6HnNNbYilIMfFYw9jA3OogVHW8IWVUEzo1e7IxFVJaq2tYebk59jMeetQOM9KVYWkvwhac5CJUPr/s2568/underworldgame.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;832&quot; data-original-width=&quot;2568&quot; height=&quot;208&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFI7eU8m0bcAmq0jsqAjYj7-dxo6Wgw1Xy1pWWt_8WxIyJsm9htcc6RcoAGfgAaX7-6HnNNbYilIMfFYw9jA3OogVHW8IWVUEzo1e7IxFVJaq2tYebk59jMeetQOM9KVYWkvwhac5CJUPr/w640-h208/underworldgame.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;在地底王國世界裡面增加了三個長老事件，其中兩個可以在勇者村裡完成，而另一個則需要進入到拳頭星的世界後才能完成。要去到拳頭星需要先解決一些問題，經由外星人的幫忙上到太空。進入拳頭星之前，會先經過一個擊破隕石的小遊戲，過關後再進入拳頭星。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;借用天線寶寶的圖，拳頭星裡面有4個小遊戲，每過一關可以獲得不同顏色的毛。4個小遊戲分別是：拼圖小遊戲、記憶小遊戲、影子小遊戲和彩虹小遊戲。收集4種毛可以找比比博士，合成另一個過關道具S擦布，用來解地底王國長老的任務。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm_kG8jxOSI4kyX2euPVWWMSHzpzAbVM5D0CUNkzKr5uflaOxx2iyWlzmVudredP_vH9Y8qwVIn5vSGPdKSItsg2Sad-avRslouMKiJAnDJI7em_2LtIWV7ykFI-NdUrSzYy79gOP4EYy3/s642/astroid.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm_kG8jxOSI4kyX2euPVWWMSHzpzAbVM5D0CUNkzKr5uflaOxx2iyWlzmVudredP_vH9Y8qwVIn5vSGPdKSItsg2Sad-avRslouMKiJAnDJI7em_2LtIWV7ykFI-NdUrSzYy79gOP4EYy3/w400-h259/astroid.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz3G6s2FSaNajsDvKhr86mRKtKsOU7jJuXFVBOZfPbnMuxLY6z3cg97aSuj8ErtcmQOUU0dXCO_s8mfrZNS1wBJGQjjb_qLUauUXowdMszJ5KctqiLHLpLH9IT23oxpaL4in_NS2Uj0eKi/s642/junken-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjz3G6s2FSaNajsDvKhr86mRKtKsOU7jJuXFVBOZfPbnMuxLY6z3cg97aSuj8ErtcmQOUU0dXCO_s8mfrZNS1wBJGQjjb_qLUauUXowdMszJ5KctqiLHLpLH9IT23oxpaL4in_NS2Uj0eKi/w400-h259/junken-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrgCYvuMCx40M10pDondpo9g7P7S5ZkB9Hvew962hfxJeOVSBVHSux-lL_J3z2bLc2cXYSz65ao6Bb0ZZp2O4ja0zKhZNNJdS4Tc0z_20uVMYPdmju_QOqcWJONPm9CzfGky132n_0ES1x/s642/junken-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrgCYvuMCx40M10pDondpo9g7P7S5ZkB9Hvew962hfxJeOVSBVHSux-lL_J3z2bLc2cXYSz65ao6Bb0ZZp2O4ja0zKhZNNJdS4Tc0z_20uVMYPdmju_QOqcWJONPm9CzfGky132n_0ES1x/w400-h259/junken-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgxiG21qxfjUP8Qlas-Bg7dAW-gyyLL_pf3d7pDcPdPEsAIOSMcEQOX_wSFCLaR0uxgDmnP27R9YplxVgDuNOTmL98zbOWN_6lSh-wtMsLY-m8h0ncIbBKHFCxkcbGsScYHwx_wMThYHd/s1284/junkengame.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;832&quot; data-original-width=&quot;1284&quot; height=&quot;414&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSgxiG21qxfjUP8Qlas-Bg7dAW-gyyLL_pf3d7pDcPdPEsAIOSMcEQOX_wSFCLaR0uxgDmnP27R9YplxVgDuNOTmL98zbOWN_6lSh-wtMsLY-m8h0ncIbBKHFCxkcbGsScYHwx_wMThYHd/w640-h414/junkengame.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;比比博士的電腦，其實是虛擬電腦遊戲世界的入口。不過現在只作了個開頭，遊戲內容還在和兒子一起設計中。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGEEDUL5YAp6jWpkQNOIL8kmsIBWSH9aZBzP_uSZlv4qseXMrjStnPKndr_rHYraZDtkHZ9S7cxPl9Vvpb70oHBVCeVJLB5Wspqs0JyKjHJdXNJ0r82_J68eMvE8I3-wZ4qpxwjExk0aM6/s642/computer.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGEEDUL5YAp6jWpkQNOIL8kmsIBWSH9aZBzP_uSZlv4qseXMrjStnPKndr_rHYraZDtkHZ9S7cxPl9Vvpb70oHBVCeVJLB5Wspqs0JyKjHJdXNJ0r82_J68eMvE8I3-wZ4qpxwjExk0aM6/w400-h259/computer.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6jqtjxPpGKpzzRcPkGyw6fFeeiC0QOyHaGzRR-FZHOi0fcE-Zd-EvjWM_oB8Se8IQheC-9o0hBZJ-TAT4ddLe1rA-O9BHm7-FO-uw2LYq-nPs0Zb7C5yZKmJjFMS_L69mchfSC20pq43N/s642/dq2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6jqtjxPpGKpzzRcPkGyw6fFeeiC0QOyHaGzRR-FZHOi0fcE-Zd-EvjWM_oB8Se8IQheC-9o0hBZJ-TAT4ddLe1rA-O9BHm7-FO-uw2LYq-nPs0Zb7C5yZKmJjFMS_L69mchfSC20pq43N/w400-h259/dq2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;獲得S擦布的事件同時也開啟了可以進入海洋世界的開關，從拳頭星回到勇者村後就可以出海了。出海後可以玩釣魚小遊戲，之後可以把魚賣給漁夫或其它人賺點零用錢。&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIxUAiyH60eFjzgPCRT6KuEnixpor1_0CRGZLlvnq4L48qIwk6ifnEEvxJ5WSULUav8bgaMO2eerfh9K9XdypccEkY1-yVZ2q6uIA_waVX-YsSc7nY0x4M3Hoz2GxjYNwXBupmZbWrH8gF/s1926/dock.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;1926&quot; height=&quot;138&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIxUAiyH60eFjzgPCRT6KuEnixpor1_0CRGZLlvnq4L48qIwk6ifnEEvxJ5WSULUav8bgaMO2eerfh9K9XdypccEkY1-yVZ2q6uIA_waVX-YsSc7nY0x4M3Hoz2GxjYNwXBupmZbWrH8gF/w640-h138/dock.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdjhcJpvS6gMQXNgQLRZiHiUCifex8o81ojrZVxhr_JVvTSNPDKybS0GkMOzDsizjCWBgzzhHeYCERwDr-WRBUkwo7AXq6-50fneI5Jy4UkOBJ3cbkrhq8dLAUNtSyOO9xX8jvxcQ3BWbU/s642/fishing.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdjhcJpvS6gMQXNgQLRZiHiUCifex8o81ojrZVxhr_JVvTSNPDKybS0GkMOzDsizjCWBgzzhHeYCERwDr-WRBUkwo7AXq6-50fneI5Jy4UkOBJ3cbkrhq8dLAUNtSyOO9xX8jvxcQ3BWbU/w400-h259/fishing.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;大海上有兩個小島，其中一個是動物園。這個原本是一個很小的遊戲，作給小孩們玩。點了動物圖案，就會發出對應動物叫聲，也把它整合進來勇者小白了。一開始是把動物園放在勇者山地圖，後來搬到勇者村世界的小島上。&lt;div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZKvf9SiVQ47OBYW_BgwCk3-WQJm-28-cNblUT55aoT5Bpi47GK9vRh5A2kbmQfPeMnGryKa7t_r3vnJ0v0QwsyE3soUFv80Vb_1O7S3J28PI4K2Nc0BxtTyx5uRyY2GDcQkAwb8U1SCu/s642/zoo.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsZKvf9SiVQ47OBYW_BgwCk3-WQJm-28-cNblUT55aoT5Bpi47GK9vRh5A2kbmQfPeMnGryKa7t_r3vnJ0v0QwsyE3soUFv80Vb_1O7S3J28PI4K2Nc0BxtTyx5uRyY2GDcQkAwb8U1SCu/w400-h259/zoo.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;另一個小島是我們這一家之島，其實就是我們一家4口的對應。我想要給我們家每個人作一個對應的小遊戲，現在完成了3個。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-CYkaDIm_mpsMaxVULvjAewYPAp3XjvhqWTwd8LyN6l-qnyDtA-gCQ78EHLJ0r7H9hTgoiDzGZDIt6M3acu-R-IzNnjm5G_FoU9xxkI81_pVL3Xml8vBgTXquQH8wCNV64SsFu5oGgPSu/s642/fam-1.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-CYkaDIm_mpsMaxVULvjAewYPAp3XjvhqWTwd8LyN6l-qnyDtA-gCQ78EHLJ0r7H9hTgoiDzGZDIt6M3acu-R-IzNnjm5G_FoU9xxkI81_pVL3Xml8vBgTXquQH8wCNV64SsFu5oGgPSu/w400-h259/fam-1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF_2kMOsn_hBh87tH9o7Lc7uEk_4SYmG7ivM49IyqpKJoJqXPhBOdEQrX4sLWVOlZNy_tQ1wPBsu6tpckUIYBCpixOGVf-Oz86zEznelU46kvQ1lU_N_cXg9ptT99v2s43UsqIWUsvT7kw/s642/fam-2.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;642&quot; height=&quot;259&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF_2kMOsn_hBh87tH9o7Lc7uEk_4SYmG7ivM49IyqpKJoJqXPhBOdEQrX4sLWVOlZNy_tQ1wPBsu6tpckUIYBCpixOGVf-Oz86zEznelU46kvQ1lU_N_cXg9ptT99v2s43UsqIWUsvT7kw/w400-h259/fam-2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;因為我老婆常在找她的拖鞋，所以我就作了一個找拖鞋的小遊戲給她。兒子雖然年紀還小，但我希望他從小養成時間觀念，所以作了一個時鐘小遊戲給他。女兒現在喜歡唱歌跳舞，所以作了一個簡單的音樂節奏小遊戲給她。至於我的遊戲，目前預計要跟拳頭星比比博士的電腦串連起來，不過還沒有進行。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbiUPcgRe0TwVLrK9aDBUtTwFra08CqJdVYUY86nVi7yM3q1K4xARpFcSwEU6rbdx3ft4nKQei-xoGHBORs-OxrO_H-DGzTEMe7BfDrLQmdUrtu_rgdc1S4_Q1XK24p9ZqQ7MiYWAtRuz/s1926/famgame.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;416&quot; data-original-width=&quot;1926&quot; height=&quot;138&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbiUPcgRe0TwVLrK9aDBUtTwFra08CqJdVYUY86nVi7yM3q1K4xARpFcSwEU6rbdx3ft4nKQei-xoGHBORs-OxrO_H-DGzTEMe7BfDrLQmdUrtu_rgdc1S4_Q1XK24p9ZqQ7MiYWAtRuz/w640-h138/famgame.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;(繼續更新)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2021/08/blog-post.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvBHxmOBTNxCgpdZB4cGVYAKwL89ide251iai5xH2UBGkPmYJXXKNrte5HSL4vQxMeBLbDSrq-U0-N_40hyZQC9ka0xWqtBgNDINHKD-SIqJjYnT-biMy_sgdE_ow9ZRp3tEI1RDKLH8Qq/s72-w400-h259-c/3470.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-8532424142086806278</guid><pubDate>Thu, 03 Jun 2021 15:39:00 +0000</pubDate><atom:updated>2022-11-02T11:11:51.857+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Android</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">QRCode</category><category domain="http://www.blogger.com/atom/ns#">ZXing</category><title>訊息刮刮樂 Message Scratch</title><description>&lt;p&gt;這個專案跟&lt;a href=&quot;https://good-ed.blogspot.com/2020/12/emoji-scratch.html&quot;&gt;繪文字刮刮樂EmojiScratch&lt;/a&gt;使用的核心技術是相同的，其實這個專案才是最早的靈感而建立的，只是因為在研發過程中嘗試了一些UI上的設計，但一直覺得不是很滿意。結果作到一半又基於同樣的技術產生了繪文字刮刮樂這個遊戲，也很快的製作完成，所以反而繪文字刮刮樂這個遊戲先release了，而訊息刮刮樂斷斷續續的修修改改直到這幾天才release。&lt;/p&gt;&lt;p&gt;&amp;lt;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.weilican.messagescratch&quot;&gt;Android&lt;/a&gt;&amp;gt; &amp;lt;&lt;a href=&quot;https://smallworld.idv.tw/game/msgscratch/?a=Zmc9JTIzYzRmZjAwJmJnPSUyM2ZmYjhmMiZ0Yz0lMjNmZjYyMDAmdHM9NDgmdHg9NCZ0eT0xMCZ0PSVFNiU5NyVBOSVFNSVBRSU4OSVFNiU4OCU5MSVFNyU5QSU4NCVFNiU5QyU4QiVFNSU4RiU4QiU1Q24lRTklODAlOTklRTYlOTglQUYlRTQlQjglODAlRTklQTElODYlRTglOTglOEIlRTYlOUUlOUMlRjAlOUYlOEQlOEUlNUNuJUU4JUFBJThEJUU1JTkwJThDJUU4JUFCJThCJUU1JTg4JTg2JUU0JUJBJUFCJUYwJTlGJThDJUI4&quot;&gt;範例&amp;gt;&lt;/a&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6p40GEUDyiTRxGxUs6mWZ8K8XtHRNHx4IpW6d1zUYr5ppjaqWPzp9TDsMXnhtuNAOEMrbmS6wnxQC34J2_i1Le71OPMlCZ9nxlZ1lZvuEZtZd4hbXChMSNrXRaqRuZS03dCgHu9Y9aivn/s1620/msgscratch.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;960&quot; data-original-width=&quot;1620&quot; height=&quot;381&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6p40GEUDyiTRxGxUs6mWZ8K8XtHRNHx4IpW6d1zUYr5ppjaqWPzp9TDsMXnhtuNAOEMrbmS6wnxQC34J2_i1Le71OPMlCZ9nxlZ1lZvuEZtZd4hbXChMSNrXRaqRuZS03dCgHu9Y9aivn/w640-h381/msgscratch.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;刮刮樂的製作相關技術可參考繪文字括括樂的記錄，而這個專案比較值得記錄的是關於QR Code掃瞄和顯示的功能。本專案的QR Code程式庫是使用&lt;a href=&quot;https://github.com/journeyapps/zxing-android-embedded&quot;&gt;zxing-android-embedded&lt;/a&gt;，這是&lt;a href=&quot;https://github.com/zxing/zxing/&quot;&gt;ZXing Barcode Scanner&lt;/a&gt;的精簡版本。&lt;/p&gt;&lt;p&gt;一開始的時候我並沒有直接整合QRCode程式庫，而是因為本來手機上己經有安裝BarcodeScanner了，所以可以直接在自己的APP裡面透過Android Intent的方式呼叫BarcodeScanner提供的掃瞄和顯示QRCode的功能。&lt;/p&gt;&lt;p&gt;呼叫BarcodeScanner的掃瞄QRCode功能很簡單，如下：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaYef4dHnrAh5KhuF3L3kJVfhpwOK0TZlsMijvw-M8Zde5jlUvQo6CmAI2jxE1kdWoUFMDzGA8WFlGb_ALB10JugtjhgpB9w4fjhaFCiqhT3tx-1h_ASRN4NFuhS6BM2l9CdRgHmphapZh/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;165&quot; data-original-width=&quot;688&quot; height=&quot;154&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaYef4dHnrAh5KhuF3L3kJVfhpwOK0TZlsMijvw-M8Zde5jlUvQo6CmAI2jxE1kdWoUFMDzGA8WFlGb_ALB10JugtjhgpB9w4fjhaFCiqhT3tx-1h_ASRN4NFuhS6BM2l9CdRgHmphapZh/w640-h154/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;顯示QRCode也同樣簡單，如下：&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpRYJo6wJadm5FQpkX386SNYc19BC3hkVJNQMhDuwU2eG7KcBgpXid2wne301IfTlpUNlj2QUWVcrAhkndtyC40hKLn_oLHo7XKzT42gc8cGPbsYTx_C1uSHPReQxUPNL7ceRspISXbtO3/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;197&quot; data-original-width=&quot;707&quot; height=&quot;178&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpRYJo6wJadm5FQpkX386SNYc19BC3hkVJNQMhDuwU2eG7KcBgpXid2wne301IfTlpUNlj2QUWVcrAhkndtyC40hKLn_oLHo7XKzT42gc8cGPbsYTx_C1uSHPReQxUPNL7ceRspISXbtO3/w640-h178/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;注意到上面二段code都是用try包起來，如果因為手機上沒有預先安裝BarcodeScanner無法使用功能的話，就可以幫user開啟google play下載頁面，讓user自行安裝。&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwvaRyx8KucGTzHnHISh4vjqGhnPkSeZoPAZKJlvYbbKRG5aTtG5Ukly7Wz6QT5_ct6mnnNVXXHZayLsSsq4I2irwtNcy03bgzJdCG3-0MTfLhJ_Tf_tUY7QfBXu1Dw726O3rNEt3AdMRo/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;86&quot; data-original-width=&quot;747&quot; height=&quot;74&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwvaRyx8KucGTzHnHISh4vjqGhnPkSeZoPAZKJlvYbbKRG5aTtG5Ukly7Wz6QT5_ct6mnnNVXXHZayLsSsq4I2irwtNcy03bgzJdCG3-0MTfLhJ_Tf_tUY7QfBXu1Dw726O3rNEt3AdMRo/w640-h74/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;;-----&lt;div&gt;&lt;br /&gt;在release之前以上面的作法快速且簡單的讓APP可以有掃瞄及顯示QRCode功能是很好，但當要真正release至google play上時，就會有違反google play policies的可能。因為在APP裡會跳出至google play的其它APP安裝頁面，會有虛假廣告的疑慮。所以這時候得要自己把QRCode程式庫整合進APP裡。&lt;p&gt;&lt;/p&gt;&lt;p&gt;選擇zxing-android-embedded作為QRCode程式庫，除了因為它是個精簡版的程式庫，最主要還是因為它的整合非常簡單，按照它的readme上的說明，只要幾行就搞定。&lt;/p&gt;&lt;p&gt;如readme上所說明的，只要在build.grandle裡加上如下幾行，即完成整合。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKj30dcQijQKMLaJCvWeX3luJ4T-wMnLRm4aBIVHa-ETm6uZIbJMlGaXBXfmPQUdleuja8mKMf3B9tB6pN50MsQf07s4ZTU-IJiQelufwQrZfYtdLWybAME2Q6_x0h1Wa__u6epy4RCbk0/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;235&quot; data-original-width=&quot;564&quot; height=&quot;266&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKj30dcQijQKMLaJCvWeX3luJ4T-wMnLRm4aBIVHa-ETm6uZIbJMlGaXBXfmPQUdleuja8mKMf3B9tB6pN50MsQf07s4ZTU-IJiQelufwQrZfYtdLWybAME2Q6_x0h1Wa__u6epy4RCbk0/w640-h266/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;接下來按照readme上的說明，透過使用IntentIntegrator就能很簡單的呼叫掃瞄QRCode的功能。&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6OV3x0hLOUxcW3Lj67Uq7D83CBC-JYDQpmd0-K2bM2mLkPVsdDT3brf9ebGW-_-dFltsjiHjR6tIePsd8FBlVzFSZj-KQyvXMYhW7m2XpQ9aovuqIOqvxBfH5jzPdJ7DJqcsVsQbIW-ZM/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;434&quot; data-original-width=&quot;747&quot; height=&quot;372&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6OV3x0hLOUxcW3Lj67Uq7D83CBC-JYDQpmd0-K2bM2mLkPVsdDT3brf9ebGW-_-dFltsjiHjR6tIePsd8FBlVzFSZj-KQyvXMYhW7m2XpQ9aovuqIOqvxBfH5jzPdJ7DJqcsVsQbIW-ZM/w640-h372/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;而使用BarcodeEncoder則可以產生一內含QRCode的Bitmap物件，有了這個Bitmap就可以指定給UI上的ImageView顯示QRCode了。&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjmlpLOBfniBkE6yg3j7wVFOKe_W9XqvT9OLSG1AasthFhq6YUW7ZH1C1lydSOmEyX8Qt8iB4ybsvqlcHksbua9IOo6W4TmBZ3GMi0bg6XSMXB7EpSh00RBhzQ9uNC0m-GH7nZWy2YlAuC/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;250&quot; data-original-width=&quot;836&quot; height=&quot;192&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjmlpLOBfniBkE6yg3j7wVFOKe_W9XqvT9OLSG1AasthFhq6YUW7ZH1C1lydSOmEyX8Qt8iB4ybsvqlcHksbua9IOo6W4TmBZ3GMi0bg6XSMXB7EpSh00RBhzQ9uNC0m-GH7nZWy2YlAuC/w640-h192/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2021/06/message-scratch.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6p40GEUDyiTRxGxUs6mWZ8K8XtHRNHx4IpW6d1zUYr5ppjaqWPzp9TDsMXnhtuNAOEMrbmS6wnxQC34J2_i1Le71OPMlCZ9nxlZ1lZvuEZtZd4hbXChMSNrXRaqRuZS03dCgHu9Y9aivn/s72-w640-h381-c/msgscratch.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-1094073369706119773</guid><pubDate>Wed, 12 May 2021 03:02:00 +0000</pubDate><atom:updated>2021-07-07T09:41:47.255+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">smallworld2</category><title>nature online 的架構</title><description>&lt;p&gt;nature online, no是以&lt;a href=&quot;https://good-ed.blogspot.com/2017/02/blog-post.html&quot;&gt;多人連線版本吃金幣的人&lt;/a&gt;為基礎所建立起來的一個網路架構實驗平台。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilUvktIc6VmKNPX0SGs0lsqNxcIZr7tLMNSvEW62xKKMdE-JsU2Irsf8b8ZGW3rXMQyFH_QQm8L-4rrRdJ9INSdRshbVrJ4FRUr4Ql0OjptrJJ_iM-Y92LRZugo047Ef-Gd519YaSyg11p/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;632&quot; data-original-width=&quot;802&quot; height=&quot;504&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilUvktIc6VmKNPX0SGs0lsqNxcIZr7tLMNSvEW62xKKMdE-JsU2Irsf8b8ZGW3rXMQyFH_QQm8L-4rrRdJ9INSdRshbVrJ4FRUr4Ql0OjptrJJ_iM-Y92LRZugo047Ef-Gd519YaSyg11p/w640-h504/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen=&quot;&quot; class=&quot;BLOG_video_class&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/X5HoJUb47wU&quot; width=&quot;320&quot; youtube-src-id=&quot;X5HoJUb47wU&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;雛形版本功能如下：&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span face=&quot;Arial, Tahoma, Helvetica, FreeSans, sans-serif&quot; style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- 分散式的網路伺服器架構，後端使用mysql。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- 使用2張測試地圖，隨時可以任意切換至任意地圖任意位置。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- 地圖物件有二種:tree,bug。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span face=&quot;Arial, Tahoma, Helvetica, FreeSans, sans-serif&quot; style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- tree物件應用&lt;/span&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Conway&#39;s_Game_of_Life&quot; style=&quot;background-color: white; color: #2288bb; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13.2px; text-decoration-line: none;&quot;&gt;生命遊戲規則&lt;/a&gt;&lt;span face=&quot;Arial, Tahoma, Helvetica, FreeSans, sans-serif&quot; style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;生成及更新。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- bug物件應用&lt;a href=&quot;https://en.wikipedia.org/wiki/Genetic_algorithm&quot;&gt;基因算法&lt;/a&gt;活動，食物為tree物件。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- 自動同步client可見視野內的內容。&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;- 使用&lt;a href=&quot;https://github.com/cnyaw/good&quot;&gt;good&lt;/a&gt;為client成象引擎。&lt;/span&gt;&lt;/div&gt;&lt;p&gt;新增功能如下：&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;- 可監控,動態增減server節點。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;- 新增地圖物件:bird,base,ship。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;- bird物件應用&lt;a href=&quot;https://en.wikipedia.org/wiki/Boids&quot;&gt;鳥群算法(boids)&lt;/a&gt;控制。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;- base物件對應每一個帳號在地圖上的基地。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;- ship物件為bot/testclient自動從base出發前往地圖採集tree物件得到log資源。&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;-&amp;nbsp;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;調整&lt;/span&gt;&lt;span style=&quot;background-color: white; color: #222222; font-size: 13.2px;&quot;&gt;自動同步client可見視野內的內容機制提升效能。&lt;/span&gt;&lt;/div&gt;&lt;p&gt;no底層是以&lt;a href=&quot;https://github.com/cnyaw/sw2&quot;&gt;smallworld2&lt;/a&gt;的Bigworld架構為基礎再往上架構出來的一個分散式game server架構，每一個server都是一個Bigword節點，設定好conf後Bigworld底層會自動建立並保持節點關係。底下是架構圖：&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGDza6T2GEXJ5RdlycK6pegnnCPe_7Tv8-ycoHza1NlPcMOKZg2EERhJ-qq1WAOFQjjrxMthEDbSHubcV14R8eWoDSW1CbX3ATJKGI-V1kaCfeeuNCp-CZz9xF-d8wKUDYDuJNPbwBbFB/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;372&quot; data-original-width=&quot;463&quot; height=&quot;514&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigGDza6T2GEXJ5RdlycK6pegnnCPe_7Tv8-ycoHza1NlPcMOKZg2EERhJ-qq1WAOFQjjrxMthEDbSHubcV14R8eWoDSW1CbX3ATJKGI-V1kaCfeeuNCp-CZz9xF-d8wKUDYDuJNPbwBbFB/w640-h514/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;center：這是所有server的server，所有server都需要連線到它。center作為一個中央控制server，可以作其它server的訊息轉發者，也能夠控制其它server的開關。&lt;/li&gt;&lt;li&gt;login：負責轉發client的登入，因此每一台login都知道所有其它game的存在。login登入center後，即註冊自己讓client可以在登入時隨機選一台login作登入。&lt;/li&gt;&lt;li&gt;game：game負責gameplay功能實作。client由login登入game時，是由login幫client隨機選擇一個game登入。&lt;/li&gt;&lt;li&gt;client：client登入時由指定url取得一隨機login位址，登入login後再由login轉發至隨機一台game。client登入game後即和login斷線。&lt;/li&gt;&lt;li&gt;db：db負責作為no架構裡mysql的代理，所以狀態讀寫都針對db，再由db對mysql讀寫。client登入game後，game即向db讀取和此client有關的帳號資料。遊戲過程中有任何變化需要儲存即存入db，再由db批次存入mysql。&lt;/li&gt;&lt;li&gt;account：所有帳號和db/mysql的關聯以及是否online等資訊由account記錄維護。client登入game後，game也會向account註冊此client帳號目前所在game位置。若是新帳號登入，則account會指派此新帳號，以後此帳號的資料會由那個db負責存取。&lt;/li&gt;&lt;li&gt;map：client畫面上看到的物件，如tree,bug,bird,base,ship等全由map產生維護。&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;以上是no節點的大略介紹。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;;-----------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;每個server節點程式就是一個console程式，所以執行起來後在畫面上都以文字模式顯示狀態及訊息，同時也能以簡單的命令操作server功能。不知道server支援什麼指令時，只需輸入help即可得到簡單的指令列表及說明。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLveKaPt9ouscNJUW-AY7khXrfXHNfXD40omUUAWNmZNBm1Zte3xxbaUK82pv6o6etRiJ0NfABHN8jL-R0WXP7qCcuArqYMrr-0xAqtNYRv7vIzrcHkNPTzKPeIZawfy-KXVWHehUST0vY/s979/center.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;979&quot; height=&quot;334&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLveKaPt9ouscNJUW-AY7khXrfXHNfXD40omUUAWNmZNBm1Zte3xxbaUK82pv6o6etRiJ0NfABHN8jL-R0WXP7qCcuArqYMrr-0xAqtNYRv7vIzrcHkNPTzKPeIZawfy-KXVWHehUST0vY/w640-h334/center.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如圖所示的certer help列表可以看到，center有help,info,exit,shutdown,remote,fork等指令可使用。前3個指令help,info,exit是所有節點都支援的common指令，不同server節點可能會提供不同的特有指令，而shutdown,remote,fork是center特有的指令。server負載過大可用fork新增節點，要關機時用shutdown指令一次全部關機，就不必一個一個server關不遺漏。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;雖然info是每個server都支援的指令，但根據server類型不同，顯示的info內容除了header格式相同外，其餘內容也會有不同。如上圖center的info就包含每一個連線到center的節點的info，而如下圖map的info內容就包含地圖info。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDEuqEnsEdzBMhSQ08x_39Qdd7MYrzuELSibpIj0E6E-WDdXy532qpvTEnyCyqszvv8SbhfyTjFTXqJ1rCmHQ3jQ9g6Iw-fTUPA_SRNkPRhL4vGxUJPr6mxZVPZVA_VNxr-nnGlBvAt1SS/s979/map.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;979&quot; height=&quot;334&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDEuqEnsEdzBMhSQ08x_39Qdd7MYrzuELSibpIj0E6E-WDdXy532qpvTEnyCyqszvv8SbhfyTjFTXqJ1rCmHQ3jQ9g6Iw-fTUPA_SRNkPRhL4vGxUJPr6mxZVPZVA_VNxr-nnGlBvAt1SS/w640-h334/map.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;附帶提一下，center同時也內建web service，所以center的console內容和操作也可以透過browser對center作存取。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;;------------&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;server程式開發最重要的就是穩定，想確保server穩定最簡單的方法是作該作的測試和夠多的測試。所以從一開始server雛形建立的同時，我也同時會建立一個testclient雛形。一開始也是一個console程式，後來再建立gui程式。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEharicojjIpi4rAh-ikU2v-Et4snOEZw_rW3zHZEXs7cJQ6hTBNykPdBdq0-jDCZqLNEhbhZlShKEPCw54GZI9-UHUWIsB_bv-WljBDo3v1M9xXlLvhf9yzp54qd28ai-9j4-7QaBreOqtU/s979/testclient.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;512&quot; data-original-width=&quot;979&quot; height=&quot;334&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEharicojjIpi4rAh-ikU2v-Et4snOEZw_rW3zHZEXs7cJQ6hTBNykPdBdq0-jDCZqLNEhbhZlShKEPCw54GZI9-UHUWIsB_bv-WljBDo3v1M9xXlLvhf9yzp54qd28ai-9j4-7QaBreOqtU/w640-h334/testclient.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;testclient的雛形就只是一個可以連線登入到game的console程式，可以顯示送到server和收到server的訊息內容這樣子就夠了，這樣簡單的程式就能讓整個server開發動起來，以後再以這樣的基礎繼續加功能繼續改良。最重要的是，有了testclient就能很方便快速的debug。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;當server開發到一個程度後，想要開始作一點簡單的壓力測試時，可以很簡單的用batch file重復多開幾個testclient就行了。寫2個批次檔，RunTest1.bat一次執行一個testclient，RunTestN.bat可以透過RunTest1.bat用for迴圈一次執行多個testclient。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如下所示：&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFp9dwJKv-Sy0eryK0xb_FHhptZr5HXh2FUudIe7us1qmBkTYHSgUVjBeGMnENYeAqrpsUYLh5qtJAW9H062gZEBfyB78MpYevQztyFQu6eHtNJtVCObXvYFpgm7UyVKP7mBMEdE7j3yQy/s608/runtestbat.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;194&quot; data-original-width=&quot;608&quot; height=&quot;204&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFp9dwJKv-Sy0eryK0xb_FHhptZr5HXh2FUudIe7us1qmBkTYHSgUVjBeGMnENYeAqrpsUYLh5qtJAW9H062gZEBfyB78MpYevQztyFQu6eHtNJtVCObXvYFpgm7UyVKP7mBMEdE7j3yQy/w640-h204/runtestbat.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;這個方法很簡單很暴力，初期這樣作簡單的壓力測試還可以，中後期要作比較大量的壓力測試時就有問題了。因為每一個testclient執行一個console，100個testclient就100個console，電腦還勉強可以。但當開了200,300,400..到一個量之後電腦資源就被吃光不行了，所以後面勢必要改成一個testclient console可以支援多個連線才行，這樣就可以作更大規模的壓力測試。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;;------------&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;一開始為了簡化設計client登入game後，每隔一段時間由game自動替這個client向map請求他的視野範圍內的可視物件狀態資訊。map回應視野內的物件資訊給game後，game再根據簡單的狀態檢查，只傳送client視野內有變化的物件資訊給client作畫面更新。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;地圖物件的更新有二種類型，一是以當前位置狀態更新給client，如tree,bug,bird,base等。另一種是有起點和終點的長距離移動物件，如ship。第一種類型物件的更新資訊會不斷從server傳至client，讓client有機會可以更新畫面。第二種類型物件只有在需要的時候才更新給client，其餘時間由client自行根據移動物件的起止點作內插更新。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;這也是很簡單又暴力的方法，當client不多時還好，但當client多起來的時候server之間的封包量非常大，server光是要處理這麼大的封包就可能來不及消化，以致於server反應愈來愈慢。game這邊定時發給map的請求是暫時方便測試的作法，所以會有大量重覆請求及大量多餘封包。以後需要改成其它機制，這是接下來要作的改良。&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2021/05/nature-online.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilUvktIc6VmKNPX0SGs0lsqNxcIZr7tLMNSvEW62xKKMdE-JsU2Irsf8b8ZGW3rXMQyFH_QQm8L-4rrRdJ9INSdRshbVrJ4FRUr4Ql0OjptrJJ_iM-Y92LRZugo047Ef-Gd519YaSyg11p/s72-w640-h504-c/image.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-7518372480384993407</guid><pubDate>Tue, 29 Dec 2020 15:09:00 +0000</pubDate><atom:updated>2022-11-02T11:12:20.109+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">javascript</category><title>繪文字刮刮樂 Emoji Scratch</title><description>&lt;p&gt;使用html5+javascript+emoji，做了一個給小孩玩的刮刮樂小遊戲，讓他們學習簡單的英文單字。如果在chrome上使用，還可以利用tts英文發音唸出單字，讓小孩也能練習英文聽力及發音。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5baPbopDKtoCgjc4q4aqU4A1JUZGUniMFOuPiH-WI9IBEtF9ONHJFG6AiFTQBQzJf_606NWjNPnrZppdJngs8UBZuRO3zf7scwu5k1nXt7kbRFWy_60EmJ1NIKGccyIMUDX0R8cVE-2_W/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1920&quot; data-original-width=&quot;1080&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5baPbopDKtoCgjc4q4aqU4A1JUZGUniMFOuPiH-WI9IBEtF9ONHJFG6AiFTQBQzJf_606NWjNPnrZppdJngs8UBZuRO3zf7scwu5k1nXt7kbRFWy_60EmJ1NIKGccyIMUDX0R8cVE-2_W/&quot; width=&quot;135&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCZuNjY-fquoS7FKZqXYhNOUgZS6OnmdtJsHxy-YLG6wREvIKL4jE49dQ7YvJWBvLCjA-BCYZamj_-2bEoauVIHjNmqAz1AkQfJm1L0FxRoL-Wk04Z9DfgUeqjMlJgb8deXLtJTrV8GOQ/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;1920&quot; data-original-width=&quot;1080&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCZuNjY-fquoS7FKZqXYhNOUgZS6OnmdtJsHxy-YLG6wREvIKL4jE49dQ7YvJWBvLCjA-BCYZamj_-2bEoauVIHjNmqAz1AkQfJm1L0FxRoL-Wk04Z9DfgUeqjMlJgb8deXLtJTrV8GOQ/&quot; width=&quot;135&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/emojiscratch/&quot;&gt;玩&lt;/a&gt;&amp;nbsp; /&amp;nbsp;&lt;a href=&quot;https://play.google.com/store/apps/details?id=com.weilican.emojiscratch&quot;&gt;Android&lt;/a&gt;&amp;nbsp;/&amp;nbsp;&lt;a href=&quot;https://github.com/cnyaw/EmojiScratch&quot;&gt;Github&lt;/a&gt;&lt;/p&gt;&lt;p&gt;底下是開發這個遊戲的一些技術重點紀錄。&lt;/p&gt;&lt;p&gt;1，刮刮樂的部分是使用html5的canvas製作。原理是使用兩個canvas，一個作底圖圖層(c0)，一個做為可被刮除的前景遮罩圖層(c1)，c1預設不可見為一記憶體圖層。把c0的原始圖型內容事先存起來作為後續更新使用，並在c0上安裝onmousedown,onmouseup及onmousemove，滑鼠滑動時以在c1上畫粗直線的方式模擬出刮除效果，然後再以新的c1前景遮罩結合事先儲存的c0底圖重新合併更新畫面，這樣就能作出刮刮樂的效果。&lt;/p&gt;&lt;p&gt;c1上的刮除效果是利用將2d context的globalCompositeOperation設為&#39;destination-out&#39;模式，並且strokeStyle設為&#39;rgba(0,0,0,1)&#39;，以這樣子的設定在c1上畫線時，得到的是一個擦除的效果，這樣就作到刮刮樂刮除的效果。&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;c0.onmousemove = function(e) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (mouse_down) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.strokeStyle = &#39;rgba(0,0,0,1)&#39;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.globalCompositeOperation = &#39;destination-out&#39;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.lineWidth = 18;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.lineCap = &#39;round&#39;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.beginPath();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.moveTo(last_x, last_y);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.lineTo(x, y);&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; ctx1.stroke();&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; last_x = x;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; last_y = y;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; updateCanvas();&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;p&gt;更新畫面的方法是以getImageData從c1抓取整張前景遮罩，對每一個pixel檢查如果alpha值是0表示這個點己刮除，則這個點取c0的同一位置的顏色值，否則表示這個點還未刮除需要取c1的前景遮罩顏色。所有pixel都處理完成後，再把整個新的合併事先儲存的c0的背景底圖內容的imagedata透過putImageData畫到c0上更新。&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;function updateCanvas() {&lt;br /&gt;&amp;nbsp; var imgData = ctx1.getImageData(0, 0, width, height);&lt;br /&gt;&amp;nbsp; var imgDataNew = ctx1.getImageData(0, 0, width, height);&lt;br /&gt;&amp;nbsp; for (var i = 0; i &amp;lt; width*height*4; i+=4) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; var a = imgData.data[i+3];&lt;br /&gt;&amp;nbsp; &amp;nbsp; if (0 == a) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; imgDataNew.data[i] = imgDataSrc.data[i];&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; imgDataNew.data[i+1] = imgDataSrc.data[i+1];&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; imgDataNew.data[i+2] = imgDataSrc.data[i+2];&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; imgDataNew.data[i+3] = imgDataSrc.data[i+3];&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; ctx.putImageData(imgDataNew, 0, 0);&lt;br /&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;2，如果是使用chrome browser來執行這個遊戲，則能夠利用chrome的文字轉語音(TTS)功能唸出英文單字。這裡是透過window.speechSynthesis及SpeechSynthesisUtterance來完成這個功能，如下程式片段所示。&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;function trySpeak(s) {&lt;/div&gt;&lt;div&gt;if (window.speechSynthesis) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; var msg = new SpeechSynthesisUtterance(s);&lt;/div&gt;&lt;div&gt;&amp;nbsp; if (msg) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; msg.lang = &quot;en-US&quot;;&lt;/div&gt;&lt;div&gt;&amp;nbsp; &amp;nbsp; window.speechSynthesis.speak(msg);&lt;/div&gt;&lt;div&gt;&amp;nbsp; }&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;3，為了讓括括樂canvas太大在計算時計算量跟著太大，所以把大小限制為300x300，但這樣一來畫面顯示的時候又會顯的太小。所以為了讓這個300x300px的canvas可以填滿畫面，需多作一點微調。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;首先在html內的viewport屬性就把它剛好設為300px，讓畫面寬度剛好符合300px。另外記得把body預設的margin和padding都設為0，才不會不小心多出其它px，讓canvas的300px被切掉。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;lt;head&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&amp;gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&amp;lt;style type=&quot;text/css&quot;&amp;gt;&lt;/div&gt;&lt;div&gt;body {margin:0;padding:0;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&amp;lt;/style&amp;gt;&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&amp;lt;/head&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如果是在android裡用WebView來作顯示時，需要多作點參數設定，確保view可以填滿畫面。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;WebView wv = findViewById(R.id.webView);&lt;/div&gt;&lt;div&gt;wv.getSettings().setLoadWithOverviewMode(true);&lt;/div&gt;&lt;div&gt;wv.getSettings().setUseWideViewPort(true);&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;最後如果是在一般browser裡顯示的話，為了讓畫面顯示比較符合原始設計，使用iframe把原始html包裹起來，大小設定可以包含括括樂canvas即可。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&amp;lt;iframe src=&quot;emojiscratch.html&quot; title=&quot;EmojiScratch&quot; width=&quot;310&quot; height=&quot;500&quot; frameborder=&quot;0&quot;&amp;gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;4、遊戲內以表格事先編好有那些emoji的資料，但因為這個遊戲是以web的方式來呈現，而在不同裝置上的browser呈現的emoji可能都各不相同，甚至有些emoji是不支援無法顯示的。所以需要在遊戲前先把那些不支援無法顯示的emoji挑選出來，只是目前沒有什麼標準的方法或api可以作這樣的檢查，所以這裡用一個間接的方式來作檢查。使用的方式是試著把要檢查的emoji畫到一個作為檢查用的canvas，這個canvas的大小只要設為1個pixel大小。如果這個canvas上面有畫出東西(alpha值不為0)，那麼就表示這個emoji是可顯示的，否則就當作它無法顯示。當然用這種方式不能保證100%正確有效，但至少是個可行的辨法，可以避免在emoji不支援時顯示出一個X。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;function supportsEmoji(ch) {&lt;/div&gt;&lt;div&gt;&amp;nbsp; const ctx = document.createElement(&quot;canvas&quot;).getContext(&quot;2d&quot;);&lt;/div&gt;&lt;div&gt;&amp;nbsp; ctx.canvas.width = ctx.canvas.height = 1;&lt;/div&gt;&lt;div&gt;&amp;nbsp; ctx.fillText(ch, -4, 4);&lt;/div&gt;&lt;div&gt;&amp;nbsp; return ctx.getImageData(0, 0, 1, 1).data[3] &amp;gt; 0; // Not a transparent pixel.&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2020/12/emoji-scratch.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5baPbopDKtoCgjc4q4aqU4A1JUZGUniMFOuPiH-WI9IBEtF9ONHJFG6AiFTQBQzJf_606NWjNPnrZppdJngs8UBZuRO3zf7scwu5k1nXt7kbRFWy_60EmJ1NIKGccyIMUDX0R8cVE-2_W/s72-c" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-2975708179852110458</guid><pubDate>Sun, 12 Jul 2020 15:20:00 +0000</pubDate><atom:updated>2023-02-16T19:59:49.879+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Emscripten</category><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">Porting</category><title>C/C++遊戲程式透過Emscripten編譯為javascript移植成web版</title><description>最近一兩周利用空檔時間將過去作過的幾個小遊戲，改版成簡單的對應的web版。原來的程式底層都是使用C/C++實作，透過&lt;a href=&quot;https://emscripten.org/&quot;&gt;Emscripten&lt;/a&gt;將原來的程式build成javascript，然後再結合web應用完成簡單的移植。因為原來的程式一開始在實作時就幾乎是可以跨平台的，所以移植很順利很快。我目前使用的Emscripten是1.35.0版本，因為只是用作移植測試目的，自從安裝後就沒有再更新過。&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;完成移植的遊戲分別是：&lt;/div&gt;&lt;div&gt;&lt;ul style=&quot;text-align: left;&quot;&gt;&lt;li&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/idiomcalc&quot;&gt;成語四則運算&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/cgo101/&quot;&gt;單人撲克101&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/pn2005/play.html&quot;&gt;Paint by Numbers 2005&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://smallworld.idv.tw/game/ks/aws.html&quot;&gt;精彩數獨詳解&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;移植的基本原則很簡單：&lt;/div&gt;&lt;div&gt;&lt;ol style=&quot;text-align: left;&quot;&gt;&lt;li&gt;首先確定原來的C/C++程式可以在Emscripten的command line環境下編譯。&lt;br /&gt;&lt;/li&gt;&lt;li&gt;再來定義一些API可以讓html綱頁裡的javascript呼，這個部份更多細節可以參考&lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html&quot;&gt;官方網站的文件&lt;/a&gt;說明。&lt;/li&gt;&lt;li&gt;C/C++讓javascript呼叫的API定義好後，也編譯成功了。就可以先用printf的方式作簡單的測試，測試方式也很簡單。如下圖的例子，是一個簡單的將兩個數字相加並回傳和數的cAPI cAdd。在mainl裡用一個printf作簡單的測試，然後在cmdline環境下編譯成功後，透過nodejs來執行觀察結果是否正確。&lt;br /&gt;&lt;img alt=&quot;&quot; src=&quot;data:image/png;base64,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&quot; /&gt;&lt;/li&gt;&lt;li&gt;API初步沒有問題了，然後就可以真正撰寫些code來呼叫這些API，主要方式是在javascript裡透過Module.ccall來呼叫我們的API。Module.ccall的第一個參數是API的名稱，第二個參數是API的回傳值類型，第三個參數是API的參數列表類型，第四個參數是參數列表。在我們的例子裡，API名稱叫作cAdd，回傳值是一個數字類型，參數列表是兩個數字類型，輸入1和2。結果用一個alert顯示出來，正確答案是3。&lt;br /&gt;&lt;img alt=&quot;&quot; src=&quot;data:image/png;base64,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&quot; /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;透過以上幾個簡單的原則，很容易就可以把一些原本用C/C++寫成的程式，改版成網頁版。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://good-ed.blogspot.com/2020/07/ccemscriptenjavascriptweb.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-3275765395971636242</guid><pubDate>Tue, 08 May 2018 17:13:00 +0000</pubDate><atom:updated>2020-10-18T23:17:33.287+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>Good Game Editor 1.6.4</title><description>&lt;ul style=&quot;background-color: white; font-family: sans-serif; font-size: 12.7px; line-height: 1.5em; list-style-image: url(&amp;quot;bullet.gif&amp;quot;); list-style-type: square; margin: 0.3em 0px 0px 1.5em; padding: 0px;&quot;&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;改良關卡編輯器(LevelEditor)中Dummy物件圖示。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;地圖物件(Map)或精靈物件(Sprite)只有在實際出現在畫面中時才載入貼圖。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;關卡編輯器(LevelEditor)點擊物件階層樹上的物件時畫面立即捲動至該物件。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;關卡編輯器(LevelEditor)中物件顯示不可見狀態圖示若父物件為不可見狀態。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;Util新增Good.GetScreenPos計算物件銀幕絕對座標。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;修正取得色塊物件大小尺寸的錯誤。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;一個DrawCall最多支援一次畫1024個物件。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;新增&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Graphics_GenCanvas&quot;&gt;Graphics.GenCanvas&lt;/a&gt;&lt;span id=&quot;goog_604922109&quot;&gt;&lt;/span&gt;&lt;a href=&quot;https://www.blogger.com/&quot;&gt;&lt;/a&gt;&lt;span id=&quot;goog_604922110&quot;&gt;&lt;/span&gt;、&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Graphics_KillCanvas&quot;&gt;Graphics.KillCanvas&lt;/a&gt;支援建立及刪除虛擬畫布。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;新增&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Resource_UpdateTex&quot;&gt;Resource.UpdateTex&lt;/a&gt;支援以虛擬畫面更新貼圖資料。&lt;/li&gt;
&lt;li style=&quot;margin-bottom: 0.1em;&quot;&gt;&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Graphics_FillRect&quot;&gt;Graphics.FillRect&lt;/a&gt;、&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Graphics_DrawImage&quot;&gt;Graphics.DrawImage&lt;/a&gt;及&lt;a href=&quot;https://good-ed.smallworld.idv.tw/wiki/index.php?title=Graphics_DrawText&quot;&gt;Graphics.DrawText&lt;/a&gt;支援繪至虛擬畫布。&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 12.7px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 12.7px;&quot;&gt;[ &lt;a href=&quot;http://good-ed.smallworld.idv.tw/forum/download/file.php?id=56&quot;&gt;下載&lt;/a&gt; ]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
</description><link>http://good-ed.blogspot.com/2018/05/good-game-editor-164.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-3642038555428727740</guid><pubDate>Tue, 10 Oct 2017 16:10:00 +0000</pubDate><atom:updated>2020-10-18T23:17:38.698+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>Good Game Editor 1.6.3</title><description>* 最佳化色塊繪製方式大幅提升繪圖效能。&lt;br /&gt;
* 修正FPS計算顯示&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&lt;a href=&quot;http://good-ed.smallworld.idv.tw/forum/download/file.php?id=55&quot;&gt;Download&lt;/a&gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2017/10/good-game-editor-163.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-6899153553246225995</guid><pubDate>Sun, 25 Jun 2017 16:52:00 +0000</pubDate><atom:updated>2020-10-18T23:17:43.839+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Emscripten</category><category domain="http://www.blogger.com/atom/ns#">good</category><category domain="http://www.blogger.com/atom/ns#">Porting</category><title>Good Emscripten Porting</title><description>最近試了一下&lt;a href=&quot;http://kripken.github.io/emscripten-site/index.html&quot;&gt;Emscripten&lt;/a&gt;將good編譯成web版本，也就是透過Emscripten使用&lt;a href=&quot;http://llvm.org/&quot;&gt;LLVM&lt;/a&gt;技術將C/C++編譯成javascript，這樣就可以在browser上執行了。&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinCupbEMYlRK3DlXSZoZDveIO2IGTkWaAYC-3Mx8HZplxtHT3y8arhNlSWBXWCRDEdAOm7DGtZPe_HcJcjc_3KCr9mtvWEFezmKCMsfnYOEMsAAwhov1a6U2Ph2BoQzP0T1aXgEfQGjwiF/s1600/emscripten.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;768&quot; data-original-width=&quot;1366&quot; height=&quot;223&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinCupbEMYlRK3DlXSZoZDveIO2IGTkWaAYC-3Mx8HZplxtHT3y8arhNlSWBXWCRDEdAOm7DGtZPe_HcJcjc_3KCr9mtvWEFezmKCMsfnYOEMsAAwhov1a6U2Ph2BoQzP0T1aXgEfQGjwiF/s400/emscripten.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span id=&quot;goog_1853761908&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_1853761909&quot;&gt;&lt;/span&gt;&lt;br /&gt;
一開始先不管圖形顯式的話，移植都還算很順利，可以在下方看到接上trace log之後表示功能移植完成。接下來使用OpenGL版本的繪圖模組來作成像移植，不過這部份不是很順利，只有色塊可以正常顯示，圖形就都無法正常顯示出來。可能是我的OpenGL版本的繪圖模組太老舊了，Emscripten沒辨法100%相容支援，最後沒辨法只好將OpenGL版本的繪圖模組換成SDL版本的繪圖模組，因為SDL是Emscripten預設內建支援的成像引擎，結果圖形就能正常顯示了，只不過缺點是SDL版本的繪圖模組功能很陽春，很多像是縮放旋轉等功能沒實作，因為是使用SDL1。&lt;br /&gt;
&lt;br /&gt;
不過還有個問題，預設參數編譯出來的js檔有10M，太大了。但如果加上-O2之類的最佳化編譯選項後，結果會造成無法執行(或者是載入太久?)。如果改成使用wasm編譯參數就可以配會-O1以上最佳化參數，編譯出來的檔案再加上使用Closure Compiler去除空白字元等，大小就會小於5M。&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNshZgY0WgjpRRzCfMRBnbxyjlYIv5qimiQ9owEXFupztS4Mad4gH8tTaQrgGI7DAm19mB1MWdCGGurMKrWowLoT8NnbcTX6rwT73Eq1h-h54SjtZrN84-5uNz50zvScTK-8pJifEiBYg5/s1600/Screenshot_2017-07-04-17-25-03.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;720&quot; data-original-width=&quot;1280&quot; height=&quot;225&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNshZgY0WgjpRRzCfMRBnbxyjlYIv5qimiQ9owEXFupztS4Mad4gH8tTaQrgGI7DAm19mB1MWdCGGurMKrWowLoT8NnbcTX6rwT73Eq1h-h54SjtZrN84-5uNz50zvScTK-8pJifEiBYg5/s400/Screenshot_2017-07-04-17-25-03.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
底下是測試連結。&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.smallworld.idv.tw/test01/&quot;&gt;Test&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
這個測試連結同時也以php簡單的實作了上傳及表列good檔案，以及執行選取的good檔案。&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrUo7R62rzREWG2vC8Dxz4Imb0SneueDYY3vYIXexrC8q-LtrShxG9GZpx6hHAMgE9cq0R3ZV77AaLCeeMuyGGAd8anKsf7lVRznMTFZX-XhQERcB-_Qf0TJzZvMi_HPvfN9FS4m392UOS/s1600/UploadPkg.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;154&quot; data-original-width=&quot;678&quot; height=&quot;90&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrUo7R62rzREWG2vC8Dxz4Imb0SneueDYY3vYIXexrC8q-LtrShxG9GZpx6hHAMgE9cq0R3ZV77AaLCeeMuyGGAd8anKsf7lVRznMTFZX-XhQERcB-_Qf0TJzZvMi_HPvfN9FS4m392UOS/s400/UploadPkg.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2017/06/blog-post.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinCupbEMYlRK3DlXSZoZDveIO2IGTkWaAYC-3Mx8HZplxtHT3y8arhNlSWBXWCRDEdAOm7DGtZPe_HcJcjc_3KCr9mtvWEFezmKCMsfnYOEMsAAwhov1a6U2Ph2BoQzP0T1aXgEfQGjwiF/s72-c/emscripten.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-7880766210202678981</guid><pubDate>Sun, 18 Jun 2017 15:35:00 +0000</pubDate><atom:updated>2020-10-18T23:17:49.384+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>Good Game Editor 1.6.2</title><description>* 修正播放器(In Editor Player)顯示貼圖資訊的問題。&lt;br /&gt;
* 修正關卡編輯器物件樹點擊關卡物件程式當掉的問題。&lt;br /&gt;
* 新增&lt;a href=&quot;http://good-ed.smallworld.idv.tw/wiki/index.php?title=Good_GenObjEx&quot;&gt;Good.GenObjEx&lt;/a&gt;支援從外部資源包(External Good Package)生成物件。&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;http://good-ed.smallworld.idv.tw/forum/download/file.php?id=54&quot;&gt;Download&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</description><link>http://good-ed.blogspot.com/2017/06/good-game-editor-162.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-9206917297569656802</guid><pubDate>Sat, 29 Apr 2017 17:33:00 +0000</pubDate><atom:updated>2020-10-18T23:17:54.892+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>戰鬥象棋</title><description>這是個休閒放置類型的即時象棋戰鬥小遊戲。(&lt;a href=&quot;https://play.google.com/store/apps/details?id=weilican.bch&amp;amp;hl=zh_TW&quot;&gt;Android下載&lt;/a&gt;) (&lt;a href=&quot;https://github.com/cnyaw/bch&quot;&gt;src&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNhocM-bsgJQNgGoPPS1FmZdLs4m3dGiWB-LIRafMy4loFlJjLZrCpb88JUDsR7ByNmO7Ha3LUCLdoibBdizDcbwL_lOb4IUqyp6xOx1V7GMEnJ_HYLP0HsLW5zUhF216R05aWE8y8a8Zq/s1600/Screenshot_2017-04-29-12-04-22.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNhocM-bsgJQNgGoPPS1FmZdLs4m3dGiWB-LIRafMy4loFlJjLZrCpb88JUDsR7ByNmO7Ha3LUCLdoibBdizDcbwL_lOb4IUqyp6xOx1V7GMEnJ_HYLP0HsLW5zUhF216R05aWE8y8a8Zq/s400/Screenshot_2017-04-29-12-04-22.png&quot; width=&quot;225&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &amp;quot;roboto&amp;quot; , &amp;quot;uilanguagefont&amp;quot; , &amp;quot;arial&amp;quot; , sans-serif; font-size: 14px;&quot;&gt;* 共有六種不同兵種可以訓練&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &amp;quot;roboto&amp;quot; , &amp;quot;uilanguagefont&amp;quot; , &amp;quot;arial&amp;quot; , sans-serif; font-size: 14px;&quot;&gt;* 戰鬥型態有近戰型及遠距型&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &amp;quot;roboto&amp;quot; , &amp;quot;uilanguagefont&amp;quot; , &amp;quot;arial&amp;quot; , sans-serif; font-size: 14px;&quot;&gt;* 兵種有攻擊型及輔助型&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &amp;quot;roboto&amp;quot; , &amp;quot;uilanguagefont&amp;quot; , &amp;quot;arial&amp;quot; , sans-serif; font-size: 14px;&quot;&gt;* 每一兵種有二種技能&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #333333; font-family: &amp;quot;roboto&amp;quot; , &amp;quot;uilanguagefont&amp;quot; , &amp;quot;arial&amp;quot; , sans-serif; font-size: 14px;&quot;&gt;* 無限關卡可以挑戰&lt;/span&gt;&lt;br /&gt;
------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
底下是演化圖...&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJVpv5QK4PCB0KuK3xl3Ir1VNfDuporPuOwuD3BGkSoPNOv26i2U5x9Sl4H8qQP4JwdWHMP7Jvt-CqJOKUyvBmoThn3rzsy0ipoSgf7FrnDrQvG5Fl0C0aqelBK_BcdJKYEBc090tEFjsu/s1600/Screenshot_2017-03-04-14-44-59.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJVpv5QK4PCB0KuK3xl3Ir1VNfDuporPuOwuD3BGkSoPNOv26i2U5x9Sl4H8qQP4JwdWHMP7Jvt-CqJOKUyvBmoThn3rzsy0ipoSgf7FrnDrQvG5Fl0C0aqelBK_BcdJKYEBc090tEFjsu/s320/Screenshot_2017-03-04-14-44-59.png&quot; width=&quot;179&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Af4way1T8mI5ok0FIz17OgzpB2GRGKbAIDfvj5JrhOecOUHInI1wQ392FXiGwO8ICBNtkhc9yM6TAX32LfdJtwE1f62bUno9guv5Qub93JFgN2QhAbEZrFdDHrEpeI9hT1_LQhBKk1Gf/s1600/Screenshot_2017-03-06-23-18-10.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Af4way1T8mI5ok0FIz17OgzpB2GRGKbAIDfvj5JrhOecOUHInI1wQ392FXiGwO8ICBNtkhc9yM6TAX32LfdJtwE1f62bUno9guv5Qub93JFgN2QhAbEZrFdDHrEpeI9hT1_LQhBKk1Gf/s320/Screenshot_2017-03-06-23-18-10.png&quot; width=&quot;179&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwlNmcTPuWiFD2bXQ6xY88hrwIgBJiYkpZerOtVrRgYem55UsYFcmVGZ7Bq1mAq7V9mGqSJJOZRv_DPymGaoYqlO9aGenhiSoFVfnalGmohGxr4edTyhp-LHCfg9pWO0SCZDUncZmJKdQ5/s1600/Screenshot_2017-03-07-00-45-18.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwlNmcTPuWiFD2bXQ6xY88hrwIgBJiYkpZerOtVrRgYem55UsYFcmVGZ7Bq1mAq7V9mGqSJJOZRv_DPymGaoYqlO9aGenhiSoFVfnalGmohGxr4edTyhp-LHCfg9pWO0SCZDUncZmJKdQ5/s320/Screenshot_2017-03-07-00-45-18.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNv9EvnSf8ojHMPusLF4yqSjkMPLHgRvJ1DSc8kntHwxUEqZXcVLH6XkNinZDL4FjfWPVZ3wGDkc9AcGOekAGCF5n5zPxj0cX0fre02kWXDi6ruyQ6mlgvexjHR69oevdTVZL4q0LvuKXR/s1600/Screenshot_2017-03-08-00-28-47.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNv9EvnSf8ojHMPusLF4yqSjkMPLHgRvJ1DSc8kntHwxUEqZXcVLH6XkNinZDL4FjfWPVZ3wGDkc9AcGOekAGCF5n5zPxj0cX0fre02kWXDi6ruyQ6mlgvexjHR69oevdTVZL4q0LvuKXR/s320/Screenshot_2017-03-08-00-28-47.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWQn-h_KagZUnUNxPY9U2pMqH7VzgWKwfajBa0ss0wktVAaw34UjqAMdySL0fO1yheZWx5gNgNy_JQvMVXJuV-Czetf_JlGyk1WDg6z5XmjrJgt4q2pTs7-yIlxCxL5dGrZrSvxtaDuKtR/s1600/Screenshot_2017-03-12-00-06-07.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWQn-h_KagZUnUNxPY9U2pMqH7VzgWKwfajBa0ss0wktVAaw34UjqAMdySL0fO1yheZWx5gNgNy_JQvMVXJuV-Czetf_JlGyk1WDg6z5XmjrJgt4q2pTs7-yIlxCxL5dGrZrSvxtaDuKtR/s320/Screenshot_2017-03-12-00-06-07.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXgOSfosXYmVuTfLoLc24jg9mDBdudyrafTE7grR7bJWRQVZ-dEzNO2FJCAj-gtt6OH49YPgGacqE5OsiBcTBAgsX0ER-c1DBKFAXHo8WV3W7hDmYWIizsknCtmRt-KuUM6v0u24ZLen8n/s1600/Screenshot_2017-03-13-23-33-14.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXgOSfosXYmVuTfLoLc24jg9mDBdudyrafTE7grR7bJWRQVZ-dEzNO2FJCAj-gtt6OH49YPgGacqE5OsiBcTBAgsX0ER-c1DBKFAXHo8WV3W7hDmYWIizsknCtmRt-KuUM6v0u24ZLen8n/s320/Screenshot_2017-03-13-23-33-14.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmDzwNvr6RG3t_prmAUVPBQUCJsE_8l362Bc7Cw9ewn2n1JO3U9b35pPs6klsmh_rg5gfZJ4h0PeB2MPmUbKzpGib9GIK0ZGujLcO1GIKTNkK2WpwxRvh8P0BBRW-jvQH0Yj2JwV8NHKQp/s1600/Screenshot_2017-03-14-12-56-38.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmDzwNvr6RG3t_prmAUVPBQUCJsE_8l362Bc7Cw9ewn2n1JO3U9b35pPs6klsmh_rg5gfZJ4h0PeB2MPmUbKzpGib9GIK0ZGujLcO1GIKTNkK2WpwxRvh8P0BBRW-jvQH0Yj2JwV8NHKQp/s320/Screenshot_2017-03-14-12-56-38.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwTkYHyGHaNpRc4_oAa7CXrjVy1r5MqlSK-5sgMLYO_ta-7B-8mBWLtTo6iB033o3-RKrya6gsig0wBcg6KV1nVcSIBhtEXnfHgGq0PxaQA7DUHwvsT8C2VK-Wudz2JPO2fYnZ9erE33lX/s1600/Screenshot_2017-03-15-01-08-43.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwTkYHyGHaNpRc4_oAa7CXrjVy1r5MqlSK-5sgMLYO_ta-7B-8mBWLtTo6iB033o3-RKrya6gsig0wBcg6KV1nVcSIBhtEXnfHgGq0PxaQA7DUHwvsT8C2VK-Wudz2JPO2fYnZ9erE33lX/s320/Screenshot_2017-03-15-01-08-43.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiruqTqAXrNMpODumzKzx-m9CrLpsIscJCCAqJNLvRVoHxEZ9ZAxhhgj7UGS3satYTTfSgWdS0U1xQsaxihC-Wb7TQFU4mN5vw_7yd8Cce9anTJrj2xoHhvxCv6zyv7Hnl1zkda__WDoK-_/s1600/Screenshot_2017-03-15-19-01-32.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiruqTqAXrNMpODumzKzx-m9CrLpsIscJCCAqJNLvRVoHxEZ9ZAxhhgj7UGS3satYTTfSgWdS0U1xQsaxihC-Wb7TQFU4mN5vw_7yd8Cce9anTJrj2xoHhvxCv6zyv7Hnl1zkda__WDoK-_/s320/Screenshot_2017-03-15-19-01-32.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjITzJVMk88ep_1qYWB4fjAbxm8233-qRBvCOMR5viSdRNcNW7UzUlZnv2cU_m8HkQTyJkia7EbaBwiGI7eUrviFtPxINmaKI5i12ULFX6lLmYhrkpW21CDQzV_TY0NY1z6R1VS47o2-v-c/s1600/Screenshot_2017-03-16-21-00-17.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjITzJVMk88ep_1qYWB4fjAbxm8233-qRBvCOMR5viSdRNcNW7UzUlZnv2cU_m8HkQTyJkia7EbaBwiGI7eUrviFtPxINmaKI5i12ULFX6lLmYhrkpW21CDQzV_TY0NY1z6R1VS47o2-v-c/s320/Screenshot_2017-03-16-21-00-17.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzuQcyxFFGw6h_3pYEqRPnEviiJQaMW17kt57Ecs26B-nLnbKAhrHgNnVfPEzGjg2p6iMtNn4Kj2Fw1U5E24toifPIdDv6Vjijjlw2yyKfu4m8tty_xBTcXiuaE4Qnj19wlapMlrtI3Fa4/s1600/Screenshot_2017-03-22-23-09-19.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzuQcyxFFGw6h_3pYEqRPnEviiJQaMW17kt57Ecs26B-nLnbKAhrHgNnVfPEzGjg2p6iMtNn4Kj2Fw1U5E24toifPIdDv6Vjijjlw2yyKfu4m8tty_xBTcXiuaE4Qnj19wlapMlrtI3Fa4/s320/Screenshot_2017-03-22-23-09-19.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgie0VLFhnDQ88yUhTRJdkac5LA6yuWgd7dYRnoTN6ivObByGyp8jK8TOW1NGzRFs9_9w6VQ3TefeWupxhI_oHMRQasiQ2daAwR0Qsqs9JwG-zB8z3LAAYLQWCPPh50r1cwAIoojesxwWJ_/s1600/Screenshot_2017-04-03-19-17-29.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgie0VLFhnDQ88yUhTRJdkac5LA6yuWgd7dYRnoTN6ivObByGyp8jK8TOW1NGzRFs9_9w6VQ3TefeWupxhI_oHMRQasiQ2daAwR0Qsqs9JwG-zB8z3LAAYLQWCPPh50r1cwAIoojesxwWJ_/s320/Screenshot_2017-04-03-19-17-29.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgntJdUsqGL9SlaxLeQ7mOxqJhgEo_CUpza9guexpS5-Pg7FWzsCOOydp4hLRTP_pTSABDdVC_TL_cgIAFOZA1WMyKk6obqTiImr4thwurwJsuMGz9nv1n82uEctUAFR8twEQ5eHO0DXrNf/s1600/Screenshot_2017-04-15-22-04-14.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgntJdUsqGL9SlaxLeQ7mOxqJhgEo_CUpza9guexpS5-Pg7FWzsCOOydp4hLRTP_pTSABDdVC_TL_cgIAFOZA1WMyKk6obqTiImr4thwurwJsuMGz9nv1n82uEctUAFR8twEQ5eHO0DXrNf/s320/Screenshot_2017-04-15-22-04-14.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm05L2E3rQKLO5HG7oaScCNHeNpoxyI4vouTfhPH248Uz6Ni1n7PbuzCBtBB3o516JTUKwO3Rn_tR9aFDLxXMBAk58OMtA_0vtwxROT5ePCYY0cRUA1taCLzAYd4vjR41l-eU53jN3P_29/s1600/Screenshot_2017-04-16-12-20-05.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm05L2E3rQKLO5HG7oaScCNHeNpoxyI4vouTfhPH248Uz6Ni1n7PbuzCBtBB3o516JTUKwO3Rn_tR9aFDLxXMBAk58OMtA_0vtwxROT5ePCYY0cRUA1taCLzAYd4vjR41l-eU53jN3P_29/s320/Screenshot_2017-04-16-12-20-05.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9xt7cwOKLUcu_jLdOJjaWLTCmLJ2Poo0RBmg9dQhafFaCsA5US-biEeUN7U-T5zp9_TgbDQp5E_MAn4wafVMW6ftmVQ9wbIi8zQwckXRbmg1XuSd47nndZ9gn0jRPt7f6bzTXFNQ9l7zW/s1600/Screenshot_2017-04-25-21-35-57.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9xt7cwOKLUcu_jLdOJjaWLTCmLJ2Poo0RBmg9dQhafFaCsA5US-biEeUN7U-T5zp9_TgbDQp5E_MAn4wafVMW6ftmVQ9wbIi8zQwckXRbmg1XuSd47nndZ9gn0jRPt7f6bzTXFNQ9l7zW/s320/Screenshot_2017-04-25-21-35-57.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyxGZViVPIQT2NzpPP6Z6Nh8JL9hyphenhyphen8k1u-EulckxQL5-VlUPrsmVaVwe3-yy0iRqoHrYfShNWg-8daRx0jFp_kcLwDim8qzWyNAKJ3g4zImjmp6WCvxYH2I2yD-xBC7uc_-3MNAiKuNLOi/s1600/Screenshot_2017-04-29-16-10-30.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyxGZViVPIQT2NzpPP6Z6Nh8JL9hyphenhyphen8k1u-EulckxQL5-VlUPrsmVaVwe3-yy0iRqoHrYfShNWg-8daRx0jFp_kcLwDim8qzWyNAKJ3g4zImjmp6WCvxYH2I2yD-xBC7uc_-3MNAiKuNLOi/s320/Screenshot_2017-04-29-16-10-30.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheTY9ZM5l9TGwPgYAubwl4J26vKZ78Mhy2yr3wlOqnX_Vk3Bd-9rTuCd9ku9E4um-2ApYbw_9pKEqQxozH1S6kjtN407hEb7lzPBOKjDiJvVbmAiamqKXj4I0YZrPA0v3lPnq3ApdBJcGX/s1600/Screenshot_2017-04-29-23-48-55.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheTY9ZM5l9TGwPgYAubwl4J26vKZ78Mhy2yr3wlOqnX_Vk3Bd-9rTuCd9ku9E4um-2ApYbw_9pKEqQxozH1S6kjtN407hEb7lzPBOKjDiJvVbmAiamqKXj4I0YZrPA0v3lPnq3ApdBJcGX/s320/Screenshot_2017-04-29-23-48-55.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/Gily0CNkrzc/0.jpg&quot; frameborder=&quot;0&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/Gily0CNkrzc?feature=player_embedded&quot; width=&quot;320&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
===========================&lt;br /&gt;
&lt;br /&gt;
底下是戰略模式玩法的新版本，目前功能己完成測試調整中，更完善後就會發佈。&lt;br /&gt;
&lt;br /&gt;
- 新增戰略地圖，共24個城市&lt;br /&gt;
- 共10個玩家，其中9個AI&lt;br /&gt;
- 目標為佔領所有城市&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgmDI83eWItOwi63C72DJ6THjDuCJmbLAWaIZ4g9_mAKsCatDiJGJMF6g4x2rocoRjNN4KD1iywAQaAueAEf75c1nA9DGAcSG46wyNlowUimE_OOlSzcjtYHHPTbUA7gVYFX-vo15U78Kq/s1600/Screenshot_2018-04-08-10-19-17.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1280&quot; data-original-width=&quot;720&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgmDI83eWItOwi63C72DJ6THjDuCJmbLAWaIZ4g9_mAKsCatDiJGJMF6g4x2rocoRjNN4KD1iywAQaAueAEf75c1nA9DGAcSG46wyNlowUimE_OOlSzcjtYHHPTbUA7gVYFX-vo15U78Kq/s320/Screenshot_2018-04-08-10-19-17.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8XeTHpeN8hZjqG6EBJks3I1dB93ZKVu8PI8eSFENByQHYqxme_exAmyOwHzbhza8Q1aMoY0Oe9gG7AA00l4NymN67b0LcpxcuZcxUkC0gY8x1S5XYuuWMR7FEu02d5tasloh_dvFyiySx/s1600/Screenshot_2018-04-17-23-29-51.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1280&quot; data-original-width=&quot;720&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8XeTHpeN8hZjqG6EBJks3I1dB93ZKVu8PI8eSFENByQHYqxme_exAmyOwHzbhza8Q1aMoY0Oe9gG7AA00l4NymN67b0LcpxcuZcxUkC0gY8x1S5XYuuWMR7FEu02d5tasloh_dvFyiySx/s320/Screenshot_2018-04-17-23-29-51.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTU9-BSpdYmxFFfy1YPnPywpAj36PdIxbX8hYmy6n3-z-3Ce6NeBbSic-OPwmAWfnveREA-Rzg9lZwaaS56U613K9mNSnSg-Zuqp7Rjj9alP-H3vnUJPuveQwlYfKHAUXTRplArw96TFq/s1600/Screenshot_2018-04-17-22-57-42.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1280&quot; data-original-width=&quot;720&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTU9-BSpdYmxFFfy1YPnPywpAj36PdIxbX8hYmy6n3-z-3Ce6NeBbSic-OPwmAWfnveREA-Rzg9lZwaaS56U613K9mNSnSg-Zuqp7Rjj9alP-H3vnUJPuveQwlYfKHAUXTRplArw96TFq/s320/Screenshot_2018-04-17-22-57-42.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL9icnKnZwy91BB6GrdVy2OsmbGU2gYNpMBZy37QJh38cjsJY_LMczh3gWiUHTXcukS0qs79gaDP4J7pdAfnr6bctcjBigzm-NpE82YLbX_dkD9UowHxRCwduA-d8AFlOU3-4ZsZOWatb1/s1600/Screenshot_2018-04-18-07-04-46.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em; text-align: center;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1280&quot; data-original-width=&quot;720&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL9icnKnZwy91BB6GrdVy2OsmbGU2gYNpMBZy37QJh38cjsJY_LMczh3gWiUHTXcukS0qs79gaDP4J7pdAfnr6bctcjBigzm-NpE82YLbX_dkD9UowHxRCwduA-d8AFlOU3-4ZsZOWatb1/s320/Screenshot_2018-04-18-07-04-46.png&quot; width=&quot;180&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;
&lt;iframe allowfullscreen=&quot;&quot; class=&quot;YOUTUBE-iframe-video&quot; data-thumbnail-src=&quot;https://i.ytimg.com/vi/tDb8Z0eW4RI/0.jpg&quot; frameborder=&quot;0&quot; height=&quot;266&quot; src=&quot;https://www.youtube.com/embed/tDb8Z0eW4RI?feature=player_embedded&quot; width=&quot;320&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2017/04/blog-post.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNhocM-bsgJQNgGoPPS1FmZdLs4m3dGiWB-LIRafMy4loFlJjLZrCpb88JUDsR7ByNmO7Ha3LUCLdoibBdizDcbwL_lOb4IUqyp6xOx1V7GMEnJ_HYLP0HsLW5zUhF216R05aWE8y8a8Zq/s72-c/Screenshot_2017-04-29-12-04-22.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-1028802989428876823</guid><pubDate>Thu, 20 Apr 2017 23:10:00 +0000</pubDate><atom:updated>2020-10-18T23:18:00.321+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Editor</category><category domain="http://www.blogger.com/atom/ns#">good</category><title>Good Game Editor 1.6.1</title><description>* 新增可以Undo關卡的寛高。&lt;br /&gt;
* 修正關卡編輯器(LevelEditor)顯示格點的效能問題。&lt;br /&gt;
* 新增可以指定關卡的位置屬性。&lt;br /&gt;
* 新增在狀態列上顯示關卡編輯器(LevelEditor)目前寛高及左上角位置資訊。&lt;br /&gt;
* 修正關卡編輯器(LevelEditor)中點擊貼圖物件右下角範圍選取小工具無效的問題。&lt;br /&gt;
* 修正當物件數量太大時造成當機的問題。&lt;br /&gt;
* 修正動作編輯器(Sprite Editor)Undo時當機的問題。&lt;br /&gt;
* 修正&lt;a href=&quot;http://good-ed.smallworld.idv.tw/wiki/index.php?title=Good_IsAnimPlaying&quot;&gt;Good.IsAnimPlaying&lt;/a&gt;不能正確工作的問題。&lt;br /&gt;
* 修正&lt;a href=&quot;http://good-ed.smallworld.idv.tw/wiki/index.php?title=Good_GenObj&quot;&gt;Good.GenObj&lt;/a&gt;生成關卡資源內的子物件時沒有設定指定script的問題。&lt;br /&gt;
* 播放器FPS資訊新增顯示目前物件數量及最大物件數量資訊。&lt;br /&gt;
* 播放器只在畫面內容有變更時才重繪畫面。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;&lt;a href=&quot;http://good-ed.smallworld.idv.tw/forum/download/file.php?id=52&quot;&gt;Download&lt;/a&gt;&amp;gt;&lt;br /&gt;
&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2017/04/good-game-editor-161.html</link><author>noreply@blogger.com (Waync Cheng)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4380486110383106325.post-4356003428308173296</guid><pubDate>Sun, 19 Feb 2017 07:28:00 +0000</pubDate><atom:updated>2020-10-18T23:18:05.231+08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Game</category><category domain="http://www.blogger.com/atom/ns#">good</category><category domain="http://www.blogger.com/atom/ns#">MMOG</category><title>多人連線版本的吃金幣的人</title><description>&lt;a href=&quot;http://good-ed.blogspot.com/2014/04/blog-post.html&quot;&gt;吃金幣的人&lt;/a&gt;是對基因算法的一個研究和實驗，主要是資料及算法上的研究和測試。後來使用good的繪圖能力把它&lt;a href=&quot;https://play.google.com/store/apps/details?id=weilican.coineater&quot;&gt;圖形化&lt;/a&gt;，同時測試及擴展good的整合能力。現在再進一步把它和&lt;a href=&quot;http://good-ed.blogspot.com/2009/12/blog-post_04.html&quot;&gt;網路底層&lt;/a&gt;作結合，建立一個新的實驗平台，命名為nature online。&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1KACOHfcrN2u2AWiphH7QA94gNBSewjdHu3CCqxmjayLme2rgSUXUCNlDSVQ_QCKlIdjXZPSJY6nLtELtwAr5NST4pq5RhSW_zPhmC5M7kClxmh7ur9UY6gsE1urlSjoDh0J-Q1LjVejR/s1600/nature.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;315&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1KACOHfcrN2u2AWiphH7QA94gNBSewjdHu3CCqxmjayLme2rgSUXUCNlDSVQ_QCKlIdjXZPSJY6nLtELtwAr5NST4pq5RhSW_zPhmC5M7kClxmh7ur9UY6gsE1urlSjoDh0J-Q1LjVejR/s400/nature.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
和good一樣建立no的目的是為了創造一個可以讓我平常利用空間時間來作研發和實驗的平台。no整合了所有到目前為止所作的小實驗和研究。主要的目標是研究分散式網路遊戲的架構及模擬生態系統。&lt;br /&gt;
&lt;br /&gt;
目前具備的功能:&lt;br /&gt;
- 分散式的網路伺服器架構，後端使用mysql。&lt;br /&gt;
- 使用2張測試地圖，隨時可以任意切換至任意地圖任意位置。&lt;br /&gt;
- 地圖物件目前有二種:tree/bug。&lt;br /&gt;
- tree物件應用&lt;a href=&quot;https://en.wikipedia.org/wiki/Conway&#39;s_Game_of_Life&quot;&gt;生命遊戲規則&lt;/a&gt;生成及更新。&lt;br /&gt;
- bug物件應用基因算法活動食物為tree物件。&lt;br /&gt;
- 自動同步client可見視野內的內容。&lt;br /&gt;
-使用good為client成象引擎。&lt;br /&gt;
&lt;br /&gt;
下階段的目標是持續底層研發及增加更多種類的物件。&lt;br /&gt;
&lt;br /&gt;
;=========================&lt;br /&gt;
&lt;br /&gt;
以下二件事是需要特別記錄的。&lt;br /&gt;
&lt;br /&gt;
A.&lt;br /&gt;
首先tree物件的更新決定以生命遊戲的規則來作更新及生成，規則沒什麼問題，問題是數量和速度。如果是像good內建的life範例，那相當於16x16的地圖格子大小，總數也才256格，每次更新時全訠256格都掃一次也沒什麼問題。不過當地圖變成像no那樣是500x500或更大時，問題就出來了。每次要掃那麼多的格子，速度就成為一個問題了，而且server每次更新不只是要更新tree物件而己，還有其它工作要作。&lt;br /&gt;
&lt;br /&gt;
一個簡單的解決方法是只檢查需要檢查的格子。&lt;br /&gt;
&lt;br /&gt;
1,記錄目前有那些存活的格子&lt;br /&gt;
2,根據存活的格子推算有那些格子在下一世代可能產生狀態變化,可能有狀態變化的格子也就是存活的格子的周圍8個空格子&lt;br /&gt;
3,下一世代只需計算(目前存活格子+可能產生狀態變化的格子),其它的格子都可以忽略不看&lt;br /&gt;
&lt;br /&gt;
假設目前存活的格子是10000個，這10000個格子周圍總共30000個空格子，那麼下一世代只需計算40000個格子，而不是全部250000個格子。數量大大的減少了!&lt;br /&gt;
&lt;br /&gt;
B.&lt;br /&gt;
bug物件是以基因算法為基礎來製作。和吃金幣的人一樣，假設基因的編碼是根據上下左右中5個格子(環境變數)共3種不同狀態，基因長度為243。現在的問題是，假設過了一段時間之後，要改變編碼需要檢查的格子數或狀態數，這樣一來原本之前花時間演化出來的基因就會無效。因為新舊編碼方法不同產生的基因長度是不同的，二者無法一一對應。雖然舊的編碼方式的基因可以作為新編碼方式基因的一個子集合被包含，但是存取的方法必須改變，否則無法相容。&lt;br /&gt;
&lt;br /&gt;
一個簡單的解決方法是另外維護一個編碼對照表，這樣即使基因的長度擴充了，舊的基因的位置還是不變可以向下相容。&lt;br /&gt;
&lt;br /&gt;
1,建立&amp;lt;狀態編碼,基因位置&amp;gt;對照表&lt;br /&gt;
2,分別處理二種不同的擴充基因的狀況&lt;br /&gt;
&amp;nbsp; * 檢查格子數擴充&lt;br /&gt;
&amp;nbsp; * 檢查狀態數擴充&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
討論檢查格子數擴充的狀況。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;/pre&gt;
&lt;br /&gt;
0 &amp;nbsp; 0 [0] &amp;nbsp; 0 [0 0] &amp;nbsp; &amp;nbsp; idx0&lt;br /&gt;
1 &amp;nbsp; 0 [1] &amp;nbsp; 0 [0 1] &amp;nbsp; &amp;nbsp; idx1&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp;0 &amp;nbsp; &amp;nbsp; 0 [1 0] &amp;nbsp; &amp;nbsp; idx2&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp;1 &amp;nbsp;1 &amp;nbsp; &amp;nbsp; 0 [1 1] &amp;nbsp; &amp;nbsp; idx3&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1 &amp;nbsp;0 0 &amp;nbsp; &amp;nbsp; &amp;nbsp; idx4&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1 &amp;nbsp;0 1 &amp;nbsp; &amp;nbsp; &amp;nbsp; idx5&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1 &amp;nbsp;1 0 &amp;nbsp; &amp;nbsp; &amp;nbsp; idx6&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1 &amp;nbsp;1 1 &amp;nbsp; &amp;nbsp; &amp;nbsp; idx7&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
假設現在只看一個格子且狀態只有0和1二種，如最上表最左行所示，基因長度為2，基因的索引位置為0和1。現在新增一個格子，每個格子一樣有二種狀態，基因長度變為4(2^2)。請看上表中間的部份，列出4種可能的狀態編碼，中括號標出來的[0]和[1]為一個格子的狀況的可能編碼，這是需要在基因擴充時保持不變且向下相容的部份。同樣的再增加一個格子，總共可能的編碼變為3^2=8。如上表右側部份列出所有可能編碼，中括號標示出來的部份[00][01][10]及[11]是必須保持不變向下相容的。&lt;br /&gt;
&lt;br /&gt;
討論檢查狀態數擴充的狀況。&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;/pre&gt;
&lt;br /&gt;
0 0 &amp;nbsp; [0 0] &amp;nbsp; [0 0] &amp;nbsp; &amp;nbsp;idx0&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0 1 &amp;nbsp; &amp;nbsp; [0 1] &amp;nbsp; idx1&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1 0 &amp;nbsp; &amp;nbsp; &amp;nbsp;0 2 &amp;nbsp; &amp;nbsp; idx2&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1 1 &amp;nbsp; &amp;nbsp;[1 0] &amp;nbsp; &amp;nbsp;idx3&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [1 1] &amp;nbsp; &amp;nbsp;idx4&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1 2 &amp;nbsp; &amp;nbsp; &amp;nbsp;idx5&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2 0 &amp;nbsp; &amp;nbsp; &amp;nbsp;idx6&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2 1 &amp;nbsp; &amp;nbsp; &amp;nbsp;idx7&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2 2 &amp;nbsp; &amp;nbsp; &amp;nbsp;idx8&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
如上表所示，類似於討論檢查格子數擴充的狀況所說明的，每增加一個新的狀態時，需要保持不變且向下相容的編碼規則會有些不同。不像上面增加檢查格子時舊的部份維持在上半部，新增的部份在下部份。每增加一個新的狀態時，舊的編碼和新的編碼會互相交錯，但還是可以看出其中的規則。&lt;br /&gt;
&lt;br /&gt;
依據以上二個不同狀況變更編碼擴充基因時變更維護的&amp;lt;狀態編碼,基因位置&amp;gt;對照表，這樣就可以繼續套用原來己花時間演化出來的基因而不必全部打掉重來。&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</description><link>http://good-ed.blogspot.com/2017/02/blog-post.html</link><author>noreply@blogger.com (Waync Cheng)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1KACOHfcrN2u2AWiphH7QA94gNBSewjdHu3CCqxmjayLme2rgSUXUCNlDSVQ_QCKlIdjXZPSJY6nLtELtwAr5NST4pq5RhSW_zPhmC5M7kClxmh7ur9UY6gsE1urlSjoDh0J-Q1LjVejR/s72-c/nature.png" height="72" width="72"/><thr:total>0</thr:total></item></channel></rss>