小游戏
介绍如何在Pixi'VN中集成小游戏,涵盖最佳实践、生命周期管理,以及基于PixiJS与React的示例实现。
AI
点击上方按钮,你还可以用 AI 快速生成属于自己的小游戏原型。
相比纯文字叙述,互动故事的魅力在于:玩家可以在剧情间隙稍作休息,通过小游戏与故事世界产生更深的互动。
在视觉小说中,小游戏通常作为剧情的延伸被触发。 To switch between the narrative UI and the minigame UI, it is recommended to link the minigame to a route (e.g., "/minigame/snake") and navigate to it from the story. 更多路由配置细节请参阅此处。
这里有一些提示:
- Use PixiJS directly — either the
pixi.jspackage itself or the@drincs/pixi-vn/pixi.jssubmodule that re-exports it — with components such asGraphics,Sprite, andText, combined with PixiJS Layers to create a separate layer for your minigame, managed independently from the main visual novel interface. - Use hotkeys to handle keyboard input for your minigame controls. See Hotkeys to learn how to set them up.
- It is always recommended not to use PixiJS to build the UI (buttons, score displays, game over messages, ...); use a framework such as React or Vue instead.
- Saving and restoring the minigame's current state is the developer's responsibility.
- Since a minigame is its own route, a project usually ends up with more than one of them under the same
/minigamepath (e.g./minigame/snake,/minigame/quiz); use TanStack Router's file-based routing to share logic between them instead of duplicating it in every minigame (see below). - Starting a minigame is nothing more than navigating to its route from the story; if it needs a parameter (a difficulty, a level id, ...), pass it through that same route (see below).
模板
useMinigame是一个自定义钩子,可帮助管理小游戏的生命周期,包括启动、更新和清理资源。 它已存在于所有模板。
例如:
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>
)}
</>
);
}Examples
The Pixi’VN Team welcomes new proposals and contributions to make this library even more complete. 欢迎在下面的聊天中分享或提出你自己的小游戏实施方案!