live2d-widgets
Version:
Live2D widget for web pages
258 lines (257 loc) • 12.1 kB
JavaScript
import { L2DBaseModel, Live2DFramework, L2DEyeBlink } from './Live2DFramework.js';
import ModelSettingJson from './utils/ModelSettingJson.js';
import LAppDefine from './LAppDefine.js';
import MatrixStack from './utils/MatrixStack.js';
import logger from '../logger.js';
class LAppModel extends L2DBaseModel {
constructor() {
super();
this.modelHomeDir = '';
this.modelSetting = null;
this.tmpMatrix = [];
}
loadJSON(callback) {
const path = this.modelHomeDir + this.modelSetting.getModelFile();
this.loadModelData(path, model => {
for (let i = 0; i < this.modelSetting.getTextureNum(); i++) {
const texPaths = this.modelHomeDir + this.modelSetting.getTextureFile(i);
this.loadTexture(i, texPaths, () => {
if (this.isTexLoaded) {
if (this.modelSetting.getExpressionNum() > 0) {
this.expressions = {};
for (let j = 0; j < this.modelSetting.getExpressionNum(); j++) {
const expName = this.modelSetting.getExpressionName(j);
const expFilePath = this.modelHomeDir +
this.modelSetting.getExpressionFile(j);
this.loadExpression(expName, expFilePath);
}
}
else {
this.expressionManager = null;
this.expressions = {};
}
if (this.eyeBlink == null) {
this.eyeBlink = new L2DEyeBlink();
}
if (this.modelSetting.getPhysicsFile() != null) {
this.loadPhysics(this.modelHomeDir + this.modelSetting.getPhysicsFile());
}
else {
this.physics = null;
}
if (this.modelSetting.getPoseFile() != null) {
this.loadPose(this.modelHomeDir + this.modelSetting.getPoseFile(), () => {
this.pose.updateParam(this.live2DModel);
});
}
else {
this.pose = null;
}
if (this.modelSetting.getLayout() != null) {
const layout = this.modelSetting.getLayout();
if (layout['width'] != null)
this.modelMatrix.setWidth(layout['width']);
if (layout['height'] != null)
this.modelMatrix.setHeight(layout['height']);
if (layout['x'] != null)
this.modelMatrix.setX(layout['x']);
if (layout['y'] != null)
this.modelMatrix.setY(layout['y']);
if (layout['center_x'] != null)
this.modelMatrix.centerX(layout['center_x']);
if (layout['center_y'] != null)
this.modelMatrix.centerY(layout['center_y']);
if (layout['top'] != null)
this.modelMatrix.top(layout['top']);
if (layout['bottom'] != null)
this.modelMatrix.bottom(layout['bottom']);
if (layout['left'] != null)
this.modelMatrix.left(layout['left']);
if (layout['right'] != null)
this.modelMatrix.right(layout['right']);
}
for (let j = 0; j < this.modelSetting.getInitParamNum(); j++) {
this.live2DModel.setParamFloat(this.modelSetting.getInitParamID(j), this.modelSetting.getInitParamValue(j));
}
for (let j = 0; j < this.modelSetting.getInitPartsVisibleNum(); j++) {
this.live2DModel.setPartsOpacity(this.modelSetting.getInitPartsVisibleID(j), this.modelSetting.getInitPartsVisibleValue(j));
}
this.live2DModel.saveParam();
this.preloadMotionGroup(LAppDefine.MOTION_GROUP_IDLE);
this.mainMotionManager.stopAllMotions();
this.setUpdating(false);
this.setInitialized(true);
if (typeof callback == 'function')
callback();
}
});
}
});
}
async loadModelSetting(modelSettingPath, modelSetting) {
this.setUpdating(true);
this.setInitialized(false);
this.modelHomeDir = modelSettingPath.substring(0, modelSettingPath.lastIndexOf('/') + 1);
this.modelSetting = new ModelSettingJson();
this.modelSetting.json = modelSetting;
await new Promise(resolve => this.loadJSON(resolve));
}
load(gl, modelSettingPath, callback) {
this.setUpdating(true);
this.setInitialized(false);
this.modelHomeDir = modelSettingPath.substring(0, modelSettingPath.lastIndexOf('/') + 1);
this.modelSetting = new ModelSettingJson();
this.modelSetting.loadModelSetting(modelSettingPath, () => {
this.loadJSON(callback);
});
}
release(gl) {
const pm = Live2DFramework.getPlatformManager();
gl.deleteTexture(pm.texture);
}
preloadMotionGroup(name) {
for (let i = 0; i < this.modelSetting.getMotionNum(name); i++) {
const file = this.modelSetting.getMotionFile(name, i);
this.loadMotion(file, this.modelHomeDir + file, motion => {
motion.setFadeIn(this.modelSetting.getMotionFadeIn(name, i));
motion.setFadeOut(this.modelSetting.getMotionFadeOut(name, i));
});
}
}
update() {
if (this.live2DModel == null) {
logger.error('Failed to update.');
return;
}
const timeMSec = UtSystem.getUserTimeMSec() - this.startTimeMSec;
const timeSec = timeMSec / 1000.0;
const t = timeSec * 2 * Math.PI;
if (this.mainMotionManager.isFinished()) {
this.startRandomMotion(LAppDefine.MOTION_GROUP_IDLE, LAppDefine.PRIORITY_IDLE);
}
this.live2DModel.loadParam();
const 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);
}
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);
this.live2DModel.addToParamFloat('PARAM_BODY_ANGLE_X', this.dragX * 10, 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();
}
setRandomExpression() {
const tmp = [];
for (const name in this.expressions) {
tmp.push(name);
}
const no = parseInt(Math.random() * tmp.length);
this.setExpression(tmp[no]);
}
startRandomMotion(name, priority) {
const max = this.modelSetting.getMotionNum(name);
const no = parseInt(Math.random() * max);
this.startMotion(name, no, priority);
}
startMotion(name, no, priority) {
const motionName = this.modelSetting.getMotionFile(name, no);
if (motionName == null || motionName == '') {
return;
}
if (priority == LAppDefine.PRIORITY_FORCE) {
this.mainMotionManager.setReservePriority(priority);
}
else if (!this.mainMotionManager.reserveMotion(priority)) {
logger.trace('Motion is running.');
return;
}
let motion;
if (this.motions[name] == null) {
this.loadMotion(null, this.modelHomeDir + motionName, mtn => {
motion = mtn;
this.setFadeInFadeOut(name, no, priority, motion);
});
}
else {
motion = this.motions[name];
this.setFadeInFadeOut(name, no, priority, motion);
}
}
setFadeInFadeOut(name, no, priority, motion) {
const motionName = this.modelSetting.getMotionFile(name, no);
motion.setFadeIn(this.modelSetting.getMotionFadeIn(name, no));
motion.setFadeOut(this.modelSetting.getMotionFadeOut(name, no));
logger.trace('Start motion : ' + motionName);
if (this.modelSetting.getMotionSound(name, no) == null) {
this.mainMotionManager.startMotionPrio(motion, priority);
}
else {
const soundName = this.modelSetting.getMotionSound(name, no);
const snd = document.createElement('audio');
snd.src = this.modelHomeDir + soundName;
logger.trace('Start sound : ' + soundName);
snd.play();
this.mainMotionManager.startMotionPrio(motion, priority);
}
}
setExpression(name) {
var _b;
const motion = this.expressions[name];
logger.trace('Expression : ' + name);
(_b = this.expressionManager) === null || _b === void 0 ? void 0 : _b.startMotion(motion, false);
}
draw(gl) {
MatrixStack.push();
MatrixStack.multMatrix(this.modelMatrix.getArray());
this.tmpMatrix = MatrixStack.getMatrix();
this.live2DModel.setMatrix(this.tmpMatrix);
this.live2DModel.draw();
MatrixStack.pop();
}
hitTest(id, testX, testY) {
const len = this.modelSetting.getHitAreaNum();
if (len == 0) {
const hitAreasCustom = this.modelSetting.getHitAreaCustom();
if (hitAreasCustom) {
const x = hitAreasCustom[id + '_x'];
const y = hitAreasCustom[id + '_y'];
if (testX > Math.min(...x) && testX < Math.max(...x) &&
testY > Math.min(...y) && testY < Math.max(...y)) {
return true;
}
}
}
for (let i = 0; i < len; i++) {
if (id == this.modelSetting.getHitAreaName(i)) {
const drawID = this.modelSetting.getHitAreaID(i);
return this.hitTestSimple(drawID, testX, testY);
}
}
return false;
}
}
export default LAppModel;