iT邦幫忙

2026 iThome 鐵人賽

DAY 12
0
Build on Google AI

《30天打造喵語日誌:Gemini API × Vibe Coding 實戰》系列 第 12

Day 12:【成就系統】遊戲化設計:成就解鎖卡片與徽章牆 UI

  • 分享至 

  • xImage
  •  

用遊戲化打破養成習慣的怠惰期

在產品設計中,最困難的往往不是吸引使用者下載,而是讓使用者願意持續使用。

尤其是習慣養成、心情紀錄這類工具,剛開始使用時可能會感到新鮮,但隨著時間經過,熱情容易逐漸降低。當每天的操作變得重複,使用者也可能慢慢失去持續紀錄的動力。

因此,今天我為《喵語日誌》加入了遊戲化機制,希望將原本較為單調的心情紀錄,轉化成一場溫柔又療癒的徽章收集遊戲。

這次的實作重點包括:

  • 成就系統

  • 成就進度追蹤

  • 徽章牆 UI

  • 已解鎖與未解鎖狀態

  • 底部導覽列整合

透過解鎖徽章的正向回饋,讓使用者在持續記錄的過程中,感受到累積與成長。

遊戲化設計的三大核心

在規劃《喵語日誌》的成就系統時,我參考了遊戲化設計中常見的三個核心元素。

1. 明確的目標

使用者需要清楚知道完成什麼事情可以解鎖成就

例如:

  • 第一次傳送訊息

  • 連續紀錄心情 3 天

  • 紀錄過所有 5 種心情

  • 上傳第一張美食照片

  • 分享 5 張生活照片

  • 在晚上 11 點後紀錄心情

有了明確的目標,使用者才能知道下一步該努力完成什麼。

2. 視覺化回饋

除了文字提示之外,也需要透過視覺元素呈現目前的完成狀態。

這次使用了以下設計:

  • 已解鎖徽章使用明亮的粉紅色背景

  • 未解鎖徽章使用灰階與半透明效果

  • 未解鎖徽章顯示鎖頭圖示

  • 使用進度條呈現目前進度

  • 在頁面頂部顯示整體完成度

使用者可以透過畫面快速理解目前的收藏狀態,以及距離下一個成就還有多遠。

3. 成就感與獎勵

當成就完成時,徽章會從灰階狀態轉為亮色狀態,並顯示已解鎖標籤。

雖然這些徽章沒有實際的功能獎勵,但可愛的貓咪主題圖示與收集設計,仍然能為日常紀錄增加一點期待感與成就感。

成就資料結構設計

首先,我在 src/data/achievements.ts 中建立 Achievement TypeScript 型態,統一管理每個成就所需要的資料。

export type Achievement = {
  id: string;
  title: string;
  description: string;
  icon: string;
  isUnlocked: boolean;
  progress: number;
  total: number;
  unlockedDate?: string;
};

各欄位用途如下:

  • id:成就的唯一識別名稱
  • title:成就標題
  • description:成就解鎖條件說明
  • icon:成就使用的 Emoji 圖示
  • isUnlocked:是否已經解鎖
  • progress:目前完成進度
  • total:解鎖所需的總進度
  • unlockedDate:解鎖日期,可選欄位

接著建立初始成就清單:

export const INITIAL_ACHIEVEMENTS: Achievement[] = [
  {
    id: "first_message",
    title: "初來乍到 🐾",
    description: "發送第一條訊息給喵喵",
    icon: "🐾",
    isUnlocked: true,
    progress: 1,
    total: 1,
  },
  {
    id: "streak_3",
    title: "持之以恆 📅",
    description: "連續紀錄心情達 3 天",
    icon: "📅",
    isUnlocked: false,
    progress: 2,
    total: 3,
  },
  {
    id: "gourmet",
    title: "美食家 🍣",
    description: "上傳美味的美食照片",
    icon: "🍣",
    isUnlocked: true,
    progress: 1,
    total: 1,
  },
  {
    id: "mood_master",
    title: "情緒大師 🌈",
    description: "紀錄過所有 5 種心情",
    icon: "🌈",
    isUnlocked: false,
    progress: 3,
    total: 5,
  },
  {
    id: "photo_lover",
    title: "快門高手 📸",
    description: "累計分享 5 張生活照片",
    icon: "📸",
    isUnlocked: false,
    progress: 2,
    total: 5,
  },
  {
    id: "night_cat",
    title: "夜貓族 🌙",
    description: "在深夜 11 點後紀錄心情",
    icon: "🌙",
    isUnlocked: false,
    progress: 0,
    total: 1,
  },
];

目前一共有 6 個成就,其中 2 個已經解鎖,因此整體完成度為:
https://ithelp.ithome.com.tw/upload/images/20260813/20178708BDwSGVlLol.png

成就卡片元件

接下來建立 AchievementCard.tsx,負責呈現單一成就卡片。

成就卡片需要根據 isUnlocked 顯示不同的視覺狀態。

已解鎖狀態
已解鎖的成就會呈現:

  • 柔和的粉紅色背景

  • 亮色 Emoji 圖示

  • 右上角顯示「已解鎖」

  • 進度條顯示為滿格

未解鎖狀態
尚未解鎖的成就則會呈現:

  • 灰階背景

  • 半透明效果

  • 灰階化的 Emoji 圖示

  • 右上角顯示鎖頭圖示

  • 使用黃色進度條提示目前進度

實作如下:

import { Lock } from "lucide-react";
import type { Achievement } from "@/data/achievements";

type AchievementCardProps = {
  data: Achievement;
};

