BongoCat - 桌面互动猫咪
项目描述
BongoCat是一款创新的桌面互动应用,通过Live2D技术呈现可爱的猫咪角色,能够实时响应您的鼠标、键盘操作和游戏手柄输入。基于Tauri框架构建,提供跨平台的桌面体验,让您的数字工作空间更加生动有趣。
功能特性
- :cat_face: Live2D猫咪模型 - 支持多种可爱的猫咪Live2D模型展示
- :keyboard: 实时输入反馈 - 猫咪会对鼠标点击、键盘敲击做出生动反应
- :video_game: 游戏手柄支持 - 完美兼容游戏手柄操作,摇杆和按键均有对应动作
- :desktop_computer: 跨平台兼容 - 支持Windows、macOS和Linux三大操作系统
- :artist_palette: 自定义界面 - 可调整窗口尺寸、透明度和穿透效果
- :wrench: Tauri技术栈 - 基于Rust后端和Vue3前端的高性能架构
安装指南
系统要求
- Windows 10+ / macOS 10.15+ / Linux (Ubuntu 18.04+)
- 支持WebGL的现代浏览器内核
安装步骤
- 从GitHub Releases页面下载对应平台的安装包
- 运行安装程序并按照提示完成安装
- 启动应用,可爱的BongoCat就会出现在您的桌面上
开发环境搭建
# 克隆项目
git clone https://github.com/ayangweb/BongoCat.git
# 安装依赖
npm install
# 启动开发服务器
npm run tauri dev
使用说明
基本操作
启动应用后,BongoCat会自动出现在桌面上,它会实时响应您的输入操作:
- 鼠标移动: 猫咪的眼睛和头部会跟随鼠标移动
- 鼠标点击: 左右键点击会有不同的反应动作
- 键盘输入: 敲击键盘时猫咪会做出相应的动作
- 游戏手柄: 连接手柄后可使用摇杆和按钮与猫咪互动
偏好设置
通过系统托盘菜单或快捷键打开偏好设置窗口,可以调整:
- 窗口尺寸缩放比例(50%-150%)
- 窗口不透明度(25%-100%)
- 窗口穿透模式(允许鼠标点击穿透)
- 模型选择和个性化设置
核心代码
设备输入监听核心逻辑
// useDevice.ts - 处理鼠标键盘输入
export function useDevice() {
const processMouseMove = (point: CursorPoint) => {
const roundedValue = mapValues(point, Math.round)
if (isEqual(lastCursorPoint.value, roundedValue)) return
lastCursorPoint.value = roundedValue
return handleMouseMove(point)
}
useTauriListen<DeviceEvent>(LISTEN_KEY.DEVICE_CHANGED, ({ payload }) => {
const { kind, value } = payload
// 处理不同类型的输入事件
switch (kind) {
case 'KeyboardPress':
return handlePress(getSupportedKey(value))
case 'MouseMove':
return processMouseMove(value)
// ... 其他事件处理
}
})
}
游戏手柄支持实现
// useGamepad.ts - 游戏手柄控制
export function useGamepad() {
useTauriListen<GamepadEvent>(LISTEN_KEY.GAMEPAD_CHANGED, ({ payload }) => {
const { name, value } = payload
switch (name) {
case 'LeftStickX':
sticks.left.x = value
return handleAxisChange('CatParamStickLX', value)
case 'LeftThumb':
sticks.left.pressed = value !== 0
return live2d.setParameterValue('CatParamStickLeftDown', value !== 0)
// ... 其他手柄事件
}
})
}
Live2D模型控制
// useModel.ts - 模型加载和控制
export function useModel() {
async function handleLoad() {
try {
const { path } = modelStore.currentModel
const { width, height, ...rest } = await live2d.load(path)
modelSize.value = { width, height }
Object.assign(modelStore, rest)
} catch (error) {
message.error(String(error))
}
}
function handleMouseMove(point: CursorPoint) {
// 计算鼠标位置并更新模型参数
const xRatio = (cursorPoint.x - position.x) / size.width
const yRatio = (cursorPoint.y - position.y) / size.height
live2d.setParameterValue('ParamMouseX', value)
}
}
Rust后端设备监听
// device.rs - Rust后端输入监听
#[command]
pub async fn start_device_listening<R: Runtime>(app_handle: AppHandle<R>) -> Result<(), String> {
let callback = move |event: Event| {
let device_event = match event.event_type {
EventType::ButtonPress(button) => DeviceEvent {
kind: DeviceEventKind::MousePress,
value: json!(format!("{:?}", button)),
},
EventType::MouseMove { x, y } => DeviceEvent {
kind: DeviceEventKind::MouseMove,
value: json!({ "x": x, "y": y }),
},
// ... 其他事件类型
};
app_handle.emit("device-changed", device_event).unwrap();
};
listen(callback).map_err(|err| format!("Failed to listen device: {:?}", err))
}