From f76b6d162b98b1eaf886d548ab0acea46e6ec3f4 Mon Sep 17 00:00:00 2001 From: None <134219525+None-44@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:53:18 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat:=E4=BD=BF=E5=BE=97=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E6=8B=93=E5=B1=95=E8=AF=AD=E6=B3=95=E5=AF=B9=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E5=90=8D=E7=A7=B0=E6=9C=89=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.修改了showName类型以及相关引用 2.由于脚本中的第一个':'会被认为是角色名称与对话文本的分割,因此在对角色名称使用拓展文本语法时需要将‘:’替换为'~',再由代码对其进行替换 --- .../webgal/src/Stage/TextBox/IMSSTextbox.tsx | 133 +++++++++++------- packages/webgal/src/Stage/TextBox/TextBox.tsx | 6 +- .../legacy-standard/StandardTextbox.tsx | 38 +++-- packages/webgal/src/Stage/TextBox/types.ts | 2 +- packages/webgal/src/UI/Backlog/Backlog.tsx | 22 ++- .../Menu/Options/TextPreview/TextPreview.tsx | 2 +- 6 files changed, 135 insertions(+), 68 deletions(-) diff --git a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx index b6179a4a0..9e2cb92ca 100644 --- a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx @@ -41,6 +41,78 @@ export default function IMSSTextbox(props: ITextboxProps) { }, []); let allTextIndex = 0; + const nameElementList = showName.map((line, index)=>{ + const textline = line.map((en,index)=>{ + const e = en.reactNode; + let style = ''; + let tips = ''; + let style_alltext = ''; + if (en.enhancedValue) { + const data = en.enhancedValue; + console.log(data); + for (const dataElem of data) { + const { key, value } = dataElem; + switch (key) { + case 'style': + style = value; + break; + case 'tips': + tips = value; + break; + case 'style-alltext': + style_alltext = value; + break; + } + } + } + let prevLength = currentConcatDialogPrev.length; + const styleClassName = ' ' + css(style); + const styleAllText = ' ' + css(style_alltext); + if (index < prevLength) { + return ( + + + {e} + {e} + {isUseStroke && {e}} + + + ); + } + return ( + + + {e} + {e} + {isUseStroke && {e}} + + + ); + + }) + return ( +
+ {textline} +
+ ); + }); const textElementList = textArray.map((line, index) => { const textLine = line.map((en, index) => { const e = en.reactNode; @@ -159,53 +231,20 @@ export default function IMSSTextbox(props: ITextboxProps) { miniAvatar )} - {showName !== '' && ( - <> -
-
- {showName.split('').map((e, i) => { - return ( - - - {e} - {e} - {isUseStroke && {e}} - - - ); - })} -
-
-
- {showName.split('').map((e, i) => { - return ( - - - {e} - {e} - {isUseStroke && {e}} - - - ); - })} -
- + {showName !== null && ( +
+ {nameElementList} +
)}
{ .default(() => 2); // 拆字 const textArray = compileSentence(stageState.showText, lineLimit); - const showName = stageState.showName; + const showName = compileSentence(stageState.showName,lineLimit); const currentConcatDialogPrev = stageState.currentConcatDialogPrev; const currentDialogKey = stageState.currentDialogKey; const miniAvatar = stageState.miniAvatar; @@ -264,9 +264,9 @@ function parseEnhancedString(enhanced: string): KeyValuePair[] { while ((match = regex.exec(enhanced)) !== null) { result.push({ key: match[1], - value: match[2].trim(), + value: match[2].replace(/~/g,':').trim(), }); } return result; -} +} \ No newline at end of file diff --git a/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx b/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx index 33ca4f88b..adc0219ba 100644 --- a/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx @@ -38,7 +38,25 @@ export default function StandardTextbox(props: ITextboxProps) { WebGAL.events.textSettle.off(settleText); }; }, []); - + const nameElementList = showName.map((e,index)=>{ + let prevLength = currentConcatDialogPrev.length; + if (index < prevLength) { + return ( + + {e} + {e} + {isUseStroke && {e}} + + ); + } + return ( + + {e} + {e} + {isUseStroke && {e}} + + ); + }); const textElementList = textArray.map((e, index) => { // if (e === '
') { // return
; @@ -83,7 +101,7 @@ export default function StandardTextbox(props: ITextboxProps) { }); const padding = isHasMiniAvatar ? 500 : undefined; - const isHasName = showName !== ''; + const isHasName = showName !== null; let paddingTop = isHasName ? undefined : 15; if (textSizeState === textSize.small && !isHasName) { paddingTop = 35; @@ -114,19 +132,9 @@ export default function StandardTextbox(props: ITextboxProps) {
{miniAvatar !== '' && miniAvatar}
- {showName !== '' && ( -
- {showName.split('').map((e, i) => { - return ( - - - {e} - {e} - {isUseStroke && {e}} - - - ); - })} + {showName !== null && ( +
+ {nameElementList}
)}
{
); }); + const showNameArray = compileSentence(backlogItem.currentStageState.showName, 3, true); + const showNameArray2 = showNameArray.map((line)=>{ + return line.map((c) => { + return c.reactNode; + }); + }); + const showNameArrayReduced = mergeStringsAndKeepObjects(showNameArray2); + const nameElementList = showNameArrayReduced.map((line,index)=>{ + return ( +
+ {line.map((e, index) => { + if (e === '
') { + return
; + } else { + return e; + } + })} +
+ ); + }); const singleBacklogView = (
{
) : null}
-
{backlogItem.currentStageState.showName}
+
{nameElementList}
{showTextElementList} diff --git a/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx b/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx index d6d9e0459..a5fdb5f80 100644 --- a/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx +++ b/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx @@ -30,7 +30,7 @@ export const TextPreview = (props: any) => { textArray: previewTextArray, isText: true, textDelay: textDelay, - showName: t('textPreview.title'), + showName: compileSentence(t('textPreview.title'),3), currentConcatDialogPrev: '', fontSize: size, currentDialogKey: '', From 08bf35353de6184274e05ef3d0c7937791746de9 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Thu, 22 Aug 2024 23:13:20 +0800 Subject: [PATCH 02/15] fix: fig and bg live animation key --- .../webgal/src/Core/Modules/animationFunctions.ts | 10 ++++++---- packages/webgal/src/Stage/MainStage/useSetBg.ts | 12 +++++++----- packages/webgal/src/Stage/MainStage/useSetFigure.ts | 7 ++++--- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/webgal/src/Core/Modules/animationFunctions.ts b/packages/webgal/src/Core/Modules/animationFunctions.ts index 4c77e6e2b..e1cc14658 100644 --- a/packages/webgal/src/Core/Modules/animationFunctions.ts +++ b/packages/webgal/src/Core/Modules/animationFunctions.ts @@ -35,10 +35,12 @@ export function getAnimateDuration(animationName: string) { return 0; } +// eslint-disable-next-line max-params export function getEnterExitAnimation( target: string, type: 'enter' | 'exit', isBg = false, + realTarget?: string, // 用于立绘和背景移除时,以当前时间打上特殊标记 ): { duration: number; animation: { @@ -57,11 +59,11 @@ export function getEnterExitAnimation( setStartState: () => void; tickerFunc: (delta: number) => void; setEndState: () => void; - } | null = generateUniversalSoftInAnimationObj(target, duration); + } | null = generateUniversalSoftInAnimationObj(realTarget ?? target, duration); const animarionName = WebGAL.animationManager.nextEnterAnimationName.get(target); if (animarionName) { logger.debug('取代默认进入动画', target); - animation = getAnimationObject(animarionName, target, getAnimateDuration(animarionName)); + animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName)); duration = getAnimateDuration(animarionName); // 用后重置 WebGAL.animationManager.nextEnterAnimationName.delete(target); @@ -77,11 +79,11 @@ export function getEnterExitAnimation( setStartState: () => void; tickerFunc: (delta: number) => void; setEndState: () => void; - } | null = generateUniversalSoftOffAnimationObj(target, duration); + } | null = generateUniversalSoftOffAnimationObj(realTarget ?? target, duration); const animarionName = WebGAL.animationManager.nextExitAnimationName.get(target); if (animarionName) { logger.debug('取代默认退出动画', target); - animation = getAnimationObject(animarionName, target, getAnimateDuration(animarionName)); + animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName)); duration = getAnimateDuration(animarionName); // 用后重置 WebGAL.animationManager.nextExitAnimationName.delete(target); diff --git a/packages/webgal/src/Stage/MainStage/useSetBg.ts b/packages/webgal/src/Stage/MainStage/useSetBg.ts index 542ea447a..a292c0dd4 100644 --- a/packages/webgal/src/Stage/MainStage/useSetBg.ts +++ b/packages/webgal/src/Stage/MainStage/useSetBg.ts @@ -40,13 +40,15 @@ export function useSetBg(stageState: IStageState) { function removeBg(bgObject: IStageObject) { WebGAL.gameplay.pixiStage?.removeAnimationWithSetEffects('bg-main-softin'); const oldBgKey = bgObject.key; - bgObject.key = 'bg-main-off'; + bgObject.key = 'bg-main-off' + String(new Date().getTime()); + const bgKey = bgObject.key; + const bgAniKey = bgObject.key + '-softoff'; WebGAL.gameplay.pixiStage?.removeStageObjectByKey(oldBgKey); - const { duration, animation } = getEnterExitAnimation('bg-main-off', 'exit', true); - WebGAL.gameplay.pixiStage!.registerAnimation(animation, 'bg-main-softoff', 'bg-main-off'); + const { duration, animation } = getEnterExitAnimation('bg-main-off', 'exit', true, bgKey); + WebGAL.gameplay.pixiStage!.registerAnimation(animation, bgAniKey, bgKey); setTimeout(() => { - WebGAL.gameplay.pixiStage?.removeAnimation('bg-main-softoff'); - WebGAL.gameplay.pixiStage?.removeStageObjectByKey('bg-main-off'); + WebGAL.gameplay.pixiStage?.removeAnimation(bgAniKey); + WebGAL.gameplay.pixiStage?.removeStageObjectByKey(bgKey); }, duration); } diff --git a/packages/webgal/src/Stage/MainStage/useSetFigure.ts b/packages/webgal/src/Stage/MainStage/useSetFigure.ts index 9f9d91c47..425323a93 100644 --- a/packages/webgal/src/Stage/MainStage/useSetFigure.ts +++ b/packages/webgal/src/Stage/MainStage/useSetFigure.ts @@ -192,11 +192,12 @@ function removeFig(figObj: IStageObject, enterTikerKey: string, effects: IEffect return; } const oldFigKey = figObj.key; - figObj.key = figObj.key + '-off'; - WebGAL.gameplay.pixiStage?.removeStageObjectByKey(oldFigKey); + const figLeaveAniKey = oldFigKey + '-off'; + figObj.key = oldFigKey + String(new Date().getTime()) + '-off'; const figKey = figObj.key; + WebGAL.gameplay.pixiStage?.removeStageObjectByKey(oldFigKey); const leaveKey = figKey + '-softoff'; - const { duration, animation } = getEnterExitAnimation(figKey, 'exit'); + const { duration, animation } = getEnterExitAnimation(figLeaveAniKey, 'exit', false, figKey); WebGAL.gameplay.pixiStage!.registerPresetAnimation(animation, leaveKey, figKey, effects); setTimeout(() => { WebGAL.gameplay.pixiStage?.removeAnimation(leaveKey); From 64c6898451cbd0aa9e4baed0bf510227c84ce585 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Sun, 1 Sep 2024 01:39:31 +0800 Subject: [PATCH 03/15] feat: add simulate vocal animation --- packages/webgal/src/Core/gameScripts/say.ts | 50 ++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/webgal/src/Core/gameScripts/say.ts b/packages/webgal/src/Core/gameScripts/say.ts index 9048c4365..84eeafd97 100644 --- a/packages/webgal/src/Core/gameScripts/say.ts +++ b/packages/webgal/src/Core/gameScripts/say.ts @@ -9,6 +9,8 @@ import { getSentenceArgByKey } from '@/Core/util/getSentenceArg'; import { textSize, voiceOption } from '@/store/userDataInterface'; import { WebGAL } from '@/Core/WebGAL'; import { compileSentence } from '@/Stage/TextBox/TextBox'; +import { performMouthAnimation } from '@/Core/gameScripts/vocal/vocalAnimation'; +import { match } from '@/Core/util/match'; /** * 进行普通对话的显示 @@ -84,9 +86,52 @@ export const say = (sentence: ISentence): IPerform => { } dispatch(setStage({ key: 'showName', value: showName })); + // 模拟说话 + let performSimulateVocalTimeout: ReturnType | null = null; + let performSimulateVocalDelay = 0; + let pos = ''; + let key = ''; + for (const e of sentence.args) { + if (e.value === true) { + match(e.key) + .with('left', () => { + pos = 'left'; + }) + .with('right', () => { + pos = 'right'; + }) + .endsWith('center', () => { + pos = 'center'; + }); + } + if (e.key === 'figureId') { + key = `${e.value.toString()}`; + } + } // 播放一段语音 if (vocal) { playVocal(sentence); + } else if (key || pos) { + const figureId = String(getSentenceArgByKey(sentence, 'figureId')); + performSimulateVocalDelay = len * 250; + const performSimulateVocal = () => { + const audioLevel = Math.random() * 100; + const currentStageState = webgalStore.getState().stage; + const figureAssociatedAnimation = currentStageState.figureAssociatedAnimation; + const animationItem = figureAssociatedAnimation.find((tid) => tid.targetId === figureId); + performMouthAnimation({ + audioLevel, + OPEN_THRESHOLD: 50, + HALF_OPEN_THRESHOLD: 25, + currentMouthValue: 0, + lerpSpeed: 1, + key: figureId ? figureId : `fig-${pos}`, + animationItem, + pos, + }); + performSimulateVocalTimeout = setTimeout(performSimulateVocal, 250); + }; + performSimulateVocal(); } const performInitName: string = getRandomPerformName(); @@ -98,10 +143,13 @@ export const say = (sentence: ISentence): IPerform => { return { performName: performInitName, - duration: sentenceDelay + endDelay, + duration: sentenceDelay + endDelay + performSimulateVocalDelay, isHoldOn: false, stopFunction: () => { WebGAL.events.textSettle.emit(); + if (performSimulateVocalTimeout) { + clearTimeout(performSimulateVocalTimeout); + } }, blockingNext: () => false, blockingAuto: () => true, From 77e20d83575c5bf92a3ec724cfee804c1ae12304 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Sun, 1 Sep 2024 01:53:20 +0800 Subject: [PATCH 04/15] update simulate argo --- packages/webgal/src/Core/gameScripts/say.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/webgal/src/Core/gameScripts/say.ts b/packages/webgal/src/Core/gameScripts/say.ts index 84eeafd97..ec03c7395 100644 --- a/packages/webgal/src/Core/gameScripts/say.ts +++ b/packages/webgal/src/Core/gameScripts/say.ts @@ -112,20 +112,26 @@ export const say = (sentence: ISentence): IPerform => { if (vocal) { playVocal(sentence); } else if (key || pos) { - const figureId = String(getSentenceArgByKey(sentence, 'figureId')); performSimulateVocalDelay = len * 250; + let audioLevel = Math.random() * 100; const performSimulateVocal = () => { - const audioLevel = Math.random() * 100; + let nextAudioLevel = audioLevel + (Math.random() * 60 - 30); // 在 -30 到 +30 之间波动 + // 确保波动幅度不小于 5 + if (Math.abs(nextAudioLevel - audioLevel) < 5) { + nextAudioLevel = audioLevel + Math.sign(nextAudioLevel - audioLevel) * 5; + } + // 确保结果在 0 到 100 之间 + audioLevel = Math.max(0, Math.min(nextAudioLevel, 100)); const currentStageState = webgalStore.getState().stage; const figureAssociatedAnimation = currentStageState.figureAssociatedAnimation; - const animationItem = figureAssociatedAnimation.find((tid) => tid.targetId === figureId); + const animationItem = figureAssociatedAnimation.find((tid) => tid.targetId === key); performMouthAnimation({ audioLevel, OPEN_THRESHOLD: 50, HALF_OPEN_THRESHOLD: 25, currentMouthValue: 0, lerpSpeed: 1, - key: figureId ? figureId : `fig-${pos}`, + key: key ? key : `fig-${pos}`, animationItem, pos, }); From 664168e49539636ccb079c2234f58f3a993954a9 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Sun, 1 Sep 2024 02:18:51 +0800 Subject: [PATCH 05/15] fix: simulation algo --- packages/webgal/src/Core/gameScripts/say.ts | 53 +++++++++++---------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/webgal/src/Core/gameScripts/say.ts b/packages/webgal/src/Core/gameScripts/say.ts index ec03c7395..90a2eb7da 100644 --- a/packages/webgal/src/Core/gameScripts/say.ts +++ b/packages/webgal/src/Core/gameScripts/say.ts @@ -108,35 +108,39 @@ export const say = (sentence: ISentence): IPerform => { key = `${e.value.toString()}`; } } + let audioLevel = 80; + const performSimulateVocal = (end = false) => { + let nextAudioLevel = audioLevel + (Math.random() * 60 - 30); // 在 -30 到 +30 之间波动 + // 确保波动幅度不小于 5 + if (Math.abs(nextAudioLevel - audioLevel) < 5) { + nextAudioLevel = audioLevel + Math.sign(nextAudioLevel - audioLevel) * 5; + } + // 确保结果在 25 到 100 之间 + audioLevel = Math.max(15, Math.min(nextAudioLevel, 100)); + const currentStageState = webgalStore.getState().stage; + const figureAssociatedAnimation = currentStageState.figureAssociatedAnimation; + const animationItem = figureAssociatedAnimation.find((tid) => tid.targetId === key); + const targetKey = key ? key : `fig-${pos}`; + if (end) { + audioLevel = 0; + } + performMouthAnimation({ + audioLevel, + OPEN_THRESHOLD: 50, + HALF_OPEN_THRESHOLD: 25, + currentMouthValue: 0, + lerpSpeed: 1, + key: targetKey, + animationItem, + pos, + }); + if (!end) performSimulateVocalTimeout = setTimeout(performSimulateVocal, 50); + }; // 播放一段语音 if (vocal) { playVocal(sentence); } else if (key || pos) { performSimulateVocalDelay = len * 250; - let audioLevel = Math.random() * 100; - const performSimulateVocal = () => { - let nextAudioLevel = audioLevel + (Math.random() * 60 - 30); // 在 -30 到 +30 之间波动 - // 确保波动幅度不小于 5 - if (Math.abs(nextAudioLevel - audioLevel) < 5) { - nextAudioLevel = audioLevel + Math.sign(nextAudioLevel - audioLevel) * 5; - } - // 确保结果在 0 到 100 之间 - audioLevel = Math.max(0, Math.min(nextAudioLevel, 100)); - const currentStageState = webgalStore.getState().stage; - const figureAssociatedAnimation = currentStageState.figureAssociatedAnimation; - const animationItem = figureAssociatedAnimation.find((tid) => tid.targetId === key); - performMouthAnimation({ - audioLevel, - OPEN_THRESHOLD: 50, - HALF_OPEN_THRESHOLD: 25, - currentMouthValue: 0, - lerpSpeed: 1, - key: key ? key : `fig-${pos}`, - animationItem, - pos, - }); - performSimulateVocalTimeout = setTimeout(performSimulateVocal, 250); - }; performSimulateVocal(); } @@ -154,6 +158,7 @@ export const say = (sentence: ISentence): IPerform => { stopFunction: () => { WebGAL.events.textSettle.emit(); if (performSimulateVocalTimeout) { + performSimulateVocal(true); clearTimeout(performSimulateVocalTimeout); } }, From 9b85b7c1825439779984cb1f37a0bb25606e17d0 Mon Sep 17 00:00:00 2001 From: None <134219525+None-44@users.noreply.github.com> Date: Tue, 3 Sep 2024 18:02:36 +0800 Subject: [PATCH 06/15] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=A7=93=E5=90=8D?= =?UTF-8?q?=E6=A1=86=E9=94=99=E8=AF=AF=E6=98=BE=E7=A4=BA=E5=B9=B6=E6=94=B9?= =?UTF-8?q?=E6=AD=A3=E8=A7=92=E8=89=B2=E5=90=8D=E7=A7=B0=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1,解决没有角色名称依旧会出现姓名框 2,由于使用角色名称默认样式时改变颜色的拓展文本语法无法生效,因此当使用拓展文本语法时将使用与文本相同的样式 3,目前无法复现角色名称闪烁 --- .../webgal/src/Stage/TextBox/IMSSTextbox.tsx | 56 ++++++++++--------- packages/webgal/src/Stage/TextBox/TextBox.tsx | 2 + .../legacy-standard/StandardTextbox.tsx | 4 +- packages/webgal/src/Stage/TextBox/types.ts | 1 + .../Menu/Options/TextPreview/TextPreview.tsx | 6 +- 5 files changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx index 9e2cb92ca..5507a31b1 100644 --- a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx @@ -16,6 +16,7 @@ export default function IMSSTextbox(props: ITextboxProps) { isFirefox: boolean, fontSize, miniAvatar, + isHasName, showName, font, textDuration, @@ -39,7 +40,6 @@ export default function IMSSTextbox(props: ITextboxProps) { WebGAL.events.textSettle.off(settleText); }; }, []); - let allTextIndex = 0; const nameElementList = showName.map((line, index)=>{ const textline = line.map((en,index)=>{ @@ -47,7 +47,9 @@ export default function IMSSTextbox(props: ITextboxProps) { let style = ''; let tips = ''; let style_alltext = ''; + let isEnhanced = false; if (en.enhancedValue) { + isEnhanced = true; const data = en.enhancedValue; console.log(data); for (const dataElem of data) { @@ -65,16 +67,13 @@ export default function IMSSTextbox(props: ITextboxProps) { } } } - let prevLength = currentConcatDialogPrev.length; const styleClassName = ' ' + css(style); const styleAllText = ' ' + css(style_alltext); - if (index < prevLength) { + if(isEnhanced){ return ( {e} @@ -86,19 +85,16 @@ export default function IMSSTextbox(props: ITextboxProps) { } return ( {e} - {e} - {isUseStroke && {e}} + {e} + {isUseStroke && {e}} ); - }) return (
)}
- {showName !== null && ( -
+
+ {nameElementList} +
+
- {nameElementList} -
+ > + {nameElementList} +
+ )}
{ .default(() => 2); // 拆字 const textArray = compileSentence(stageState.showText, lineLimit); + const isHasName = stageState.showName !== ''; const showName = compileSentence(stageState.showName,lineLimit); const currentConcatDialogPrev = stageState.currentConcatDialogPrev; const currentDialogKey = stageState.currentDialogKey; @@ -79,6 +80,7 @@ export const TextBox = () => { isText={isText} textDelay={textDelay} showName={showName} + isHasName={isHasName} currentConcatDialogPrev={currentConcatDialogPrev} fontSize={size} currentDialogKey={currentDialogKey} diff --git a/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx b/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx index adc0219ba..465b918bb 100644 --- a/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/legacy-themes/legacy-standard/StandardTextbox.tsx @@ -15,6 +15,7 @@ export default function StandardTextbox(props: ITextboxProps) { isFirefox, fontSize, miniAvatar, + isHasName, showName, font, textDuration, @@ -101,7 +102,6 @@ export default function StandardTextbox(props: ITextboxProps) { }); const padding = isHasMiniAvatar ? 500 : undefined; - const isHasName = showName !== null; let paddingTop = isHasName ? undefined : 15; if (textSizeState === textSize.small && !isHasName) { paddingTop = 35; @@ -132,7 +132,7 @@ export default function StandardTextbox(props: ITextboxProps) {
{miniAvatar !== '' && miniAvatar}
- {showName !== null && ( + {isHasName && (
{nameElementList}
diff --git a/packages/webgal/src/Stage/TextBox/types.ts b/packages/webgal/src/Stage/TextBox/types.ts index fe1e53845..59e41e126 100644 --- a/packages/webgal/src/Stage/TextBox/types.ts +++ b/packages/webgal/src/Stage/TextBox/types.ts @@ -11,6 +11,7 @@ export interface ITextboxProps { fontSize: string; miniAvatar: string; showName: EnhancedNode[][]; + isHasName: boolean; font: string; textDuration: number; textSizeState: number; diff --git a/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx b/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx index a5fdb5f80..4e8bbc4d3 100644 --- a/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx +++ b/packages/webgal/src/UI/Menu/Options/TextPreview/TextPreview.tsx @@ -23,6 +23,9 @@ export const TextPreview = (props: any) => { const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent); const previewText = t('textPreview.text'); const previewTextArray = compileSentence(previewText, 3); + const showNameText = t('textPreview.title'); + const showNameArray = compileSentence(showNameText, 3); + const isHasName = showNameText !== ''; const Textbox = IMSSTextbox; @@ -30,7 +33,8 @@ export const TextPreview = (props: any) => { textArray: previewTextArray, isText: true, textDelay: textDelay, - showName: compileSentence(t('textPreview.title'),3), + isHasName: isHasName, + showName: showNameArray, currentConcatDialogPrev: '', fontSize: size, currentDialogKey: '', From e38ab42256f3d4004f116a4a0e9b79274e710030 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Fri, 6 Sep 2024 20:31:28 +0800 Subject: [PATCH 07/15] feat: can override bounds --- packages/webgal/package.json | 2 +- .../controller/stage/pixi/PixiController.ts | 20 +++++++++++-- .../src/Core/gameScripts/changeFigure.ts | 29 ++++++++++++++++--- packages/webgal/src/store/stageInterface.ts | 1 + packages/webgal/src/store/stageReducer.ts | 5 ++-- yarn.lock | 8 ++--- 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/packages/webgal/package.json b/packages/webgal/package.json index cf884027a..6e8d459a4 100644 --- a/packages/webgal/package.json +++ b/packages/webgal/package.json @@ -21,7 +21,7 @@ "mitt": "^3.0.0", "modern-css-reset": "^1.4.0", "pixi-filters": "^4.2.0", - "pixi-live2d-display-webgal": "^0.5.2", + "pixi-live2d-display-webgal": "^0.5.8", "pixi-spine": "^3.1.2", "pixi.js": "^6.3.0", "popmotion": "^11.0.5", diff --git a/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts b/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts index 33b310834..4a191af6c 100644 --- a/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts +++ b/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts @@ -12,7 +12,7 @@ import 'pixi-spine'; // Do this once at the very start of your code. This regist import { Spine } from 'pixi-spine'; import { SCREEN_CONSTANTS } from '@/Core/util/constants'; // import { figureCash } from '@/Core/gameScripts/vocal/conentsCash'; // 如果要使用 Live2D,取消这里的注释 -// import { Live2DModel, SoundManager } from 'pixi-live2d-display'; // 如果要使用 Live2D,取消这里的注释 +// import { Live2DModel, SoundManager } from 'pixi-live2d-display-webgal'; // 如果要使用 Live2D,取消这里的注释 export interface IAnimationObject { setStartState: Function; @@ -689,7 +689,23 @@ export default class PixiStage { // const setup = () => { // if (thisFigureContainer) { // (async function () { - // const models = await Promise.all([Live2DModel.from(jsonPath, { autoInteract: false })]); + // let overrideBounds: [number, number, number, number] = [0, 0, 0, 0]; + // const mot = webgalStore.getState().stage.live2dMotion.find((e) => e.target === key); + // if (mot?.overrideBounds) { + // overrideBounds = mot.overrideBounds; + // } + // console.log(overrideBounds); + // const models = await Promise.all([ + // Live2DModel.from(jsonPath, { + // autoInteract: false, + // overWriteBounds: { + // x0: overrideBounds[0], + // y0: overrideBounds[1], + // x1: overrideBounds[2], + // y1: overrideBounds[3], + // }, + // }), + // ]); // // models.forEach((model) => { // const scaleX = stageWidth / model.width; diff --git a/packages/webgal/src/Core/gameScripts/changeFigure.ts b/packages/webgal/src/Core/gameScripts/changeFigure.ts index a662159cd..92deb9e5b 100644 --- a/packages/webgal/src/Core/gameScripts/changeFigure.ts +++ b/packages/webgal/src/Core/gameScripts/changeFigure.ts @@ -33,6 +33,7 @@ export function changeFigure(sentence: ISentence): IPerform { let animationFlag: any = ''; let mouthAnimationKey: any = 'mouthAnimation'; let eyesAnimationKey: any = 'blinkAnimation'; + let overrideBounds = ''; const dispatch = webgalStore.dispatch; for (const e of sentence.args) { @@ -63,6 +64,9 @@ export function changeFigure(sentence: ISentence): IPerform { case 'motion': motion = e.value.toString(); break; + case 'bounds': + overrideBounds = String(e.value); + break; case 'expression': expression = e.value.toString(); break; @@ -215,8 +219,10 @@ export function changeFigure(sentence: ISentence): IPerform { */ const freeFigureItem: IFreeFigure = { key, name: content, basePosition: pos }; setAnimationNames(key, sentence); - if (motion) { - dispatch(stageActions.setLive2dMotion({ target: key, motion })); + if (motion || overrideBounds) { + dispatch( + stageActions.setLive2dMotion({ target: key, motion, overrideBounds: getOverrideBoundsArr(overrideBounds) }), + ); } if (expression) { dispatch(stageActions.setLive2dExpression({ target: key, expression })); @@ -236,8 +242,10 @@ export function changeFigure(sentence: ISentence): IPerform { key = positionMap[pos]; setAnimationNames(key, sentence); - if (motion) { - dispatch(stageActions.setLive2dMotion({ target: key, motion })); + if (motion || overrideBounds) { + dispatch( + stageActions.setLive2dMotion({ target: key, motion, overrideBounds: getOverrideBoundsArr(overrideBounds) }), + ); } if (expression) { dispatch(stageActions.setLive2dExpression({ target: key, expression })); @@ -255,3 +263,16 @@ export function changeFigure(sentence: ISentence): IPerform { stopTimeout: undefined, // 暂时不用,后面会交给自动清除 }; } + +function getOverrideBoundsArr(raw: string): undefined | [number, number, number, number] { + const parseOverrideBoundsResult = raw.split(',').map((e) => Number(e)); + let isPass = true; + parseOverrideBoundsResult.forEach((e) => { + if (isNaN(e)) { + isPass = false; + } + }); + isPass = isPass && parseOverrideBoundsResult.length === 4; + if (isPass) return parseOverrideBoundsResult as [number, number, number, number]; + else return undefined; +} diff --git a/packages/webgal/src/store/stageInterface.ts b/packages/webgal/src/store/stageInterface.ts index 51273975c..ea611ce70 100644 --- a/packages/webgal/src/store/stageInterface.ts +++ b/packages/webgal/src/store/stageInterface.ts @@ -108,6 +108,7 @@ export interface IRunPerform { export interface ILive2DMotion { target: string; motion: string; + overrideBounds?: [number, number, number, number]; } export interface ILive2DExpression { diff --git a/packages/webgal/src/store/stageReducer.ts b/packages/webgal/src/store/stageReducer.ts index 37c9abb1a..e53b604f3 100644 --- a/packages/webgal/src/store/stageReducer.ts +++ b/packages/webgal/src/store/stageReducer.ts @@ -154,16 +154,17 @@ const stageSlice = createSlice({ } }, setLive2dMotion: (state, action: PayloadAction) => { - const { target, motion } = action.payload; + const { target, motion, overrideBounds } = action.payload; const index = state.live2dMotion.findIndex((e) => e.target === target); if (index < 0) { // Add a new motion - state.live2dMotion.push({ target, motion }); + state.live2dMotion.push({ target, motion, overrideBounds }); } else { // Update the existing motion state.live2dMotion[index].motion = motion; + state.live2dMotion[index].overrideBounds = overrideBounds; } }, setLive2dExpression: (state, action: PayloadAction) => { diff --git a/yarn.lock b/yarn.lock index 89362fd36..74f5bb3bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4255,10 +4255,10 @@ pixi-filters@^4.2.0: "@pixi/filter-twist" "4.2.0" "@pixi/filter-zoom-blur" "4.2.0" -pixi-live2d-display-webgal@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/pixi-live2d-display-webgal/-/pixi-live2d-display-webgal-0.5.2.tgz#a9153e39540a92293b91ccff8b106908415cfc52" - integrity sha512-XWI9Ev4OOB0cmve5RPdKP22LjjB7RdF2GkgRv55A3hEJgMvueuU4IZ5wBDuLYqHwiVxeWA/gTMycj7vyDCyn1g== +pixi-live2d-display-webgal@^0.5.8: + version "0.5.8" + resolved "https://registry.yarnpkg.com/pixi-live2d-display-webgal/-/pixi-live2d-display-webgal-0.5.8.tgz#1ff7b5016559ff56a5cfaa96abeac84c878a2bbf" + integrity sha512-yekmPckXykqziyFcmmgYlZU4ad42rRGGmUFvrm96YJrdRIi+V9uv/xKOrRBMxD/tr3Sckqp6hOr9Wi3UX6NNLw== dependencies: gh-pages "^4.0.0" From 3fd1b193a61c117bc4f846b6c76065faee46f2ad Mon Sep 17 00:00:00 2001 From: Mahiru Date: Mon, 9 Sep 2024 01:06:12 +0800 Subject: [PATCH 08/15] fix: enhance value do not effect when at first of line --- .../webgal/src/Stage/TextBox/IMSSTextbox.tsx | 38 ++++++++----------- packages/webgal/src/Stage/TextBox/TextBox.tsx | 11 ++++-- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx index 5507a31b1..413dcb6e2 100644 --- a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx @@ -41,8 +41,8 @@ export default function IMSSTextbox(props: ITextboxProps) { }; }, []); let allTextIndex = 0; - const nameElementList = showName.map((line, index)=>{ - const textline = line.map((en,index)=>{ + const nameElementList = showName.map((line, index) => { + const textline = line.map((en, index) => { const e = en.reactNode; let style = ''; let tips = ''; @@ -51,7 +51,6 @@ export default function IMSSTextbox(props: ITextboxProps) { if (en.enhancedValue) { isEnhanced = true; const data = en.enhancedValue; - console.log(data); for (const dataElem of data) { const { key, value } = dataElem; switch (key) { @@ -67,27 +66,21 @@ export default function IMSSTextbox(props: ITextboxProps) { } } } - const styleClassName = ' ' + css(style); - const styleAllText = ' ' + css(style_alltext); - if(isEnhanced){ + const styleClassName = ' ' + css(style, { label: 'showname' }); + const styleAllText = ' ' + css(style_alltext, { label: 'showname' }); + if (isEnhanced) { return ( - + {e} - {e} - {isUseStroke && {e}} + {e} + {isUseStroke && {e}} ); } return ( - + {e} {e} @@ -95,7 +88,7 @@ export default function IMSSTextbox(props: ITextboxProps) { ); - }) + }); return (
- {nameElementList} + {nameElementList}
{nameElementList}
diff --git a/packages/webgal/src/Stage/TextBox/TextBox.tsx b/packages/webgal/src/Stage/TextBox/TextBox.tsx index 216ad0b14..7e6edcb88 100644 --- a/packages/webgal/src/Stage/TextBox/TextBox.tsx +++ b/packages/webgal/src/Stage/TextBox/TextBox.tsx @@ -68,7 +68,7 @@ export const TextBox = () => { // 拆字 const textArray = compileSentence(stageState.showText, lineLimit); const isHasName = stageState.showName !== ''; - const showName = compileSentence(stageState.showName,lineLimit); + const showName = compileSentence(stageState.showName, lineLimit); const currentConcatDialogPrev = stageState.currentConcatDialogPrev; const currentDialogKey = stageState.currentDialogKey; const miniAvatar = stageState.miniAvatar; @@ -137,7 +137,7 @@ export function compileSentence(sentence: string, lineLimit: number, ignoreLineL * @param sentence */ export function splitChars(sentence: string) { - if (!sentence) return []; + if (!sentence) return ['']; const words: string[] = []; let word = ''; let cjkFlag = isCJK(sentence[0]); @@ -250,6 +250,9 @@ function parseString(input: string): Segment[] { } } + // 我也不知道为什么,不加这个就会导致在 Enhanced Value 处于行首时故障 + // 你可以认为这个代码不明所以,但是不要删除 + result.unshift({ type: SegmentType.String, value: '' }); return result; } @@ -266,9 +269,9 @@ function parseEnhancedString(enhanced: string): KeyValuePair[] { while ((match = regex.exec(enhanced)) !== null) { result.push({ key: match[1], - value: match[2].replace(/~/g,':').trim(), + value: match[2].replace(/~/g, ':').trim(), }); } return result; -} \ No newline at end of file +} From 3e80091043b6b846512d94392f03ccf4bb402264 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Thu, 19 Sep 2024 22:08:02 +0800 Subject: [PATCH 09/15] fix: check stage obj exist when update effects --- packages/webgal/src/Core/constants.ts | 6 ++++++ packages/webgal/src/store/stageReducer.ts | 10 ++++++++++ 2 files changed, 16 insertions(+) create mode 100644 packages/webgal/src/Core/constants.ts diff --git a/packages/webgal/src/Core/constants.ts b/packages/webgal/src/Core/constants.ts new file mode 100644 index 000000000..82132f84e --- /dev/null +++ b/packages/webgal/src/Core/constants.ts @@ -0,0 +1,6 @@ +export const STAGE_KEYS = { + BGMAIN: 'bg-main', + FIG_C: 'fig-center', + FIG_L: 'fig-left', + FIG_R: 'fig-right', +}; diff --git a/packages/webgal/src/store/stageReducer.ts b/packages/webgal/src/store/stageReducer.ts index 37c9abb1a..730f652a8 100644 --- a/packages/webgal/src/store/stageReducer.ts +++ b/packages/webgal/src/store/stageReducer.ts @@ -16,6 +16,7 @@ import { import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import cloneDeep from 'lodash/cloneDeep'; import { commandType } from '@/Core/controller/scene/sceneInterface'; +import { STAGE_KEYS } from '@/Core/constants'; // 初始化舞台数据 @@ -92,6 +93,15 @@ const stageSlice = createSlice({ }, updateEffect: (state, action: PayloadAction) => { const { target, transform } = action.payload; + // 如果找不到目标,不能设置 transform + const activeTargets = [ + STAGE_KEYS.BGMAIN, + STAGE_KEYS.FIG_C, + STAGE_KEYS.FIG_L, + STAGE_KEYS.FIG_R, + ...state.freeFigure.map((figure) => figure.key), + ]; + if (!activeTargets.includes(target)) return; // 尝试找到待修改的 Effect const effectIndex = state.effects.findIndex((e) => e.target === target); if (effectIndex >= 0) { From 6eea82fa3b9d81cbbf32f83d2fd6d930e32872a8 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Tue, 15 Oct 2024 21:32:51 +0800 Subject: [PATCH 10/15] feat: set figure z-index use argument `zIndex` --- .../controller/stage/pixi/PixiController.ts | 26 ++++++++++++++++++- .../src/Core/gameScripts/changeFigure.ts | 20 +++++++++++--- packages/webgal/src/store/stageInterface.ts | 7 +++++ packages/webgal/src/store/stageReducer.ts | 20 ++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts b/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts index 4a191af6c..1bd5a72a6 100644 --- a/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts +++ b/packages/webgal/src/Core/controller/stage/pixi/PixiController.ts @@ -3,7 +3,7 @@ import { v4 as uuid } from 'uuid'; import { webgalStore } from '@/store/store'; import { setStage, stageActions } from '@/store/stageReducer'; import cloneDeep from 'lodash/cloneDeep'; -import { IEffect, IFigureAssociatedAnimation } from '@/store/stageInterface'; +import { IEffect, IFigureAssociatedAnimation, IFigureMetadata } from '@/store/stageInterface'; import { logger } from '@/Core/util/logger'; import { isIOS } from '@/Core/initializeScript'; import { WebGALPixiContainer } from '@/Core/controller/stage/pixi/WebGALPixiContainer'; @@ -125,6 +125,7 @@ export default class PixiStage { this.effectsContainer = new PIXI.Container(); this.effectsContainer.zIndex = 3; this.figureContainer = new PIXI.Container(); + this.figureContainer.sortableChildren = true; // 允许立绘启用 z-index this.figureContainer.zIndex = 2; this.backgroundContainer = new PIXI.Container(); this.backgroundContainer.zIndex = 0; @@ -493,6 +494,12 @@ export default class PixiStage { this.removeStageObjectByKey(key); } + const metadata = this.getFigureMetadataByKey(key); + if (metadata) { + if (metadata.zIndex) { + thisFigureContainer.zIndex = metadata.zIndex; + } + } // 挂载 this.figureContainer.addChild(thisFigureContainer); const figureUuid = uuid(); @@ -578,6 +585,12 @@ export default class PixiStage { this.removeStageObjectByKey(key); } + const metadata = this.getFigureMetadataByKey(key); + if (metadata) { + if (metadata.zIndex) { + thisFigureContainer.zIndex = metadata.zIndex; + } + } // 挂载 this.figureContainer.addChild(thisFigureContainer); const figureUuid = uuid(); @@ -673,6 +686,12 @@ export default class PixiStage { // this.removeStageObjectByKey(key); // } // + // const metadata = this.getFigureMetadataByKey(key); + // if (metadata) { + // if (metadata.zIndex) { + // thisFigureContainer.zIndex = metadata.zIndex; + // } + // } // // 挂载 // this.figureContainer.addChild(thisFigureContainer); // this.figureObjects.push({ @@ -978,6 +997,11 @@ export default class PixiStage { private getExtName(url: string) { return url.split('.').pop() ?? 'png'; } + + private getFigureMetadataByKey(key: string): IFigureMetadata | undefined { + console.log(key, webgalStore.getState().stage.figureMetaData); + return webgalStore.getState().stage.figureMetaData[key]; + } } function updateCurrentBacklogEffects(newEffects: IEffect[]) { diff --git a/packages/webgal/src/Core/gameScripts/changeFigure.ts b/packages/webgal/src/Core/gameScripts/changeFigure.ts index 92deb9e5b..bad8e7201 100644 --- a/packages/webgal/src/Core/gameScripts/changeFigure.ts +++ b/packages/webgal/src/Core/gameScripts/changeFigure.ts @@ -34,6 +34,7 @@ export function changeFigure(sentence: ISentence): IPerform { let mouthAnimationKey: any = 'mouthAnimation'; let eyesAnimationKey: any = 'blinkAnimation'; let overrideBounds = ''; + let zIndex = -1; const dispatch = webgalStore.dispatch; for (const e of sentence.args) { @@ -96,6 +97,9 @@ export function changeFigure(sentence: ISentence): IPerform { case 'none': content = ''; break; + case 'zIndex': + zIndex = Number(e.value); + break; default: break; } @@ -157,6 +161,9 @@ export function changeFigure(sentence: ISentence): IPerform { const deleteKey2 = `${key}`; webgalStore.dispatch(stageActions.removeEffectByTargetId(deleteKey)); webgalStore.dispatch(stageActions.removeEffectByTargetId(deleteKey2)); + // 重设 figureMetaData,这里是 zIndex,实际上任何键都可以,因为整体是移除那条记录 + dispatch(stageActions.setFigureMetaData([deleteKey, 'zIndex', 0, true])); + dispatch(stageActions.setFigureMetaData([deleteKey2, 'zIndex', 0, true])); } const setAnimationNames = (key: string, sentence: ISentence) => { // 处理 transform 和 默认 transform @@ -212,10 +219,8 @@ export function changeFigure(sentence: ISentence): IPerform { } }; if (isFreeFigure) { - const currentFreeFigures = webgalStore.getState().stage.freeFigure; - /** - * 重设 + * 下面的代码是设置自由立绘的 */ const freeFigureItem: IFreeFigure = { key, name: content, basePosition: pos }; setAnimationNames(key, sentence); @@ -227,8 +232,14 @@ export function changeFigure(sentence: ISentence): IPerform { if (expression) { dispatch(stageActions.setLive2dExpression({ target: key, expression })); } + if (zIndex > 0) { + dispatch(stageActions.setFigureMetaData([key, 'zIndex', zIndex, false])); + } dispatch(stageActions.setFreeFigureByKey(freeFigureItem)); } else { + /** + * 下面的代码是设置与位置关联的立绘的 + */ const positionMap = { center: 'fig-center', left: 'fig-left', @@ -250,6 +261,9 @@ export function changeFigure(sentence: ISentence): IPerform { if (expression) { dispatch(stageActions.setLive2dExpression({ target: key, expression })); } + if (zIndex > 0) { + dispatch(stageActions.setFigureMetaData([key, 'zIndex', zIndex, false])); + } dispatch(setStage({ key: dispatchMap[pos], value: content })); } diff --git a/packages/webgal/src/store/stageInterface.ts b/packages/webgal/src/store/stageInterface.ts index ea611ce70..e1f7633b7 100644 --- a/packages/webgal/src/store/stageInterface.ts +++ b/packages/webgal/src/store/stageInterface.ts @@ -116,6 +116,12 @@ export interface ILive2DExpression { expression: string; } +export interface IFigureMetadata { + zIndex?: number; +} + +type figureMetaData = Record; + /** * @interface IStageState 游戏舞台数据接口 */ @@ -159,6 +165,7 @@ export interface IStageState { enableFilm: string; isDisableTextbox: boolean; replacedUIlable: Record; + figureMetaData: figureMetaData; } /** diff --git a/packages/webgal/src/store/stageReducer.ts b/packages/webgal/src/store/stageReducer.ts index 4ab0d4bc4..964f2a6b3 100644 --- a/packages/webgal/src/store/stageReducer.ts +++ b/packages/webgal/src/store/stageReducer.ts @@ -5,6 +5,7 @@ import { IEffect, + IFigureMetadata, IFreeFigure, ILive2DExpression, ILive2DMotion, @@ -57,6 +58,7 @@ export const initState: IStageState = { enableFilm: '', isDisableTextbox: false, replacedUIlable: {}, + figureMetaData: {}, }; /** @@ -193,6 +195,24 @@ const stageSlice = createSlice({ replaceUIlable: (state, action: PayloadAction<[string, string]>) => { state.replacedUIlable[action.payload[0]] = action.payload[1]; }, + /** + * 设置 figure 元数据 [立绘 key, metadata key, 值, 是否重设] + * @param state + * @param action + */ + setFigureMetaData: (state, action: PayloadAction<[string, keyof IFigureMetadata, any, undefined | boolean]>) => { + // 立绘退出,重设 + if (action.payload[3]) { + if (state.figureMetaData[action.payload[0]]) delete state.figureMetaData[action.payload[0]]; + } else { + console.log('yeah'); + // 初始化对象 + if (!state.figureMetaData[action.payload[0]]) { + state.figureMetaData[action.payload[0]] = {}; + } + state.figureMetaData[action.payload[0]][action.payload[1]] = action.payload[2]; + } + }, }, }); From d5f5d0a59f8af89f9b5a85a1eb5d218bf7b632aa Mon Sep 17 00:00:00 2001 From: RinPV2 Date: Thu, 17 Oct 2024 21:49:04 +0900 Subject: [PATCH 11/15] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=8C=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E6=98=BE=E7=A4=BA=E6=8E=92=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.把所有字都向下对齐 2.固定行距保证无论这行有没有拼音都会显示在同样的高度 --- packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx | 2 ++ .../webgal/src/Stage/TextBox/textbox.module.scss | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx index 413dcb6e2..46e5e4b3f 100644 --- a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx @@ -175,6 +175,7 @@ export default function IMSSTextbox(props: ITextboxProps) { wordBreak: isSafari || props.isFirefox ? 'break-all' : undefined, display: isSafari ? 'flex' : undefined, flexWrap: isSafari ? 'wrap' : undefined, + height: '2.2em', //这里是为了让每一行都有一个固定的高度,不然会出现高度不一致的情况 }} key={`text-line-${index}`} > @@ -251,6 +252,7 @@ export default function IMSSTextbox(props: ITextboxProps) { flexFlow: 'column', overflow: 'hidden', paddingLeft: '0.1em', + lineHeight: '3em', //不加的话上半拼音可能会被截断,同时保持排版整齐 }} > {textElementList} diff --git a/packages/webgal/src/Stage/TextBox/textbox.module.scss b/packages/webgal/src/Stage/TextBox/textbox.module.scss index eaf84accc..480afc70d 100644 --- a/packages/webgal/src/Stage/TextBox/textbox.module.scss +++ b/packages/webgal/src/Stage/TextBox/textbox.module.scss @@ -73,11 +73,10 @@ $height: 330px; opacity: 0; } + .outer { position: absolute; white-space: nowrap; - left: 0; - top: 0; //background-image: linear-gradient(rgba(255, 255, 255, 1) 0%, rgb(225, 237, 255) 100%); background-image: linear-gradient(#0B346E 0%, //#f5f7fa 45%, @@ -87,21 +86,26 @@ $height: 330px; -webkit-background-clip: text; color: transparent; z-index: 2; + display: inline-block; /* 与文本对齐 */ + vertical-align: middle; /* 确保注音整体的垂直居中 */ } .inner { white-space: nowrap; position: absolute; - left: 0; - top: 0; -webkit-text-stroke: 0.1em rgba(255, 255, 255, 1); z-index: 1; //text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.75); + display: inline-block; /* 内层元素同样行内块布局 */ + vertical-align: middle; /* 确保与外层的对齐一致 */ } .zhanwei { color: transparent; white-space: nowrap; + display: inline-block; /* 保持行内块布局 */ + vertical-align: baseline; /* 确保文本基线对齐 */ + position: relative; /* 保持相对定位 */ } // @@ -116,6 +120,8 @@ $height: 330px; position: relative; @include text_shadow_textElement; opacity: 1; + display: inline-flex; + align-content: space-between } // From 5181a3debc925eb0f718f08a09047cf74c96382e Mon Sep 17 00:00:00 2001 From: Mahiru Date: Tue, 22 Oct 2024 22:21:14 +0800 Subject: [PATCH 12/15] fix: remove line height limit of single segment of line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这里的行是逻辑的行,实际上是可能换行的。另外,也稍微修改了字体大小。 --- packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx | 5 +++-- packages/webgal/src/Stage/TextBox/TextBox.tsx | 2 +- packages/webgal/src/UI/getTextSize.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx index 46e5e4b3f..9381649cc 100644 --- a/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx +++ b/packages/webgal/src/Stage/TextBox/IMSSTextbox.tsx @@ -4,6 +4,7 @@ import { WebGAL } from '@/Core/WebGAL'; import { ITextboxProps } from './types'; import useApplyStyle from '@/hooks/useApplyStyle'; import { css } from '@emotion/css'; +import { textSize } from '@/store/userDataInterface'; export default function IMSSTextbox(props: ITextboxProps) { const { @@ -22,6 +23,7 @@ export default function IMSSTextbox(props: ITextboxProps) { textDuration, isUseStroke, textboxOpacity, + textSizeState, } = props; const applyStyle = useApplyStyle('Stage/TextBox/textbox.scss'); @@ -175,7 +177,6 @@ export default function IMSSTextbox(props: ITextboxProps) { wordBreak: isSafari || props.isFirefox ? 'break-all' : undefined, display: isSafari ? 'flex' : undefined, flexWrap: isSafari ? 'wrap' : undefined, - height: '2.2em', //这里是为了让每一行都有一个固定的高度,不然会出现高度不一致的情况 }} key={`text-line-${index}`} > @@ -252,7 +253,7 @@ export default function IMSSTextbox(props: ITextboxProps) { flexFlow: 'column', overflow: 'hidden', paddingLeft: '0.1em', - lineHeight: '3em', //不加的话上半拼音可能会被截断,同时保持排版整齐 + lineHeight: textSizeState === textSize.medium ? '2.2em' : '2em', // 不加的话上半拼音可能会被截断,同时保持排版整齐 }} > {textElementList} diff --git a/packages/webgal/src/Stage/TextBox/TextBox.tsx b/packages/webgal/src/Stage/TextBox/TextBox.tsx index 7e6edcb88..9e33b072d 100644 --- a/packages/webgal/src/Stage/TextBox/TextBox.tsx +++ b/packages/webgal/src/Stage/TextBox/TextBox.tsx @@ -60,7 +60,7 @@ export const TextBox = () => { size = getTextSize(stageState.showTextSize) + '%'; textSizeState = stageState.showTextSize; } - const lineLimit = match(userDataState.optionData.textSize) + const lineLimit = match(textSizeState) .with(textSize.small, () => 3) .with(textSize.medium, () => 2) .with(textSize.large, () => 2) diff --git a/packages/webgal/src/UI/getTextSize.ts b/packages/webgal/src/UI/getTextSize.ts index bdad545c2..85824bc0b 100644 --- a/packages/webgal/src/UI/getTextSize.ts +++ b/packages/webgal/src/UI/getTextSize.ts @@ -1,11 +1,11 @@ export function getTextSize(size: number) { switch (size) { case 0: - return 150; + return 155; case 1: return 205; case 2: - return 240; + return 230; default: return 205; } From fe03456ae20d747a7f4bee50fc2cd94b87a2dbb5 Mon Sep 17 00:00:00 2001 From: Mahiru Date: Tue, 22 Oct 2024 22:26:43 +0800 Subject: [PATCH 13/15] fix: basic style of .TextBox_textElement should be same. --- packages/webgal/src/Stage/TextBox/textbox.module.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/webgal/src/Stage/TextBox/textbox.module.scss b/packages/webgal/src/Stage/TextBox/textbox.module.scss index 480afc70d..e26491867 100644 --- a/packages/webgal/src/Stage/TextBox/textbox.module.scss +++ b/packages/webgal/src/Stage/TextBox/textbox.module.scss @@ -71,6 +71,8 @@ $height: 330px; position: relative; animation: TextDelayShow 1000ms ease-out forwards; opacity: 0; + display: inline-flex; + align-content: space-between } From 29a685ab9a1a04e73f354bcfc61a30cec6161f8e Mon Sep 17 00:00:00 2001 From: Mahiru Date: Sat, 26 Oct 2024 00:26:56 +0800 Subject: [PATCH 14/15] fix: temporary disable source map --- packages/webgal/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webgal/vite.config.ts b/packages/webgal/vite.config.ts index 725a227b0..0fb7f4bbe 100644 --- a/packages/webgal/vite.config.ts +++ b/packages/webgal/vite.config.ts @@ -58,6 +58,6 @@ export default defineConfig({ }, }, build: { - sourcemap: true, + // sourcemap: true, }, }); From 71a7e85c17ff872c6138e0bfd23ea976008dcffa Mon Sep 17 00:00:00 2001 From: Mahiru Date: Mon, 28 Oct 2024 21:06:54 +0800 Subject: [PATCH 15/15] update version --- packages/webgal/package.json | 2 +- .../webgal/public/game/template/template.json | 2 +- packages/webgal/src/config/info.ts | 2 +- releasenote.md | 92 +++++-------------- 4 files changed, 27 insertions(+), 71 deletions(-) diff --git a/packages/webgal/package.json b/packages/webgal/package.json index 0ddf9fa16..6a62bf813 100644 --- a/packages/webgal/package.json +++ b/packages/webgal/package.json @@ -1,7 +1,7 @@ { "name": "webgal", "private": true, - "version": "4.5.7", + "version": "4.5.8", "scripts": { "dev": "vite --host --port 3000", "build": "cross-env NODE_ENV=production tsc && vite build --base=./", diff --git a/packages/webgal/public/game/template/template.json b/packages/webgal/public/game/template/template.json index ea42e4120..f0934b9a3 100644 --- a/packages/webgal/public/game/template/template.json +++ b/packages/webgal/public/game/template/template.json @@ -1,4 +1,4 @@ { "name":"Default Template", - "webgal-version":"4.5.7" + "webgal-version":"4.5.8" } diff --git a/packages/webgal/src/config/info.ts b/packages/webgal/src/config/info.ts index dc89641af..f3171e664 100644 --- a/packages/webgal/src/config/info.ts +++ b/packages/webgal/src/config/info.ts @@ -1,5 +1,5 @@ export const __INFO = { - version: 'WebGAL 4.5.7', + version: 'WebGAL 4.5.8', contributors: [ // 现在改为跳转到 GitHub 了 ], diff --git a/releasenote.md b/releasenote.md index 6a9a3ac66..10bcad7e3 100644 --- a/releasenote.md +++ b/releasenote.md @@ -8,36 +8,21 @@ #### 新功能 -新增参数,用于控制 “在本条语句的演出结束后,执行下一条”。 +文本拓展语法对角色名称生效 -#### 修复 - -4.5.7 修复:无法从状态中获取到对应 key 的变量时,返回 {key} 以避免变换不生效 - -修复了 `-concat` 选项动画在新行中的错误。 - -修复了样式定义时 ruby 不显示的问题。 - -修复了 intro 的 hold 问题。 - -修复了 say 延迟计算问题。 - -修复了 restoreScene 中的竞争状态。 +模拟口型同步 -修复了删除已关闭的自由图形的问题。 +允许修改 Live2D 绘制范围 -修复了变量值处理的问题。 +允许设定立绘的 z-index -修复了 setVar 进行 compile 字符串时异常的问题。 - -增强了 getValueFromState。 - -调整了对 `style-alltext` 键的正则匹配,使其可以触发文本框的样式修改。 +#### 修复 -修复了变量正则表达式的问题。 +修复了文本增强语法在首行不生效的问题 -修复了 logo 图片的问题。 +优化为立绘应用效果的性能 +优化立绘进出场效果的性能 ## Release Notes @@ -50,36 +35,21 @@ #### New Features -Added a new parameter to control "execute the next statement after the performance of this statement is finished". - -#### Bug Fixes - -4.5.7 Fix: When the corresponding key variable cannot be obtained from the state, return {key} to avoid ineffective transformation. - -Fixed an animation error with the `-concat` option in a new line. - -Fixed an issue where ruby was not displayed when a style was defined. +Text extension syntax now affects character names -Fixed the hold problem of intro. +Simulate lip sync -Fixed the say delay calculation problem. +Allow modification of Live2D drawing range -Fixed a race condition in restoreScene. +Allow setting the z-index of the character sprite -Fixed an issue with deleting closed free figures. +#### Fixes -Fixed the variable value handling problem. +Fixed the issue where text enhancement syntax did not take effect on the first line -Fixed an exception when setVar compiled a string. - -Enhanced getValueFromState. - -Adjusted the regular expression matching for the `style-alltext` key to allow it to trigger text box style modifications. - -Fixed the variable regular expression problem. - -Fixed the logo image issue. +Optimized the performance of applying effects to character sprites +Optimized the performance of character sprite entry and exit effects ## リリースノート @@ -92,32 +62,18 @@ Fixed the logo image issue. #### 新機能 -「このステートメントの演出終了後に次のステートメントを実行する」を制御するための新しいパラメータが追加されました。 - -#### 修正 - -4.5.7 修正:状態から対応する key の変数が取得できない場合、{key} を返すようにし、変換が無効になるのを回避しました +テキスト拡張文法がキャラクタ名に有効になった -`-concat` オプションのアニメーションが新しい行でエラーになる問題を修正しました。 +口パク同期 -スタイルが定義されているときにルビが表示されない問題を修正しました。 +Live2D の描画範囲変更が可能になった -イントロのホールド問題を修正しました。 +立ち絵の z-index 設定が可能になった -say 遅延計算の問題を修正しました。 - -restoreScene の競合状態を修正しました。 - -閉じたフリーフィギュアを削除する際の問題を修正しました。 - -変数値処理の問題を修正しました。 - -setVar が文字列をコンパイルする際の例外を修正しました。 - -getValueFromState を強化しました。 +#### 修正 -`style-alltext` キーの正規表現マッチングを調整し、テキストボックスのスタイル変更をトリガーできるようにしました。 +テキスト拡張文法が先頭行に有効にならない問題を修正 -変数正規表現の問題を修正しました。 +立ち絵にエフェクトを適用する時のパフォーマンスを最適化 -ロゴ画像の問題を修正しました。 +立ち絵の登場・退場エフェクトのパフォーマンスを最適化