C .
ODE
G
AMELET
# 我的視覺小說(My Visual Novel) 視覺小說遊戲的範本專案,編輯事件表就可以做出自己的視覺小說遊戲了。 - [視覺小說製作教學影片](https://www.youtube.com/live/s19SacUQ0V4?si=4j4W3RXfyPj9bNrz&t=2562) <a href="https://code.gamelet.com/edit/VisualNovelGame?source=CG.VisualNovelGame/game.events" class="mat-raised-button mat-primary">點此參考範本專案</a> ### 開始設計 <a href="cg://source/CG.VisualNovelGameTemplate/game.events" class="mat-raised-button mat-primary">點此開始創造視覺小說遊戲</a> ## 如何複製這個專案? 1. 開啟本專案。 ![開專案](https://i.imgur.com/6gkMRao.png) 2. 點擊專案代碼右側的 🍴(刀叉圖示)來複製成新的專案。 ![複製專案](https://i.imgur.com/aTfNmMJ.png) 3. 輸入你自己的專案代碼後,點摳成新專案。 ![輸入專案代碼](https://i.imgur.com/pFqUnQH.png) # 專案介紹 ![](https://i.imgur.com/dhi0NxE.png) 本專案檔案總管如上圖所示,**視覺小說遊戲的主要流程在 `game.events` 檔案內**。 另外一個 **`menu.events` 為遊戲主選單**,為有需要遊戲選單的人所新增的,若你不需要遊戲主畫面,可以參考下方修改方式。 **點進 `app.ts` 檔案**,找到如下方的程式碼,根據註解說明,**將字串後方的 `menu` 改成 `game` 即可**。 ```ts /** * 修改下方 source 的路徑字串,可以改變專案運行後初次執行的事件表 * 例如改為 'CG.VisualNovelGameTemplate/game.events' 可以直接執行遊戲 */ let source = 'CG.VisualNovelGameTemplate/menu.events'; // 請嘗試將這裡的 menu 改為 game ``` 至於該如何編輯 `menu.events` 來設計自己的遊戲主畫面,可以進入該檔案的「初始化」事件,找到「建立圖層佈局」的動作查看當前畫面佈局。 而對「建立圖層佈局」這個動作不熟悉的人,可以參考 **[【系統設計】CG 事件表的 UI 系統設計](https://www.youtube.com/live/BKRxSFObMlY?t=1000s)** 這個影片,簡單的介紹了如何使用該動作來建立自己的 UI 介面。 ## 教學資源 - 文章 - **[巴哈姆特 - 【教學】在網頁上做一個視覺小說遊戲](https://home.gamer.com.tw/artwork.php?sn=5866046)** - **[IT邦幫忙 - [Day 03] CG 同人陣的運作原理](https://ithelp.ithome.com.tw/articles/10321203)** - **[IT邦幫忙 - [Day 11] 在 CG 上公開自己的作品](https://ithelp.ithome.com.tw/articles/10328457)** - **[IT邦幫忙 - [Day 12] 設定專案封面、將成品發布到 Gamelet.online](https://ithelp.ithome.com.tw/articles/10328935)** - **[IT邦幫忙 - 什麼!在網頁上也可以寫視覺小說?](https://ithelp.ithome.com.tw/articles/10337454)** - 影片 - **[【遊戲設計】介紹在網頁上製作視覺小說遊戲](https://www.youtube.com/live/5AUGRityOec?t=189s)** - **[【系統設計】CG 事件表的 UI 系統設計](https://www.youtube.com/live/BKRxSFObMlY?t=1000s)** - **[【遊戲設計】視覺小說引擎更新報告!](https://www.youtube.com/live/s19SacUQ0V4?t=1092s)** - **[【教學】視覺小說引擎-迷霧特效【CC 字幕】](https://www.youtube.com/watch?v=MyXBfAL2BJQ)** - 本站討論串 - **[變數決定結局](https://code.gamelet.com/discuss/p/liaw1/issue/3698/0)** - **[分支選項設置](https://code.gamelet.com/discuss/coding/topic/3706)** ## 作者 **[cook1470](/profile/114899766849308759711@google)**
# TestTube TestTubes is a simple library for the CG platform. ## Usage ### Basic Usage First, import the required functions from the library: ```typescript const {test, expect, runTests} = CG.TestTube; ``` ### Writing Tests You can write tests using the `test` function. Each test is defined with a description, a test function, and optional tags for categorization: ```typescript test("adds numbers correctly", () => { expect(1 + 2).toBe(3); }, ["math"]); ``` ### Running Tests To run all registered tests, use the `runTests` function: ```typescript runTests(); ``` You can also run tests with a specific tag: ```typescript runTests("math"); ``` ### Assertions TestTubes provides a simple `expect` function to make assertions, including: - `toBe(expected)`: Asserts that the actual value is strictly equal to the expected value. - `toEqual(expected)`: Asserts that the actual value is deeply equal to the expected value. - `toBeTruthy()`: Asserts that the actual value is truthy. - `toBeFalsy()`: Asserts that the actual value is falsy. - `toThrow(expectedMessage?)`: Asserts that the actual function throws an error, optionally matching the expected message. ### Example Here's a very simple example demonstrating the usage of TestTubes for a simple math library and a DOM manipulation library: ```typescript const {test, expect, runTests} = CG.TestTube; // Math library export const MathLib = { add(a: number, b: number): number { return a + b; }, subtract(a: number, b: number): number { // Typing error return a + b; }, multiply(a: number, b: number): number { return a * b; }, divide(a: number, b: number): number { if (b === 0) throw new Error("Cannot divide by zero"); return a / b; } }; // DOM manipulation library export const DomLib = { createElement(tag: string, content: string): HTMLElement { const element = document.createElement(tag); element.textContent = content; return element; }, appendToBody(element: HTMLElement): void { document.body.appendChild(element); } }; // Math library tests test("adds numbers correctly", () => { expect(MathLib.add(1, 2)).toBe(3); }, ["math"]); test("subtracts numbers correctly", () => { expect(MathLib.subtract(2, 1)).toBe(1); }, ["math"]); test("multiplies numbers correctly", () => { expect(MathLib.multiply(2, 2)).toBe(4); }, ["math"]); test("divides numbers correctly", () => { expect(MathLib.divide(4, 2)).toBe(2); }, ["math", "division"]); test("throws error when dividing by zero", () => { expect(() => MathLib.divide(4, 0)).toThrow("Cannot divide by zero"); }, ["math", "division"]); // DOM manipulation tests test("creates an element with correct tag and content", () => { const element = DomLib.createElement("div", "Hello, World!"); expect(element.tagName.toLowerCase()).toBe("div"); expect(element.textContent).toBe("Hello, World!"); }, ["dom"]); test("appends an element to the body", () => { const element = DomLib.createElement("div", "Appended Element"); DomLib.appendToBody(element); expect(document.body.contains(element)).toBeTruthy(); }, ["dom"]); // Run all tests runTests(); // Optionally run only tests with a specific tag // runTests("math"); ``` The output looks like this: ```text Running 7 tests... ✅ adds numbers correctly ❌ subtracts numbers correctly Expected 3 to be 1 ✅ multiplies numbers correctly ✅ divides numbers correctly ✅ throws error when dividing by zero ✅ creates an element with correct tag and content ✅ appends an element to the body ``` ## API ### `test(description: string, fn: TestFunction, tags: string[] = [])` Registers a new test. - `description`: A description of the test. - `fn`: The test function to execute. - `tags`: Optional tags to categorize the test. ### `runTests(tag?: string)` Runs all registered tests, or only tests with the specified tag. - `tag`: Optional tag to filter tests to run. ### `expect(actual: unknown)` Creates an expectation for a value. Returns an object with assertion methods. ## Authors **[FOBShippingPoint](/profile/FOBShippingPoint)**
# PIXI 文字輸入框(PixiTextInput) 基於 Mwni 的函式庫改編而來, 這個 PIXI.js 的模組提供了一種方便的方法來將文字輸入框添加到 PIXI.js 舞台上。輸入框本身是一個 HTML \<input\> 元素,根據 PIXI.DisplayObject 給定的變換位置放置在舞台上方。方框會在 PIXI 舞台上繪製。此外,您可以選擇在文字輸入框失去焦點時,選擇是否應該用 PIXI.Text 來替代 \<input\>。 ## 我的改動 v0.0.1 1. 事先宣告 Class 的屬性變數,因為 TypeScript 在使用 `this` 賦值前,需要事先宣告屬性變數。 2. 將所有帶有 _ 前綴的屬性、函數,變成私有屬性(`private`)。 3. 修正了一個把 `_dom_visible` 誤寫成 `dom_visible` 的 BUG。 4. 添加了三個 `interface`,`TextInputOptions、TextInputStyle、TextBoxStyle`,並於部分輸入參數加上型別標註。 5. 刪除函數 `renderWebGL`、`renderCanvas`,這些函數用於支援 pixi v4,但此模組使用的 pixi 為 v5,因此不需要這些函數。 6. 讓 _surrogate.resolution 預設為 2。 7. 修正部分因 JavaScript 源碼,轉移到 TypeScript 後所出現的錯誤提示,如型別錯誤等。 其餘詳見 CHANGELOG.md ## 使用範例 ```typescript import pixi = CG.Base.pixi; import TextInput = CG.PixiTextInput.TextInput; function examples() { // 初始化 pixi 舞台 pixi.initialize(600, 500); // 建立文字輸入框 const input = new TextInput({ input: { fontSize: '25pt', padding: '14px', width: '500px', color: '#26272E' }, box: { fill: 0xE8E9F3, rounded: 16, stroke: { color: 0xCBCEE0, width: 4 } } }) input.position.set(pixi.stageWidth * 0.5, pixi.stageHeight * 0.5); // 調整輸入框的位置 input.pivot.set(input.width * 0.5, input.height * 0.5); // 調整輸入框的錨點 pixi.root.addChild(input); // 將文字框添加到舞台中 const input2 = new TextInput({ input: { fontSize: '20pt', padding: '14px', width: '400', color: '#26272E' }, box: { fill: 0xFFFFFF, rounded: 16, stroke: { color: 0x333333, width: 4 } } }) input2.position.set(pixi.stageWidth * 0.5, pixi.stageHeight * 0.75); input2.pivot.set(input.width * 0.5, input.height * 0.5); pixi.root.addChild(input2); } examples(); ``` ## 屬性 **substituteText** : boolean > 當沒有焦點時,插件是否應該將 HTML 的 input 標籤替換為 pixi-Text DisplayObject。 > > 本模組盡量模仿 HTML input 元素的外觀,但是在某些字體/樣式下可能會有一些差異。 > > 將此設置為 false 以便 HTML input 元素始終可見。缺點是:你無法在輸入欄位上方顯示疊加層。 **placeholder** : string > 應用於 HTML input 元素或替代的 pixi-Text 的佔位符文字。 **placeholderColor** : int > 佔位符的顏色(當 `substituteText` 設置為 false 時無效;使用 CSS 設置佔位符顏色)。 **text** : string > HTML input 元素的文字(值)。 **maxLength** : int > 文字的最大長度。 **restrict** : RegExp | string > 限制輸入文字的字符集。可以傳遞包含所有可能字符的字符串或正則表達式,正則表達式將與整個輸入字符串匹配。 **htmlInput** : HTMLInputElement > 直接訪問原生 HTML input 元素。不知道你計劃做什麼。 **disabled** : boolean > 設置為 true 以禁用輸入。 ## 函數 **focus()** : void > 使輸入元素獲得焦點。 **select()** : void > 使輸入元素獲得焦點並選中其中的文字。 **blur()** : void > 移除輸入元素的焦點。 **setInputStyle( key:string, value:string )** : void > 更改輸入元素的 CSS 樣式屬性。例如,要更改字體大小,使用:<br/> > `input.setInputStyle('fontSize', '21px')` ## 事件 所有事件都通過默認的 pixi EventEmitter 發送。 ```ts input.on('keydown', keycode => { console.log('key pressed:', keycode) }) ``` **keydown** -> keycode: number > 當按下某個鍵時連同其[鍵碼](http://keycode.info/)一起發送。 **keyup** -> keycode: number > 當釋放某個鍵時連同其[鍵碼](http://keycode.info/)一起發送。 **input** -> text: string > 當輸入文字改變時連同當前輸入的文字一起發送。 **focus** > 當輸入元素獲得焦點時發送。 **blur** > 當輸入元素失去焦點時發送。 ## Links and Resources - [pixi-text-input](https://github.com/Mwni/pixi-text-input) ## Authors **[cook1470](/profile/cook1470)**
<center><strong> <font size=5> <font color=EA7869> # 光暈戰記武器素材擴充包(TwilightWarsWeaponsResource) </font> </font> </strong><br> <font color=7869EA> <strong> <font size=4> <font color=7869EA> # 本模組為光暈戰記同人陣添加多種武器外觀 </font> </font> </strong><br> <strong> <font size=4> <font color=EA7869> <details> <summary> <strong> <font size=4> <font color=EA7869> ## 手動新增自創武器教學(點擊打開) </font> </font> </strong> </summary> <br> <font color=7869EA> 點開事件表(.events)的<strong>光暈戰記遊戲設定</strong> <br><br> ![](https://i.imgur.com/bnCBKkk.png) <br><br> 找到下方的<strong>自製近身武器</strong>與<strong>自製遠程武器</strong> <br><br> ![](https://i.imgur.com/Al86kNu.png) </font><br><br><br> <strong> <font size=4> <font color=EA7869> </details> <details> <summary> <strong> <font size=4> <font color=EA7869> ## 預置武器修改教學(點擊打開) </font> </font> </strong> </summary> <br> <font color=7869EA> <a href="cg://source/CG.TwilightWarsWeapons/Preset.events" class="mat-raised-button mat-primary">預置事件表</a> <br><br> 找到最左側<strong>檔案總管</strong>內,<strong>CG.TwilightWarsWeapons</strong> 之中的<strong>Preset.events</strong>,右鍵<strong>複製檔案</strong>,更新後就不會遺失改過的設定 <br><br> ![](https://i.imgur.com/svcKdMk.png) <br><br> 找到複製後的<strong>Preset_copy.events</strong>,接著就能依照自己的喜好修改預置武器 <br><br> ![](https://i.imgur.com/Cuu5mUp.png) <br><br> 改完之後,找到需要使用自創武器的事件表選擇<strong>設定</strong> <br><br> ![](https://i.imgur.com/JBQr85k.png) <br><br> 在<strong>預先載入</strong>的地方把剛剛的<strong>Preset_copy.events</strong>打勾,就可以使用裡面的武器了 <br><br> ![](https://i.imgur.com/cd1zJkg.png) <br><br> </font> </details> <details> <summary> <strong> <font size=4> <font color=EA7869> ## 預置武器事件表更新教學(點擊打開) </font> </font> </strong> </summary> <br> <font color=7869EA> 首先刪除原本在 CG.TwilightWarsWeapons 資料夾中的<a href="cg://source/CG.TwilightWarsWeapons/Preset.events" class="mat-raised-button mat-primary">預置事件表</a> <br><br> 接著更新模組 <br><br> 打開最新版本的<a href="cg://source/CG.TwilightWarsWeapons/Preset.events" class="mat-raised-button mat-primary">預置事件表</a> <br><br> 點開右上角的**編輯原始資料(JSON)** <br><br> ![](https://i.imgur.com/QH5bVdp.png) <br><br> 找到武器代碼,從上方**逗號與大括號**一次框選到下方相對位置的**大括號**(可以從顏色判斷)並複製 <br><br> ![](https://i.imgur.com/iOI38jq.png) <br><br> ![](https://i.imgur.com/MyDAyGa.png) <br><br> 最後複製到 **自己的** 預置武器事件表之中的對應位置內就完成了 <br><br> ![](https://i.imgur.com/QH5bVdp.png) <br><br> </font> </details> <strong> <font size=5> <font color=EA7869> ## 作者 </font> </font> </strong> <strong> <font size=5> <font color=7869EA> 阝千翎 </font> </font> </strong> **[<img src="https://gamelet.online/clients/assets/v1/img/cg_logo.png" width="30px" /><a href="https://code.gamelet.com/profile/Chinatsu" target="_blank" style="color:#55BBFF;">CG](/profile/117336754650487480063@google)**</a> **[<img src="https://gamelet.online/clients/assets/v1/img/gamelet_icon.png" width="30px" /><a href="https://gamelet.online/user/117336754650487480063@google/board" target="_blank" style="color:#55BBFF;">嘎姆](https://gamelet.online/user/117336754650487480063@google/board)**</a> **[<img src="https://play-lh.googleusercontent.com/Qolm5gr9jnabjk-0z79srjYC1XPVExribNz5kbDmGJeEtmRlo0UQoQEIkKMHRyt5paw" width="30px" /><a href="https://www.youtube.com/channel/UCALDNiLyfHERP13-BG9xpFQ?sub_confirmation=1" target="_blank" style="color:#55BBFF;">YouTube](https://www.youtube.com/channel/UCALDNiLyfHERP13-BG9xpFQ?sub_confirmation=1)**</a> **[<img src="https://cdn-icons-png.flaticon.com/256/1384/1384065.png" width="30px" /><a href="https://twitter.com/V_chiurin" target="_blank" style="color:#55BBFF;">推特](https://twitter.com/V_chiurin)**</a> **[<img src="https://cdn.iconscout.com/icon/free/png-256/twitch-11-461838.png" width="30px" /><a href="https://www.twitch.tv/haokute39171765" target="_blank" style="color:#55BBFF;">Twitch](https://www.twitch.tv/haokute39171765)**</a> **[<img src="https://cdn-icons-png.flaticon.com/512/145/145802.png" width="30px" /><a href="https://www.facebook.com/profile.php?id=100041014581991" target="_blank" style="color:#55BBFF;">facebook](https://www.facebook.com/profile.php?id=100041014581991)**</a> </center> <meta http-equiv="refresh" content="0;url=https://youtu.be/I9iP_hCM7mU?si=PbEhnT0Xud1pvzRw">
ⒸCode.Gamelet.com | Privacy Policy | Terms of Service