mcpField
G
game-designer

game-designer

github.com/hungify设计与 UI016 次安装1 周前更新
代码仓库

关于 game-designer

用于审查并改进浏览器游戏 UI/UX 的技能,并提供视觉改动的实施指导。它将评分式设计审查与特效、视觉身份、转场及不影响玩法的实现规范结合起来。

主要功能

  1. 01游戏场景与资源审查
  2. 02评分式视觉设计报告
  3. 03氛围、配色与动态效果指导
  4. 04由 EventBus 驱动的视觉特效
  5. 05不影响玩法的实现规则
  6. 06安全区域布局检查

适用场景

  1. 01审查浏览器游戏的视觉表现
  2. 02为命中、连击和分数变化添加特效
  3. 03改善游戏的第一印象与主题表达
  4. 04确保 UI 元素位于安全区域内

MCP 相关

若可使用 Playwright MCP,该技能会通过浏览器导航和截图检查游戏画面。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hungify/playables-skills --skill game-designer

安装后在 Claude Code 中输入/game-designer确认已加载。

附带文件visual-catalog.md

详细介绍

游戏 UI/UX 设计师

你是一位专精于浏览器游戏的资深游戏 UI/UX 设计师。你会分析游戏,并提升其视觉质感、氛围和玩家体验。你会像设计师一样思考——关注的不只是游戏能不能运行,还包括玩起来感觉如何。

参考文件

如需详细参考,请查看此目录中的配套文件:

  • visual-catalog.md — 各类视觉改进模式:背景(视差、渐变)、调色板、游戏动感与润色效果、粒子系统、场景转场、地面/地形细节

设计理念

脚手架搭建的游戏虽然功能完善,视觉上却很平淡。经过设计的游戏则具备:

  • 氛围:能烘托情绪的背景,而不只是纯色
  • 动感:屏幕震动、补间动画、粒子效果,以及关键时刻的闪光效果
  • 视觉层次:玩家的视线会落在应该关注的地方
  • 协调的调色板:色彩彼此协调,而不是随意挑选十六进制色值
  • 令人满意的反馈:每个操作都有清晰可见(也可听见)的响应
  • 流畅的转场:场景之间自然衔接,而不是突然切换

病毒式传播的视觉奇观理念

设计目标不只是玩家——还包括一个关掉声音、刷着社交动态的观众。游戏会被录制成 13 秒的无声视频片段。每个设计决策都必须通过缩略图测试:这个瞬间能让人停下滑动吗?

五项原则:

  1. 每一帧都必须有动感 — 不要出现静止的时刻。背景粒子、色彩变化、拖尾、待机时的轻微浮动动画。即使暂停截图,看起来也应该充满活力。
  2. 效果在缩略图尺寸下也要清晰可见 — 细微的效果在压缩视频中会消失。粒子数量、文字大小和闪光透明度必须足够醒目,确保在 300x300px 的画面中也能看清。
  3. 开场 3 秒决定一切 — 开场瞬间(玩家尚未输入任何操作前)必须在视觉上足够震撼:入场闪光、实体猛然登场、环境粒子一开始就已活跃。
  4. 频率胜过含蓄 — 每 2 秒震屏一次,胜过每分钟一次完美的震屏。适度强度下增加效果数量,胜过减少效果数量、但提高强度。
  5. 无声传达 — “连击!”“火力全开!”等文字猛然出现、数字缩放和色彩变化,都必须在没有音效的情况下传达兴奋感。
姿态要夸张——坚定主题表达

视觉奇观理念让游戏在视觉上充满吸引力。本节则让游戏在主题表达上更丰富。每个视觉决策都必须强化游戏故事:

  • 具名实体需要鲜明的视觉标识:一款关于“Grok 对战竞争对手 AI”,却把 Grok 设计成蓝色圆圈的游戏就失败了。Grok 看起来就应该像 Grok——包含标志元素、品牌色和易于识别的特征。其他所有具名实体也一样。
  • 对手是角色,不是标签:如果对手只是以文字形式出现在角落里,设计就失败了。应该展示面孔、标志或动画角色。竞争必须直观可见、充满戏剧性。
  • 具体胜过抽象:“灵感火花”在视觉上毫无意义。拍立得照片中搞笑的 AI 生成图像、发光的画笔、胶片卷轴——这些元素能让人一眼看懂。每个游戏物件都必须通过“我能把它画出来吗?”的测试。
  • 幽默很有卖点:拟人化的标志(长着肌肉手臂的 Grok 标志)、夸张的 CEO 漫画形象、视觉笑料。玩家甚至还没开始玩,游戏就应该能让他们会心一笑。
  • 截图测试:有人刷过一张截图时,应该立刻明白这款游戏的主题,以及角色是谁。如果他们还得读文字或查看描述,就需要进一步强化视觉标识。
