LogoPixi’VN

小游戏

介绍如何在Pixi'VN中集成小游戏,涵盖最佳实践、生命周期管理,以及基于PixiJS与React的示例实现。

点击上方按钮,你还可以用 AI 快速生成属于自己的小游戏原型。

相比纯文字叙述,互动故事的魅力在于:玩家可以在剧情间隙稍作休息,通过小游戏与故事世界产生更深的互动。

在视觉小说中,小游戏通常作为剧情的延伸被触发。 为了在叙事界面与小游戏界面之间平滑切换,推荐将小游戏绑定到独立路由(例如 /minigame),并在剧情中通过导航跳转进入。 更多路由配置细节请参阅此处

这里有一些提示:

  • 善用@drincs/pixi-vn/pixi.js提供的子模块:如 Graphics、Sprite、Text 等组件,可快速构建游戏画面。 @drincs/pixi-vn/pixi.js本质是PixiJS的封装导入,因此你可自由使用 PixiJS 的全部能力。
  • 使用PixiJS Layers为小游戏创建独立图层。 这样,你就可以将其与视觉小说主界面解耦管理。
  • 通过Ticker类控制帧更新,同步处理游戏状态变化。
  • 借助window.addEventListener响应键盘、鼠标等交互事件。
  • 使用HTML元素创建UI,如按钮、分数面板、游戏结束提示等。
  • Pixi'VN不会自动保存图层状态,如果使用PixiJS Layers,请自行管理小游戏的状态 将状态保存在变量中,并在小游戏重新启动时恢复。

Templates

useMinigame是一个自定义钩子,可帮助管理小游戏的生命周期,包括启动、更新和清理资源。 它已存在于所有模板。

例如:

import { Layer } from "@drincs/pixi-vn";
import { Graphics, Ticker } from "@drincs/pixi-vn/pixi.js";
import { useCallback, useMemo, useRef, useState } from "react";
import useMinigame from "../hooks/useMinigame";

export default function MiniGame() {
    const ticker = useMemo(() => new Ticker(), []);
    const [displayScore, setDisplayScore] = useState(0);
    const [gameOver, setGameOver] = useState(false);

    const onKeyDown = useCallback((e: KeyboardEvent) => {
        // Handle key down events for game controls
    }, []);

    const game = useCallback(
        (layer: Layer) => {
            const endGame = () => {
                ticker.stop();
                setGameOver(true);
            };

            window.addEventListener("keydown", onKeyDown);

            ticker.add(({ deltaMS }) => {
                // Update game logic here
            });
            ticker.start();
        },
        [ticker] // They must not be changed during the game otherwise the game will restart
    );

    const options = useMemo(
        () => ({
            onExit() {
                ticker.stop();
                ticker.destroy();
                window.removeEventListener("keydown", onKeyDown);
            },
        }),
        [ticker, onKeyDown] // 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团队非常欢迎新的创意与代码贡献,共同让这套工具链更加完善。 欢迎在下面的聊天中分享或提出你自己的小游戏实施方案!