248 lines
6.8 KiB
JavaScript
248 lines
6.8 KiB
JavaScript
// 表情库系统
|
|
const ExpressionLibrary = {
|
|
expressions: {
|
|
// 原有表情
|
|
smile: {
|
|
name: '微笑',
|
|
blendShapes: {
|
|
mouthsmileleft: 0.4,
|
|
mouthsmileright: 0.4
|
|
},
|
|
duration: 2000
|
|
},
|
|
|
|
disgust: {
|
|
name: '嫌弃',
|
|
blendShapes: {
|
|
mouthupperupright: 0.43,
|
|
browdownleft: 1,
|
|
browdownright: 1,
|
|
nosesneerleft: 1,
|
|
nosesneerright: 1
|
|
},
|
|
duration: 2500
|
|
},
|
|
|
|
smirk: {
|
|
name: '冷笑',
|
|
blendShapes: {
|
|
eyeblinkleft: 0.41,
|
|
eyeblinkright: 0.41,
|
|
mouthsmileleft: 0.3
|
|
},
|
|
duration: 2000
|
|
},
|
|
|
|
grit: {
|
|
name: '咬牙切齿',
|
|
blendShapes: {
|
|
mouthrolllower: 0.3,
|
|
mouthrollupper: 0.44,
|
|
mouthshruglower: 0.42,
|
|
mouthshrugupper: 0.44,
|
|
browdownleft: 1,
|
|
browdownright: 1,
|
|
nosesneerleft: 1,
|
|
nosesneerright: 1
|
|
},
|
|
duration: 2500
|
|
},
|
|
|
|
// 新增表情
|
|
surprise: {
|
|
name: '惊讶',
|
|
blendShapes: {
|
|
eyewidenleft: 0.8,
|
|
eyewidenright: 0.8,
|
|
browouterupright: 0.7,
|
|
browouterupleft: 0.7,
|
|
jawopen: 0.4,
|
|
mouthfunnel: 0.3
|
|
},
|
|
duration: 2000
|
|
},
|
|
|
|
sad: {
|
|
name: '悲伤',
|
|
blendShapes: {
|
|
browinnerup: 0.8,
|
|
mouthfrownleft: 0.6,
|
|
mouthfrownright: 0.6,
|
|
mouthlowerdownleft: 0.4,
|
|
mouthlowerdownright: 0.4
|
|
},
|
|
duration: 3000
|
|
},
|
|
|
|
angry: {
|
|
name: '生气',
|
|
blendShapes: {
|
|
browdownleft: 1,
|
|
browdownright: 1,
|
|
eyesquintleft: 0.5,
|
|
eyesquintright: 0.5,
|
|
nosesneerleft: 0.7,
|
|
nosesneerright: 0.7,
|
|
mouthpressleft: 0.6,
|
|
mouthpressright: 0.6
|
|
},
|
|
duration: 2500
|
|
},
|
|
|
|
thinking: {
|
|
name: '思考',
|
|
blendShapes: {
|
|
eyesquintleft: 0.3,
|
|
eyesquintright: 0.3,
|
|
mouthpucker: 0.4,
|
|
eyelookupleft: 0.3,
|
|
eyelookupright: 0.3
|
|
},
|
|
duration: 3000
|
|
},
|
|
|
|
happy: {
|
|
name: '开心',
|
|
blendShapes: {
|
|
mouthsmileleft: 0.8,
|
|
mouthsmileright: 0.8,
|
|
eyesquintleft: 0.4,
|
|
eyesquintright: 0.4,
|
|
cheeksquintleft: 0.6,
|
|
cheeksquintright: 0.6
|
|
},
|
|
duration: 2500
|
|
},
|
|
|
|
confused: {
|
|
name: '困惑',
|
|
blendShapes: {
|
|
browouterupleft: 0.6,
|
|
browdownright: 0.5,
|
|
mouthfrownleft: 0.3,
|
|
eyesquintright: 0.3
|
|
},
|
|
duration: 2500
|
|
}
|
|
},
|
|
|
|
// 随机表情播放器
|
|
randomPlayer: {
|
|
enabled: false,
|
|
timeout: null,
|
|
currentExpression: null,
|
|
intervalMin: 3000,
|
|
intervalMax: 8000,
|
|
|
|
start: function() {
|
|
this.enabled = true;
|
|
this.scheduleNext();
|
|
},
|
|
|
|
stop: function() {
|
|
this.enabled = false;
|
|
if (this.timeout) {
|
|
clearTimeout(this.timeout);
|
|
this.timeout = null;
|
|
}
|
|
this.reset();
|
|
},
|
|
|
|
scheduleNext: function() {
|
|
if (!this.enabled) return;
|
|
|
|
const delay = this.intervalMin + Math.random() * (this.intervalMax - this.intervalMin);
|
|
this.timeout = setTimeout(() => {
|
|
this.playRandom();
|
|
}, delay);
|
|
},
|
|
|
|
playRandom: function() {
|
|
if (!this.enabled) return;
|
|
|
|
// 获取启用的表情列表
|
|
const enabledKeys = window.enabledExpressions && window.enabledExpressions.size > 0
|
|
? Array.from(window.enabledExpressions)
|
|
: Object.keys(ExpressionLibrary.expressions);
|
|
|
|
if (enabledKeys.length === 0) {
|
|
this.scheduleNext();
|
|
return;
|
|
}
|
|
|
|
const randomKey = enabledKeys[Math.floor(Math.random() * enabledKeys.length)];
|
|
const expression = ExpressionLibrary.expressions[randomKey];
|
|
|
|
this.play(expression);
|
|
},
|
|
|
|
play: function(expression) {
|
|
this.currentExpression = expression;
|
|
|
|
// 从主页面获取动画速度参数
|
|
const speed = window.expressionParams?.speed || 400;
|
|
|
|
// 应用表情
|
|
for (const [name, value] of Object.entries(expression.blendShapes)) {
|
|
if (window.setIdleAnimation) {
|
|
window.setIdleAnimation(name, value, speed, 'easeInOutCubic');
|
|
}
|
|
}
|
|
|
|
// 获取表情的key
|
|
const expressionKey = Object.keys(ExpressionLibrary.expressions).find(
|
|
key => ExpressionLibrary.expressions[key] === expression
|
|
);
|
|
|
|
// 使用用户设置的持续时间,如果没有则使用表情默认时间
|
|
const duration = (window.expressionDurations && window.expressionDurations[expressionKey])
|
|
|| expression.duration;
|
|
|
|
setTimeout(() => {
|
|
this.reset();
|
|
this.scheduleNext();
|
|
}, duration);
|
|
},
|
|
|
|
reset: function() {
|
|
if (!this.currentExpression) return;
|
|
|
|
// 从主页面获取参数
|
|
const speed = window.expressionParams?.speed || 400;
|
|
|
|
// 重置表情
|
|
for (const name of Object.keys(this.currentExpression.blendShapes)) {
|
|
if (window.setIdleAnimation) {
|
|
window.setIdleAnimation(name, 0, speed + 100, 'easeInOutCubic');
|
|
}
|
|
}
|
|
|
|
this.currentExpression = null;
|
|
}
|
|
},
|
|
|
|
// 手动播放指定表情
|
|
playExpression: function(expressionName) {
|
|
const expression = this.expressions[expressionName];
|
|
if (!expression) {
|
|
console.warn(`表情 "${expressionName}" 不存在`);
|
|
return;
|
|
}
|
|
|
|
this.randomPlayer.play(expression);
|
|
},
|
|
|
|
// 获取所有表情名称
|
|
getExpressionNames: function() {
|
|
return Object.keys(this.expressions).map(key => ({
|
|
key: key,
|
|
name: this.expressions[key].name
|
|
}));
|
|
}
|
|
};
|
|
|
|
// 导出到全局
|
|
if (typeof window !== 'undefined') {
|
|
window.ExpressionLibrary = ExpressionLibrary;
|
|
}
|