Skip to content

Commit dbfe5fd

Browse files
Merge branch 'dev'
2 parents 9a6629a + fd35764 commit dbfe5fd

File tree

4 files changed

+61
-86
lines changed

4 files changed

+61
-86
lines changed

packages/webgal/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "webgal-engine",
3-
"version": "4.5.15",
3+
"version": "4.5.15-1",
44
"scripts": {
55
"dev": "vite --host --port 3000",
66
"build": "cross-env NODE_ENV=production tsc && vite build --base=./",

packages/webgal/src/Core/controller/stage/pixi/animations/universalSoftIn.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,26 @@ export function generateUniversalSoftInAnimationObj(targetKey: string, duration:
44
const target = WebGAL.gameplay.pixiStage!.getStageObjByKey(targetKey);
55
let elapsedTime = 0;
66

7-
// 先设置一个通用的初态
7+
// 新增变量,用于存储动画开始时的初始透明度
8+
let startAlpha = 0;
9+
810
/**
911
* 在此书写为动画设置初态的操作
1012
*/
1113
function setStartState() {
1214
elapsedTime = 0; // Reset timer when animation starts
1315
if (target) {
14-
target.pixiContainer.alpha = 0;
16+
// 修正:不再强制设为 0,而是记录当前的透明度
17+
startAlpha = target.pixiContainer.alpha;
1518
}
1619
}
1720

18-
// TODO:通用终态设置
1921
/**
2022
* 在此书写为动画设置终态的操作
2123
*/
2224
function setEndState() {
2325
if (target) {
26+
// 终态是完全不透明,这保持不变
2427
target.pixiContainer.alpha = 1;
2528
}
2629
}
@@ -34,21 +37,19 @@ export function generateUniversalSoftInAnimationObj(targetKey: string, duration:
3437
const sprite = target.pixiContainer;
3538
const baseDuration = WebGAL.gameplay.pixiStage!.frameDuration;
3639

37-
// Increment the elapsed time by the duration of the last frame
3840
elapsedTime += baseDuration;
3941

40-
// Ensure elapsedTime does not exceed the total duration
4142
const realElapsedTime = Math.min(elapsedTime, duration);
42-
43-
// Calculate the progress of the animation as a value from 0 to 1
4443
const progress = realElapsedTime / duration;
4544

46-
// Apply the Cubic Ease-Out function
47-
// The formula is: 1 - (1 - progress)^3
45+
// 使用 Cubic Ease-Out 函数,这对于“进入”动画感觉更自然
4846
const easedProgress = 1 - Math.pow(1 - progress, 3);
4947

50-
// Set the sprite's alpha to the eased value
51-
sprite.alpha = easedProgress;
48+
// 修正:使用线性插值公式 (lerp)
49+
// 公式:最终值 = 初始值 + (目标值 - 初始值) * 进度
50+
// 在这里,目标值是 1,所以公式为:
51+
// alpha = startAlpha + (1 - startAlpha) * easedProgress
52+
sprite.alpha = startAlpha + (1 - startAlpha) * easedProgress;
5253
}
5354
}
5455

packages/webgal/src/Core/controller/stage/pixi/animations/universalSoftOff.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
44
const target = WebGAL.gameplay.pixiStage!.getStageObjByKey(targetKey);
55
let elapsedTime = 0;
66

7-
// 先设置一个通用的初态
7+
// 新增变量,用于存储动画开始时的初始透明度
8+
let startAlpha = 1;
89

910
/**
1011
* 在此书写为动画设置初态的操作
1112
*/
1213
function setStartState() {
13-
elapsedTime = 0; // Reset timer when animation starts
14+
elapsedTime = 0; // 重置计时器
1415
if (target) {
15-
// It's good practice to ensure the starting alpha is 1
16-
// in case the animation is chained or re-run.
17-
target.pixiContainer.alpha = 1;
16+
// 修正:不再强制设为1,而是记录当前的透明度
17+
startAlpha = target.pixiContainer.alpha;
1818
}
1919
}
2020

@@ -23,6 +23,7 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
2323
*/
2424
function setEndState() {
2525
if (target) {
26+
// 终态是完全透明,这保持不变
2627
target.pixiContainer.alpha = 0;
2728
}
2829
}
@@ -36,23 +37,20 @@ export function generateUniversalSoftOffAnimationObj(targetKey: string, duration
3637
const targetContainer = target.pixiContainer;
3738
const baseDuration = WebGAL.gameplay.pixiStage!.frameDuration;
3839

39-
// Increment the elapsed time by the duration of the last frame
4040
elapsedTime += baseDuration;
4141

42-
// Ensure elapsedTime does not exceed the total duration
4342
const realElapsedTime = Math.min(elapsedTime, duration);
44-
45-
// Calculate the progress of the animation as a value from 0 to 1
4643
const progress = realElapsedTime / duration;
4744

48-
// Apply the Cubic Ease-In function
49-
// The formula is: progress^3
45+
// 使用 Cubic Ease-In 函数
5046
const easedProgress = Math.pow(progress, 3);
5147

52-
// To fade out, we subtract the eased progress from 1
53-
// As easedProgress goes from 0 to 1 (slowly then quickly),
54-
// alpha will go from 1 to 0 (slowly then quickly).
55-
targetContainer.alpha = 1 - easedProgress;
48+
// 修正:基于初始透明度 startAlpha 进行计算
49+
// 公式:最终值 = 初始值 + (目标值 - 初始值) * 进度
50+
// 在这里,目标值是 0,所以公式简化为:
51+
// alpha = startAlpha + (0 - startAlpha) * easedProgress
52+
// alpha = startAlpha * (1 - easedProgress)
53+
targetContainer.alpha = startAlpha * (1 - easedProgress);
5654
}
5755
}
5856

