1. 程式人生 > 其它 >web版看板娘專案更新點選語音功能

web版看板娘專案更新點選語音功能

技術標籤:Live2D網頁看板娘javascripttypescript

web版看板娘專案更新點選語音功能

按載入流程來看,所有的音訊都事先載入完畢的,應該不會出現聲音延遲現象
但這樣也導致頁面初次載入時會比原來慢

功能修改方法

  1. 找到 Samples\TypeScript\Demo\src\lappmodel.ts 檔案

  2. 在類的屬性中新增Audio物件集合,並初始化

class LAppModel{
 ...省略...
//構造方法
public constructor() {
    ...省略...
​
  //儲存音訊物件的map集合
  this._motionSounds = new Map();   
    ...省略...
  }
  
 ...省略... 
 
 _motionSounds :Map<string,any>;//儲存adido物件的集合
}

3.在preLoadMotionGroup方法裡新建audio物件並加入集合。

public preLoadMotionGroup(group: string): void {
  for (let i = 0; i < this._modelSetting.getMotionCount(group); i++) {
   const motionFileName = this._modelSetting.getMotionFileName(group, i);
   const soundFileName = this._modelSetting.getMotionSoundFileName(group,i);
   const fileName = `${this._modelHomeDir}/${motionFileName}`;
   console.log("-------preLoadMotionGroup------當前正在載入動作檔案:【---"+fileName+"----】")
   console.log("-------preLoadMotionGroup------當前正在載入聲音檔案:【---"+this._modelHomeDir+soundFileName+"----】")
   // ex) idle_0
   const name = `${group}_${i}`;
   if (this._debugMode) {
    LAppPal.printMessage(
     `[APP]load motion: ${motionFileName} => [${name}]`
     );
    }
​
   //載入動作檔案
   fetch(`${this._modelHomeDir}/${motionFileName}`)
     .then(response => response.arrayBuffer())
     .then(arrayBuffer => {
     const tmpMotion: CubismMotion = this.loadMotion(
      arrayBuffer,
      arrayBuffer.byteLength,
      name
      );
     
​
     let fadeTime = this._modelSetting.getMotionFadeInTimeValue(group, i);
     if (fadeTime >= 0.0) {
      tmpMotion.setFadeInTime(fadeTime);
      }
​
     fadeTime = this._modelSetting.getMotionFadeOutTimeValue(group, i);
     if (fadeTime >= 0.0) {
      tmpMotion.setFadeOutTime(fadeTime);
      }
     tmpMotion.setEffectIds(this._eyeBlinkIds, this._lipSyncIds);
     if (this._motions.getValue(name) != null) {
      ACubismMotion.delete(this._motions.getValue(name));
      }
     this._motions.setValue(name, tmpMotion);
    
     //新增motion對應的聲音檔案的到map集合
     if(this._motionSounds.get(name)!=null){
      this._motionSounds.delete(name);
      }
      
      let pathOfAudio = this._modelHomeDir+soundFileName;
      if(pathOfAudio != this._modelHomeDir){
       //請求音訊檔案
       fetch(pathOfAudio).then(response => response.blob()).then(
        audioBlob =>{
         let blobUrl = URL.createObjectURL(audioBlob)
         let audio = new Audio(blobUrl)
         this._motionSounds.set(name,audio);
         }
        );
       }
     
     this._motionCount++;
     if (this._motionCount >= this._allMotionCount) {
      this._state = LoadStep.LoadTexture;
​
      // 全てのモーションを停止する
      this._motionManager.stopAllMotions();
​
      this._updating = false;
      this._initialized = true;
​
      this.createRenderer();
      this.setupTextures();
      this.getRenderer().startUp(gl);
      }
     });
   }
  }
​

4.在 startMotion 物件中取出相應物件並播放

