Si e krijojmë animacionet Rive për karakteret arabe
Lexim: 6 minMohammad Shaker

Si e krijojmë animacionet Rive për karakteret arabe

Ne përdorim Rive për animacione të avancuara karakteresh arabe me sinkronizim buzësh dhe personalizim avatarësh në aplikacionet tona.

Engineering

Përgjigje e shpejtë

Ne përdorim Rive për animacione të avancuara karakteresh arabe me sinkronizim buzësh dhe personalizim avatarësh në aplikacionet tona.

Amal përdor Rive (më parë Flare) për të gjitha animacionet e karaktereve — përfshirë të folurit me sinkronizim buzësh, personalizimin e avatarëve, reagimet e feedback-ut dhe personazhet e lojës. Ne zgjodhëm Rive mbi Lottie ose sprite sheets për shkak të mbështetjes së makinave të shtetit në kohë reale, manipulimit programatik dhe shfaqjes GPU të përshpejtuar në 60fps, të gjitha në një skedar kompakt për secilin karakter.

Biblioteka e aseteve të animacionit

Karakteret kryesore

  • lip-sync-amal-01.riv
    - Karakteri kryesor Amal (variacion trup-plote dhe vetëm fytyrë)
    - Disa artboard-e për çdo pozitë goje (për hartimin e fonemave)
    - Gjendjet: i qetë, duke folur, gabim, festim, duke fjetur
    - Madhësia e skedarit: 1.2 MB (krahasuar me 50+ MB për sprite sheets)
  • avatar.riv
    - Avatar përdoruesi i personalizueshëm (3 artboard-e)
    1. Trup i plotë: kokë, trup, pjesë të tjera me veshje
    2. Vetëm kokë: për panel dhe aplikacion prindëror
    3. Shok fluturash: animacion shpërblimi
    - Bazuar në komponentë: forma koka, flokë, sy, rroba, aksesorë, ngjyra
    - Madhësia e skedarit: 2.4 MB
  • coin-01.riv & coins-01.riv
    - Animacione shpërblimesh (monedha që fluturojnë, mblidhen)
    - Monedhë e vetme: 150 KB
    - Monedha të shumta: 300 KB
  • cute-monster-final.riv
    - Karakter reagimi me shumë gjendje emocionale
    - Gjendjet: i lumtur (përgjigje e saktë), i hutuar (jo i saktë), duke menduar (duke procesuar), duke festuar (seritë)
    - Madhësia e skedarit: 1.8 MB

Optimizim i posaçëm për Android
- Ndërtim i personalizuar NDK (Rive NDK-r28) për përputhshmëri 16KB në faqe
- Zvogëlon madhësinë e binarit me 8% krahasuar me ndërtimin standard
- Siguron përputhshmëri me menaxhimin strikt të memories në Android 12+

Procesi i sinkronizimit të buzëve (detaje teknike)

Hapi 1: Gjenerimi i audios TTS + Nxjerrja e shenjave të të folurit

# src/services/tts_client.py
from google.cloud import texttospeech

def generate_speech_with_marks(text: str, language: str = 'ar-SA'):
    client = texttospeech.TextToSpeechClient()
    
    synthesis_input = texttospeech.SynthesisInput(text=text)
    voice = texttospeech.VoiceSelectionParams(
        language_code=language,
        name='ar-SA-Neural2-A'  # Zëri WaveNet
    )
    audio_config = texttospeech.AudioConfig(
        audio_encoding=texttospeech.AudioEncoding.MP3,
        effects_profile_id=['small-bluetooth-speaker-class-device']  # Folësi i fëmijës
    )
    
    # Kërkohet shenjat e të folurit (kohëzgjatja e fonemave)
    request = texttospeech.SynthesizeSpeechRequest(
        input=synthesis_input,
        voice=voice,
        audio_config=audio_config,
        enable_text_to_speech_as_cloud_service=True
    )
    
    response = client.synthesize_speech(request=request)
    
    # Përgjigja përfshin:
    # - audio_content: bajtet MP3
    # - timepoints: [{character, byte_pos, time_ms}, ...]
    
    return {
        'audio': response.audio_content,
        'speech_marks': response.timepoints  # Kohët e fonemave
    }

Hapi 2: Hartimi i fonemave me gjendjet e gojës në Rive

lip_sync_avatar.json lidh fonemat arabe me pozicionet e gojës:

{
  "phoneme_map": {
    "ا": { "rive_state": "mouth_a_open", "duration_ms": 200 },
    "ب": { "rive_state": "mouth_lips_closed", "duration_ms": 150 },
    "ع": { "rive_state": "mouth_pharyngeal", "duration_ms": 250 },
    "ق": { "rive_state": "mouth_uvular", "duration_ms": 180 },
    ...
  },
  "mouth_positions": [
    { "id": "mouth_a_open", "blend_values": { "jaw_open": 0.8, "lips_rounded": 0.2 } },
    { "id": "mouth_lips_closed", "blend_values": { "jaw_open": 0.1, "lips_rounded": 0.9 } },
    ...
  ]
}

Hapi 3: LipSyncController dirigjon llogjikën e luajtjes

// lib/src/modules/animations/controllers/lip_sync_controller.dart
class LipSyncController extends GetxController {
  late Rive riveCharacter;
  late AudioPlayer audioPlayer;
  late LipSyncMapper mapper;
  
