Skip to content

Commit 6235704

Browse files
Feat: Decouple properties in timeline animations & support parallel animation for setTransform command
1 parent f99e5ed commit 6235704

10 files changed

Lines changed: 113 additions & 62 deletions

File tree

packages/webgal/src/Core/Modules/animationFunctions.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { baseTransform } from '@/store/stageInterface';
77
import { generateTimelineObj } from '@/Core/controller/stage/pixi/animations/timeline';
88
import { WebGAL } from '@/Core/WebGAL';
99
import PixiStage, { IAnimationObject } from '@/Core/controller/stage/pixi/PixiController';
10+
import { IUserAnimation } from './animations';
11+
import { pickBy } from 'lodash';
1012
import {
1113
DEFAULT_BG_IN_DURATION,
1214
DEFAULT_BG_OUT_DURATION,
@@ -18,12 +20,25 @@ import {
1820
export function getAnimationObject(animationName: string, target: string, duration: number, writeDefault: boolean) {
1921
const effect = WebGAL.animationManager.getAnimations().find((ani) => ani.name === animationName);
2022
if (effect) {
23+
const unionKeys = new Set<string>();
24+
const unionScaleKeys = new Set<string>();
25+
const unionPositionKeys = new Set<string>();
26+
effect.effects.forEach((effect) => {
27+
Object.keys(effect).forEach((k) => unionKeys.add(k));
28+
if (effect.scale) Object.keys(effect.scale).forEach((k) => unionScaleKeys.add(k));
29+
if (effect.position) Object.keys(effect.position).forEach((k) => unionPositionKeys.add(k));
30+
});
2131
const mappedEffects = effect.effects.map((effect) => {
2232
const targetSetEffect = webgalStore.getState().stage.effects.find((e) => e.target === target);
2333
let newEffect;
2434

2535
if (!writeDefault && targetSetEffect && targetSetEffect.transform) {
26-
newEffect = cloneDeep({ ...targetSetEffect.transform, duration: 0, ease: '' });
36+
const targetScale = pickBy(targetSetEffect.transform.scale, (source, key)=> unionScaleKeys.has(key))
37+
const targetPosition = pickBy(targetSetEffect.transform.position, (source, key)=> unionPositionKeys.has(key))
38+
const originalTransform = { ...pickBy(targetSetEffect.transform, (source, key)=> unionKeys.has(key))};
39+
originalTransform.scale = targetScale
40+
originalTransform.position = targetPosition
41+
newEffect = cloneDeep({ ...originalTransform, duration: 0, ease: '' });
2742
} else {
2843
newEffect = cloneDeep({ ...baseTransform, duration: 0, ease: '' });
2944
}
@@ -51,6 +66,14 @@ export function getAnimateDuration(animationName: string) {
5166
return 0;
5267
}
5368

69+
export function getAnimateDurationFromObj(animation: IUserAnimation) {
70+
let duration = 0;
71+
animation.effects.forEach((e) => {
72+
duration += e.duration;
73+
});
74+
return duration;
75+
}
76+
5477
// eslint-disable-next-line max-params
5578
export function getEnterExitAnimation(
5679
target: string,

packages/webgal/src/Core/Modules/perform/performController.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ export class PerformController {
1919
public performList: Array<IPerform> = [];
2020

2121
public arrangeNewPerform(perform: IPerform, script: ISentence, syncPerformState = true) {
22-
// 检查演出列表内是否有相同的演出,如果有,一定是出了什么问题
23-
const dupPerformIndex = this.performList.findIndex((p) => p.performName === perform.performName);
24-
if (dupPerformIndex > -1) {
25-
// 结束并删除全部重复演出
26-
for (let i = 0; i < this.performList.length; i++) {
27-
const e = this.performList[i];
28-
if (e.performName === perform.performName) {
29-
e.stopFunction();
30-
clearTimeout(e.stopTimeout as unknown as number);
31-
this.performList.splice(i, 1);
32-
i--;
22+
if (!perform.isParallel){
23+
// 检查演出列表内是否有相同的演出,如果有,一定是出了什么问题
24+
const dupPerformIndex = this.performList.findIndex((p) => p.performName === perform.performName);
25+
if (dupPerformIndex > -1) {
26+
// 结束并删除全部重复演出
27+
for (let i = 0; i < this.performList.length; i++) {
28+
const e = this.performList[i];
29+
if (e.performName === perform.performName) {
30+
e.stopFunction();
31+
clearTimeout(e.stopTimeout as unknown as number);
32+
this.performList.splice(i, 1);
33+
i--;
34+
}
3335
}
3436
}
3537
}

packages/webgal/src/Core/Modules/perform/performInterface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export interface IPerform {
2323
arrangePerformPromise?: Promise<IPerform>;
2424
// 跳过由 nextSentence 函数引发的演出回收
2525
skipNextCollect?: boolean;
26+
//
27+
isParallel?: boolean;
2628
}
2729

2830
// next之后,可以被打断的演出会被打断,不能被打断的演出会继续,阻塞next的演出会阻止next被响应。

packages/webgal/src/Core/controller/stage/pixi/PixiController.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { SCREEN_CONSTANTS } from '@/Core/util/constants';
1010
import { logger } from '@/Core/util/logger';
1111
import { v4 as uuid } from 'uuid';
1212
import { cloneDeep, isEqual } from 'lodash';
13+
import omitBy from 'lodash/omitBy';
14+
import isUndefined from 'lodash/isUndefined';
1315
import * as PIXI from 'pixi.js';
1416
import { INSTALLED } from 'pixi.js';
1517
import { GifResource } from './GifResource';
@@ -71,9 +73,9 @@ export default class PixiStage {
7173
if (!source) return;
7274
const targetScale = target.scale;
7375
const targetPosition = target.position;
74-
if (target.scale) Object.assign(targetScale, source.scale);
75-
if (target.position) Object.assign(targetPosition, source.position);
76-
Object.assign(target, source);
76+
if (target.scale) Object.assign(targetScale!, omitBy(source.scale,isUndefined));
77+
if (target.position) Object.assign(targetPosition!, omitBy(source.position,isUndefined));
78+
Object.assign(target, omitBy(source,isUndefined));
7779
target.scale = targetScale;
7880
target.position = targetPosition;
7981
}

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AnimationFrame } from '@/Core/Modules/animations';
22
import { webgalStore } from '@/store/store';
3+
import { has, pickBy } from 'lodash';
34
import isNull from 'lodash/isNull';
45

56
type AnimationObj = Array<AnimationFrame>;
@@ -10,6 +11,7 @@ export function generateTransformAnimationObj(
1011
applyFrame: AnimationFrame,
1112
duration: number | string | boolean | null,
1213
ease: string,
14+
writeFullEffect: boolean = true,
1315
): AnimationObj {
1416
let animationObj;
1517
// 获取那个 target 的当前变换
@@ -25,8 +27,18 @@ export function generateTransformAnimationObj(
2527

2628
// 找到 effect
2729
if (targetEffect) {
28-
const effectWithDuration = { ...targetEffect!.transform!, duration: 0, ease };
29-
animationObj.unshift(effectWithDuration);
30+
if (writeFullEffect) {
31+
const effectWithDuration = { ...targetEffect!.transform!, duration: 0, ease };
32+
animationObj.unshift(effectWithDuration);
33+
}
34+
else {
35+
const targetScale = pickBy(targetEffect!.transform!.scale, (source, key)=> has(applyFrame.scale, key))
36+
const targetPosition = pickBy(targetEffect!.transform!.position, (source, key)=> has(applyFrame.position, key))
37+
const effectWithDuration = { ...pickBy(targetEffect!.transform!, (source, key)=> has(applyFrame, key) ), duration: 0, ease };
38+
effectWithDuration.scale = targetScale
39+
effectWithDuration.position = targetPosition
40+
animationObj.unshift(effectWithDuration);
41+
}
3042
} else {
3143
// 应用默认effect,也就是最终的 effect 的 alpha = 0 版本
3244
const effectWithDuration = { ...applyFrame, alpha: 0, duration: 0, ease };

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function generateTimelineObj(
3333
currentDelay += segmentDuration;
3434
const { position, scale, ...segmentValues } = segment;
3535
// 不能用 scale,因为 popmotion 不能用嵌套
36-
values.push({ x: position.x, y: position.y, scaleX: scale.x, scaleY: scale.y, ...segmentValues });
36+
values.push({ x: position?.x, y: position?.y, scaleX: scale?.x, scaleY: scale?.y, ...segmentValues });
3737
// Easing 需要比 values 的长度少一个
3838
if (i > 0) {
3939
easeArray.push(stringToEasing(segment.ease));
@@ -74,11 +74,11 @@ export function generateTimelineObj(
7474
if (target?.pixiContainer) {
7575
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
7676
const { position, scale, ...state } = getStartStateEffect();
77-
const assignValue = omitBy({ x: position.x, y: position.y, ...state }, isUndefined);
77+
const assignValue = omitBy({ x: position?.x, y: position?.y, ...state }, isUndefined);
7878
// @ts-ignore
7979
PixiStage.assignTransform(target?.pixiContainer, assignValue);
80-
if (target?.pixiContainer) {
81-
if (!isUndefined(scale.x)) {
80+
if (scale && target?.pixiContainer) {
81+
if (!isUndefined(scale?.x)) {
8282
target.pixiContainer.scale.x = scale.x;
8383
}
8484
if (!isUndefined(scale?.y)) {
@@ -101,11 +101,11 @@ export function generateTimelineObj(
101101
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
102102
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
103103
const { position, scale, ...state } = getEndStateEffect();
104-
const assignValue = omitBy({ x: position.x, y: position.y, ...state }, isUndefined);
104+
const assignValue = omitBy({ x: position?.x, y: position?.y, ...state }, isUndefined);
105105
// @ts-ignore
106106
PixiStage.assignTransform(target?.pixiContainer, assignValue);
107-
if (target?.pixiContainer) {
108-
if (!isUndefined(scale.x)) {
107+
if (scale && target?.pixiContainer) {
108+
if (!isUndefined(scale?.x)) {
109109
target.pixiContainer.scale.x = scale.x;
110110
}
111111
if (!isUndefined(scale?.y)) {

packages/webgal/src/Core/gameScripts/setTransform.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ import { baseTransform, ITransform } from '@/store/stageInterface';
1010
import { AnimationFrame, IUserAnimation } from '../Modules/animations';
1111
import { generateTransformAnimationObj } from '@/Core/controller/stage/pixi/animations/generateTransformAnimationObj';
1212
import { WebGAL } from '@/Core/WebGAL';
13-
import { getAnimateDuration, getAnimationObject } from '../Modules/animationFunctions';
14-
13+
import { getAnimateDurationFromObj, getAnimationObject } from '../Modules/animationFunctions';
14+
import { v4 as uuid } from 'uuid';
1515
/**
1616
* 设置变换
1717
* @param sentence
1818
*/
1919
export const setTransform = (sentence: ISentence): IPerform => {
2020
const startDialogKey = webgalStore.getState().stage.currentDialogKey;
21-
const animationName = (Math.random() * 10).toString(16);
21+
const animationName = uuid();
2222
const animationString = sentence.content;
2323
let animationObj: AnimationFrame[];
2424

@@ -27,14 +27,16 @@ export const setTransform = (sentence: ISentence): IPerform => {
2727
const writeDefault = getBooleanArgByKey(sentence, 'writeDefault') ?? false;
2828
const target = getStringArgByKey(sentence, 'target') ?? '0';
2929
const keep = getBooleanArgByKey(sentence, 'keep') ?? false;
30+
const parallel = getBooleanArgByKey(sentence, 'parallel') ?? false;
3031

3132
const performInitName = `animation-${target}`;
3233

33-
WebGAL.gameplay.performController.unmountPerform(performInitName, true);
34+
if (!parallel) WebGAL.gameplay.performController.unmountPerform(performInitName, true);
3435

3536
try {
3637
const frame = JSON.parse(animationString) as AnimationFrame;
37-
animationObj = generateTransformAnimationObj(target, frame, duration, ease);
38+
// writeDefault时需要完整的当前effect,其他时候不需要
39+
animationObj = generateTransformAnimationObj(target, frame, duration, ease, writeDefault);
3840
console.log('animationObj:', animationObj);
3941
} catch (e) {
4042
// 解析都错误了,歇逼吧
@@ -43,8 +45,7 @@ export const setTransform = (sentence: ISentence): IPerform => {
4345

4446
const newAnimation: IUserAnimation = { name: animationName, effects: animationObj };
4547
WebGAL.animationManager.addAnimation(newAnimation);
46-
const animationDuration = getAnimateDuration(animationName);
47-
48+
const animationDuration = getAnimateDurationFromObj(newAnimation);
4849
const key = `${target}-${animationName}-${animationDuration}`;
4950
let keepAnimationStopped = false;
5051
setTimeout(() => {
@@ -82,5 +83,6 @@ export const setTransform = (sentence: ISentence): IPerform => {
8283
blockingNext: () => false,
8384
blockingAuto: () => !keep,
8485
stopTimeout: undefined, // 暂时不用,后面会交给自动清除
86+
isParallel: parallel,
8587
};
8688
};

packages/webgal/src/Stage/MainStage/useSetEffects.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { baseTransform, IEffect, IStageState, ITransform } from '@/store/stageIn
22

33
import { WebGAL } from '@/Core/WebGAL';
44
import PixiStage from '@/Core/controller/stage/pixi/PixiController';
5+
import { isUndefined, omitBy } from 'lodash';
56

67
export function setStageObjectEffects(stageState: IStageState) {
78
const effects = stageState.effects;
@@ -42,5 +43,5 @@ function convertTransform(transform: ITransform | undefined) {
4243
return {};
4344
}
4445
const { position, ...rest } = transform;
45-
return { ...rest, x: position.x, y: position.y };
46+
return omitBy({ ...rest, x: position?.x, y: position?.y },isUndefined);
4647
}

packages/webgal/src/store/stageInterface.ts

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,41 +25,41 @@ export interface IChooseItem {
2525
}
2626

2727
export interface ITransform {
28-
alpha: number;
29-
scale: {
30-
x: number;
31-
y: number;
28+
alpha?: number;
29+
scale?: {
30+
x?: number;
31+
y?: number;
3232
};
3333
// pivot: {
3434
// x: number;
3535
// y: number;
3636
// };
37-
position: {
38-
x: number;
39-
y: number;
37+
position?: {
38+
x?: number;
39+
y?: number;
4040
};
41-
rotation: number;
42-
blur: number;
43-
brightness: number;
44-
contrast: number;
45-
saturation: number;
46-
gamma: number;
47-
colorRed: number;
48-
colorGreen: number;
49-
colorBlue: number;
50-
bevel: number;
51-
bevelThickness: number;
52-
bevelRotation: number;
53-
bevelSoftness: number;
54-
bevelRed: number;
55-
bevelGreen: number;
56-
bevelBlue: number;
57-
bloom: number;
58-
bloomBrightness: number;
59-
bloomBlur: number;
60-
bloomThreshold: number;
61-
shockwaveFilter: number;
62-
radiusAlphaFilter: number;
41+
rotation?: number;
42+
blur?: number;
43+
brightness?: number;
44+
contrast?: number;
45+
saturation?: number;
46+
gamma?: number;
47+
colorRed?: number;
48+
colorGreen?: number;
49+
colorBlue?: number;
50+
bevel?: number;
51+
bevelThickness?: number;
52+
bevelRotation?: number;
53+
bevelSoftness?: number;
54+
bevelRed?: number;
55+
bevelGreen?: number;
56+
bevelBlue?: number;
57+
bloom?: number;
58+
bloomBrightness?: number;
59+
bloomBlur?: number;
60+
bloomThreshold?: number;
61+
shockwaveFilter?: number;
62+
radiusAlphaFilter?: number;
6363
}
6464

6565
/**

packages/webgal/src/store/stageReducer.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2323
import cloneDeep from 'lodash/cloneDeep';
2424
import { commandType } from '@/Core/controller/scene/sceneInterface';
2525
import { STAGE_KEYS } from '@/Core/constants';
26+
import { isUndefined, omitBy } from 'lodash';
2627

2728
// 初始化舞台数据
2829

@@ -123,7 +124,13 @@ const stageSlice = createSlice({
123124
const effectIndex = state.effects.findIndex((e) => e.target === target);
124125
if (effectIndex >= 0) {
125126
// Update the existing effect
126-
state.effects[effectIndex].transform = transform;
127+
const targetScale = state.effects[effectIndex]!.transform!.scale;
128+
const targetPosition = state.effects[effectIndex]!.transform!.position;
129+
if (transform!.scale) Object.assign(targetScale!, omitBy(transform!.scale,isUndefined));
130+
if (transform!.position) Object.assign(targetPosition!, omitBy(transform!.position,isUndefined));
131+
Object.assign(state.effects[effectIndex]!.transform!, omitBy(transform,isUndefined))
132+
state.effects[effectIndex].transform!.scale = targetScale;
133+
state.effects[effectIndex].transform!.position = targetPosition;
127134
} else {
128135
// Add a new effect
129136
state.effects.push({

0 commit comments

Comments
 (0)