经过这么多周的努力,我们小组的创新实训项目主要功能已经基本实现。而我负责的工作,主要就是针对我们所实现的项目对前端进行编程设计。为了更好的切合我们项目的主题以及带来更好的游戏体验,这周我对前端页面进行了统一的升级改进,并且连接后端对游玩体验进行了测试。

页面全面改进详解

游戏启动页(WorldSelect.vue )

这是用户进入游戏的第一印象,我将其设计为一个具有沉浸感的开屏页面。

设计亮点:

  • 游戏LOGO动画:“渡厄峰”三字使用渐变金色,配合浮动动画和光晕效果

  • 毛玻璃故事卡片:半透明背景+模糊效果,展示世界观简介

  • 背景音乐系统:支持播放/暂停,音量可调,设置自动保存

  • 设置弹窗:可调节音乐音量、音效音量、文字速度和画面效果

技术难点:

  • 浏览器音频自动播放策略:现代浏览器禁止未经用户交互的音频自动播放,我通过在<audio>标签上同时设置autoplaymuted属性,并在首次用户交互时取消静音来解决

  • 云雾动画性能:使用CSS transform而非position实现平移,利用GPU加速,确保动画流畅

  • 响应式布局:手机端按钮变为横向排列,音乐控制按钮简化显示

实现效果:
用户打开游戏后,首先看到精美的启动画面,背景音乐尝试自动播放(若被阻止则静音等待用户点击),点击“开始新的旅程”跳转到角色创建页,如果之前玩过游戏并且有存档时点击“继续未竟之途”则加载存档直接进入游戏。

角色创建页(CharacterCreate.vue)

这个页面让玩家从四个角色中选择一个,每个角色都有独特的背景故事。

四个可选角色:

角色ID 名称 身份 心厄形态 开场物品
hua_jianke 花间客 女剑客 黑衣仇人 染血的残剑穗
liu_jianqing 柳见青 药师 病弱弟弟 旧药方
yunchang 云裳 刺客 被害小女孩 褪色小风筝
he_buyu 何不语 盲厨 背叛他的女子 断弦残谱

设计亮点:

  • 角色卡片网格:四列网格布局,卡片悬停有上浮和光效扫过动画

  • 选中状态特效:选中卡片有紫色渐变边框、光晕阴影和右上角“✓ 已选择”标记

  • 详情区域:选中角色后右侧展开详细档案,包含角色立绘、背景故事、心厄形态、初始物品、专属线索、角色目标、性格标签

  • BGM系统:独立的角色选择页面背景音乐,与启动页共享音乐设置

  • 加载遮罩:确认选择后显示加载动画,模拟“编织命运之网”的沉浸感

技术难点:

  • 立绘图片加载:图片加载失败时自动降级显示emoji头像

  • 角色数据传递:通过localStorage保存选中角色,跳转到游戏页面后读取

  • 后端初始化调用:选择角色后调用/api/chat/init接口,传递角色ID、模型名称和温度参数

实现效果:
玩家点击角色卡片查看详细信息,确认选择后系统调用后端初始化游戏会话,生成入场剧情后进入游戏主界面。

游戏主界面(GameView.vue)

这是游戏的核心界面,采用三栏深色玻璃态布局设计。

左侧角色信息区:

  • 角色立绘卡片:圆形立绘头像,心厄值>50时显示红色脉冲光晕特效

  • 角色属性面板:生命值(❤️)和心厄侵蚀度(🌑)进度条,心厄值过高时文字变红

  • 当前位置面板:场景名称带淡入淡出切换动画

  • 背包简览:显示前3个物品,超出显示“+N 更多”

  • 当前任务简览:显示前2个未完成任务及完成状态

中间对话区:

  • 消息气泡:用户消息靠右显示紫蓝渐变背景,AI消息靠左显示

  • 旁白消息:使用斜体样式,背景更透明,区分剧情叙述

  • 正在输入指示器:三点跳动动画 + “正在编织命运...”文字

  • 快捷短语按钮:询问、调查、对话、观察、探索、思考

  • 清除对话按钮:一键清空对话记录

右侧功能按钮区:

  • 竖列按钮设计:任务、剧情、线索、角色、背包、存档、设置、重置

  • 任务角标:未完成任务数量红色角标

  • 线索角标:新线索获得时橙色角标+按钮闪烁动画

  • 弹出面板:点击按钮从右侧滑出详情面板

弹出面板功能:

  • 任务面板:从后端quest_flags动态生成任务列表,显示任务名称和提示,自动同步完成状态

  • 剧情面板:环形进度条显示整体进度,里程碑节点展示

  • 线索面板:显示已获得线索,新线索带“新”标记和闪烁动画

  • 角色面板:显示NPC名称、身份、信任值进度条,点击可快速对话

  • 背包面板:展示所有持有物品

存档/读档系统:

  • 3个独立存档槽,支持保存和加载

  • 自动存档功能(可开关),每60秒自动保存

  • 存档信息包含场景位置、保存时间

通知系统:

  • 线索获得时弹出通知并闪烁线索按钮

  • 任务完成时弹出通知

  • 通知4秒后自动消失

技术难点:

  • WebSocket实时通信:实现消息实时收发,断线自动重连,心跳保活

  • 任务系统联动:任务列表从questFlags动态生成,完成后自动更新

  • 线索通知:监听known_clues数组变化,比较新旧值判断新线索

  • 心厄值特效:立绘外围红色脉冲动画,属性文字变红

  • 场景切换动画:场景名称变化时淡入淡出过渡

实现效果:
玩家输入行动或对话,通过WebSocket发送到后端,AI响应后实时显示在对话区。任务完成、线索获得时会有通知提示,游戏进度自动保存。

结局页面(EndingPage.vue)

根据玩家的游戏进度展示个性化结局,与主界面保持统一的深色玻璃态风格。

核心功能:

  • 四种结局类型:

    • good(天命所归):击败照影雾魇后触发,圆满结局

    • normal(凡尘一梦):面对心厄投影但未击败,普通结局

    • hidden(暗涌奇缘):接触心厄但未面对投影,隐藏结局

    • bad(宿命之殇):未完成任何关键任务,悲剧结局

  • 结局文本打字机效果:结局文字逐字显示,句号等标点处自然停顿

  • 任务完成总结:显示五个主线任务的完成状态

  • NPC关系总结:从questFlags读取信任值,用信任圆环可视化,根据信任值生成关系描述

  • 成就系统:7个成就,根据任务完成情况自动解锁

与后端联动:

  • gameState.world.quest_flags读取任务完成状态

  • gameState.npcs读取NPC信任值

  • 根据玩家选择的角色生成个性化结局文案

  • 游戏时长从gameStartTime计算

设计亮点

  • 打字机效果:逐字显示,中英文标点差异化停顿,增强沉浸感

  • 信任圆环:使用CSS conic-gradient实现圆形进度条

  • 成就卡片:解锁成就高亮显示,稀有成就特殊背景

  • 分享功能:支持复制结局文案和保存结局图片(html2canvas)

  • BGM系统:独立的结局页面背景音乐

实现效果:
游戏结束后,系统根据任务完成情况自动判断结局类型,逐字显示结局故事,展示任务总结、NPC羁绊和已解锁成就,玩家可以分享结局或重新开始游戏。

部分重要功能实现

任务系统与后端联动

任务系统是游戏的核心玩法之一。我设计了一个动态任务列表,从后端的quest_flags实时生成:

// 任务映射关系
const questMapping = [
  { flag: 'found_mist_source', name: '调查雾气来源', hint: '询问清尘子或调查白雾' },
  { flag: 'asked_about_mist', name: '询问心厄', hint: '与清尘子交谈' },
  { flag: 'touched_heart_affliction', name: '接触心厄', hint: '走入白雾深处' },
  { flag: 'faced_personal_shadow', name: '面对心厄投影', hint: '面对自己的心厄投影' },
  { flag: 'defeated_shadow_mist', name: '击败照影雾魇', hint: '击败照影雾魇' }
]

任务完成时会自动弹出通知,任务按钮上的角标也会实时更新。

通知系统

为了让用户及时了解游戏中的重要事件,我实现了一个全局通知系统:

  • 线索获得通知:当获得新线索时,右上角弹出通知,线索按钮闪烁

  • 任务完成通知:当任务完成时,弹出成功通知

  • 存档成功通知:保存游戏后弹出确认通知

音效与背景音乐

为了增强沉浸感,我实现了背景音乐和音效系统:

  • 启动页和游戏内统一背景音乐

  • 音乐控制按钮(播放/暂停)

  • 音量调节滑块

遇到的问题与解决方案

问题一:开屏剧情打字机效果

问题描述

游戏启动后需要播放一段开屏剧情,逐字显示文字,营造沉浸感。但简单的逐字显示存在以下问题:

  • 中英文混合时显示不流畅

  • 标点符号处没有停顿,显得生硬

  • 用户无法跳过或加速

  • 长文本时滚动不同步

解决方案

我设计了一个带有智能停顿的打字机系统:

核心思路:

  • 根据字符类型动态调整打字速度

  • 中文标点处增加停顿时间

  • 支持用户点击跳过或加速

