Live2D Web端實現
demo預覽:http://www.kakinuma.date/l2d.html
官方:http://www.live2d.com/en/
sdk下載:https://link.zhihu.com/?target=http%3A//app2.live2d.com/cubism/sdk/bowiuex/webgl/Live2D_SDK_WebGL_2.0.05_1_en.zip
sdk目錄:
framework框架有一個js,lib庫有1個,這是最基本的構成
下面有SampleApp1,Simple兩個例子,simple是前者的精簡版,只有顯示沒有功能,就不看它了
SampleApp1中
assets包括了背景和模型等資源
src則是模型的初始化,顯示,事件繫結等等的功能實現程式碼
首先為了測試,先導進了所有的.js,然後新增個標籤
<!DOCTYPE HTML> <html> <head> <script src='lib/live2d.min.js'></script> <script src='framework/Live2DFramework.js'></script> <script src="src/utils/MatrixStack.js"></script> <script src="src/utils/ModelSettingJson.js"></script> <script src="src/PlatformManager.js"></script> <script src="src/LAppDefine.js"></script> <script src="src/LAppModel.js"></script> <script src="src/LAppLive2DManager.js"></script> <script src="src/SampleApp1.js"></script> </head> <body> <canvas id="test" width="450px" height="500px" style="position:fixed;right:0px;bottom:-10px;"> </canvas> <script> sampleApp1(); </script> </body> </html>
.js 檔案都按路徑放好就好了
然後試著開啟頁面,看看報錯(壓根就沒覺得可以直接用,因為我壓根就沒有新增模型檔案
init……應該是初始化有錯,具體看看
說是null了應該是沒傳到引數,所以引數canvasId應該是有問題(順便Canvas在這應該是畫布的意思)
頂上面一行,getId出錯,那就應該是html裡id沒寫對……隨手寫了個test確實太隨意了……
這個canvasId的來源就在這函式頭頂上,就是初始化的Sample1()
改一下,改成glcanvas,改掉以後出現了新的錯誤,是同樣類別的錯誤,因為官方Sample裡有換模型的按鈕,所以我沒寫,Id一樣沒get到,但是我不想使用換模型的功能,所以我嘗試不使用者這功能
所以在初始化函式SampleApp1()中呼叫的init中,選擇不要那個Button
然後所有的change的地方都暫時選擇註釋掉,地方不少……change的定義,和一些呼叫,因為Sample中右鍵模型也是可以change的
然後問題沒了,但是理所當然是空白,因為我沒加模型
不過審查元素的話,元素是在的(當然在了
現在的SampleApp1.js被修改為
var thisRef = this; window.onerror = function(msg, url, line, col, error) { var errmsg = "file:" + url + "<br>line:" + line + " " + msg; l2dError(errmsg); } function SampleApp1() { this.platform = window.navigator.platform.toLowerCase(); this.live2DMgr = new LAppLive2DManager(); this.isDrawStart = false; this.gl = null; this.canvas = null; this.dragMgr = null; /*new L2DTargetPoint();*/ this.viewMatrix = null; /*new L2DViewMatrix();*/ this.projMatrix = null; /*new L2DMatrix44()*/ this.deviceToScreen = null; /*new L2DMatrix44();*/ this.drag = false; this.oldLen = 0; this.lastMouseX = 0; this.lastMouseY = 0; this.isModelShown = false; initL2dCanvas("glCanvas"); init(); } function initL2dCanvas(canvasId) { this.canvas = document.getElementById(canvasId); if(this.canvas.addEventListener) { this.canvas.addEventListener("mousewheel", mouseEvent, false); this.canvas.addEventListener("click", mouseEvent, false); this.canvas.addEventListener("mousedown", mouseEvent, false); this.canvas.addEventListener("mousemove", mouseEvent, false); this.canvas.addEventListener("mouseup", mouseEvent, false); this.canvas.addEventListener("mouseout", mouseEvent, false); this.canvas.addEventListener("contextmenu", mouseEvent, false); this.canvas.addEventListener("touchstart", touchEvent, false); this.canvas.addEventListener("touchend", touchEvent, false); this.canvas.addEventListener("touchmove", touchEvent, false); } } function init() { var width = this.canvas.width; var height = this.canvas.height; this.dragMgr = new L2DTargetPoint(); var ratio = height / width; var left = LAppDefine.VIEW_LOGICAL_LEFT; var right = LAppDefine.VIEW_LOGICAL_RIGHT; var bottom = -ratio; var top = ratio; this.viewMatrix = new L2DViewMatrix(); this.viewMatrix.setScreenRect(left, right, bottom, top); this.viewMatrix.setMaxScreenRect(LAppDefine.VIEW_LOGICAL_MAX_LEFT, LAppDefine.VIEW_LOGICAL_MAX_RIGHT, LAppDefine.VIEW_LOGICAL_MAX_BOTTOM, LAppDefine.VIEW_LOGICAL_MAX_TOP); this.viewMatrix.setMaxScale(LAppDefine.VIEW_MAX_SCALE); this.viewMatrix.setMinScale(LAppDefine.VIEW_MIN_SCALE); this.projMatrix = new L2DMatrix44(); this.projMatrix.multScale(1, (width / height)); this.deviceToScreen = new L2DMatrix44(); this.deviceToScreen.multTranslate(-width / 2.0, -height / 2.0); this.deviceToScreen.multScale(2 / width, -2 / width); this.gl = getWebGLContext(); if (!this.gl) { l2dError("Failed to create WebGL context."); return; } this.gl.clearColor(0.0, 0.0, 0.0, 0.0); changeModel(); startDraw(); } function startDraw() { if(!this.isDrawStart) { this.isDrawStart = true; (function tick() { draw(); var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; requestAnimationFrame(tick ,this.canvas); })(); } } function draw() { // l2dLog("--> draw()"); MatrixStack.reset(); MatrixStack.loadIdentity(); this.dragMgr.update(); this.live2DMgr.setDrag(this.dragMgr.getX(), this.dragMgr.getY()); this.gl.clear(this.gl.COLOR_BUFFER_BIT); MatrixStack.multMatrix(projMatrix.getArray()); MatrixStack.multMatrix(viewMatrix.getArray()); MatrixStack.push(); for (var i = 0; i < this.live2DMgr.numModels(); i++) { var model = this.live2DMgr.getModel(i); if(model == null) return; if (model.initialized && !model.updating) { model.update(); model.draw(this.gl); if (!this.isModelShown && i == this.live2DMgr.numModels()-1) { this.isModelShown = !this.isModelShown; } } } MatrixStack.pop(); } function changeModel() { this.isModelShown = false; this.live2DMgr.reloadFlg = true; this.live2DMgr.count++; this.live2DMgr.changeModel(this.gl); } function modelScaling(scale) { var isMaxScale = thisRef.viewMatrix.isMaxScale(); var isMinScale = thisRef.viewMatrix.isMinScale(); thisRef.viewMatrix.adjustScale(0, 0, scale); if (!isMaxScale) { if (thisRef.viewMatrix.isMaxScale()) { thisRef.live2DMgr.maxScaleEvent(); } } if (!isMinScale) { if (thisRef.viewMatrix.isMinScale()) { thisRef.live2DMgr.minScaleEvent(); } } } function modelTurnHead(event) { thisRef.drag = true; var rect = event.target.getBoundingClientRect(); var sx = transformScreenX(event.clientX - rect.left); var sy = transformScreenY(event.clientY - rect.top); var vx = transformViewX(event.clientX - rect.left); var vy = transformViewY(event.clientY - rect.top); if (LAppDefine.DEBUG_MOUSE_LOG) l2dLog("onMouseDown device( x:" + event.clientX + " y:" + event.clientY + " ) view( x:" + vx + " y:" + vy + ")"); thisRef.lastMouseX = sx; thisRef.lastMouseY = sy; thisRef.dragMgr.setPoint(vx, vy); thisRef.live2DMgr.tapEvent(vx, vy); } function followPointer(event) { var rect = event.target.getBoundingClientRect(); var sx = transformScreenX(event.clientX - rect.left); var sy = transformScreenY(event.clientY - rect.top); var vx = transformViewX(event.clientX - rect.left); var vy = transformViewY(event.clientY - rect.top); if (LAppDefine.DEBUG_MOUSE_LOG) l2dLog("onMouseMove device( x:" + event.clientX + " y:" + event.clientY + " ) view( x:" + vx + " y:" + vy + ")"); if (thisRef.drag) { thisRef.lastMouseX = sx; thisRef.lastMouseY = sy; thisRef.dragMgr.setPoint(vx, vy); } } function lookFront() { if (thisRef.drag) { thisRef.drag = false; } thisRef.dragMgr.setPoint(0, 0); } function mouseEvent(e) { e.preventDefault(); if (e.type == "mousewheel") { if (e.clientX < 0 || thisRef.canvas.clientWidth < e.clientX || e.clientY < 0 || thisRef.canvas.clientHeight < e.clientY) { return; } if (e.wheelDelta > 0) modelScaling(1.1); else modelScaling(0.9); } else if (e.type == "mousedown") { if("button" in e && e.button != 0) return; modelTurnHead(e); } else if (e.type == "mousemove") { followPointer(e); } else if (e.type == "mouseup") { if("button" in e && e.button != 0) return; lookFront(); } else if (e.type == "mouseout") { lookFront(); } else if (e.type == "contextmenu") { changeModel(); } } function touchEvent(e) { e.preventDefault(); var touch = e.touches[0]; if (e.type == "touchstart") { if (e.touches.length == 1) modelTurnHead(touch); // onClick(touch); } else if (e.type == "touchmove") { followPointer(touch); if (e.touches.length == 2) { var touch1 = e.touches[0]; var touch2 = e.touches[1]; var len = Math.pow(touch1.pageX - touch2.pageX, 2) + Math.pow(touch1.pageY - touch2.pageY, 2); if (thisRef.oldLen - len < 0) modelScaling(1.025); else modelScaling(0.975); thisRef.oldLen = len; } } else if (e.type == "touchend") { lookFront(); } } function transformViewX(deviceX) { var screenX = this.deviceToScreen.transformX(deviceX); return viewMatrix.invertTransformX(screenX); } function transformViewY(deviceY) { var screenY = this.deviceToScreen.transformY(deviceY); return viewMatrix.invertTransformY(screenY); } function transformScreenX(deviceX) { return this.deviceToScreen.transformX(deviceX); } function transformScreenY(deviceY) { return this.deviceToScreen.transformY(deviceY); } function getWebGLContext() { var NAMES = [ "webgl" , "experimental-webgl" , "webkit-3d" , "moz-webgl"]; for( var i = 0; i < NAMES.length; i++ ){ try{ var ctx = this.canvas.getContext(NAMES[i], {premultipliedAlpha : true}); if(ctx) return ctx; } catch(e){} } return null; }; function l2dLog(msg) { if(!LAppDefine.DEBUG_LOG) return; console.log(msg); } function l2dError(msg) { if(!LAppDefine.DEBUG_LOG) return; l2dLog( "<span style='color:red'>" + msg + "</span>"); console.error(msg); };
這時的index.html為
<!DOCTYPE HTML> <html> <head> <script src='lib/live2d.min.js'></script> <script src='framework/Live2DFramework.js'></script> <script src="src/utils/MatrixStack.js"></script> <script src="src/utils/ModelSettingJson.js"></script> <script src="src/PlatformManager.js"></script> <script src="src/LAppDefine.js"></script> <script src="src/LAppModel.js"></script> <script src="src/LAppLive2DManager.js"></script> <script src="src/SampleApp1.js"></script> </head> <body> <canvas id="glCanvas" width="450px" height="500px" style="position:fixed;right:0px;bottom:-10px;"> </canvas> <script> SampleApp1(); </script> </body> </html>
這時的控制檯已經有了我們想要的錯誤了
PlatformManager中
failed to load,所以我們就能知道我們的模型到底該導到哪去
這裡要的是一個json,我看官方的文件寫的json是定義的模型類,這裡就直接試著改一下,去下載一個模型檔案,看看都有些什麼……
下載到KcWiki曾經使用過的叢雲模型,檔案結構為
model.json中內容為
{ "version":"Sample 1.0.0", "model":"murakumo.moc", "textures":[ "murakumo.2048/texture_00.png" ], "motions":{ "tap_bust":[ {"file":"motions/murakumo_tap_bust_01.mtn"}, {"file":"motions/murakumo_tap_bust_02.mtn"} ], "idle":[ {"file":"motions/murakumo_idle_01.mtn"}, {"file":"motions/murakumo_idle_02.mtn"}, {"file":"motions/murakumo_idle_03.mtn"} ], "tap_ear":[ {"file":"motions/murakumo_tap_ear_01.mtn"} ], "tap":[ {"file":"motions/murakumo_m_01.mtn"}, {"file":"motions/murakumo_m_02.mtn"} ] }, "physics":"murakumo.physics.json" }
所以我們能在這裡看到……版本,模型地址,資源動作和……物理特性(講道理我猜是乳搖用的……
試著匯入模型……匯入到哪??
platform不是直接用到的,仔細看一看發現,
SampleApp1中有 this.live2DMgr = new LAppLive2DManager();
而LppLive2DManager.js中,有function LAppLive2DManager(),其中有一句Live2DFramework.setPlatformManager(new PlatformManager);
那麼Platform就是這樣被初始化的,這樣產生了模型載入錯誤,但是路徑是在哪設定的……
重新掃一眼檔案結構就能發現,有個js叫LAppDefine,看之
var LAppDefine = { DEBUG_LOG : true, DEBUG_MOUSE_LOG : false, // DEBUG_DRAW_HIT_AREA : false, // DEBUG_DRAW_ALPHA_MODEL : false, VIEW_MAX_SCALE : 2, VIEW_MIN_SCALE : 0.8, VIEW_LOGICAL_LEFT : -1, VIEW_LOGICAL_RIGHT : 1, VIEW_LOGICAL_MAX_LEFT : -2, VIEW_LOGICAL_MAX_RIGHT : 2, VIEW_LOGICAL_MAX_BOTTOM : -2, VIEW_LOGICAL_MAX_TOP : 2, PRIORITY_NONE : 0, PRIORITY_IDLE : 1, PRIORITY_NORMAL : 2, PRIORITY_FORCE : 3, BACK_IMAGE_NAME : "assets/image/back_class_normal.png", MODEL_HARU : "assets/live2d/haru/haru.model.json", MODEL_HARU_A : "assets/live2d/haru/haru_01.model.json", MODEL_HARU_B : "assets/live2d/haru/haru_02.model.json", MODEL_SHIZUKU : "assets/live2d/shizuku/shizuku.model.json", MODEL_WANKO : "assets/live2d/wanko/wanko.model.json", MOTION_GROUP_IDLE : "idle", MOTION_GROUP_TAP_BODY : "tap_body", MOTION_GROUP_FLICK_HEAD : "flick_head", MOTION_GROUP_PINCH_IN : "pinch_in", MOTION_GROUP_PINCH_OUT : "pinch_out", MOTION_GROUP_SHAKE : "shake", HIT_AREA_HEAD : "head", HIT_AREA_BODY : "body" };
這地方大概綁了模型,和它的動作,這時候最好對比一下Sample模型的json
這是haru的json
{ "type":"Live2D Model Setting", "name":"haru", "model":"haru_01.moc", "textures": [ "haru_01.1024/texture_00.png", "haru_01.1024/texture_01.png", "haru_01.1024/texture_02.png" ], "physics":"haru.physics.json", "pose":"haru.pose.json", "expressions": [ {"name":"f01","file":"expressions/f01.exp.json"}, {"name":"f02","file":"expressions/f02.exp.json"}, {"name":"f03","file":"expressions/f03.exp.json"}, {"name":"f04","file":"expressions/f04.exp.json"}, {"name":"f05","file":"expressions/f05.exp.json"}, {"name":"f06","file":"expressions/f06.exp.json"}, {"name":"f07","file":"expressions/f07.exp.json"}, {"name":"f08","file":"expressions/f08.exp.json"} ], "layout": { "center_x":0, "y":1.2, "width":2.9 }, "hit_areas": [ {"name":"head", "id":"D_REF.HEAD"}, {"name":"body", "id":"D_REF.BODY"} ], "motions": { "idle": [ {"file":"motions/idle_00.mtn" ,"fade_in":2000, "fade_out":2000}, {"file":"motions/idle_01.mtn" ,"fade_in":2000, "fade_out":2000}, {"file":"motions/idle_02.mtn" ,"fade_in":2000, "fade_out":2000} ], "tap_body": [ { "file":"motions/tapBody_00.mtn" , "sound":"sounds/tapBody_00.mp3"}, { "file":"motions/tapBody_01.mtn" , "sound":"sounds/tapBody_01.mp3"}, { "file":"motions/tapBody_02.mtn" , "sound":"sounds/tapBody_02.mp3"} ], "pinch_in": [ { "file":"motions/pinchIn_00.mtn", "sound":"sounds/pinchIn_00.mp3" } ], "pinch_out": [ { "file":"motions/pinchOut_00.mtn", "sound":"sounds/pinchOut_00.mp3" } ], "shake": [ { "file":"motions/shake_00.mtn", "sound":"sounds/shake_00.mp3","fade_in":500 } ], "flick_head": [ { "file":"motions/flickHead_00.mtn", "sound":"sounds/flickHead_00.mp3" } ] } }
shizuku的json
{ "type":"Live2D Model Setting", "name":"shizuku", "model":"shizuku.moc", "textures": [ "shizuku.1024/texture_00.png", "shizuku.1024/texture_01.png", "shizuku.1024/texture_02.png", "shizuku.1024/texture_03.png", "shizuku.1024/texture_04.png", "shizuku.1024/texture_05.png" ], "physics":"shizuku.physics.json", "pose":"shizuku.pose.json", "expressions": [ {"name":"f01","file":"expressions/f01.exp.json"}, {"name":"f02","file":"expressions/f02.exp.json"}, {"name":"f03","file":"expressions/f03.exp.json"}, {"name":"f04","file":"expressions/f04.exp.json"} ], "layout": { "center_x":0, "y":1.2, "width":2.4 }, "hit_areas": [ {"name":"head", "id":"D_REF.HEAD"}, {"name":"body", "id":"D_REF.BODY"} ], "motions": { "idle": [ {"file":"motions/idle_00.mtn" ,"fade_in":2000, "fade_out":2000}, {"file":"motions/idle_01.mtn" ,"fade_in":2000, "fade_out":2000}, {"file":"motions/idle_02.mtn" ,"fade_in":2000, "fade_out":2000} ], "tap_body": [ { "file":"motions/tapBody_00.mtn", "sound":"sounds/tapBody_00.mp3" }, { "file":"motions/tapBody_01.mtn", "sound":"sounds/tapBody_01.mp3" }, { "file":"motions/tapBody_02.mtn", "sound":"sounds/tapBody_02.mp3" } ], "pinch_in": [ { "file":"motions/pinchIn_00.mtn", "sound":"sounds/pinchIn_00.mp3" }, { "file":"motions/pinchIn_01.mtn", "sound":"sounds/pinchIn_01.mp3" }, { "file":"motions/pinchIn_02.mtn", "sound":"sounds/pinchIn_02.mp3" } ], "pinch_out": [ { "file":"motions/pinchOut_00.mtn", "sound":"sounds/pinchOut_00.mp3" }, { "file":"motions/pinchOut_01.mtn", "sound":"sounds/pinchOut_01.mp3" }, { "file":"motions/pinchOut_02.mtn", "sound":"sounds/pinchOut_02.mp3" } ], "shake": [ { "file":"motions/shake_00.mtn", "sound":"sounds/shake_00.mp3","fade_in":500 }, { "file":"motions/shake_01.mtn", "sound":"sounds/shake_01.mp3","fade_in":500 }, { "file":"motions/shake_02.mtn", "sound":"sounds/shake_02.mp3","fade_in":500 } ], "flick_head": [ { "file":"motions/flickHead_00.mtn", "sound":"sounds/flickHead_00.mp3" }, { "file":"motions/flickHead_01.mtn", "sound":"sounds/flickHead_01.mp3" }, { "file":"motions/flickHead_02.mtn", "sound":"sounds/flickHead_02.mp3" } ] } }
motions大概都是對應的,根據上邊貼了的叢雲(murakumo)的json,試著把Define的js改為
var LAppDefine = { DEBUG_LOG : true, DEBUG_MOUSE_LOG : false, // DEBUG_DRAW_HIT_AREA : false, // DEBUG_DRAW_ALPHA_MODEL : false, VIEW_MAX_SCALE : 2, VIEW_MIN_SCALE : 0.8, VIEW_LOGICAL_LEFT : -1, VIEW_LOGICAL_RIGHT : 1, VIEW_LOGICAL_MAX_LEFT : -2, VIEW_LOGICAL_MAX_RIGHT : 2, VIEW_LOGICAL_MAX_BOTTOM : -2, VIEW_LOGICAL_MAX_TOP : 2, PRIORITY_NONE : 0, PRIORITY_IDLE : 1, PRIORITY_NORMAL : 2, PRIORITY_FORCE : 3, /* BACK_IMAGE_NAME : "assets/image/back_class_normal.png", MODEL_HARU : "assets/live2d/haru/haru.model.json", MODEL_HARU_A : "assets/live2d/haru/haru_01.model.json", MODEL_HARU_B : "assets/live2d/haru/haru_02.model.json", MODEL_SHIZUKU : "assets/live2d/shizuku/shizuku.model.json", MODEL_WANKO : "assets/live2d/wanko/wanko.model.json", MOTION_GROUP_IDLE : "idle", MOTION_GROUP_TAP_BODY : "tap_body", MOTION_GROUP_FLICK_HEAD : "flick_head", MOTION_GROUP_PINCH_IN : "pinch_in", MOTION_GROUP_PINCH_OUT : "pinch_out", MOTION_GROUP_SHAKE : "shake", HIT_AREA_HEAD : "head", HIT_AREA_BODY : "body" */ MODEL_MURAKUMO : "murakumo/murakumo.model.json", MOTION_GROUP_IDLE : "idle", MOTION_GROUP_TAP : "tap", MOTION_GROUP_TAP_EAR : "tap_ear", MOTION_GROUP_TAP_BUST : "tap_bust", HIT_AREA_HEAD : "head", HIT_AREA_BODY : "body", HIT_AREA_EAR_L : "ear_l", HIT_AREA_EAR_R : "ear_r", HIT_AREA_BUST : "bust" };
接著出現的新的錯誤:
LAPPModel在Load時出了問題……PATH不對,搜搜看哪裡使用了它……
LAppLive2DManager.prototype.changeModel 有使用,是因為Sample裡官方包含了好多模型……改之
LAppLive2DManager.prototype.changeModel = function(gl) { // console.log("--> LAppLive2DManager.update(gl)"); if (this.reloadFlg) { this.reloadFlg = false; var no = parseInt(this.count % 4); var thisRef = this; switch (no) { case 0: this.releaseModel(1, gl); this.releaseModel(0, gl); this.createModel(); this.models[0].load(gl, LAppDefine.MODEL_MURAKUMO); break; /* case 1: this.releaseModel(0, gl); this.createModel(); this.models[0].load(gl, LAppDefine.MODEL_SHIZUKU); break; case 2: this.releaseModel(0, gl); this.createModel(); this.models[0].load(gl, LAppDefine.MODEL_WANKO); break; case 3: this.releaseModel(0, gl); // 一體目のモデル this.createModel(); this.models[0].load(gl, LAppDefine.MODEL_HARU_A, function() { // 二體目のモデル thisRef.createModel(); thisRef.models[1].load(gl, LAppDefine.MODEL_HARU_B); }); break; */ default: break; } } };
然後再重新整理……看看啥錯誤
臥槽!
野生的叢雲出現了
測試一下motions……無效
點選沒有給出反應,並且點選耳朵應該會有特殊動作(json中的說明)
想來也是,不同的模型有不同的motion,只對json進行了繫結,具體執行好像沒有寫/改過,應該還漏了某些地方……
試著去搜一下最開始json中繫結的motion變數,能搜到同樣LAPPLive2DManager中,有
LAppLive2DManager.prototype.tapEvent = function(x, y) { if (LAppDefine.DEBUG_LOG) console.log("tapEvent view x:" + x + " y:" + y); for (var i = 0; i < this.models.length; i++) { if (this.models[i].hitTest(LAppDefine.HIT_AREA_HEAD, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap face."); this.models[i].setRandomExpression(); } else if (this.models[i].hitTest(LAppDefine.HIT_AREA_BODY, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_BODY, LAppDefine.PRIORITY_NORMAL); } } return true; };
所以可以根據murakumo的json來改一下這個函式
for (var i = 0; i < this.models.length; i++) { if (this.models[i].hitTest(LAppDefine.HIT_AREA_HEAD, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap face."); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP, LAppDefine.PRIORITY_NORMAL); } else if (this.models[i].hitTest(LAppDefine.HIT_AREA_EAR_L, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_EAR, LAppDefine.PRIORITY_NORMAL); } else if (this.models[i].hitTest(LAppDefine.HIT_AREA_EAR_R, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_EAR, LAppDefine.PRIORITY_NORMAL); } else if (this.models[i].hitTest(LAppDefine.HIT_AREA_BUST, x, y)) { if (LAppDefine.DEBUG_LOG) console.log("Tap body." + " models[" + i + "]"); this.models[i].startRandomMotion(LAppDefine.MOTION_GROUP_TAP_BUST, LAppDefine.PRIORITY_NORMAL); } }
事實上改過以後控制檯仍無輸出
意思是點選事件還是沒成功
tapEvent報告了點選座標,但是沒有觸發事件
而murakumo_idle是隨機的表情動作,與點選事件是不同的,那麼只能再跟蹤一下tapEvent
tapEvent上來首先是列印座標,有座標列印出來說明函式是執行了
重新理一遍,經過前輩提醒,json資料被有繫結完全,再翻上去看看json
官方的sample裡
除了textures,model,motion等等還有一個hit_areas,看來就是這樣了
沒有獲取到hitareas,所以相當於沒點上什麼的
json中新增
"hit_areas": [ {"name":"head", "id":"D_REF.HEAD"}, {"name":"body", "id":"D_REF.BODY"}, {"name":"ear_l", "id":"D_REF.EAR_L"}, {"name":"ear_r", "id":"D_REF.EAR_R"}, {"name":"bust", "id":"D_REF.BUST"} ],
至於這裡的ID,是根據.moc模型檔案獲取的,是模型製作者在製作模型時為部位新增的,官方有提供模型編輯軟體,或者記事本去開moc也能看到?
最後大功告成~
後
這篇博是邊摸索邊寫的,可能會相當的亂……難以看懂
後邊重新梳理思路的時候會貼一篇新文
相關文章
- Web 端 APNG 播放實現原理Web
- web端 網頁端分享功能的實現Web網頁
- 用js實現web端錄屏JSWeb
- Django實現web端tailf日誌檔案DjangoWebAI
- 純web端實現二維碼識別Web
- web技術支援| Web 客戶端實現錄音、錄影Web客戶端
- web端作業控制系統簡易實現Web
- 突破技術限制,實現Web端靜默列印Web
- 基於Web實現遠端與硬體互動Web
- 基於vue實現web端超大資料量表格VueWeb大資料
- Web 端 實現 app “輸入驗證碼 ”的效果WebAPP
- vue全家桶實現移動端電商web-appVueWebAPP
- 如何在 web 端實現一個有日曆的報表Web
- 使用springboot+angular實現web端微信掃碼登陸Spring BootAngularWeb
- web 端展現報表資料時如何實現摺疊展開效果?Web
- Netty實現Web SocketNettyWeb
- Tomcat實現Web SocketTomcatWeb
- web 端展現報表時查詢表單如何實現引數聯動Web
- Spring Boot實現Web SocketSpring BootWeb
- 實現web置頂效果Web
- Live2D - 模型預覽圖模型
- Hexo 新增 Live2D看板娘Hexo
- 大華攝像頭二次開發-web端實現實時視訊監控Web
- web 端怎麼實現套打發票、快遞單等套打功能?Web
- c++ web框架實現之靜態反射實現C++Web框架反射
- web 實現分頁列印功能Web
- web頁面錄屏實現Web
- Jmeter BlazeMeter實現web錄製JMeterWeb
- 老虎證券web端PWA實踐總結Web
- 《遠端控制》-服務端實現(一)服務端
- 【SpringBoot實戰】實現WEB的常用功能Spring BootWeb
- pytorch實現yolov3(5) 實現端到端的目標檢測PyTorchYOLO
- 輕鬆實現 Web 效能優化Web優化
- web網頁設計實現——04.16Web網頁
- Golang web filter 輕量級實現GolangWebFilter
- 【web前端】自己實現Array.reduce()Web前端
- 端智慧系列文章|端側如何實現實時CEP引擎
- Django websocket之web端實時檢視日誌實踐案例DjangoWeb