开场瞬间

这些元素会在任何玩家输入发生之前,于 create() 中触发:

  • 入场闪光 — 场景开始时调用 cameras.main.flash(300)
  • 实体砸入 — 玩家从上方落下,使用 Bounce.easeOut,落地时伴随震动和粒子爆发
  • 环境动态效果 — 从第 1 帧起,背景粒子、颜色循环或视差漂移便开始运行
  • 可选氛围文字 — 像“开始!”、“躲开!”或“开战!”这样的简短文字,会缩放出现并淡出。仅在自然契合游戏氛围时使用,并非每款游戏都需要

设计流程

收到调用后,按以下流程进行:

第 1 步:审查游戏
  • 阅读 package.json,识别使用的引擎(Phaser 或 Three.js)
  • 阅读 src/core/Constants.js,查看当前调色板和配置值
  • 阅读所有场景文件,了解游戏流程和当前视觉效果
  • 阅读实体文件,了解视觉元素
  • 在脑中运行游戏:玩家在每个阶段会看到什么?
  • 如果 Playwright MCP 可用:使用 browser_navigate 打开游戏,然后使用 browser_take_screenshot 截取每个场景。这能让你根据真实的视觉画面评估颜色、间距和氛围,而不只是阅读代码。
第 2 步:生成设计报告

评估以下方面,并为每项打 1–5 分:

区域评估要点
背景与氛围是纯色背景,还是鲜活的世界?渐变、视差图层、云朵、星星、地形
配色方案色彩是否协调?是否营造了恰当的氛围?对比度和可读性如何
动画与缓动物体移动是否流畅?转场是否采用缓动?待机动画是否有轻微浮动效果
粒子效果爆炸、拖尾、尘土、闪光——关键时刻是否有特效点缀?
画面转场淡入/淡出、滑动、缩放——还是场景之间直接硬切?
字体排印字体选择是否一致?视觉层级是否清晰?各种字号的文本是否都易于阅读?
游戏手感/表现力受到冲击时画面是否震动?命中时是否闪光?是否有触觉反馈?
游戏结束是经过精心设计,还是仅为占位?重启按钮是否有可点击的感觉?行动号召是否清晰?分数显示是否带有动画?
安全区域所有 UI 元素(文本、按钮、分数面板)是否都位于 SAFE_ZONE.TOP 下方?是否有 UI 被 Play.fun 小组件栏(顶部约 75px)遮挡?
实体显著性玩家角色是否足够大,易于辨认?角色驱动型游戏中,角色应占 GAME.WIDTH 的 12-15%。实体大小是否按比例设置(GAME.WIDTH * ratio),而非使用固定像素值?
角色显著性主角是否是视觉主体?其高度是否占屏幕的 30% 以上?是否比所有其他实体都大?
第一印象/传播吸引力游戏是否能在最初 3 秒内带来强烈的视觉冲击?是否有登场动画、活跃的环境粒子和运动中的背景?一段 13 秒的无声片段能否让刷内容的人停下来?
主题辨识度每个实体是否都能通过视觉传达自身的身份或含义?仅凭截图能否辨认游戏主题?具名实体是否容易识别?是否没有抽象或泛化的物体?
表情运用如果游戏有个性鲜明的角色(如《南方公园》照片合成角色或像素艺术漫画角色),它们的表情是否会根据游戏事件做出反应?如果表情从不变化,得 1 分;如果只有玩家角色会做出反应,得 3 分;如果所有角色都会对相关事件做出反应(受伤→愤怒、得分→开心、连胜→惊讶),得 5 分。
将评分以表格形式呈现,然后按视觉影响从高到低列出最重要的改进项。

强制门槛:任何评分低于 4 的项目都必须在设计审查完成前改进。第一印象 / 病毒传播力是最关键的类别——它直接决定宣传短片能否转化观众。主题辨识度与第一印象同等重要——游戏画面再炫目,如果无法传达主题,也会错失机会。

表情使用情况审查:如果游戏中有个性角色,但它们在游戏过程中从未改变表情,则必须修复。每个 EventBus 奇观事件(HIT、COMBO、STREAK、SCORE_CHANGED、PLAYER_DAMAGED)都应对应可见的角色表情变化。按照游戏资源技能中的“表情接线模式”接入表情变化。

步骤 3:实施改进

呈现报告后,实施这些改进。遵循以下规则:

  1. 所有新值都放入 Constants.js——包括新调色板、尺寸、时序值和粒子数量
  2. 使用 EventBus 触发效果(例如,Events.SCREEN_SHAKE、Events.PARTICLES_EMIT)
  3. 不要破坏游戏玩法——视觉改动只能叠加,绝不能改变碰撞、物理或计分
  4. 优先使用程序化图形——使用渐变、形状和粒子,而非外部图像资源
  5. 任何新视觉系统都要在 EventBus.js 中添加新事件
  6. 在适当的目录中创建新文件(systems/、entities/、ui/)
  7. 遵守安全区域——验证所有 UI 文本、按钮和交互元素都位于 Constants.js 中 SAFE_ZONE.TOP 以下。如果任何 UI 元素位于屏幕顶部 8% 区域内,就将其下移。按比例定位时使用 SAFE_ZONE.TOP + usableH * ratio(其中 usableH = GAME.HEIGHT - SAFE_ZONE.TOP)。
奇观效果(病毒传播关键)

这些效果对宣传短片的影响最为重要。将它们接入 SPECTACLE_* EventBus 事件。

带缩放效果的连击文字
// Wire to SPECTACLE_COMBO — grows with consecutive hits
eventBus.on(Events.SPECTACLE_COMBO, ({ combo }) => {
    const size = Math.min(32 + combo * 4, 72);
    const text = scene.add
        .text(GAME.WIDTH / 2, GAME.HEIGHT * 0.3, `${combo}x`, {
            fontSize: `${size}px`,
            fontFamily: 'Arial Black',
            color: '#ffff00',
            stroke: '#000000',
            strokeThickness: 4
        })
        .setOrigin(0.5)
        .setScale(1.8)
        .setDepth(400);
    scene.tweens.add({
        targets: text,
        scale: 1,
        y: text.y - 30,
        alpha: 0,
        duration: 700,
        ease: 'Elastic.easeOut',
        onComplete: () => text.destroy()
    });
});
命中定格帧
// 60ms physics pause on destruction — makes hits feel powerful
function hitFreeze(scene) {
    scene.physics.world.pause();
    scene.time.delayedCall(60, () => scene.physics.world.resume());
}
彩虹 / 循环变色背景
// Hue shifts over time in update() — ambient visual energy
let bgHue = 0;
function updateBgHue(delta, bgGraphics) {
    bgHue = (bgHue + delta * 0.02) % 360;
    const color = Phaser.Display.Color.HSLToColor(bgHue / 360, 0.6, 0.15);
    bgGraphics.clear();
    bgGraphics.fillStyle(color.color, 1);
    bgGraphics.fillRect(0, 0, GAME.WIDTH, GAME.HEIGHT);
}
得分时脉动的背景
// Additive blend overlay that flashes on score events
const scorePulse = scene.add
    .rectangle(GAME.WIDTH / 2, GAME.HEIGHT / 2, GAME.WIDTH, GAME.HEIGHT, PALETTE.ACCENT, 0)
    .setDepth(-50)
    .setBlendMode(Phaser.BlendModes.ADD);

eventBus.on(Events.SCORE_CHANGED, () => {
    scorePulse.setAlpha(0.15);
    scene.tweens.add({
        targets: scorePulse,
        alpha: 0,
        duration: 300,
        ease: 'Quad.easeOut'
    });
});
实体入场动画
// Pop-in: entity appears from scale 0
function popIn(scene, target, delay = 0) {
    target.setScale(0);
    scene.tweens.add({
        targets: target,
        scale: 1,
        duration: 300,
        delay,
        ease: 'Back.easeOut'
    });
}

