Learn More →
這篇主要教的內容是使用 Electron 來部署輸出你的 RPG Maker MV/MZ 的遊戲,
本次將使用 Intel 機種的 macOS 10.15.7 (Catalina) 作業系統來進行操作教學。
Electron 目前不支援 OS X 10.10 (Yosemite) 及較早以前版本的作業系統。
更新履歷
2022/05/03 更新文章的部分內容。
2022/05/01 修正package.json的部分內容。
2022/01/04 新增禁止擷取畫面的功能部分。
2021/11/12 新增關於 asar 檔案的加密部分。
1.首先到以下網址下載對應 macOS 作業系統的 Node.js 並安裝到電腦。
https://nodejs.org/en/download/
Learn More →
2.安裝完成後,在右上角的「Spotlight 搜尋」輸入並執行「終端機」,接著分別輸入node -v
和npm -v
檢查是否有成功安裝。
Learn More →
Learn More →
然後,因為在macOS平台上部署遊戲時,需要用到「Xcode Command Lines Tool」,所以在「終端機」輸入xcode-select --install
來下載安裝此工具。
3.建立一個檔案夾之後,並新增一個名為「package.json」檔案,並編輯檔案加入以下的語法內容。
加入以下的語法內容之後,記得將 // 以及後面的註釋內容清除。
{
"name": "RPG_Game", //部署輸出的專案名稱,必須為英文數字且不含任何半形空白。
"version": "1.0.0", //版本號,格式必須為X.X.X的數字格式。
"description": "這是 Electron 部署測試", //檔案描述。
"main": "index.js",
//【RPG Maker MZ】
"chromium-args": "--force-color-profile=srgb",
//【RPG Maker MV】
"js-flags": "--expose-gc",
"build": {
"appId": "com.rpgmaker.game", //應用程式 ID。
//※通常輸入 com.(你的遊戲英文名).(你的英文署名) 這類英文數字的格式。
"productName": "Game",
"asar": true, //建議將此項設為 true ,如果你需要將遊戲內容進行加密封裝的話...
"afterPack": "./myAfterPackHook.js", // ※ 如果你有需要使用「asarmor」加密套件的話,請確保加入此項參數。
"mac": {
"category": "public.app-category.role-playing-games",
"icon": "icon/icon.icns", //遊戲圖示,圖片格式為 icns 格式。
//※使用 png 轉 icns 的線上轉換圖片的網站,並將 icns 格式的圖檔放在 icon 檔案夾裡。
"target": {
"target": "dir",
"arch": "universal" //指定 「universal」的情況時,將同時兼容 x64 (Intel 機種) 和 arm64 (Apple M1 機種)。
}
}
},
"scripts": {
"start": "electron .",
"pack": "electron-builder --dir",
"dist": "electron-builder"
},
"author": "Mirai", //作者/團隊署名
"copyright": "Copyright © 2021 ${author} All rights reserved.", //版權宣告文字
"devDependencies": {
"electron": "^11.5.0",
"electron-builder": "^22.5.1",
"asarmor": "^2.0.0" // ※ 如果你有需要使用「asarmor」加密套件的話...
}
}
如果你有需要使用「asarmor」加密套件的話,請建立一個名為「myAfterPackHook.js」的檔案,並且將以下程式碼放進此檔案並保存在此輸出檔案夾之中。
const asarmor = require('asarmor');
const { join } = require("path");
exports.default = async ({ appOutDir, packager }) => {
try {
const asarPath = join(packager.getResourcesDir(appOutDir), 'app.asar');
console.log(`applying asarmor patches to ${asarPath}`);
const archive = await asarmor.open(asarPath);
archive.patch(); // apply default patches
await archive.write(asarPath);
} catch (err) {
console.error(err);
}
};
【示範】
Learn More →
接著使用「終端機」的cd
指令來指定檔案夾的路徑,然後在「終端機」輸入npm install
指令來安裝所需要的套件。
記得你的檔案夾名稱只能英文數字且不含半行空白,如果有需要用到半形空白,請用半形底線( _ )替代半形空白。
4.開啟你的 RPG Maker MV/MZ 遊戲專案,並且按「檔案→部署…」,選擇「網頁瀏覽器 / Android / iOS」後,RPG Maker MV 為選擇「網頁瀏覽器」後,按下「OK」等待部署輸出完成。
【RPG Maker MZ】
Learn More →
【RPG Maker MV】
Learn More →
5.建立一個「index.js」的檔案,並輸入以下內容:
const { app, BrowserWindow, ipcMain, shell } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 816, //遊戲解析度寬度
height: 624, //遊戲解析度高度
icon: 'icon/icon.png',
useContentSize: true,
autoHideMenuBar: true,
backgroundColor: '#000000',
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
const gametitleString = "遊戲測試"; //遊戲標題
const isTest = false; //是否為測試模式
const testString = isTest ? '?test' : '';
app.allowRendererProcessReuse = false;
win.loadURL(`file://${__dirname}/index.html${testString}`);
if (process.platform !== 'darwin') {
win.setMenu(null);
} else {
var { Menu } = require('electron');
var menu = Menu.buildFromTemplate([
{
label: 'Electron',
submenu: [
{
label: `關於 ${gametitleString}`,
selector: 'orderFrontStandardAboutPanel:'
},
{type: 'separator'},
{
label: `隱藏 ${gametitleString}`,
accelerator: 'Command+H',
selector: 'hide:'
},
{
label: '隱藏其他',
accelerator: 'Command+Alt+H',
selector: 'hideOtherApplications:'
},
{
label: '全部顯示',
selector: 'unhideAllApplications:'
},
{
type: 'separator'
},
{
label: `結束 ${gametitleString}`,
accelerator: 'Command+Q',
click: function() { app.quit(); }
}
]
}
]);
Menu.setApplicationMenu(menu);
}
require('electron').ipcMain.on('focusMainWindow', function (e) {
win.focus();
});
require('electron').ipcMain.on('openDevTools', function (e) {
win.webContents.openDevTools();
});
require('electron').ipcMain.on('openExternal', function (e, arg) {
shell.openExternal(arg);
});
//※需要搭配NekoGakuen_BlockedCapture.js的插件使用。
require('electron').ipcMain.on('setProtection', function (e, arg) {
win.setContentProtection(arg);
});
};
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
app.quit();
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
6.在部署輸出後的檔案夾,並且將除了「package.json」以外的所有檔案複製,並貼到這邊 Electron 用的輸出檔案夾內。
【RPG Maker MZ】
【RPG Maker MV】
7.接下來將分為兩種專案並修改在 js 檔案夾下的一些內容。
【RPG Maker MZ】
分別修改「main.js」、「rmmz_core.js」、「rmmz_managers.js」為以下內容。
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
return (
Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var")
);
}
改成
isPathRandomized() {
// [Note] We cannot save the game properly when Gatekeeper Path
// Randomization is in effect.
if (Utils.isElectronjs()) {
return (__filename.startsWith("/private/var"));
} else {
return (Utils.isNwjs() &&
process.mainModule.filename.startsWith("/private/var"));
}
}
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
改為
Utils.isNwjs = function() {
return typeof require === "function" && typeof process === "object";
};
Utils.isElectronjs = function () {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
Utils.isOptionValid = function(name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
return false;
};
改為
Utils.isOptionValid = function (name) {
const args = location.search.slice(1);
if (args.split("&").includes(name)) {
return true;
}
if (this.isElectronjs()) {
if (process.argv.length > 0) {
return process.argv[0].split("&").includes(name);
}
} else {
if (this.isNwjs() && nw.App.argv.length > 0) {
return nw.App.argv[0].split("&").includes(name);
}
}
return false;
};
StorageManager.fileDirectoryPath = function() {
const path = require("path");
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
};
改為
StorageManager.fileDirectoryPath = function () {
const path = require("path");
if (Utils.isElectronjs()) {
const base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, "save/") : path.join(base, '../../save/');
} else {
const base = path.dirname(process.mainModule.filename);
return path.join(base, "save/");
}
};
SceneManager.reloadGame = function () {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
};
SceneManager.showDevTools = function () {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
};
改為
SceneManager.reloadGame = function () {
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
chrome.runtime.reload();
}
}
};
SceneManager.showDevTools = function () {
if (Utils.isElectronjs()) {
if (Utils.isOptionValid("test")) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid("test")) {
nw.Window.get().showDevTools();
}
}
};
【RPG Maker MV】
分別修改「rpg_core.js」、「rpg_managers.js」為以下內容。
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
改為
Utils.isNwjs = function() {
return typeof require === 'function' && typeof process === 'object';
};
Utils.isElectronjs = function() {
return window && window.process && window.process.versions && window.process.versions['electron'];
};
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
return 0;
};
改為
Utils.isOptionValid = function (name) {
if (location.search.slice(1).split('&').contains(name)) { return 1; };
if (this.isElectronjs()) {
if (this.isNwjs() && process.argv.length > 0 && process.argv[0].split('&').contains(name)) { return 1; };
} else {
if (typeof nw !== "undefined" && nw.App.argv.length > 0 && nw.App.argv[0].split('&').contains(name)) { return 1; };
}
return 0;
};
Input._wrapNwjsAlert = function() {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function() {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
};
改為
Input._wrapNwjsAlert = function () {
if (Utils.isElectronjs()) {
var _alert = window.alert;
window.alert = function () {
_alert.apply(this, arguments);
require('electron').ipcRenderer.send('focusMainWindow');
Input.clear();
};
} else {
if (Utils.isNwjs()) {
var _alert = window.alert;
window.alert = function () {
var gui = require('nw.gui');
var win = gui.Window.get();
_alert.apply(this, arguments);
win.focus();
Input.clear();
};
}
}
};
StorageManager.localFileDirectoryPath = function() {
var path = require('path');
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
};
改為
StorageManager.localFileDirectoryPath = function () {
var path = require('path');
if (Utils.isElectronjs()) {
var base = path.dirname(__filename);
return Utils.isOptionValid('test') ? path.join(base, 'save/') : path.join(base, '../../save/');
} else {
var base = path.dirname(process.mainModule.filename);
return path.join(base, 'save/');
}
};
SceneManager.initialize = function() {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
this.initNwjs();
this.checkPluginErrors();
this.setupErrorHandlers();
};
改為
SceneManager.initialize = function () {
this.initGraphics();
this.checkFileAccess();
this.initAudio();
this.initInput();
if (!Utils.isElectronjs()) {
this.initNwjs();
}
this.checkPluginErrors();
this.setupErrorHandlers();
};
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isNwjs()) {
location.reload();
}
break;
case 119: // F8
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
break;
}
}
};
改為
SceneManager.onKeyDown = function (event) {
if (!event.ctrlKey && !event.altKey) {
switch (event.keyCode) {
case 116: // F5
if (Utils.isElectronjs()) {
location.reload();
} else {
if (Utils.isNwjs()) {
location.reload();
}
}
break;
case 119: // F8
if (Utils.isElectronjs()) {
if (Utils.isOptionValid('test')) {
require('electron').ipcRenderer.send('openDevTools');
}
} else {
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
require('nw.gui').Window.get().showDevTools();
}
}
break;
}
}
};
如果上述內容覺得非常複雜的話,也可以到以下GitLab直接下載懶人包。
https://gitlab.com/MiraiSoSad/rpg_maker_mv_and_mz_electron/-/tree/zh_TW
8.回到「終端機」並輸入npm start
檢查是否能正常執行遊戲,如果執行遊戲 OK 的話,輸入npm run dist
後就能執行部署輸出。
9.最後,部署輸出完成後,可以在「dist/mac-universal/」檔案夾中找到部署輸出好的內容,執行Game.app即可。
如果你初次執行遊戲時,遊戲畫面跳出「Please move the Game.app to a different folder.」錯誤訊息,你可以建立一個檔案夾將 Gamp.app 移動到此檔案夾中並再次執行遊戲即可。
https://github.com/electron/electron-quick-start
https://qiita.com/RaTTiE/items/63f2e351a93f81bc8039
https://a091234765.pixnet.net/blog/post/402450719-[electron學習筆記]electron安裝檔打包攻略補充_el
https://www.npmjs.com/package/asarmor
《Mirai》Patreon創作:
https://www.patreon.com/MiraiDiary
《Mirai》個人推特(X):
https://twitter.com/Mirai_so_Sad
《Mirai》itch.io頁面:
https://miraisosad.itch.io
《Mirai》個人Instagram
https://www.instagram.com/miraisosad/
貓咪學園
RPG 製作大師
RPG Maker MV
RPG Maker MZ
皆さんこんにちは、私はMiraiです。もし昨年私が投稿した「BooGooTEAM CooMIC 2 - 展示レポート」をご覧になったなら、今年も5/31にBooGooTEAM公式が開催した「CooMIC 3」にて、「DIYGM」が再びインディーゲームや女性向けゲーム開発者に出展の機会を設けてくれました。今回私は「Rabbit Tea Party」の名義で応募し、また兄にブース出展を手伝ってもらいました。
Jun 8, 2025Hello everyone, I’m Mirai. If you read my post last year, “BooGooTEAM CooMIC 2 - Exhibition Review”, you’ll know that on 5/31 this year, BooGooTEAM officially held “CooMIC 3”. “DIYGM” once again provided indie and female‑oriented game creators with an opportunity to exhibit. This time I applied under the name “Rabbit Tea Party” and had my brother help me run the booth.
Jun 8, 2025大家好,我是Mirai,如果你們大家有看過去年我發過的「布穀町CooMIC二元創庫2 - 展覽心得」這篇文章的話,今年於5/31布穀町官方所舉辦「二元創庫3」場次,「自製遊戲公會」也再次為小眾遊戲及女性向遊戲的獨立遊戲開發者們有展出的機會,而我這次以「兔子茶會」的名義報名了這次的活動,並拜託我哥再次替我擺攤囉~
Jun 8, 2025大家好,我是Mirai,我這次想跟大家分享下由「布穀町」於今年5/25所舉辦的活動「CooMIC二元創庫2」的其中一個場次「自製遊戲ONLY【自遊公會】」。這個是在同人展場次的展出之中,唯一一個可以展出自己所開發「獨立遊戲」的展出機會,其實在其他國家能讓一些獨立遊戲在現場對外公開展出的機會我印象中好像真的不多,以我所居住的地方有像是「自製遊戲Only(by 自製遊戲公會)」、「巴哈姆特週年站聚(by 旺普網路資訊股份有限公司)」、「異校遊戲大亂鬥(by 中部獨立遊戲勇者交流會)」、「G-Eight(by 巨罷娛樂股份有限公司)」等活動,我記得好像是這樣..而在日本當地那邊也有像是「BitSummit Drift(by 日本獨立遊戲協會)」、「東京遊戲迷宮(by 東京遊戲迷宮)」等活動,雖然我印象中日本當地應該還有更多這類型的活動,只是我需要Google搜尋一下…😅
Jun 3, 2025or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up