实现细节:

  1. 字符类型识别:判断每个字符的类型,中文句号、感叹号、问号等标点处增加200ms停顿,逗号、顿号等处增加60ms停顿,普通字符使用40ms基础速度。

  2. 段落管理:将开屏文本按段落拆分,用户点击“下一节”时才继续显示下一段,避免一次性显示过多内容。

  3. 跳过功能:用户点击“跳过剧情”按钮时,清除定时器并直接显示全部文本,方便老玩家快速进入游戏。

  4. 滚动跟随:每显示完一段文字,自动滚动到底部,确保最新内容始终可见。

遇到的问题:

  • 初始实现时,段落切换时打字机状态没有重置,导致新段落直接显示全部内容。通过在切换段落时重置索引和定时器解决了这个问题。

问题二:背景音乐自动播放被阻止

问题描述

现代浏览器(Chrome、Safari等)出于用户体验考虑,默认阻止音频的自动播放。当用户打开游戏时,背景音乐无法自动播放,需要在控制台看到错误信息:

DOMException: play() failed because the user didn't interact with the document first.

解决方案

核心思路:浏览器允许自动播放的条件是用户已经与页面进行过交互。因此,我采取了以下策略:

  1. 尝试自动播放:页面加载时仍然尝试调用audio.play(),如果成功则正常播放;如果被阻止,静默失败并设置播放状态为暂停。

  2. 首次交互激活:在用户首次点击页面任意位置(如“开始游戏”按钮)时,调用audio.play()激活音频。这是最可靠的方案。

  3. 音乐控制按钮:在页面右下角添加音乐控制按钮,用户可以手动开启/关闭音乐。按钮状态实时显示当前播放状态。

  4. 音量设置持久化:将用户的音量设置保存到localStorage,下次进入游戏时自动恢复。

遇到的问题

  • 部分浏览器在用户交互后仍需要短暂延迟才能播放音频,通过将播放调用放在用户点击事件的回调中解决。

  • 页面跳转后音频状态丢失,通过在Vuex中保存音乐状态并在路由切换时恢复解决。

问题三:进度条不更新,任务列表停滞不前

在我进行《渡厄峰》游戏测试过程中,我发现了一个严重影响游戏体验的问题:玩家完成第一章后,游戏界面的右侧剧情进度显示为100%,但第二章开启后进度条不再更新,任务列表也停滞不前。

问题层面 具体原因
进度计算 进度计算逻辑只考虑了第一章5个任务,没有根据当前章节动态调整
任务列表 任务列表只在初始化时生成,不会根据章节变化更新
数据读取 前端没有从 branch_progress 读取支线任务数据

核心思路

  1. 任务列表动态化:根据当前章节(第一章/第二章/第三章)显示不同的任务列表

  2. 进度计算动态化:根据当前章节计算对应的进度百分比

  3. 数据源统一:任务完成状态直接从 questFlags 和 branchProgress 读取

第一步:增加章节状态判断

chapter1Completed() {
    return this.questFlags.defeated_shadow_mist === true
  },
  chapter2Unlocked() {
    return this.questFlags?.chapter_2_unlocked || false
  },
  chapter3Unlocked() {
    return this.questFlags?.chapter_3_unlocked || false
  },

第二步:动态生成任务列表

dynamicQuests() {
    // 第一章任务配置
    const chapter1Quests = [
      { flag: 'found_mist_source', name: '调查雾气来源', hint: '...' },
      // ... 其他4个任务
    ]
    
    // 第二章支线任务(从 branch_progress 读取)
    const branchProgress = this.questFlags.branch_progress || {}
    const chapter2Quests = [
      { id: 'blood_letter', name: '山下血书', completed: branchProgress.blood_letter?.completed },
      // ... 其他3个支线
    ]
    
    // 第三章任务
    const chapter3Quests = [
      { id: 'mind_realm', name: '不二观心境', completed: this.questFlags.mind_realm_entered },
      // ... 其他2个任务
    ]
    
    // 根据章节返回对应任务
    if (this.chapter3Unlocked) return chapter3Quests
    if (this.chapter2Unlocked && this.chapter1Completed) return chapter2Quests
    return chapter1Quests
  },

第三步:动态计算进度

computedProgress() {
    // 第三章进度
    if (this.chapter3Unlocked) {
      const total = 3
      const completed = [/* 第三章完成标志 */].filter(Boolean).length
      return Math.floor((completed / total) * 100)
    }
    
    // 第二章进度(基于支线完成数量)
    if (this.chapter2Unlocked && this.chapter1Completed) {
      const total = 4
      const completed = this.completedBranchCount
      return Math.floor((completed / total) * 100)
    }
    
    // 第一章进度
    const total = 5
    const completed = this.completedQuestCount
    return Math.floor((completed / total) * 100)
  }
}

最终修改后进入第二章后任务列表和剧情进度都会更新。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