Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 2 additions & 47 deletions packages/webgal/src/Core/Modules/stage/stageInterface.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ISentence } from '@/Core/controller/scene/sceneInterface';
import { BlinkParam, FocusParam } from '@/Core/live2DCore';
import type { Transform } from '@/types/editorPreviewProtocol';

/**
* 游戏内变量
Expand All @@ -24,49 +25,7 @@ export interface IChooseItem {
isSubScene: boolean; // 是否是子场景调用
}

export interface ITransform {
alpha?: number;
scale?: {
x?: number;
y?: number;
};
// pivot: {
// x: number;
// y: number;
// };
position?: {
x?: number;
y?: number;
};
rotation?: number;
blur?: number;
brightness?: number;
contrast?: number;
saturation?: number;
gamma?: number;
colorRed?: number;
colorGreen?: number;
colorBlue?: number;
bevel?: number;
bevelThickness?: number;
bevelRotation?: number;
bevelSoftness?: number;
bevelRed?: number;
bevelGreen?: number;
bevelBlue?: number;
bloom?: number;
bloomBrightness?: number;
bloomBlur?: number;
bloomThreshold?: number;
oldFilm?: number;
dotFilm?: number;
reflectionFilm?: number;
glitchFilm?: number;
rgbFilm?: number;
godrayFilm?: number;
shockwaveFilter?: number;
radiusAlphaFilter?: number;
}
export type ITransform = Transform;

/**
* 基本效果接口
Expand Down Expand Up @@ -104,10 +63,6 @@ export const baseTransform: ITransform = {
x: 1,
y: 1,
},
// pivot: {
// x: 0.5,
// y: 0.5,
// },
position: {
x: 0,
y: 0,
Expand Down
10 changes: 7 additions & 3 deletions packages/webgal/src/Core/controller/gamePlay/nextSentence.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { scriptExecutor } from './scriptExecutor';
import { scriptExecutor, type ScriptExecutionOptions } from './scriptExecutor';
import { logger } from '../../util/logger';
import { webgalStore } from '@/store/store';

Expand Down Expand Up @@ -32,7 +32,11 @@ export const preForward = () => {
/**
* 执行一条语句或由 -next 连接的语句序列,只修改演算状态并收集演出。
*/
export const forward = () => {
export interface ForwardOptions {
scriptExecution?: ScriptExecutionOptions;
}

export const forward = (options: ForwardOptions = {}) => {
if (WebGAL.sceneManager.lockSceneWrite) {
logger.warn('forward 被场景切换阻塞!');
return false;
Expand All @@ -47,7 +51,7 @@ export const forward = () => {
WebGAL.gameplay.performController.clearNonHoldPerformsFromStageState();
WebGAL.gameplay.performController.beginCollectingPerforms();
try {
scriptExecutor();
scriptExecutor(0, options.scriptExecution);
} finally {
WebGAL.gameplay.performController.endCollectingPerforms();
}
Expand Down
24 changes: 19 additions & 5 deletions packages/webgal/src/Core/controller/gamePlay/scriptExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ import { prefetchCurrentSceneByProgress } from '@/Core/util/prefetcher/progressP

const MAX_FORWARD_SCRIPT_EXECUTION = 1000;

export interface ScriptExecutionContext {
sceneName: string;
sentenceId: number;
}

export interface ScriptExecutionOptions {
beforeSentenceExecute?: (context: ScriptExecutionContext) => void;
}

export const whenChecker = (whenValue: string | undefined): boolean => {
if (whenValue === undefined) {
return true;
Expand All @@ -39,7 +48,7 @@ export const whenChecker = (whenValue: string | undefined): boolean => {
* 语句执行器
* 执行语句,同步场景状态,并根据情况立即执行下一句或者加入backlog
*/
export const scriptExecutor = (depth = 0) => {
export const scriptExecutor = (depth = 0, options: ScriptExecutionOptions = {}) => {
if (depth > MAX_FORWARD_SCRIPT_EXECUTION) {
logger.error('forward 中执行的语句数量超过限制,可能存在 jumpLabel 或 -next 死循环');
return;
Expand All @@ -59,8 +68,13 @@ export const scriptExecutor = (depth = 0) => {
}
return;
}
const sentenceId = WebGAL.sceneManager.sceneData.currentSentenceId;
options.beforeSentenceExecute?.({
sceneName: WebGAL.sceneManager.sceneData.currentScene.sceneName,
sentenceId,
});
const currentScript: ISentence = cloneDeep(
WebGAL.sceneManager.sceneData.currentScene.sentenceList[WebGAL.sceneManager.sceneData.currentSentenceId],
WebGAL.sceneManager.sceneData.currentScene.sentenceList[sentenceId],
);

const interpolationOneItem = (content: string): string => {
Expand Down Expand Up @@ -104,7 +118,7 @@ export const scriptExecutor = (depth = 0) => {
if (!runThis) {
logger.warn('不满足条件,跳过本句!');
WebGAL.sceneManager.sceneData.currentSentenceId++;
scriptExecutor(depth + 1);
scriptExecutor(depth + 1, options);
return;
}

Expand All @@ -115,7 +129,7 @@ export const scriptExecutor = (depth = 0) => {
logger.warn(`未找到标签 ${currentScript.content},跳过 jumpLabel`);
WebGAL.sceneManager.sceneData.currentSentenceId++;
}
scriptExecutor(depth + 1);
scriptExecutor(depth + 1, options);
return;
}

Expand Down Expand Up @@ -148,7 +162,7 @@ export const scriptExecutor = (depth = 0) => {
if (isNext && !hasPendingBlockingStateCalculationPerform && !WebGAL.sceneManager.lockSceneWrite) {
WebGAL.sceneManager.sceneData.currentSentenceId++;
saveBacklogIfNeeded();
scriptExecutor(depth + 1);
scriptExecutor(depth + 1, options);
return;
}

Expand Down
50 changes: 49 additions & 1 deletion packages/webgal/src/Core/controller/stage/pixi/PixiController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as PIXI from 'pixi.js';
import { INSTALLED } from 'pixi.js';
import { GifResource } from './GifResource';
import { stageStateManager } from '@/Core/Modules/stage/stageStateManager';
import { queryStageObjectReferenceBox, type QueryTargetReferenceBoxResult } from './referenceBox';

export interface IAnimationObject {
setStartState: Function;
Expand Down Expand Up @@ -120,6 +121,7 @@ export default class PixiStage {
private isRenderPending = false;
// 更新 ticker 状态的防抖标记
private isTickerUpdatePending = false;
private referenceBoxWaiters = new Map<string, Set<() => void>>();

/**
* 暂时没用上,以后可能用
Expand Down Expand Up @@ -467,6 +469,7 @@ export default class PixiStage {

// 挂载
thisBgContainer.addChild(bgSprite);
this.notifyTargetReferenceBoxChanged(key);
this.requestRender();
}
}, 0);
Expand Down Expand Up @@ -551,6 +554,7 @@ export default class PixiStage {
thisBgContainer.setBaseY(this.stageHeight / 2);
thisBgContainer.pivot.set(0, this.stageHeight / 2);
thisBgContainer.addChild(bgSprite);
this.notifyTargetReferenceBoxChanged(key);
});
}
}, 0);
Expand Down Expand Up @@ -609,7 +613,6 @@ export default class PixiStage {
sourceType: sourceExt === 'gif' ? 'gif' : 'img',
sourceExt,
});

// 完成图片加载后执行的函数
const setup = () => {
// TODO:找一个更好的解法,现在的解法是无论是否复用原来的资源,都设置一个延时以让动画工作正常!
Expand Down Expand Up @@ -646,6 +649,7 @@ export default class PixiStage {
}
thisFigureContainer.pivot.set(0, this.stageHeight / 2);
thisFigureContainer.addChild(figureSprite);
this.notifyTargetReferenceBoxChanged(key);
this.requestRender();
}
}, 0);
Expand Down Expand Up @@ -807,6 +811,7 @@ export default class PixiStage {
Live2D.SoundManager.volume = 0; // @ts-ignore

thisFigureContainer.addChild(model);
instance.notifyTargetReferenceBoxChanged(key);
});
})();
}
Expand Down Expand Up @@ -1030,6 +1035,36 @@ export default class PixiStage {
return [...this.figureObjects, ...this.backgroundObjects, this.mainStageObject].find((e) => e.key === key);
}

public queryTargetReferenceBox(target: string): QueryTargetReferenceBoxResult {
return queryStageObjectReferenceBox(target, this.getStageObjByKey(target), {
width: this.stageWidth,
height: this.stageHeight,
});
}

public waitForTargetReferenceBox(target: string, timeoutMs: number): Promise<void> {
return new Promise((resolve) => {
const existingWaiters = this.referenceBoxWaiters.get(target);
const waiters = existingWaiters ?? new Set<() => void>();
if (!existingWaiters) {
this.referenceBoxWaiters.set(target, waiters);
}

let timeoutId = 0;
const resolveAndCleanup = () => {
window.clearTimeout(timeoutId);
waiters.delete(resolveAndCleanup);
if (waiters.size === 0) {
this.referenceBoxWaiters.delete(target);
}
resolve();
};

timeoutId = window.setTimeout(resolveAndCleanup, timeoutMs);
waiters.add(resolveAndCleanup);
});
}

public getStageObjByUuid(objUuid: string) {
return [...this.figureObjects, ...this.backgroundObjects, this.mainStageObject].find((e) => e.uuid === objUuid);
}
Expand Down Expand Up @@ -1057,6 +1092,7 @@ export default class PixiStage {
}
bgSprite.pixiContainer = null;
this.figureObjects.splice(indexFig, 1);
this.notifyTargetReferenceBoxChanged(key);
}
if (indexBg >= 0) {
const bgSprite = this.backgroundObjects[indexBg];
Expand All @@ -1070,6 +1106,7 @@ export default class PixiStage {
}
bgSprite.pixiContainer = null;
this.backgroundObjects.splice(indexBg, 1);
this.notifyTargetReferenceBoxChanged(key);
}
// /**
// * 删掉相关 Effects,因为已经移除了
Expand Down Expand Up @@ -1142,6 +1179,17 @@ export default class PixiStage {
}
}

public notifyTargetReferenceBoxChanged(target: string): void {
const waiters = this.referenceBoxWaiters.get(target);
if (!waiters) {
return;
}

for (const resolve of [...waiters]) {
resolve();
}
}

private callLoader() {
if (!this.assetLoader.loading) {
const front = this.loadQueue.shift();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,34 @@ const PROPERTY_CONFIGS: Record<string, PropertyConfig> = {
},
};

function getChildReferenceBounds(child: PIXI.DisplayObject, containerPivot: PIXI.IPointData): PIXI.Rectangle {
child.transform.updateLocalTransform();
const bounds = child.getLocalBounds();
const transform = child.transform.localTransform;
const left = bounds.x * child.scale.x + transform.tx - containerPivot.x;
const right = (bounds.x + bounds.width) * child.scale.x + transform.tx - containerPivot.x;
const top = bounds.y * child.scale.y + transform.ty - containerPivot.y;
const bottom = (bounds.y + bounds.height) * child.scale.y + transform.ty - containerPivot.y;

return new PIXI.Rectangle(
Math.min(left, right),
Math.min(top, bottom),
Math.abs(right - left),
Math.abs(bottom - top),
);
}
Comment thread
A-kirami marked this conversation as resolved.

function mergeBounds(target: PIXI.Rectangle, next: PIXI.Rectangle): void {
const minX = Math.min(target.x, next.x);
const minY = Math.min(target.y, next.y);
const maxX = Math.max(target.x + target.width, next.x + next.width);
const maxY = Math.max(target.y + target.height, next.y + next.height);
target.x = minX;
target.y = minY;
target.width = maxX - minX;
target.height = maxY - minY;
}

export class WebGALPixiContainer extends PIXI.Container {
public containerFilters = new Map<string, PIXI.Filter>();
private filterToName = new Map<PIXI.Filter, string>();
Expand Down Expand Up @@ -415,6 +443,33 @@ export class WebGALPixiContainer extends PIXI.Container {
this.y = old;
}

public getBasePosition(): { x: number; y: number } {
return {
x: this.baseX,
y: this.baseY,
};
}

public getReferenceLocalBounds(): PIXI.Rectangle | undefined {
if (this.children.length === 0) {
return undefined;
}

let referenceBounds: PIXI.Rectangle | undefined;
for (const child of this.children) {
const localBounds = getChildReferenceBounds(child, this.pivot);

if (!referenceBounds) {
referenceBounds = localBounds;
continue;
}

mergeBounds(referenceBounds, localBounds);
}

return referenceBounds;
}

// --- Standard Filters ---
public get blur(): number {
return this._getPropertyValue('blur');
Expand Down
Loading
Loading