packages/webgal/src/Stage/Stage.tsx

Lines changed: 35 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { FullScreenPerform } from './FullScreenPerform/FullScreenPerform';
66
import { nextSentence } from '@/Core/controller/gamePlay/nextSentence';
77
import { stopAll } from '@/Core/controller/gamePlay/fastSkip';
88
import { useDispatch, useSelector } from 'react-redux';
9-
import { RootState } from '@/store/store';
9+
import { RootState, webgalStore } from '@/store/store';
1010
import { setVisibility } from '@/store/GUIReducer';
1111
import { TextBoxFilm } from '@/Stage/TextBox/TextBoxFilm';
1212
import { useHotkey } from '@/hooks/useHotkey';
@@ -18,52 +18,12 @@ import { IGuiState } from '@/store/guiInterface';
1818
import { IStageState } from '@/store/stageInterface';
1919
// import OldStage from '@/Components/Stage/OldStage/OldStage';
2020

21-
function inTextBox(event: React.MouseEvent) {
22-
const tb = document.getElementById('textBoxMain');
23-
if (!tb) {
24-
return false;
25-
}
26-
let bounds = tb.getBoundingClientRect();
27-
return (
28-
event.clientX > bounds.left &&
29-
event.clientX < bounds.right &&
30-
event.clientY > bounds.top &&
31-
event.clientY < bounds.bottom
32-
);
33-
}
34-
35-
function checkMousePosition(event: React.MouseEvent, GUIState: IGuiState, dispatch: ReturnType<typeof useDispatch>) {
36-
if (!GUIState.controlsVisibility && inTextBox(event)) {
37-
dispatch(setVisibility({ component: 'controlsVisibility', visibility: true }));
38-
}
39-
if (GUIState.controlsVisibility && !inTextBox(event)) {
40-
dispatch(setVisibility({ component: 'controlsVisibility', visibility: false }));
41-
}
42-
}
43-
44-
function isTextboxHidden(stageState: IStageState, GUIState: IGuiState) {
45-
if (!GUIState.showTextBox) {
46-
return true;
47-
}
48-
49-
if (stageState.isDisableTextbox) {
50-
return true;
51-
}
52-
53-
const isText = stageState.showText !== '' || stageState.showName !== '';
54-
if (!isText) {
55-
return true;
56-
}
57-
58-
const isInIntro = document.getElementById('introContainer')?.style.display === 'block';
59-
if (isInIntro) {
60-
return true;
61-
}
62-
63-
return false;
64-
}
65-
6621
let timeoutEventHandle: ReturnType<typeof setTimeout> | null = null;
22+
// 视为“未移动”的最小移动阈值(像素^2),例如 4px -> 16
23+
const MOVE_THRESHOLD_SQ = 16;
24+
let lastMouseX = 0;
25+
let lastMouseY = 0;
26+
let hasLastMousePos = false;
6727

6828
/**
6929
* 检查并更新控制可见性
@@ -79,22 +39,38 @@ function updateControlsVisibility(
7939
GUIState: IGuiState,
8040
dispatch: ReturnType<typeof useDispatch>,
8141
) {
82-
if (isTextboxHidden(stageState, GUIState)) {
83-
// 当文本框被隐藏时
84-
// 逻辑:鼠标移动时显示,一段时间(默认:1秒)后隐藏
85-
if (timeoutEventHandle) {
86-
clearTimeout(timeoutEventHandle);
87-
}
42+
// 新逻辑:超过阈值的鼠标移动立刻显示,2s 无操作后隐藏(未锁定时)
43+
const { clientX, clientY } = event;
44+
let movedEnough = false;
45+
if (!hasLastMousePos) {
46+
movedEnough = true; // 第一次移动视为足够
47+
hasLastMousePos = true;
48+
} else {
49+
const dx = clientX - lastMouseX;
50+
const dy = clientY - lastMouseY;
51+
movedEnough = dx * dx + dy * dy >= MOVE_THRESHOLD_SQ;
52+
}
53+
lastMouseX = clientX;
54+
lastMouseY = clientY;
55+
56+
if (!movedEnough) {
57+
// 微小移动,视为无操作,不重置计时器
58+
return;
59+
}
60+
61+
if (timeoutEventHandle) {
62+
clearTimeout(timeoutEventHandle);
63+
}
8864

65+
if (!GUIState.controlsVisibility) {
8966
dispatch(setVisibility({ component: 'controlsVisibility', visibility: true }));
90-
timeoutEventHandle = setTimeout(() => {
91-
dispatch(setVisibility({ component: 'controlsVisibility', visibility: false }));
92-
}, 1000);
93-
} else {
94-
// 当文本框正常显示时
95-
// 逻辑:鼠标位置在文本框内时显示
96-
checkMousePosition(event, GUIState, dispatch);
9767
}
68+
69+
timeoutEventHandle = setTimeout(() => {
70+
if (!webgalStore.getState().GUI.showControls) {
71+
dispatch(setVisibility({ component: 'controlsVisibility', visibility: false }));
72+
}
73+
}, 2000);
9874
}
9975

10076
export const Stage: FC = () => {

0 commit comments

Comments
 (0)