  void playWithLipSync(String text, String audioPath) {
    // Hapi 1: Ngarkon karakterin Rive
    riveCharacter.loadRiveFile('lip-sync-amal-01.riv');
    
    // Hapi 2: Ngarkon shenjat e të folurit nga TTS
    mapper = LipSyncMapper.fromJson(loadJsonAsset('lip_sync_avatar.json'));
    
    // Hapi 3: Luaj audio dhe drejto animacionin e gojës
    audioPlayer.play(AudioSource.file(audioPath));
    
    // Hapi 4: Përditëson pozicionin e gojës në secilën kornizë audio
    audioPlayer.onPositionChanged.listen((Duration position) {
      String phoneme = mapper.phonemeAtTime(position.inMilliseconds);
      String riveState = mapper.riveStateForPhoneme(phoneme);
      
      riveCharacter.setStateInput('mouth_state', riveState);
    });
  }
}

Hapi 4: RiveCharacterController menaxhon ciklin e jetës së karakterit

// Menaxhon gjendjet e plota të animacionit të karakterit (jo vetëm gojën)
class RiveCharacterController extends GetxController {
  // Gjendjet: idle → prepare → speaking → idle → error/celebration
  
  void startExercise() {
    // Ndërron gjendjet: idle → prepare (gati për dëgjim)
    character.setStateInput('state_machine', 'prepare');
  }
  
  void childSpeaks(String recognizedText, double accuracy) {
    character.setStateInput('state_machine', 'speaking');
    lipSyncController.playFeedback(recognizedText);
  }
  
  void onFeedbackComplete(bool wasCorrect) {
    if (wasCorrect) {
      character.setStateInput('state_machine', 'celebrate');
      playRewardAnimation();
    } else {
      character.setStateInput('state_machine', 'error');
      playEncouragingPhrase();
    }
  }
}

Sistemi i personalizimit të avatarit

Arkitektura bazuar në komponentë

Fëmijët personalizojnë avatarin e tyre nga pjesë të ndryshme:

{
  "avatar_customization": {
    "head_shapes": [
      { "id": "round", "rive_element": "head_round" },
      { "id": "oval", "rive_element": "head_oval" },
      { "id": "square", "rive_element": "head_square" }
    ],
    "hair_styles": [
      { "id": "ponytail", "rive_element": "hair_ponytail" },
      { "id": "braids", "rive_element": "hair_braids" },
      { "id": "straight", "rive_element": "hair_straight" }
    ],
    "colors": {
      "skin_tone": ["light", "medium", "dark"],
      "hair_color": ["black", "brown", "blonde", "red"],
      "shirt_color": ["blue", "pink", "green", "yellow", "purple"],
      "accent_color": ["red", "orange", "green", "blue"]
    }
  }
}

Hartimi i emrave të elementeve Rive (avatar_customization_rive_names.dart)

const avatarRiveNames = {
  'head_round': 'Head_Round',
  'head_oval': 'Head_Oval',
  'hair_ponytail': 'Hair_Ponytail',
  'shirt_blue': 'Shirt_Blue',
  'shirt_pink': 'Shirt_Pink',
  // ... 50+ hartime të elementeve
};

Kur fëmija zgjedh “kokë e rrumbullakët + këmishë blu,” aplikacioni:

  1. Aktivizon elementin Rive Head_Round
  2. Aktivizon elementin Rive Shirt_Blue
  3. Çaktivizon të gjitha format e tjera të kokës dhe ngjyrat e këmishës
  4. Avatar i personalizuar shfaqet në të gjithë aplikacionin

Pse Rive është më i mirë se alternativat

VeçoriRiveLottieSprite SheetsVideo
Makinat e shtetit
Kontroll në kohë reale✓ (plot)ParadoksalManual✗ (pasiv)
Madhësia e skedarit1-2 MB2-3 MB50+ MB100+ MB
Performanca60fps GPU30fps CPU60fps GPUVariabël
Ndërveprimi✓ Plottë✓ Pjesërisht✓ Plottë✗ Asnjë
Kurba e të mësuaritMesatareLehtëLehtëLehtë
MirëmbajtjeNjë skedar .rivNjë JSONQindra imazheNjë video

Rive fiton pasi ne kemi nevojë për kontroll programatik, makina shtetesh dhe skedarë kompakt për një aplikacion mobil.

Optimizimi i performancës

  • Ngarkimi paraprak i karaktereve: Ngarkoni skedarët .riv gjatë nisjes së aplikacionit, jo për çdo ushtrim
  • Shfaqja me GPU: Rive përdor automatikisht GPU kur është e disponueshme, me CPU si zgjidhje alternative në pajisjet më të vjetra
  • Përdorimi i memorjes: Rishfrytëzoni kontrollet Rive midis ekranëve për të shmangur vonesën e mbledhjes së plehrave
  • Komprimimi: Skedarët Rive janë të kompresuar natyrshëm, nuk kërkohet optimizim shtesë

Rezultati: animacione në 60fps në Snapdragon 662+ (telefonat e klasës mesatare të vitit 2019).

Pyetje të shpeshta

Pyetje: A mund të eksportoj animacione nga Adobe Animate në Rive?
Përgjigje: Jo direkt. Ne përdorim editorin origjinal të Rive (rive.app). Animatoret krijojnë në Rive dhe jo në Animate apo After Effects. Fluksi ynë: dizajnoni karakterin në Rive → eksportoni si .riv → integroni në aplikacionin Flutter.

Pyetje: Si trajtoni lloje të ndryshme trupore apo aftësi të kufizuara?
Përgjigje: Personalizimi i avatarit përfshin opsione për llojet e trupit (të hollë, atletik, i rrumbullakët) dhe aksesorë (syze, ndihma dëgjimi, ndihma lëvizjeje). Kjo siguron përfaqësim për të gjitha fëmijët.

Pyetje: Çfarë nëse një fëmijë nuk pëlqen avatarin e vet?
Përgjigje: Ata mund të personalizojnë avatarin në çdo kohë. Aplikacioni nuk e detyron një pamje të caktuar — fëmijët kanë kontroll kreativ plotësisht.

Artikuj të Ngjashëm