在微信小遊戲中實現語音互動
之前在unity裡嘗試用過語音控制,當時的想法是實時控制遊戲角色的移動與攻擊,這在通過線上api解析語義的方式下體驗一般,不過也想到在實時性要求不那麼高的互動場景應該可以用起來。這裡就在微信小遊戲中嘗試一下。
語音互動自然需要一個物件,像我這種手殘人士最適合的設計當然就是卡通的小動物了。經過多次修改,在iPad上完成了形象設計(有點醜,有點歪,大家不要見怪):
設計好形象之後就可以設計動畫了。一幀一幀的畫出連貫的動作。因為偷懶,所以一個動畫也就幾幀,準備了下面幾個動畫:
- 眨眼。1幀,空閒狀態的時候播放,避免什麼都不做的時候畫面看起來太死板。
- 撓頭。2幀,錄音結束髮給伺服器等待伺服器結果的時候播放,使得能在話音剛落時就給出反應。
- 微笑。1幀,對它說“笑一個”的時候播放。
- 舉牌子。3幀,狗狗不會說話,要通過寫字的方式和玩家交流。
接下來就可以參考飛機示例,完成遊戲的程式碼部分。
首先新建一個class InterAction,在constructor中進行各種初始化,主要是載入一些圖片資源,註冊事件等:
constructor(c, returnTitle) {
ctx = c
this.returnTitle = returnTitle
this.bg = wx.createImage()
this.bg.src = 'images/bg2.png'
this.recordBtn = wx.createImage()
this .recordBtn.src = 'images/record.png'
this.recordBtnDown = wx.createImage()
this.recordBtnDown.src = 'images/recorddown.png'
this.btn = this.recordBtn
this.dog = new Dog()
this.idleFrameCount = 0
this.result = ''
this.recorderManager = wx.getRecorderManager()
this.recorderManager.onStop(this .onRecordEnd.bind(this))
this.restart()
}
restart() {
this._touchStartHandler = this.touchStartHandler.bind(this)
wx.onTouchStart(this._touchStartHandler)
this._touchEndHandler = this.touchEndHandler.bind(this)
wx.onTouchEnd(this._touchEndHandler)
requestAnimationFrame(this.loop.bind(this))
}
之後,可以看到主執行緒結構和飛機的基本一樣:
loop() {
this.update()
this.render()
requestAnimationFrame(this.loop.bind(this))
}
在update和按鈕、錄音的回撥函式中更新狀態,在render中顯示當前幀的內容。
錄音結束後,呼叫happycxz提供的介面進行語音解析:
onRecordEnd(res) {
// 向伺服器傳送錄音檔案
let url = 'https://api.happycxz.com/wxapp/mp32asr'
this.dog.playAnimation('thinking', 0, true)
this.idleFrameCount = 0
this.processFileUploadForAsr(url, res.tempFilePath)
}
processFileUploadForAsr(url, filePath) {
wx.uploadFile({
url: url,
filePath: filePath,
name: 'file',
formData: { 'appKey': appkey, 'appSecret': appsecret, 'userId': UTIL.getUserUnique()},
header: {'content-type': 'multipart/form-data'},
success: function(res) {
let nliResult = this.getNliFromResult(res.data)
let stt = this.getSttFromResult(res.data)
let result = ''
if (nliResult != undefined && nliResult.length != 0) {
result = nliResult[0].desc_obj.result
} else {
result = '出了點問題'
}
this.handleResult(result)
}.bind(this),
fail: function (res) {
wx.showModal({
title: '提示',
content: "網路請求失敗,請確保網路是否正常",
showCancel: false,
success: function (res) {
}
})
}.bind(this)
})
}
處理返回結果:
handleResult(res) {
if (res.length > 6) {
res = res.substr(0, 6)
}
this.result = res
if (this.result == '微笑') {
this.dog.playAnimation('smile', 0, true, 60)
this.idleFrameCount = 0
} else if (this.result == 'exit') {
wx.offTouchStart(this._touchStartHandler)
wx.offTouchEnd(this._touchEndHandler)
this.returnTitle()
} else {
this.dog.playAnimation('answer',
0,
false,
240,
function () {
ctx.fillStyle = "#ffffff"
ctx.font = "15px Arial"
ctx.fillText(
this.result,
constants.screenWidth * 17 / 32,
constants.screenHeight * 15 / 32
)}.bind(this),
2)
this.idleFrameCount = 0
}
}
Dog是繼承自我擴充套件之後的Animation類,主要的改動有兩個,一個是支援多個動畫,另一個是在playAnimation時增加了多個引數,可以控制動畫迴圈的方式,並可以指定在特定的幀顯示時呼叫的回撥函式。具體的程式碼可以看文末的程式碼包,這裡就不多說了。
最後來看看測試效果。
按下錄音鍵,說話,鬆開後會做撓頭動作(有點難看),等待一段時間會舉起牌子顯示結果。目前只在olami平臺配置了閒聊、24點和算術功能。為了適應牌子大小,結果做了截斷處理。下面是幾個測試例子:
笑一個/笑一笑:會做出笑臉
再見/拜拜:會返回標題介面
其他:會通過牌子上顯示文字資訊
另外,程式碼中還包含了一個跳躍的小遊戲,通過在主介面點選開始可以進入。如果進一步開發,可以把小遊戲的分數做為獎勵,在互動介面購置一些裝飾品之類的,應該會增加不少遊戲的趣味性。
附: