1. 项目背景与核心需求
春节期间走亲访友时,我们常常因为忙碌而忘记及时补充水分。等到感觉口渴时,身体其实已经处于轻度脱水状态。这个AR喝水提醒助手的设计初衷,就是利用Rokid AR眼镜的特性,在用户视野角落提供非侵入式的饮水提醒。
1.1 AR交互的优势分析
与传统手机提醒相比,AR眼镜的提醒方式具有三个显著优势:
- 无感提醒:不需要掏出手机或查看通知,直接在视野边缘显示
- 多模态反馈:结合视觉(图标闪烁)、触觉(震动)和听觉(语音)多种提醒方式
- 场景融合:提醒信息与现实场景自然融合,不会打断当前活动
1.2 核心功能设计
经过需求分析,我们确定了六个核心功能点:
- 定时提醒:每小时自动触发一次提醒(可调节间隔)
- 饮水记录:自动记录每次提醒时的饮水量,支持手动添加
- 每日重置:跨日自动清零记录
- 多感官反馈:视觉闪烁+设备震动+语音提醒的组合提醒
- 数据持久化:应用关闭后仍能保存当前状态
- 非干扰UI:半透明界面固定在视野右下角
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 模块化设计思路
采用MVC架构将系统分为三个主要模块:
code复制┌───────────────────────┐
│ Manager层 │
│ (数据逻辑与事件分发中心) │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ UI层 │
│ (界面展示与用户交互) │
└───────────┬───────────┘
│
┌───────────▼───────────┐
│ 设备接口层 │
│ (震动、语音等硬件功能) │
└───────────────────────┘
2.2 关键类设计
2.2.1 WaterReminderManager
作为系统的核心单例,主要职责包括:
- 计时逻辑处理
- 饮水数据管理
- 事件触发与分发
- 数据持久化存储
2.2.2 WaterReminderUI
负责所有界面相关功能:
- 悬浮面板的创建与布局
- 状态信息显示
- 用户交互处理
- 提醒动画效果
3. 核心逻辑实现
3.1 单例模式实现
csharp复制public class WaterReminderManager : MonoBehaviour
{
public static WaterReminderManager Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
}
注意事项:单例模式确保全局只有一个实例,方便其他模块访问。DontDestroyOnLoad保证场景切换时不被销毁。
3.2 计时器实现
采用Unity的Time.deltaTime实现跨平台精准计时:
csharp复制private void Update()
{
_timerAccumulator += Time.deltaTime;
if (_timerAccumulator >= interval)
{
_timerAccumulator -= interval;
TriggerReminder();
}
}
技术细节:Time.deltaTime返回上一帧到当前帧的时间间隔,不受帧率影响,适合实现精确计时。
3.3 数据持久化方案
使用PlayerPrefs存储三类数据:
- 最后记录日期(用于跨日重置)
- 已饮水杯数
- 当前计时进度
csharp复制private void SaveDailyData()
{
PlayerPrefs.SetString("WaterReminder_Date", DateTime.Now.ToString("yyyy-MM-dd"));
PlayerPrefs.SetInt("WaterReminder_Cups", _cupsDrunk);
PlayerPrefs.SetFloat("WaterReminder_Timer", _timerAccumulator);
PlayerPrefs.Save();
}
避坑指南:移动端应用可能随时被系统回收,需要在OnApplicationPause和OnApplicationQuit中都调用保存方法。
4. UI系统实现
4.1 动态UI创建
为方便集成,UI系统支持两种模式:
- 绑定模式:手动拖拽已有UI元素
- 自动创建模式:运行时动态生成所有UI元素
csharp复制private void BuildFloatingPanel()
{
// 创建根面板
var panel = new GameObject("WaterReminderPanel").AddComponent<RectTransform>();
panel.SetParent(transform, false);
panel.anchorMin = new Vector2(1, 0);
panel.anchorMax = new Vector2(1, 0);
panel.pivot = new Vector2(1, 0);
panel.anchoredPosition = new Vector2(-24, 24);
// 添加背景
var bg = panel.gameObject.AddComponent<Image>();
bg.color = new Color(0.1f, 0.1f, 0.15f, 0.75f);
// 创建其他UI元素...
}
4.2 提醒动画效果
实现图标闪烁效果使用Color.Lerp配合PingPong函数:
csharp复制_icon.color = Color.Lerp(
Color.white,
new Color(1f, 0.9f, 0.5f),
Mathf.PingPong(Time.time * 8f, 1f)
);
参数说明:8f控制闪烁频率,数值越大闪烁越快。Color.Lerp实现颜色平滑过渡。
5. 多设备适配
5.1 震动反馈实现
csharp复制private void TryHaptic()
{
#if UNITY_ANDROID || UNITY_IOS
Handheld.Vibrate();
#endif
// Rokid设备专用接口
// Rokid.UXR.Haptic.Vibrate(200);
}
5.2 语音提醒集成
预留语音接口方便不同平台实现:
csharp复制private void SpeakReminder(string message)
{
// 通用平台使用Unity的TextToSpeech
// 或接入Rokid专用语音接口
// Rokid.Speech.SpeechSynthesizer.GetInstance().Speak(message);
}
6. 调试与优化
6.1 编辑器快速测试
为方便调试,添加调试参数:
csharp复制[Header("调试参数")]
public float debugIntervalSeconds = 0;
在编辑器中设置较小的值(如10秒)可以快速验证提醒逻辑。
6.2 性能优化建议
- 事件订阅管理:确保在OnEnable/OnDisable中正确订阅和取消订阅事件
- UI更新频率:避免在Update中频繁更新UI,只在状态变化时刷新
- 对象池技术:如需创建大量临时对象,考虑使用对象池
7. 扩展功能设计
7.1 个性化设置
可通过扩展实现:
- 自定义目标饮水量
- 调整提醒间隔时间
- 更换UI主题颜色
- 选择提醒音效
7.2 健康数据整合
未来可接入:
- 心率数据(运动后增加提醒频率)
- 环境温度(炎热天气增加饮水量)
- 活动识别(长时间坐着时提醒)
8. 项目部署指南
8.1 Rokid设备集成步骤
- 导入Rokid UXR SDK
- 创建AR场景并设置AR Session
- 添加WaterReminderManager到场景
- 创建Canvas并添加WaterReminderUI组件
- 替换震动和语音接口为Rokid专用API
- 构建Android应用并安装到眼镜
8.2 性能测试要点
- 内存占用:长时间运行后检查内存增长
- 电量消耗:监测提醒功能对电量的影响
- 发热情况:连续使用时的设备温度
- UI响应:提醒时的界面流畅度
9. 开发经验分享
在实际开发过程中,有几个关键点值得注意:
- AR界面布局:需要反复测试UI在真实场景中的可见性和干扰度,找到最佳位置和透明度
- 多提醒方式平衡:震动强度、语音音量和闪烁频率需要合理搭配,避免过度打扰
- 数据持久化时机:除了常规的退出保存,还需要处理应用被系统强制终止的情况
- 跨平台兼容性:不同设备的屏幕比例、分辨率和性能差异需要考虑
一个实用的调试技巧是使用Unity的Remote功能,直接在真机上实时调试UI位置和大小,这比反复构建安装要高效得多。
对于想进一步优化项目的开发者,我建议:
- 添加数据分析功能,统计每周饮水趋势
- 实现云端同步,多设备间共享饮水记录
- 开发配套手机应用,提供更详细的数据查看和设置功能
- 增加社交功能,与好友互相监督饮水习惯