public startMotion(
  group: string,
  no: number,
  priority: number,
  onFinishedMotionHandler?: FinishedMotionCallback
  ): CubismMotionQueueEntryHandle {
  if (priority == LAppDefine.PriorityForce) {
   this._motionManager.setReservePriority(priority);
   } else if (!this._motionManager.reserveMotion(priority)) {
   if (this._debugMode) {
    LAppPal.printMessage("[APP]can't start motion.");
    }
   return InvalidMotionQueueEntryHandleValue;
   }
  const motionFileName = this._modelSetting.getMotionFileName(group, no);
  const fileName = `${this._modelHomeDir}/${motionFileName}`;
​
 
 
  const soundFileName = this._modelSetting.getMotionSoundFileName(group, no);
  const fileName1 = `${this._modelHomeDir}/${soundFileName}`;
  console.log("-------startMotion------當前正在載入音訊檔案:【---"+fileName1+"----】")
 
 
 
 
  // ex) idle_0
  const name = `${group}_${no}`;
  //從motions Map裡面取出motions物件,故想載入對應的聲音檔案也同樣需要將聲音物件儲存到map裡面
  let motion: CubismMotion = this._motions.getValue(name) as CubismMotion;
  let audio = this._motionSounds.get(name);
  if(audio!=null){
   if(audio.paused==false)
    {
    audio.load();
    }
   }
  let autoDelete = false;
  //如果motion物件為空,則重新載入檔案,生成物件
  if (motion == null) {
   fetch(`${this._modelHomeDir}/${motionFileName}`)
     .then(response => response.arrayBuffer())
     .then(arrayBuffer => {
     motion = this.loadMotion(
      arrayBuffer,
      arrayBuffer.byteLength,
      null,
      onFinishedMotionHandler
      );
     let fadeTime: number = this._modelSetting.getMotionFadeInTimeValue(
      group,
      no
      );
     if (fadeTime >= 0.0) {
      motion.setFadeInTime(fadeTime);
      }
     fadeTime = this._modelSetting.getMotionFadeOutTimeValue(group, no);
     if (fadeTime >= 0.0) {
      motion.setFadeOutTime(fadeTime);
      }
​
     motion.setEffectIds(this._eyeBlinkIds, this._lipSyncIds);
     autoDelete = true; // 終了時にメモリから削除
     });
   } else {
   //motion物件不為空,關閉當前的motion動作並重新載入正在播放的聲音
   motion.setFinishedMotionHandler(onFinishedMotionHandler);
   if(audio!=null){
    audio.load();
    }
   
   }
 
  if(audio!=null){
   audio.play();
   }else{
   console.log("當前動作沒有語音");
   }
  if (this._debugMode) {
   LAppPal.printMessage(`[APP]start motion: [${group}_${no}`);
   }
  //按優先順序呼叫motion
  return this._motionManager.startMotionPriority(
   motion,
   autoDelete,
   priority
   );
  }

5.模型檔案的修改【*.moc3.json

{
 "Version": 3,
 "FileReferences": {
  "Moc": "l2d01.u.moc3",
  "Textures": [
   "textures/texture_00.png"
   ],
  "Physics": "l2d01.u.physics3.json",
  "Motions": {
   "Idle":[
     {
    "File":"motions/Mgirl10_tingge.motion3.json",
      ##在這裡新增音訊檔案的相對路徑
    
   },
     {"File":"Mgirl10_stand_c.motion3.json"}
    ],
    "TapBody":[
      {
        "File":"motions/Mgirl10_haixiu_a.motion3.json",
         "Sound": "voice/03.wav" ##在這裡新增音訊檔案的相對路徑
      },
      {
      "File":"motions/Mgirl10_shihao_a.motion3.json",
       "Sound": "voice/02.wav"
    }
    ],
    "TapHead":[
      {"File":"motions/Mgirl10_motouyihuo.motion3.json"},
      {"File":"motions/Mgirl10_zeguai_a.motion3.json"}
    ]
   }
  }
}

注意事項

  1. 由於原生的web sdk並未提供播放聲音相關的api,且使用按優先順序播放人物動作,故音訊可能會出現與動作不一致的情況