小游戏
将小游戏集成到 Pixi’VN 中的指南,包括最佳实践、生命周期管理,以及使用 PixiJS 和 React 的示例实现。
AI
你可以使用上方的按钮,通过 AI 创建你自己的小游戏。
与普通文本相比,交互式故事的魅力在于,你可以稍作休息,与故事相关的小游戏进行互动。
视觉小说中的小游戏通常会在叙事过程中启动。为了在叙事 UI 与小游戏 UI 之间切换,建议将小游戏关联到一个路由(例如 "/minigame/snake"),并从故事中导航至该路由。更多信息请参见此处。
以下是一些提示:
- 直接使用 PixiJS——可以是
pixi.js包本身,也可以是重新导出它的@drincs/pixi-vn/pixi.js子模块——搭配Graphics、Sprite、Text等组件,并结合PixiJS 图层,为你的小游戏创建一个独立于主视觉小说界面进行管理的单独图层。 - 使用快捷键来处理小游戏控制的键盘输入。请参阅Hotkeys了解如何设置它们。
- 始终建议不要使用 PixiJS 来构建 UI(按钮、分数显示、游戏结束提示等);而应使用诸如React或Vue之类的框架。
- 保存和恢复小游戏的当前状态是开发者的责任。
- 由于小游戏本身就是一个路由,一个项目通常最终会在同一个
/minigame路径下拥有不止一个小游戏(例如/minigame/snake、/minigame/quiz);请使用TanStack Router的基于文件的路由机制,在它们之间共享逻辑,而不是在每个小游戏中重复编写(见下文)。 - 启动一个小游戏,无非就是从故事中导航到它的路由;如果它需要参数(例如难度、关卡 ID 等),则通过同一个路由传递该参数(见下文)。
模板
useMinigame 是一个自定义 Hook,可帮助你管理小游戏的生命周期,包括启动、更新和清理资源。它包含在所有模板中。
例如:
import { Layer } from "@drincs/pixi-vn";
import { Graphics, Ticker } from "@drincs/pixi-vn/pixi.js";
import { createFileRoute } from "@tanstack/react-router";
import { useCallback, useMemo, useState } from "react";
import { useHotkey } from "@tanstack/react-hotkeys";
import useMinigame from "@/lib/hooks/minigame-hooks";
export const Route = createFileRoute("/minigame/example")({
component: MiniGame,
});
function MiniGame() {
const [displayScore, setDisplayScore] = useState(0);
const [gameOver, setGameOver] = useState(false);
const ticker = useMemo(() => {
const ticker = new Ticker();
const endGame = () => {
ticker.stop();
setGameOver(true);
};
ticker.add(({ deltaMS }) => {
// Update game logic here
});
return ticker;
}, []);
useHotkey(
"ArrowUp",
() => {
// Handle key down events for game controls
},
{ enabled: !gameOver },
);
const game = useCallback(
(layer: Layer) => {
ticker.start();
},
[ticker], // They must not be changed during the game otherwise the game will restart
);
const options = useMemo(
() => ({
onExit() {
ticker.stop();
ticker.destroy();
},
}),
[ticker], // They must not be changed during the game otherwise the game will restart
);
const { loading } = useMinigame(game, options);
return (
<>
<div
style={{
position: "absolute",
top: 10,
left: 10,
color: "white",
fontSize: "24px",
background: "rgba(0,0,0,0.5)",
padding: "5px 10px",
borderRadius: "5px",
}}
>
Score: {displayScore}
</div>
{gameOver && (
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
color: "red",
fontSize: "48px",
background: "rgba(0,0,0,0.7)",
padding: "20px 40px",
borderRadius: "10px",
}}
>
GAME OVER
</div>
)}
</>
);
}示例
Pixi’VN 团队欢迎大家提出新的建议并做出贡献,让这个库变得更加完善。欢迎在下方的聊天区分享或提出你的小游戏实现方案!