export default function AchievementCard({
  data,
}: AchievementCardProps) {
  const percent = Math.min(
    100,
    Math.round((data.progress / data.total) * 100)
  );

  return (
    <div
      className={`relative flex flex-col justify-between rounded-2xl border p-3.5 transition-all ${
        data.isUnlocked
          ? "border-rose-200/80 bg-rose-50/40"
          : "border-stone-200/80 bg-stone-100/50 opacity-70"
      }`}
    >
      <div className="absolute right-3 top-3">
        {data.isUnlocked ? (
          <span className="text-[10px] text-rose-400">
            已解鎖
          </span>
        ) : (
          <Lock className="h-3.5 w-3.5 text-stone-400" />
        )}
      </div>

      <div>
        <div
          className={`mb-2 flex h-10 w-10 items-center justify-center rounded-xl text-xl ${
            data.isUnlocked
              ? "bg-rose-100/80"
              : "bg-stone-200/80 grayscale"
          }`}
        >
          {data.icon}
        </div>

        <h4 className="text-xs font-bold text-stone-800">
          {data.title}
        </h4>

        <p className="mt-0.5 text-[11px] text-stone-500">
          {data.description}
        </p>
      </div>

      <div className="mt-3">
        <div className="h-1.5 w-full overflow-hidden rounded-full bg-stone-200">
          <div
            className={`h-full transition-all ${
              data.isUnlocked
                ? "bg-rose-400"
                : "bg-amber-400"
            }`}
            style={{ width: `${percent}%` }}
          />
        </div>

        {!data.isUnlocked && (
          <p className="mt-1 text-right text-[10px] text-stone-400">
            {data.progress} / {data.total}
          </p>
        )}
      </div>
    </div>
  );
}

其中,進度百分比是透過目前進度除以總進度計算:

const percent = Math.min(
  100,
  Math.round((data.progress / data.total) * 100)
);

使用 Math.min(100, ...) 可以避免進度超過 100%,讓進度條維持在合理範圍內。

建立成就徽章牆

完成卡片元件後,接著在 AwardsView.tsx 中建立成就頁面。

頁面主要分成兩個部分:

  • 頂部統計區塊

  • 成就卡片雙欄網格

統計區塊可以顯示:

  • 已解鎖成就數量

  • 成就總數

  • 整體完成度

  • 完成度進度條

成就卡片則使用 Tailwind CSS 的雙欄網格排版:

<div className="grid grid-cols-2 gap-3">
  {achievements.map((achievement) => (
    <AchievementCard
      key={achievement.id}
      data={achievement}
    />
  ))}
</div>

在手機畫面上使用雙欄配置,可以在不佔用太多垂直空間的情況下,同時展示更多徽章。

使用者也能快速瀏覽目前已收藏與尚未解鎖的成就。

整合底部導覽列

最後,我將 AwardsView 整合到 App.tsx 的底部導覽列中。

目前《喵語日誌》共有三個主要模組:

  • 喵喵對話

  • 情緒分析

  • 成就徽章

使用者可以透過底部導覽列,在不同功能頁面之間切換。

這樣的設計讓成就系統不只是藏在某個功能頁面裡,而是成為 App 中清楚可見的核心模組。當使用者完成一筆紀錄後,也更容易主動前往成就頁面查看自己的收集進度。

實測成果

完成整合後,點擊底部導覽列最右側的「成就徽章」,即可進入成就收藏牆。

目前畫面中可以看到:

  • 頁面頂部顯示整體完成度 33%

  • 「初來乍到 🐾」已成功解鎖

  • 「美食家 🍣」已成功解鎖

  • 「持之以恆 📅」顯示目前進度為 2 / 3

  • 「情緒大師 🌈」顯示目前進度為 3 / 5

  • 尚未解鎖的徽章會顯示鎖頭與進度條

https://ithelp.ithome.com.tw/upload/images/20260813/20178708o40Woi6cnR.png
從實際畫面來看,已解鎖與未解鎖狀態有明顯區別,使用者可以不需要閱讀太多文字,就理解每個成就目前的完成情況。

這次實作的心得

這次加入成就系統後,我更深刻體會到,軟體開發不只是把功能邏輯寫出來,也需要思考使用者在操作過程中的心理感受。

如果一個 App 只有記錄功能,使用者可能很快就會覺得重複與單調。但透過遊戲化設計,原本平凡的日常紀錄,便能轉化成一個持續累積、逐步解鎖的體驗。

每一次完成紀錄,都可能讓某個進度條前進一點;每一次達成條件,都能點亮一個可愛的貓咪主題徽章。

這些小小的回饋,或許就能成為使用者持續使用的動力。

此外,新增第三個頁籤之後,《喵語日誌》的整體架構也更加完整:

  • 對話功能負責陪伴

  • 情緒分析協助理解自己的狀態

  • 成就徽章鼓勵持續紀錄

三個模組彼此搭配,讓 App 不只是單純的聊天工具,也逐漸形成一個兼具陪伴、紀錄與回饋的生活應用。

結語

今天順利完成了成就系統與徽章牆 UI!明天我們將暫緩新功能的開發,專注於**【UI/UX 介面微調與視覺優化】**。我們將為《喵語日誌》進行一輪精細的介面修飾,包含卡片比例、底部導覽列動態反饋與全站配色一致性優化,讓整體的使用體驗更加療癒與精緻!

明天見,喵~


上一篇
Day 11:【圖表模組】情緒歷程視覺化:用 Chart.js 畫出情緒起伏月曆
下一篇
Day 13:【UI/UX 微調】打造極致療癒感:介面細節修飾與視覺一致性優化
系列文
《30天打造喵語日誌:Gemini API × Vibe Coding 實戰》16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言