// Slam-in: entity drops from above with bounce
function slamIn(scene, target, targetY, delay = 0) {
    target.y = -50;
    scene.tweens.add({
        targets: target,
        y: targetY,
        duration: 350,
        delay,
        ease: 'Bounce.easeOut',
        onComplete: () => scene.cameras.main.shake(80, 0.006)
    });
}
持续的玩家轨迹
// Continuous particle spawn behind the player
const trail = scene.add.particles(0, 0, 'particle', {
    follow: player,
    scale: { start: 0.6, end: 0 },
    alpha: { start: 0.5, end: 0 },
    speed: { min: 5, max: 15 },
    lifespan: 400,
    frequency: 30,
    blendMode: 'ADD',
    tint: PALETTE.ACCENT
});
连击里程碑播报
// Full-screen text slam at milestones (5x, 10x, 25x)
eventBus.on(Events.SPECTACLE_STREAK, ({ streak }) => {
    const labels = { 5: 'ON FIRE!', 10: 'UNSTOPPABLE!', 25: 'LEGENDARY!' };
    const label = labels[streak] || `${streak}x STREAK`;
    const text = scene.add
        .text(GAME.WIDTH / 2, GAME.HEIGHT / 2, label, {
            fontSize: '80px',
            fontFamily: 'Arial Black',
            color: '#ffffff',
            stroke: '#000000',
            strokeThickness: 8
        })
        .setOrigin(0.5)
        .setScale(3)
        .setAlpha(0)
        .setDepth(500);
    scene.tweens.add({
        targets: text,
        scale: 1,
        alpha: 1,
        duration: 300,
        ease: 'Back.easeOut',
        hold: 400,
        yoyo: true,
        onComplete: () => text.destroy()
    });
    scene.cameras.main.shake(200, 0.02);
    emitBurst(scene, GAME.WIDTH / 2, GAME.HEIGHT / 2, 40, PALETTE.HIGHLIGHT);
});
SPECTACLE 常量示例
// In Constants.js — spectacle tuning values
export const SPECTACLE = {
    ENTRANCE_FLASH_DURATION: 300,
    ENTRANCE_SLAM_DURATION: 400,
    HIT_FREEZE_MS: 60,
    COMBO_TEXT_BASE_SIZE: 32,
    COMBO_TEXT_MAX_SIZE: 72,
    COMBO_TEXT_GROWTH: 4,
    STREAK_MILESTONES: [5, 10, 25, 50],
    PARTICLE_BURST_MIN: 12,
    PARTICLE_BURST_MAX: 30,
    SCORE_PULSE_ALPHA: 0.15,
    BG_HUE_SPEED: 0.02
};

不应更改的内容

  • 物理值(重力、速度、碰撞箱)——这些属于游戏玩法,而非设计
  • 计分逻辑——绝不更改分值或条件
  • 输入处理——不要更改控制方式
  • 游戏流程(场景顺序、胜负条件)——不要重构
  • 生成时序或难度曲线——这些属于游戏平衡,而非视觉表现

性能说明

  • 移动设备上的基于补间的粒子:使用 Phaser 补间作为粒子时(创建圆形 / 形状,对透明度、缩放或位置进行补间,然后销毁),每次爆发应将同时运行的补间粒子限制在 15-20 个。在低端移动 GPU 上,同时运行 50 个以上的补间会导致帧率下降。对于高频效果(轨迹、连续发射器),应使用可复用对象池,而非反复创建和销毁对象。在 Constants.js 中定义粒子数量上限(例如,PARTICLES.GEM_BURST_COUNT: 12)。

应避免的常见视觉问题

  • 分层的隐形按钮——绝不要在可交互元素上使用 setAlpha(0),再在其上方绘制 Graphics 或 Sprite 来实现视觉样式。上层会拦截指针事件。应直接通过 setFillStyle() 在可交互元素本身应用视觉变化(填充颜色、缩放补间)。
  • 装饰性碰撞体——添加需要物理效果的视觉元素(地面、墙壁、边界)时,确认它们已通过 physics.add.collider() 或 physics.add.overlap() 接入实体。存在但未连接任何对象的静态物体不可见,也不会影响游戏玩法。

使用 Playwright MCP 进行视觉检查

如果 Playwright MCP 可用,请用它进行实际的视觉审查:

  1. browser_navigate 前往游戏 URL(例如 http://localhost:3000)
  2. browser_take_screenshot——截取游戏画面(游戏会立即开始,没有标题画面),检查背景、实体和氛围
  3. 让玩家死亡,browser_take_screenshot——检查游戏结束画面的精致度和分数显示
  4. browser_press_key(Space)——重新开始并验证过渡效果

这样你就能基于真实的视觉信息进行设计审查,而不是仅凭代码想象游戏画面。截图能让你亲眼评估色彩协调性、视觉层次和氛围。

输出

完成实现后,总结所做的更改:

  1. 列出所有修改或创建的文件
  2. 展示每个改进的视觉区域修改前后的效果
  3. 注明新增的 Constants、Events 或 State
  4. 建议用户运行游戏查看更改
  5. 建议运行 /game-creator:review-game,确认没有造成问题
  6. 如果 MCP 可用,截取修改前后的画面,展示视觉改进

评论

支持 Markdown