鸿蒙5桌面电子宠物小组件开发指南 原创

进修的泡芙
发布于 2025-6-20 13:35
浏览
0收藏

鸿蒙5桌面电子宠物小组件开发指南

一、项目概述

本文基于HarmonyOS 5的原子化服务和动画引擎,开发一款桌面电子宠物小组件,借鉴《鸿蒙跨端U同步》中游戏多设备同步的技术原理,实现宠物状态的多设备同步和互动。该电子宠物能够展示丰富动画效果、响应多设备交互,并通过分布式能力实现状态同步。

二、系统架构

±--------------------+ ±--------------------+ ±--------------------+
桌面小组件 <-----> 原子化服务 <-----> 分布式数据总线
(Widget) (Atomic Service) (Distributed Bus)
±---------±---------+ ±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+ ±---------v----------+
动画渲染引擎 宠物状态管理 多设备同步服务
(Animation Engine) (State Manager) (Sync Service)

±--------------------+ ±--------------------+ ±--------------------+

三、核心代码实现
宠物数据模型

// src/main/ets/model/PetModel.ts
export enum PetType {
CAT = ‘cat’,
DOG = ‘dog’,
RABBIT = ‘rabbit’,
DRAGON = ‘dragon’
export enum PetAnimation {

IDLE = ‘idle’,
EATING = ‘eating’,
PLAYING = ‘playing’,
SLEEPING = ‘sleeping’,
WALKING = ‘walking’,
HAPPY = ‘happy’,
SAD = ‘sad’
export class VirtualPet {

petId: string;
name: string;
type: PetType;
level: number;
happiness: number;
hunger: number;
energy: number;
experience: number;
lastFed: number;
lastPlayed: number;
isSleeping: boolean;
currentAnimation: PetAnimation;
position: { x: number, y: number };
deviceId: string;

constructor(name: string, type: PetType = PetType.CAT) {
this.petId = ‘pet_’ + Math.random().toString(36).substring(2, 11);
this.name = name;
this.type = type;
this.level = 1;
this.happiness = 70;
this.hunger = 50;
this.energy = 80;
this.experience = 0;
this.lastFed = Date.now();
this.lastPlayed = Date.now();
this.isSleeping = false;
this.currentAnimation = PetAnimation.IDLE;
this.position = { x: 0.5, y: 0.7 };
this.deviceId = ‘’;
feed(): void {

this.hunger = Math.min(100, this.hunger + 30);
this.happiness = Math.min(100, this.happiness + 10);
this.lastFed = Date.now();
this.currentAnimation = PetAnimation.EATING;

play(): void {

this.happiness = Math.min(100, this.happiness + 20);
this.energy = Math.max(0, this.energy - 15);
this.experience += 10;
this.lastPlayed = Date.now();
this.currentAnimation = PetAnimation.PLAYING;

sleep(): void {

this.isSleeping = true;
this.energy = Math.min(100, this.energy + 5);
this.currentAnimation = PetAnimation.SLEEPING;

wakeUp(): void {

this.isSleeping = false;
this.currentAnimation = PetAnimation.IDLE;

updateStatus(): void {

const now = Date.now();
const hoursSinceFed = (now - this.lastFed) / (1000  60  60);
const hoursSincePlayed = (now - this.lastPlayed) / (1000  60  60);

if (!this.isSleeping) {
  this.hunger = Math.max(0, this.hunger - hoursSinceFed * 5);
  this.happiness = Math.max(0, this.happiness - hoursSincePlayed * 3);
  this.energy = Math.max(0, this.energy - hoursSincePlayed * 2);

else {

  this.energy = Math.min(100, this.energy + hoursSincePlayed * 8);

if (this.experience >= this.level * 100) {

  this.level++;
  this.experience = 0;
  this.currentAnimation = PetAnimation.HAPPY;

// 自动恢复空闲状态

if (this.currentAnimation !== PetAnimation.IDLE && 
    this.currentAnimation !== PetAnimation.SLEEPING &&
    now - Math.max(this.lastFed, this.lastPlayed) > 3000) {
  this.currentAnimation = PetAnimation.IDLE;

}

toJson(): string {
return JSON.stringify({
petId: this.petId,
name: this.name,
type: this.type,
level: this.level,
happiness: this.happiness,
hunger: this.hunger,
energy: this.energy,
experience: this.experience,
lastFed: this.lastFed,
lastPlayed: this.lastPlayed,
isSleeping: this.isSleeping,
currentAnimation: this.currentAnimation,
position: this.position,
deviceId: this.deviceId
});
static fromJson(jsonStr: string): VirtualPet {

const json = JSON.parse(jsonStr);
const pet = new VirtualPet(json.name, json.type);
pet.petId = json.petId;
pet.level = json.level;
pet.happiness = json.happiness;
pet.hunger = json.hunger;
pet.energy = json.energy;
pet.experience = json.experience;
pet.lastFed = json.lastFed;
pet.lastPlayed = json.lastPlayed;
pet.isSleeping = json.isSleeping;
pet.currentAnimation = json.currentAnimation;
pet.position = json.position;
pet.deviceId = json.deviceId;
return pet;

}

分布式同步服务

// src/main/ets/service/DistributedSyncService.ts
import { distributedData } from ‘@ohos.data.distributedData’;
import { BusinessError } from ‘@ohos.base’;
import { VirtualPet } from ‘…/model/PetModel’;
import { deviceManager } from ‘@ohos.distributedDeviceManager’;

export class DistributedSyncService {
private static instance: DistributedSyncService;
private kvManager: distributedData.KVManager;
private kvStore: distributedData.KVStore;
private readonly STORE_ID = ‘pet_store’;
private readonly PET_KEY_PREFIX = ‘pet_’;
private subscribers: ((data: VirtualPet) => void)[] = [];

private constructor() {
this.initDistributedData();
public static getInstance(): DistributedSyncService {

if (!DistributedSyncService.instance) {
  DistributedSyncService.instance = new DistributedSyncService();

return DistributedSyncService.instance;

private initDistributedData(): void {

const config: distributedData.KVManagerConfig = {
  bundleName: 'com.example.virtualpet',
  userInfo: {
    userId: '0',
    userType: distributedData.UserType.SAME_USER_ID

};

distributedData.createKVManager(config, (err: BusinessError, manager: distributedData.KVManager) => {
  if (err) {
    console.error(Failed to create KVManager. Code: {err.code}, message: {err.message});
    return;

this.kvManager = manager;

  const options: distributedData.Options = {
    createIfMissing: true,
    encrypt: false,
    backup: false,
    autoSync: true,
    kvStoreType: distributedData.KVStoreType.SINGLE_VERSION,
    securityLevel: distributedData.SecurityLevel.S1
  };

  this.kvManager.getKVStore(this.STORE_ID, options, (err: BusinessError, store: distributedData.KVStore) => {
    if (err) {
      console.error(Failed to get KVStore. Code: {err.code}, message: {err.message});
      return;

this.kvStore = store;

    this.registerDataListener();
  });
});

private registerDataListener(): void {

this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data: distributedData.ChangeData) => {
  if (data.key.startsWith(this.PET_KEY_PREFIX)) {
    const pet = VirtualPet.fromJson(data.value.value as string);
    this.notifySubscribers(pet);

});

public subscribe(callback: (data: VirtualPet) => void): void {

this.subscribers.push(callback);

public unsubscribe(callback: (data: VirtualPet) => void): void {

this.subscribers = this.subscribers.filter(sub => sub !== callback);

private notifySubscribers(data: VirtualPet): void {

this.subscribers.forEach(callback => callback(data));

public syncPet(pet: VirtualPet): void {

deviceManager.getLocalDeviceInfo((err: BusinessError, info) => {
  if (err) {
    console.error(Failed to get device info. Code: {err.code}, message: {err.message});
    return;

pet.deviceId = info.deviceId;

  const key = this.PET_KEY_PREFIX + pet.petId;
  this.kvStore.put(key, pet.toJson(), (err: BusinessError) => {
    if (err) {
      console.error(Failed to sync pet. Code: {err.code}, message: {err.message});

});

});

public async getPet(petId: string): Promise<VirtualPet | null> {

return new Promise((resolve) => {
  const key = this.PET_KEY_PREFIX + petId;
  this.kvStore.get(key, (err: BusinessError, value: distributedData.Value) => {
    if (err) {
      console.error(Failed to get pet. Code: {err.code}, message: {err.message});
      resolve(null);
      return;

resolve(VirtualPet.fromJson(value.value as string));

  });
});

}

动画引擎实现

// src/main/ets/engine/AnimationEngine.ts
import { VirtualPet, PetAnimation, PetType } from ‘…/model/PetModel’;
import { LottieAnimation } from ‘@ohos/lottie’;
import { BusinessError } from ‘@ohos.base’;

export class AnimationEngine {
private animations: Map<string, LottieAnimation> = new Map();
private currentPet: VirtualPet | null = null;
private animationContainer: HTMLElement | null = null;

constructor(container: HTMLElement) {
this.animationContainer = container;
this.loadAnimations();
private async loadAnimations(): Promise<void> {

const animationTypes = Object.values(PetAnimation);
const petTypes = Object.values(PetType);

for (const petType of petTypes) {
  for (const animType of animationTypes) {
    const animId = {petType}_{animType};
    try {
      const anim = new LottieAnimation({
        container: this.animationContainer,
        renderer: 'svg',
        loop: true,
        autoplay: false,
        path: resources/animations/{petType}/{animType}.json
      });
      this.animations.set(animId, anim);

catch (e) {

      console.error(Failed to load animation {animId}. Code: {e.code}, message: ${e.message});

}

}

public setPet(pet: VirtualPet): void {
this.currentPet = pet;
this.playAnimation(pet.currentAnimation);
public playAnimation(animType: PetAnimation): void {

if (!this.currentPet) return;

const animId = {this.currentPet.type}_{animType};
const animation = this.animations.get(animId);

if (animation) {
  // 停止所有动画
  this.animations.forEach(anim => anim.stop());
  
  // 播放新动画
  animation.play();
  this.currentPet.currentAnimation = animType;

else {

  console.error(Animation not found: ${animId});

}

public updatePosition(x: number, y: number): void {
if (!this.currentPet) return;

this.currentPet.position = { x, y };
if (this.animationContainer) {
  this.animationContainer.style.left = ${x * 100}%;
  this.animationContainer.style.top = ${y * 100}%;

}

原子化服务实现

// src/main/ets/service/AtomicService.ts
import { VirtualPet } from ‘…/model/PetModel’;
import { DistributedSyncService } from ‘./DistributedSyncService’;
import { featureAbility } from ‘@ohos.ability.featureAbility’;

export class PetAtomicService {
private static instance: PetAtomicService;
private syncService = DistributedSyncService.getInstance();
private currentPet: VirtualPet | null = null;

private constructor() {
this.initService();
public static getInstance(): PetAtomicService {

if (!PetAtomicService.instance) {
  PetAtomicService.instance = new PetAtomicService();

return PetAtomicService.instance;

private initService(): void {

// 注册原子化服务
featureAbility.registerAbilityLifecycleCallback({
  onStart: (want) => {
    console.log('PetAtomicService started');
  },
  onStop: () => {
    console.log('PetAtomicService stopped');

});

// 加载或创建宠物
this.loadOrCreatePet();

private async loadOrCreatePet(): Promise<void> {

// 尝试从分布式数据加载已有宠物
const petId = localStorage.getItem('current_pet_id');
if (petId) {
  this.currentPet = await this.syncService.getPet(petId);

// 如果没有找到宠物,创建新宠物

if (!this.currentPet) {
  this.currentPet = new VirtualPet('小可爱', PetType.CAT);
  localStorage.setItem('current_pet_id', this.currentPet.petId);

// 同步宠物状态

this.syncService.syncPet(this.currentPet);

public getCurrentPet(): VirtualPet | null {

return this.currentPet;

public feedPet(): void {

if (!this.currentPet) return;

this.currentPet.feed();
this.syncService.syncPet(this.currentPet);

public playWithPet(): void {

if (!this.currentPet) return;

this.currentPet.play();
this.syncService.syncPet(this.currentPet);

public putPetToSleep(): void {

if (!this.currentPet) return;

this.currentPet.sleep();
this.syncService.syncPet(this.currentPet);

public wakeUpPet(): void {

if (!this.currentPet) return;

this.currentPet.wakeUp();
this.syncService.syncPet(this.currentPet);

public updatePetStatus(): void {

if (!this.currentPet) return;

this.currentPet.updateStatus();
this.syncService.syncPet(this.currentPet);

}

桌面小组件实现

// src/main/ets/widget/PetWidget.ets
import { VirtualPet, PetAnimation } from ‘…/model/PetModel’;
import { PetAtomicService } from ‘…/service/AtomicService’;
import { AnimationEngine } from ‘…/engine/AnimationEngine’;

@Component
export struct PetWidget {
@State pet: VirtualPet | null = null;
@State touchX: number = 0;
@State touchY: number = 0;
private atomicService = PetAtomicService.getInstance();
private animationEngine: AnimationEngine | null = null;

aboutToAppear(): void {
this.pet = this.atomicService.getCurrentPet();
this.animationEngine = new AnimationEngine(this.$element(‘animationContainer’));

if (this.pet) {
  this.animationEngine.setPet(this.pet);
  this.animationEngine.updatePosition(this.pet.position.x, this.pet.position.y);

// 每10秒更新一次状态

setInterval(() => {
  this.atomicService.updatePetStatus();
  this.pet = this.atomicService.getCurrentPet();
}, 10000);

build() {

Stack() {
  // 宠物动画容器
  Div() {
    // Lottie动画将通过AnimationEngine动态加载

.id(‘animationContainer’)

  .width(100)
  .height(100)
  .position({ x: this.touchX, y: this.touchY })
  .onTouch((event: TouchEvent) => {
    // 拖动宠物
    if (event.type === TouchType.Move) {
      this.touchX = event.touches[0].x / this.$width();
      this.touchY = event.touches[0].y / this.$height();
      if (this.pet && this.animationEngine) {
        this.pet.position = { x: this.touchX, y: this.touchY };
        this.animationEngine.updatePosition(this.touchX, this.touchY);
        this.atomicService.syncPet(this.pet);

}

  })
  .onClick(() => {
    // 点击互动
    this.atomicService.playWithPet();
    this.pet = this.atomicService.getCurrentPet();
    if (this.pet && this.animationEngine) {
      this.animationEngine.playAnimation(this.pet.currentAnimation);

})

  // 控制按钮
  Row() {
    Button('喂食')
      .width(60)
      .height(30)
      .onClick(() => {
        this.atomicService.feedPet();
        this.pet = this.atomicService.getCurrentPet();
        if (this.pet && this.animationEngine) {
          this.animationEngine.playAnimation(this.pet.currentAnimation);

})

    Button(this.pet?.isSleeping ? '唤醒' : '睡觉')
      .width(60)
      .height(30)
      .margin({ left: 10 })
      .onClick(() => {
        if (this.pet?.isSleeping) {
          this.atomicService.wakeUpPet();

else {

          this.atomicService.putPetToSleep();

this.pet = this.atomicService.getCurrentPet();

        if (this.pet && this.animationEngine) {
          this.animationEngine.playAnimation(this.pet.currentAnimation);

})

.position({ x: ‘50%’, y: ‘90%’ })

  .justifyContent(FlexAlign.Center)

.width(‘100%’)

.height('100%')

}

四、与游戏同步技术的结合点
状态同步机制:借鉴游戏中玩家状态同步技术,实现宠物状态的多设备同步

实时交互响应:类似游戏中的实时互动,实现多设备对宠物的同步操作

数据压缩传输:采用游戏中的高效数据压缩算法,减少状态同步数据量

设备角色分配:主设备作为状态权威,类似游戏中的主机角色

冲突解决策略:采用类似游戏的时间戳优先策略解决状态冲突

五、关键特性实现
动画状态管理:

  // 平滑过渡动画状态

private transitionAnimation(newAnim: PetAnimation): void {
if (this.currentAnimation === newAnim) return;

 // 播放过渡动画
 const transitionAnim = this.getTransitionAnimation(this.currentAnimation, newAnim);
 if (transitionAnim) {
   transitionAnim.playOnce(() => {
     this.playAnimation(newAnim);
   });

else {

   this.playAnimation(newAnim);

}

多设备交互:

  // 处理来自其他设备的交互

private handleRemoteInteraction(deviceId: string, action: string): void {
if (deviceId === this.currentDeviceId) return;

 switch (action) {
   case 'feed':
     this.pet.onFedRemotely();
     break;
   case 'play':
     this.pet.onPlayedRemotely();
     break;

this.updatePetDisplay();

离线状态处理:

  // 恢复离线期间的状态变化

private recoverOfflineChanges(): void {
const offlineTime = Date.now() - this.lastSyncTime;
if (offlineTime > 60000) { // 离线超过1分钟
const hours = offlineTime / (1000 60 60);
this.pet.simulateOfflineChanges(hours);
}

自适应动画质量:

  // 根据设备性能调整动画质量

private adjustAnimationQuality(): void {
const perfLevel = device.getPerformanceLevel();
this.animationQuality = perfLevel === ‘high’ ? ‘high’ : ‘low’;
this.loadAnimations(this.animationQuality);

六、性能优化策略
动画资源按需加载:

  // 只加载当前需要的动画资源

private loadRequiredAnimations(petType: PetType): void {
this.unloadAllAnimations();
const requiredAnims = [
PetAnimation.IDLE,
PetAnimation.EATING,
PetAnimation.PLAYING,
PetAnimation.SLEEPING
];
requiredAnims.forEach(anim => this.loadAnimation(petType, anim));

状态更新批处理:

  // 批量处理状态更新

private batchUpdates(): void {
if (this.updateBatchTimer) return;

 this.updateBatchTimer = setTimeout(() => {
   this.syncService.syncPet(this.currentPet);
   this.updateBatchTimer = null;
 }, 500); // 每500ms批量同步一次

内存敏感模式:

  // 低内存设备启用简化模式

private checkMemoryStatus(): void {
const memoryInfo = device.getMemoryInfo();
if (memoryInfo.level === ‘low’) {
this.enableLowMemoryMode();
}

后台运行优化:

  // 后台运行时减少更新频率

private handleAppStateChange(state: string): void {
if (state === ‘background’) {
this.updateInterval = 30000; // 30秒
else {

   this.updateInterval = 10000; // 10秒

}

七、项目扩展方向
宠物换装系统:支持自定义宠物外观

社交互动功能:宠物之间的互动玩法

AR宠物展示:通过AR技术将宠物投射到现实环境

智能语音交互:支持语音指令控制宠物

健康监测集成:结合健康数据影响宠物状态

八、总结

本桌面电子宠物小组件实现了以下核心功能:
基于原子化服务的轻量级宠物模拟

丰富的Lottie动画效果展示

多设备状态同步与互动

响应式用户交互体验

自适应不同设备性能

通过借鉴游戏中的多设备同步技术,我们构建了一个生动有趣的桌面宠物应用。该项目展示了HarmonyOS分布式能力在互动娱乐领域的创新应用,为开发者提供了实现多设备协同互动应用的参考方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