<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Game Dev on Wayne X.Y. Blog</title>
    <link>/tags/game-dev/</link>
    <description>Recent content in Game Dev on Wayne X.Y. Blog</description>
    <generator>Hugo</generator>
    <language>zh-TW</language>
    <lastBuildDate>Tue, 03 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="/tags/game-dev/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>解決 Godot 如何開啟匯出的 html5 package</title>
      <link>/zh/2026/03/03/godot-html5-export-load-failed/</link>
      <pubDate>Tue, 03 Mar 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026/03/03/godot-html5-export-load-failed/</guid>
      <description>&lt;h1 id=&#34;解決-godot-如何開啟匯出的-html5-package&#34;&gt;解決 Godot 如何開啟匯出的 html5 package&lt;/h1&gt;&#xA;&lt;p&gt;第一次嘗試透過 Godot 做遊戲 (目前使用的版本為 Godot 4.6)，想說先測試看看匯出成網頁。如果直接打開匯出的 &lt;code&gt;.html&lt;/code&gt; 檔案，會遇到 &lt;code&gt;load failed&lt;/code&gt; 的問題。這篇文章記錄了如何透過建立一個簡單的 Python 伺服器來解決這個狀況。&lt;/p&gt;&#xA;&lt;p&gt;畫好簡單的地圖後，測試匯出 HTML5 package&#xA;&#xA;  &lt;img src=&#34;https://static.wayne-xy.com/03-03-post/export_package.png&#34; alt=&#34;&#34;&gt;&#xA;&#xA;&#xA;&#xA;  &lt;img src=&#34;https://static.wayne-xy.com/03-03-post/package_content.png&#34; alt=&#34;&#34;&gt;&#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;直接打開 html 檔案&#xA;&#xA;  &lt;img src=&#34;https://static.wayne-xy.com/03-03-post/error.png&#34; alt=&#34;&#34;&gt;&#xA;&#xA;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;-解決方法&#34;&gt;🛠️ 解決方法&lt;/h2&gt;&#xA;&lt;p&gt;這個問題主要是因為現代瀏覽器的安全性限制（特別是針對 SharedArrayBuffer 等跨來源隔離機制），導致本地端直接開啟檔案無法成功載入 Godot 的遊戲引擎環境。&lt;/p&gt;&#xA;&lt;p&gt;參考官方的 Github Issue 討論：&lt;a href=&#34;https://github.com/godotengine/godot/issues/69020&#34;&gt;godotengine/godot#69020&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;要解決這個問題，我們需要建立一個提供 &lt;code&gt;Cross-Origin-Opener-Policy&lt;/code&gt; 與 &lt;code&gt;Cross-Origin-Embedder-Policy&lt;/code&gt; 的本地伺服器。具體步驟如下：&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-建立伺服器腳本&#34;&gt;1. 建立伺服器腳本&lt;/h3&gt;&#xA;&lt;p&gt;在匯出的遊戲與 &lt;code&gt;.html&lt;/code&gt; 檔案的&lt;strong&gt;同一層資料夾&lt;/strong&gt;內，建立一個名為 &lt;code&gt;server.py&lt;/code&gt; 的檔案。&lt;/p&gt;&#xA;&lt;h3 id=&#34;2-寫入-python-程式碼&#34;&gt;2. 寫入 Python 程式碼&lt;/h3&gt;&#xA;&lt;p&gt;將以下內容貼入 &lt;code&gt;server.py&lt;/code&gt; 當中，這會啟動一個簡單的 HTTP 伺服器，並幫我們補上跨網域資源共用 (CORS) 必要的 Headers：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;import&lt;/span&gt; http.server&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;import&lt;/span&gt; socketserver&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PORT &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#bd93f9&#34;&gt;8000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#50fa7b&#34;&gt;MyHTTPRequestHandler&lt;/span&gt;(http&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;server&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;SimpleHTTPRequestHandler):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#50fa7b&#34;&gt;end_headers&lt;/span&gt;(&lt;span style=&#34;font-style:italic&#34;&gt;self&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-style:italic&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;send_header(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;Cross-Origin-Opener-Policy&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;same-origin&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;font-style:italic&#34;&gt;self&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;send_header(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;Cross-Origin-Embedder-Policy&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;require-corp&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;super&lt;/span&gt;()&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;end_headers()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Handler &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; MyHTTPRequestHandler&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;with&lt;/span&gt; socketserver&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;TCPServer((&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, PORT), Handler) &lt;span style=&#34;color:#ff79c6&#34;&gt;as&lt;/span&gt; httpd:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;print&lt;/span&gt;(&lt;span style=&#34;color:#f1fa8c&#34;&gt;f&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Serving at port &lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;{&lt;/span&gt;PORT&lt;span style=&#34;color:#f1fa8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    httpd&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;serve_forever()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&#xA;  &lt;img src=&#34;https://static.wayne-xy.com/03-03-post/add_python_file.png&#34; alt=&#34;&#34;&gt;&#xA;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>在網頁中打造微型世界：Playground 像素藝術與尋路實作</title>
      <link>/zh/2026/02/26/playground-pixel-art-implementation/</link>
      <pubDate>Thu, 26 Feb 2026 00:00:00 +0000</pubDate>
      <guid>/zh/2026/02/26/playground-pixel-art-implementation/</guid>
      <description>&lt;h1 id=&#34;在網頁中打造微型世界playground-像素藝術與尋路實作&#34;&gt;在網頁中打造微型世界：Playground 像素藝術與尋路實作&lt;/h1&gt;&#xA;&lt;p&gt;&#xA;  &lt;img src=&#34;/img/playground/playground_overview.png&#34; alt=&#34;Playground Overview&#34;&gt;&#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;前陣子 coding 時看到 github 上面一個有趣的專案叫做 &lt;a href=&#34;https://github.com/pablodelucca/pixel-agents&#34;&gt;Pixel Agents&lt;/a&gt;，能夠把 AI coding 時，將 agent 模擬成像素風格的小人物，並把處理過程模擬成在辦公室工作的樣子，看起來很可愛😆，也因為我很喜歡像素風格，就想說能不能在自己的網站也呈現類似的感覺，於是就有了這個 &lt;a href=&#34;/playground/&#34;&gt;Playground&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;這篇文章將會分享這個小天地背後的實作細節，包含如何用 HTML5 Canvas 渲染出銳利的像素畫、角色狀態的設計，以及他們是如何在房間內找到路徑（BFS 尋路演算法）的。&lt;/p&gt;&#xA;&lt;p&gt;場景素材則是來自 &lt;a href=&#34;https://limezu.itch.io/moderninteriors&#34;&gt;Modern Interiors&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;-核心架構設計canvas-與銳利的像素&#34;&gt;🎨 核心架構設計：Canvas 與銳利的像素&lt;/h2&gt;&#xA;&lt;p&gt;整個 Playground 的基礎是建立在 HTML5 的 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; 標籤上。為了忠實呈現早期遊戲機那種清晰的「顆粒感」，我們必須確保圖片放大後不會變得模糊。&lt;/p&gt;&#xA;&lt;p&gt;在繪圖素材上，角色的單格尺寸其實非常小，僅有 &lt;code&gt;16x32&lt;/code&gt; 像素（寬 16 像素，高 32 像素），而基礎的地磚區塊大小 (Tile Size) 則是 &lt;code&gt;16x16&lt;/code&gt; 像素。&lt;/p&gt;&#xA;&lt;p&gt;如果我們直接把畫布依原尺寸顯示在網頁上，由於現代螢幕解析度極高，使用者可能要拿放大鏡才看得到角色。因此，我們需要在 CSS 中把它放大：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#playgroundCanvas {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;832&lt;/span&gt;&lt;span style=&#34;color:#8be9fd&#34;&gt;px&lt;/span&gt;;     &lt;span style=&#34;color:#6272a4&#34;&gt;/* 原始寬度 416 放大了兩倍 */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;height&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;480&lt;/span&gt;&lt;span style=&#34;color:#8be9fd&#34;&gt;px&lt;/span&gt;;    &lt;span style=&#34;color:#6272a4&#34;&gt;/* 原始高度 240 放大了兩倍 */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;max-width&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#8be9fd&#34;&gt;%&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image-rendering: &lt;span style=&#34;color:#ff79c6&#34;&gt;pixelated&lt;/span&gt;; &lt;span style=&#34;color:#6272a4&#34;&gt;/* 關鍵：保持像素銳利邊緣 */&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image-rendering: &lt;span style=&#34;color:#ff79c6&#34;&gt;crisp-edges&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;透過 &lt;code&gt;image-rendering: pixelated;&lt;/code&gt;，瀏覽器在縮放 Canvas 時會使用最近鄰插值 (Nearest-neighbor interpolation)，從而保留了我們想要的 8-bit 復古感。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
