開発環境
・Live2D WebGL SDK 2.0.04_1
・iPhoneシュミレーター
iPhoneだとaudioタグの音声が鳴らない?
「Live2D WebGLでスマホだと音声が鳴らないよー」って困ってる人がいたのでちょっと対策を調べてみました。
→ [ Live2Dコミュニティ ] スマートフォンで音声がならない
原因としては、以下の記事にまとまってました。ブログ書いてくれた方に感謝です!
→ スマートフォンでのvideoタグ操作(自動再生の試行錯誤)
iPhoneのsafariではユーザーアクションからの再生(ボタン押下時など)しか許可されないらしい
(コールバックもダメ)
なのでちょっとLive2D WebGL版のSampleApp1を修正して、iOSでも音声がなるようにしてみました。
修正するソースはSampleApp1.jsとLAppModel.jsです。
SampleApp1.jsはvoiceplay()を追加し、mouseEventとtouchEventでvoiceplay()を呼び出します。
LAppModel.jsはaudioタグ生成部分を修正しました。
(修正した部分にnaotaroとコメント入れておきました)
var thisRef = this;
// JavaScriptで発生したエラーを取得
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;
// モデル描画用canvasの初期化
initL2dCanvas("glcanvas");
// モデル用マトリクスの初期化と描画の開始
init();
}
// naotaro add start
function voiceplay(){
if(soudfile != null){
snd.src = soudfile;
snd.load();
snd.play();
soudfile = null;
}
}
// naotaro add end
function initL2dCanvas(canvasId)
{
// canvasオブジェクトを取得
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);
}
btnChangeModel = document.getElementById("btnChange");
btnChangeModel.addEventListener("click", function(e) {
changeModel();
});
}
function init()
{
// 3Dバッファの初期化
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();
// デバイスに対応する画面の範囲。 Xの左端, Xの右端, Yの下端, Yの上端
this.viewMatrix.setScreenRect(left, right, bottom, top);
// デバイスに対応する画面の範囲。 Xの左端, Xの右端, Yの下端, Yの上端
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);
// WebGLのコンテキストを取得する
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(); // 1回分描画
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());
// Canvasをクリアする
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;
var btnChange = document.getElementById("btnChange");
btnChange.textContent = "Change Model";
btnChange.removeAttribute("disabled");
btnChange.setAttribute("class", "active");
}
}
}
MatrixStack.pop();
}
function changeModel()
{
var btnChange = document.getElementById("btnChange");
btnChange.setAttribute("disabled","disabled");
btnChange.setAttribute("class", "inactive");
btnChange.textContent = "Now Loading...";
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") {
// naotaro ボイスあれば再生 start
voiceplay();
// naotaro ボイスあれば再生 end
// 右クリック以外なら処理を抜ける
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") {
// naotaro ボイスあれば再生 start
voiceplay();
// naotaro ボイスあれば再生 end
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);
}
/*
* WebGLのコンテキストを取得する
*/
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;
var myconsole = document.getElementById("myconsole");
myconsole.innerHTML = myconsole.innerHTML + "<br>" + msg;
console.log(msg);
}
/*
* 画面エラーを出力
*/
function l2dError(msg)
{
if(!LAppDefine.DEBUG_LOG) return;
l2dLog( "<span style='color:red'>" + msg + "</span>");
console.error(msg);
};
//============================================================
//============================================================
// class LAppModel extends L2DBaseModel
//============================================================
//============================================================
function LAppModel()
{
//L2DBaseModel.apply(this, arguments);
L2DBaseModel.prototype.constructor.call(this);
this.modelHomeDir = "";
this.modelSetting = null;
this.tmpMatrix = [];
}
LAppModel.prototype = new L2DBaseModel();
/*
* モデルを初期化する
*/
LAppModel.prototype.load = function(gl, modelSettingPath, callback)
{
this.setUpdating(true);
this.setInitialized(false);
this.modelHomeDir = modelSettingPath.substring(0, modelSettingPath.lastIndexOf("/") + 1);
this.modelSetting = new ModelSettingJson();
var thisRef = this;
this.modelSetting.loadModelSetting(modelSettingPath, function(){
// モデルデータを読み込む
var path = thisRef.modelHomeDir + thisRef.modelSetting.getModelFile();
thisRef.loadModelData(path, function(model){
for (var i = 0; i < thisRef.modelSetting.getTextureNum(); i++)
{
// テクスチャを読み込む
var texPaths = thisRef.modelHomeDir +
thisRef.modelSetting.getTextureFile(i);
thisRef.loadTexture(i, texPaths, function() {
// すべてのテクスチャを読み込んだ後の処理
if( thisRef.isTexLoaded ) {
// 表情
if (thisRef.modelSetting.getExpressionNum() > 0)
{
// 古い表情を削除
thisRef.expressions = {};
for (var j = 0; j < thisRef.modelSetting.getExpressionNum(); j++)
{
var expName = thisRef.modelSetting.getExpressionName(j);
var expFilePath = thisRef.modelHomeDir +
thisRef.modelSetting.getExpressionFile(j);
thisRef.loadExpression(expName, expFilePath);
}
}
else
{
thisRef.expressionManager = null;
thisRef.expressions = {};
}
// 自動目パチ
if (thisRef.eyeBlink == null)
{
thisRef.eyeBlink = new L2DEyeBlink();
}
// 物理演算
if (thisRef.modelSetting.getPhysicsFile() != null)
{
thisRef.loadPhysics(thisRef.modelHomeDir +
thisRef.modelSetting.getPhysicsFile());
}
else
{
thisRef.physics = null;
}
// パーツ切り替え
if (thisRef.modelSetting.getPoseFile() != null)
{
thisRef.loadPose(
thisRef.modelHomeDir +
thisRef.modelSetting.getPoseFile(),
function() {
thisRef.pose.updateParam(thisRef.live2DModel);
}
);
}
else
{
thisRef.pose = null;
}
// レイアウト
if (thisRef.modelSetting.getLayout() != null)
{
var layout = thisRef.modelSetting.getLayout();
if (layout["width"] != null)
thisRef.modelMatrix.setWidth(layout["width"]);
if (layout["height"] != null)
thisRef.modelMatrix.setHeight(layout["height"]);
if (layout["x"] != null)
thisRef.modelMatrix.setX(layout["x"]);
if (layout["y"] != null)
thisRef.modelMatrix.setY(layout["y"]);
if (layout["center_x"] != null)
thisRef.modelMatrix.centerX(layout["center_x"]);
if (layout["center_y"] != null)
thisRef.modelMatrix.centerY(layout["center_y"]);
if (layout["top"] != null)
thisRef.modelMatrix.top(layout["top"]);
if (layout["bottom"] != null)
thisRef.modelMatrix.bottom(layout["bottom"]);
if (layout["left"] != null)
thisRef.modelMatrix.left(layout["left"]);
if (layout["right"] != null)
thisRef.modelMatrix.right(layout["right"]);
}
for (var j = 0; j < thisRef.modelSetting.getInitParamNum(); j++)
{
// パラメータを上書き
thisRef.live2DModel.setParamFloat(
thisRef.modelSetting.getInitParamID(j),
thisRef.modelSetting.getInitParamValue(j)
);
}
for (var j = 0; j < thisRef.modelSetting.getInitPartsVisibleNum(); j++)
{
// パーツの透明度を設定
thisRef.live2DModel.setPartsOpacity(
thisRef.modelSetting.getInitPartsVisibleID(j),
thisRef.modelSetting.getInitPartsVisibleValue(j)
);
}
// パラメータを保存。次回のloadParamで読みだされる
thisRef.live2DModel.saveParam();
thisRef.live2DModel.setGL(gl);
// アイドリングはあらかじめ読み込んでおく。
thisRef.preloadMotionGroup(LAppDefine.MOTION_GROUP_IDLE);
thisRef.mainMotionManager.stopAllMotions();
thisRef.setUpdating(false); // 更新状態の完了
thisRef.setInitialized(true); // 初期化完了
if (typeof callback == "function") callback();
}
});
}
});
});
};
/*
* GCだけで解放されないメモリを解放
*/
LAppModel.prototype.release = function(gl)
{
// this.live2DModel.deleteTextures();
var pm = Live2DFramework.getPlatformManager();
gl.deleteTexture(pm.texture);
};
/*
* モーションファイルをあらかじめ読み込む
*/
LAppModel.prototype.preloadMotionGroup = function(name)
{
var thisRef = this;
for (var i = 0; i < this.modelSetting.getMotionNum(name); i++)
{
var file = this.modelSetting.getMotionFile(name, i);
this.loadMotion(file, this.modelHomeDir + file, function(motion) {
motion.setFadeIn(thisRef.modelSetting.getMotionFadeIn(name, i));
motion.setFadeOut(thisRef.modelSetting.getMotionFadeOut(name, i));
});
}
};
LAppModel.prototype.update = function()
{
// console.log("--> LAppModel.update()");
if(this.live2DModel == null)
{
if (LAppDefine.DEBUG_LOG) console.error("Failed to update.");
return;
}
var timeMSec = UtSystem.getUserTimeMSec() - this.startTimeMSec;
var timeSec = timeMSec / 1000.0;
var t = timeSec * 2 * Math.PI; // 2πt
// 待機モーション判定
if (this.mainMotionManager.isFinished())
{
// モーションの再生がない場合、待機モーションの中からランダムで再生する
this.startRandomMotion(LAppDefine.MOTION_GROUP_IDLE, LAppDefine.PRIORITY_IDLE);
}
//-----------------------------------------------------------------
// 前回セーブされた状態をロード
this.live2DModel.loadParam();
/* インスタンスが作られていたら更新 */
var update = this.mainMotionManager.updateParam(this.live2DModel); // モーションを更新
if (!update) {
// 目ぱち
if(this.eyeBlink != null) {
this.eyeBlink.updateParam(this.live2DModel);
}
}
// 状態を保存
this.live2DModel.saveParam();
//-----------------------------------------------------------------
// 表情でパラメータ更新(相対変化)
if (this.expressionManager != null &&
this.expressions != null &&
!this.expressionManager.isFinished())
{
this.expressionManager.updateParam(this.live2DModel);
}
// ドラッグによる顔の向きの調整
// -30から30の値を加える
this.live2DModel.addToParamFloat("PARAM_ANGLE_X", this.dragX * 30, 1);
this.live2DModel.addToParamFloat("PARAM_ANGLE_Y", this.dragY * 30, 1);
this.live2DModel.addToParamFloat("PARAM_ANGLE_Z", (this.dragX * this.dragY) * -30, 1);
// ドラッグによる体の向きの調整
// -10から10の値を加える
this.live2DModel.addToParamFloat("PARAM_BODY_ANGLE_X", this.dragX*10, 1);
// ドラッグによる目の向きの調整
// -1から1の値を加える
this.live2DModel.addToParamFloat("PARAM_EYE_BALL_X", this.dragX, 1);
this.live2DModel.addToParamFloat("PARAM_EYE_BALL_Y", this.dragY, 1);
// 呼吸など
this.live2DModel.addToParamFloat("PARAM_ANGLE_X",
Number((15 * Math.sin(t / 6.5345))), 0.5);
this.live2DModel.addToParamFloat("PARAM_ANGLE_Y",
Number((8 * Math.sin(t / 3.5345))), 0.5);
this.live2DModel.addToParamFloat("PARAM_ANGLE_Z",
Number((10 * Math.sin(t / 5.5345))), 0.5);
this.live2DModel.addToParamFloat("PARAM_BODY_ANGLE_X",
Number((4 * Math.sin(t / 15.5345))), 0.5);
this.live2DModel.setParamFloat("PARAM_BREATH",
Number((0.5 + 0.5 * Math.sin(t / 3.2345))), 1);
// 物理演算
if (this.physics != null)
{
this.physics.updateParam(this.live2DModel); // 物理演算でパラメータ更新
}
// リップシンクの設定
if (this.lipSync == null)
{
this.live2DModel.setParamFloat("PARAM_MOUTH_OPEN_Y",
this.lipSyncValue);
}
// ポーズ
if( this.pose != null ) {
this.pose.updateParam(this.live2DModel);
}
this.live2DModel.update();
};
/*
* 表情をランダムに切り替える
*/
LAppModel.prototype.setRandomExpression = function()
{
var tmp = [];
for (var name in this.expressions)
{
tmp.push(name);
}
var no = parseInt(Math.random() * tmp.length);
this.setExpression(tmp[no]);
};
/*
* モーションをランダムで再生する
*/
LAppModel.prototype.startRandomMotion = function(name, priority)
{
var max = this.modelSetting.getMotionNum(name);
var no = parseInt(Math.random() * max);
this.startMotion(name, no, priority);
};
/*
* モーションの開始。
* 再生できる状態かチェックして、できなければ何もしない。
* 再生出来る場合は自動でファイルを読み込んで再生。
* 音声付きならそれも再生。
* フェードイン、フェードアウトの情報があればここで設定。なければ初期値。
*/
LAppModel.prototype.startMotion = function(name, no, priority)
{
// console.log("startMotion : " + name + " " + no + " " + priority);
var motionName = this.modelSetting.getMotionFile(name, no);
if (motionName == null || motionName == "")
{
if (LAppDefine.DEBUG_LOG)
console.error("Failed to motion.");
return;
}
if (priority == LAppDefine.PRIORITY_FORCE)
{
this.mainMotionManager.setReservePriority(priority);
}
else if (!this.mainMotionManager.reserveMotion(priority))
{
if (LAppDefine.DEBUG_LOG)
console.log("Motion is running.")
return;
}
var thisRef = this;
var motion;
if (this.motions[name] == null)
{
this.loadMotion(null, this.modelHomeDir + motionName, function(mtn) {
motion = mtn;
// フェードイン、フェードアウトの設定
thisRef.setFadeInFadeOut(name, no, priority, motion);
});
}
else
{
motion = this.motions[name];
// フェードイン、フェードアウトの設定
thisRef.setFadeInFadeOut(name, no, priority, motion);
}
};
LAppModel.prototype.setFadeInFadeOut = function(name, no, priority, motion)
{
var motionName = this.modelSetting.getMotionFile(name, no);
motion.setFadeIn(this.modelSetting.getMotionFadeIn(name, no));
motion.setFadeOut(this.modelSetting.getMotionFadeOut(name, no));
if (LAppDefine.DEBUG_LOG)
console.log("Start motion : " + motionName);
if (this.modelSetting.getMotionSound(name, no) == null)
{
this.mainMotionManager.startMotionPrio(motion, priority);
}
else
{
// naotaro modify start
// var soundName = this.modelSetting.getMotionSound(name, no);
// var player = new Sound(this.modelHomeDir + soundName);
// var snd = document.createElement("audio");
// snd = document.createElement("audio");
// snd.id = "voice0";
// snd.src = this.modelHomeDir + soundName;
// snd.load();
snd = document.createElement("audio");
soundName = this.modelSetting.getMotionSound(name, no);
soudfile = this.modelHomeDir + soundName;
// naotaro modify end
if (LAppDefine.DEBUG_LOG)
console.log("Start sound : " + soundName);
// naotaro delete start
// snd.play();
// naotaro delete end
this.mainMotionManager.startMotionPrio(motion, priority);
}
};
// naotaro add start
var snd;
var soundName;
var soudfile;
// naotaro add end
/*
* 表情を設定する
*/
LAppModel.prototype.setExpression = function(name)
{
var motion = this.expressions[name];
if (LAppDefine.DEBUG_LOG)
console.log("Expression : " + name);
this.expressionManager.startMotion(motion, false);
};
/*
* 描画
*/
LAppModel.prototype.draw = function(gl)
{
//console.log("--> LAppModel.draw()");
// if(this.live2DModel == null) return;
// 通常
MatrixStack.push();
MatrixStack.multMatrix(this.modelMatrix.getArray());
this.tmpMatrix = MatrixStack.getMatrix()
this.live2DModel.setMatrix(this.tmpMatrix);
this.live2DModel.draw();
MatrixStack.pop();
};
/*
* 当たり判定との簡易テスト。
* 指定IDの頂点リストからそれらを含む最大の矩形を計算し、点がそこに含まれるか判定
*/
LAppModel.prototype.hitTest = function(id, testX, testY)
{
var len = this.modelSetting.getHitAreaNum();
for (var i = 0; i < len; i++)
{
if (id == this.modelSetting.getHitAreaName(i))
{
var drawID = this.modelSetting.getHitAreaID(i);
return this.hitTestSimple(drawID, testX, testY);
}
}
return false; // 存在しない場合はfalse
};
iPhoneが手元にないので、iOSシュミレーターでしか試してないです。
これでお腹のあたりをクリックすると音声が再生されると思います。