Live2D Web端實現

CopperDong發表於2018-03-13

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也能看到?

最後大功告成~

 

這篇博是邊摸索邊寫的,可能會相當的亂……難以看懂

後邊重新梳理思路的時候會貼一篇新文

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 http://blog.csdn.net/Kakinuma/article/details/50697762

相關文章