Animate VN mode expression changes

This commit is contained in:
Cohee
2023-07-07 19:09:53 +03:00
parent 0d5cdcd0b1
commit 57ee954ad5

View File

@@ -152,7 +152,7 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
const path = currentSpritePath || defaultSpritePath || ''; const path = currentSpritePath || defaultSpritePath || '';
const img = expressionImage.find('img'); const img = expressionImage.find('img');
setImage(img, path); await setImage(img, path);
} }
expressionImage.toggleClass('hidden', noSprites); expressionImage.toggleClass('hidden', noSprites);
} else { } else {
@@ -163,7 +163,7 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
$('#visual-novel-wrapper').append(template); $('#visual-novel-wrapper').append(template);
dragElement($(template[0])); dragElement($(template[0]));
template.toggleClass('hidden', noSprites); template.toggleClass('hidden', noSprites);
setImage(template.find('img'), defaultSpritePath || ''); await setImage(template.find('img'), defaultSpritePath || '');
const fadeInPromise = new Promise(resolve => { const fadeInPromise = new Promise(resolve => {
template.fadeIn(250, () => resolve()); template.fadeIn(250, () => resolve());
}); });
@@ -284,7 +284,9 @@ async function setLastMessageSprite(img, avatar, labels) {
} }
} }
function setImage(img, path) { async function setImage(img, path) {
// Cohee: If something goes wrong, uncomment this to return to the old behavior
/*
img.attr('src', path); img.attr('src', path);
img.removeClass('default'); img.removeClass('default');
img.off('error'); img.off('error');
@@ -293,6 +295,66 @@ function setImage(img, path) {
$(this).off('error'); $(this).off('error');
$(this).attr('src', ''); $(this).attr('src', '');
}); });
*/
return new Promise(resolve => {
const prevExpressionSrc = img.attr('src');
const expressionClone = img.clone();
const originalId = img.attr('id');
//only swap expressions when necessary
if (prevExpressionSrc !== path && !img.hasClass('expression-animating')) {
//clone expression
expressionClone.addClass('expression-clone')
//make invisible and remove id to prevent double ids
//must be made invisible to start because they share the same Z-index
expressionClone.attr('id', '').css({ opacity: 0 });
//add new sprite path to clone src
expressionClone.attr('src', path);
//add invisible clone to html
expressionClone.appendTo(img.parent());
const duration = 200;
//add animation flags to both images
//to prevent multiple expression changes happening simultaneously
img.addClass('expression-animating')
//position absolute prevent the original from jumping around during transition
img.css('position', 'absolute')
expressionClone.addClass('expression-animating')
//fade the clone in
expressionClone.css({
opacity: 0
}).animate({
opacity: 1
}, duration)
//when finshed fading in clone, fade out the original
.promise().done(function () {
img.animate({
opacity: 0
}, duration);
//remove old expression
img.remove();
//replace ID so it becomes the new 'original' expression for next change
expressionClone.attr('id', originalId);
expressionClone.removeClass('expression-animating');
resolve();
});
expressionClone.removeClass('expression-clone');
expressionClone.removeClass('default');
expressionClone.off('error');
expressionClone.on('error', function () {
console.debug('Expression image error', sprite.path);
$(this).attr('src', '');
$(this).off('error');
resolve();
});
} else {
resolve();
}
});
} }
function onExpressionsShowDefaultInput() { function onExpressionsShowDefaultInput() {
@@ -640,7 +702,7 @@ async function setExpression(character, expression, force) {
} }
if (groupMember.name == character) { if (groupMember.name == character) {
setImage($(`.expression-holder[data-avatar="${member}"] img`), sprite.path); await setImage($(`.expression-holder[data-avatar="${member}"] img`), sprite.path);
return; return;
} }
} }