Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
31 changes: 31 additions & 0 deletions packages/webgal/public/game/scene/demo_parallel_animation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
changeBg:WebGalEnter.webp -next;
changeFigure:stand.webp -id=figure01 -transform={"position":{"x":1000,"y":720}};
;演示setAnimation平行执行
setAnimation:shockwaveIn -target=figure01 -next
setAnimation:move-front-and-back -target=figure01 -parallel
;演示通过-continue接续执行两个常规setTransform正常运作、不被打断
setTransform:{"position":{"x":-1000}} -duration=5000 -target=figure01 -continue
setTransform:{"position":{"x":1000}} -duration=5000 -target=figure01
;演示setTransform平行执行
setTransform:{"position":{"x":-1000},"scale":{"x":0.5},"contrast":0.5} -duration=5000 -target=figure01 -ease=easeOut -next -keep
wait:2000
setTransform:{"position":{"y":0},"scale":{"y":0.5},"saturation":0} -duration=5000 -target=figure01 -ease=linear -parallel -continue
setTransform:{"position":{"y":-720},"scale":{"y":1},"saturation":1} -duration=5000 -target=figure01 -ease=linear -next
setTransform:{"position":{"x":1000},"scale":{"x":1},"contrast":1} -duration=5000 -target=figure01 -ease=easeIn -parallel;
;演示参数解耦改动后setTempAnimation普通运作是否正常
setTempAnimation:[{"duration":0}, {"duration":500,"position":{"x":-1000}}, {"duration":500,"position":{"y":720},"scale":{"y":0.5},"saturation":0}, {"duration":500,"position":{"x":-1000, "y":720}}, {"duration":500}, {"duration":500,"position":{"x":-1000},"scale":{"x":0.5},"contrast":0.5}] -target=figure01
setTempAnimation:[{"duration":0}, {"duration":500,"position":{"x":1000}}, {"duration":500,"position":{"y":720}}, {"duration":500,"position":{"x":1000, "y":720}}, {"duration":500}, {"duration":500,"position":{"x":1000}}] -target=figure01
;演示参数解耦改动后setTransform的-writeDefault参数是否运作正常
setTransform:{} -writeDefault -target=figure01 -duration=500
setTransform:{"position":{"x":1000,"y":720}} -target=figure01 -next;
setAnimation:shockwaveOut -target=figure01 -parallel
;演示setTempAnimation平行执行
setTempAnimation:[{"duration":0},{"position":{"x":-1000},"scale":{"x":0.5},"contrast":0.5,"duration":5000,"ease":"easeOut"},{"position":{"x":-1000},"scale":{"x":0.5},"contrast":0.5,"duration":2000},{"position":{"x":600},"scale":{"x":1},"contrast":1,"duration":5000,"ease":"easeIn"},{"duration":2000}] -target=figure01 -next;
setTempAnimation:[{"duration":2000},{"position":{"y":0},"scale":{"y":0.5},"saturation":0,"duration":5000,"ease":"linear"},{"position":{"y":-720},"scale":{"y":1},"saturation":1,"duration":5000,"ease":"linear"},{"duration":2000}] -target=figure01 -parallel -continue;
;演示并行执行多条终止时间点不一致的setTransform
setTransform:{"position":{"x":-1000}} -duration=5000 -next -target=figure01;
setTransform:{"position":{"y":0}} -duration=3000 -parallel -target=figure01;
setTransform:{"position":{"x":1000}} -duration=3000 -next -target=figure01;
setTransform:{"position":{"y":-720}} -duration=5000 -parallel -target=figure01;
changeBg: -next;
changeFigure: -id=figure01
25 changes: 24 additions & 1 deletion packages/webgal/src/Core/Modules/animationFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { baseTransform } from '@/store/stageInterface';
import { generateTimelineObj } from '@/Core/controller/stage/pixi/animations/timeline';
import { WebGAL } from '@/Core/WebGAL';
import PixiStage, { IAnimationObject } from '@/Core/controller/stage/pixi/PixiController';
import { IUserAnimation } from './animations';
import { pickBy } from 'lodash';
import {
DEFAULT_BG_IN_DURATION,
DEFAULT_BG_OUT_DURATION,
Expand All @@ -18,12 +20,25 @@ import {
export function getAnimationObject(animationName: string, target: string, duration: number, writeDefault: boolean) {
const effect = WebGAL.animationManager.getAnimations().find((ani) => ani.name === animationName);
if (effect) {
const unionKeys = new Set<string>();
const unionScaleKeys = new Set<string>();
const unionPositionKeys = new Set<string>();
effect.effects.forEach((effect) => {
Object.keys(effect).forEach((k) => unionKeys.add(k));
if (effect.scale) Object.keys(effect.scale).forEach((k) => unionScaleKeys.add(k));
if (effect.position) Object.keys(effect.position).forEach((k) => unionPositionKeys.add(k));
});
const mappedEffects = effect.effects.map((effect) => {
const targetSetEffect = webgalStore.getState().stage.effects.find((e) => e.target === target);
let newEffect;

if (!writeDefault && targetSetEffect && targetSetEffect.transform) {
newEffect = cloneDeep({ ...targetSetEffect.transform, duration: 0, ease: '' });
const targetScale = pickBy(targetSetEffect.transform.scale || {}, (source, key)=> unionScaleKeys.has(key))
const targetPosition = pickBy(targetSetEffect.transform.position || {}, (source, key)=> unionPositionKeys.has(key))
const originalTransform = { ...pickBy(targetSetEffect.transform, (source, key)=> unionKeys.has(key))};
originalTransform.scale = targetScale
originalTransform.position = targetPosition
newEffect = cloneDeep({ ...originalTransform, duration: 0, ease: '' });
} else {
newEffect = cloneDeep({ ...baseTransform, duration: 0, ease: '' });
}
Expand Down Expand Up @@ -51,6 +66,14 @@ export function getAnimateDuration(animationName: string) {
return 0;
}

export function getAnimateDurationFromObj(animation: IUserAnimation) {
let duration = 0;
animation.effects.forEach((e) => {
duration += e.duration;
});
return duration;
}

// eslint-disable-next-line max-params
export function getEnterExitAnimation(
target: string,
Expand Down
46 changes: 34 additions & 12 deletions packages/webgal/src/Core/Modules/perform/performController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ export class PerformController {
public performList: Array<IPerform> = [];

public arrangeNewPerform(perform: IPerform, script: ISentence, syncPerformState = true) {
// 检查演出列表内是否有相同的演出,如果有,一定是出了什么问题
const dupPerformIndex = this.performList.findIndex((p) => p.performName === perform.performName);
if (dupPerformIndex > -1) {
// 结束并删除全部重复演出
for (let i = 0; i < this.performList.length; i++) {
const e = this.performList[i];
if (e.performName === perform.performName) {
e.stopFunction();
clearTimeout(e.stopTimeout as unknown as number);
this.performList.splice(i, 1);
i--;
if (!perform.isParallel){
// 检查演出列表内是否有相同的演出,如果有,一定是出了什么问题
const dupPerformIndex = this.performList.findIndex((p) => p.performName === perform.performName);
if (dupPerformIndex > -1) {
// 结束并删除全部重复演出
for (let i = 0; i < this.performList.length; i++) {
const e = this.performList[i];
if (e.performName === perform.performName) {
e.stopFunction();
clearTimeout(e.stopTimeout as unknown as number);
this.performList.splice(i, 1);
i--;
}
}
}
}
Expand All @@ -50,7 +52,7 @@ export class PerformController {
// perform.isOver = true;
if (!perform.isHoldOn) {
// 如果不是保持演出,清除
this.unmountPerform(perform.performName);
this.softUnmountPerformObject(perform);
}
}, perform.duration);

Expand Down Expand Up @@ -103,6 +105,26 @@ export class PerformController {
}
}

public softUnmountPerformObject(perform: IPerform) {
const idx = this.performList.indexOf(perform)
if (idx < 0) return;
perform.stopFunction();
clearTimeout(perform.stopTimeout as unknown as number);
/**
* 在演出列表里删除演出对象的操作必须在调用 goNextWhenOver 之前
* 因为 goNextWhenOver 会调用 nextSentence,而 nextSentence 会清除目前未结束的演出
* 那么 nextSentence 函数就会删除这个演出,但是此时,在这个上下文,i 已经被确定了
* 所以 goNextWhenOver 后的代码会多删东西,解决方法就是在调用 goNextWhenOver 前先删掉这个演出对象
* 此问题对所有 goNextWhenOver 属性为真的演出都有影响,但只有 2 个演出有此问题
*/
this.performList.splice(idx, 1);
if (perform.goNextWhenOver) {
// nextSentence();
this.goNextWhenOver();
}

}

public erasePerformFromState(name: string) {
webgalStore.dispatch(stageActions.removePerformByName(name));
}
Expand Down
2 changes: 2 additions & 0 deletions packages/webgal/src/Core/Modules/perform/performInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export interface IPerform {
arrangePerformPromise?: Promise<IPerform>;
// 跳过由 nextSentence 函数引发的演出回收
skipNextCollect?: boolean;
//
isParallel?: boolean;
}

// next之后,可以被打断的演出会被打断,不能被打断的演出会继续,阻塞next的演出会阻止next被响应。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { SCREEN_CONSTANTS } from '@/Core/util/constants';
import { logger } from '@/Core/util/logger';
import { v4 as uuid } from 'uuid';
import { cloneDeep, isEqual } from 'lodash';
import omitBy from 'lodash/omitBy';
import isUndefined from 'lodash/isUndefined';
import * as PIXI from 'pixi.js';
import { INSTALLED } from 'pixi.js';
import { GifResource } from './GifResource';
Expand Down Expand Up @@ -71,9 +73,9 @@ export default class PixiStage {
if (!source) return;
const targetScale = target.scale;
const targetPosition = target.position;
if (target.scale) Object.assign(targetScale, source.scale);
if (target.position) Object.assign(targetPosition, source.position);
Object.assign(target, source);
if (target.scale) Object.assign(targetScale!, omitBy(source.scale || {},isUndefined));
if (target.position) Object.assign(targetPosition!, omitBy(source.position || {},isUndefined));
Object.assign(target, omitBy(source,isUndefined));
target.scale = targetScale;
target.position = targetPosition;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AnimationFrame } from '@/Core/Modules/animations';
import { webgalStore } from '@/store/store';
import { has, pickBy } from 'lodash';
import isNull from 'lodash/isNull';

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

// 找到 effect
if (targetEffect) {
const effectWithDuration = { ...targetEffect!.transform!, duration: 0, ease };
animationObj.unshift(effectWithDuration);
if (writeFullEffect) {
const effectWithDuration = { ...targetEffect!.transform!, duration: 0, ease };
animationObj.unshift(effectWithDuration);
}
else {
const targetScale = pickBy(targetEffect.transform?.scale || {}, (source, key)=> has(applyFrame.scale, key))
const targetPosition = pickBy(targetEffect.transform?.position || {}, (source, key)=> has(applyFrame.position, key))
const effectWithDuration = { ...pickBy(targetEffect.transform || {}, (source, key)=> has(applyFrame, key) ), duration: 0, ease };
effectWithDuration.scale = targetScale
effectWithDuration.position = targetPosition
animationObj.unshift(effectWithDuration);
}
} else {
// 应用默认effect,也就是最终的 effect 的 alpha = 0 版本
const effectWithDuration = { ...applyFrame, alpha: 0, duration: 0, ease };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function generateTimelineObj(
currentDelay += segmentDuration;
const { position, scale, ...segmentValues } = segment;
// 不能用 scale,因为 popmotion 不能用嵌套
values.push({ x: position.x, y: position.y, scaleX: scale.x, scaleY: scale.y, ...segmentValues });
values.push({ x: position?.x, y: position?.y, scaleX: scale?.x, scaleY: scale?.y, ...segmentValues });
// Easing 需要比 values 的长度少一个
if (i > 0) {
easeArray.push(stringToEasing(segment.ease));
Expand Down Expand Up @@ -74,11 +74,11 @@ export function generateTimelineObj(
if (target?.pixiContainer) {
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
const { position, scale, ...state } = getStartStateEffect();
const assignValue = omitBy({ x: position.x, y: position.y, ...state }, isUndefined);
const assignValue = omitBy({ x: position?.x, y: position?.y, ...state }, isUndefined);
// @ts-ignore
PixiStage.assignTransform(target?.pixiContainer, assignValue);
if (target?.pixiContainer) {
if (!isUndefined(scale.x)) {
if (scale && target?.pixiContainer) {
if (!isUndefined(scale?.x)) {
target.pixiContainer.scale.x = scale.x;
}
if (!isUndefined(scale?.y)) {
Expand All @@ -101,11 +101,11 @@ export function generateTimelineObj(
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
// 不能赋值到 position,因为 x 和 y 被 WebGALPixiContainer 代理,而 position 属性没有代理
const { position, scale, ...state } = getEndStateEffect();
const assignValue = omitBy({ x: position.x, y: position.y, ...state }, isUndefined);
const assignValue = omitBy({ x: position?.x, y: position?.y, ...state }, isUndefined);
// @ts-ignore
PixiStage.assignTransform(target?.pixiContainer, assignValue);
if (target?.pixiContainer) {
if (!isUndefined(scale.x)) {
if (scale && target?.pixiContainer) {
if (!isUndefined(scale?.x)) {
target.pixiContainer.scale.x = scale.x;
}
if (!isUndefined(scale?.y)) {
Expand Down
4 changes: 3 additions & 1 deletion packages/webgal/src/Core/gameScripts/setAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ export const setAnimation = (sentence: ISentence): IPerform => {
target = target !== '' ? target : 'default_id';
const writeDefault = getBooleanArgByKey(sentence, 'writeDefault') ?? false;
const keep = getBooleanArgByKey(sentence, 'keep') ?? false;
const parallel = getBooleanArgByKey(sentence, 'parallel') ?? false;

const key = `${target}-${animationName}-${animationDuration}`;
const performInitName = `animation-${target}`;

WebGAL.gameplay.performController.unmountPerform(performInitName, true);
if (!parallel) WebGAL.gameplay.performController.unmountPerform(performInitName, true);

let stopFunction;
setTimeout(() => {
Expand Down Expand Up @@ -56,5 +57,6 @@ export const setAnimation = (sentence: ISentence): IPerform => {
blockingNext: () => false,
blockingAuto: () => !keep,
stopTimeout: undefined, // 暂时不用,后面会交给自动清除
isParallel: parallel,
};
};
11 changes: 7 additions & 4 deletions packages/webgal/src/Core/gameScripts/setTempAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import { generateTimelineObj } from '@/Core/controller/stage/pixi/animations/tim
import cloneDeep from 'lodash/cloneDeep';
import { baseTransform } from '@/store/stageInterface';
import { IUserAnimation } from '../Modules/animations';
import { getAnimateDuration, getAnimationObject } from '@/Core/Modules/animationFunctions';
import { getAnimateDurationFromObj, getAnimationObject } from '@/Core/Modules/animationFunctions';
import { WebGAL } from '@/Core/WebGAL';
import { v4 as uuid } from 'uuid';

/**
* 设置临时动画
* @param sentence
*/
export const setTempAnimation = (sentence: ISentence): IPerform => {
const startDialogKey = webgalStore.getState().stage.currentDialogKey;
const animationName = (Math.random() * 10).toString(16);
const animationName = uuid();
const animationString = sentence.content;
let animationObj;
try {
Expand All @@ -27,15 +28,16 @@ export const setTempAnimation = (sentence: ISentence): IPerform => {
}
const newAnimation: IUserAnimation = { name: animationName, effects: animationObj };
WebGAL.animationManager.addAnimation(newAnimation);
const animationDuration = getAnimateDuration(animationName);
const animationDuration = getAnimateDurationFromObj(newAnimation);
const target = getStringArgByKey(sentence, 'target') ?? '0';
const writeDefault = getBooleanArgByKey(sentence, 'writeDefault') ?? false;
const keep = getBooleanArgByKey(sentence, 'keep') ?? false;
const parallel = getBooleanArgByKey(sentence, 'parallel') ?? false;

const key = `${target}-${animationName}-${animationDuration}`;
const performInitName = `animation-${target}`;

WebGAL.gameplay.performController.unmountPerform(performInitName, true);
if (!parallel) WebGAL.gameplay.performController.unmountPerform(performInitName, true);

let stopFunction = () => {};
setTimeout(() => {
Expand Down Expand Up @@ -67,5 +69,6 @@ export const setTempAnimation = (sentence: ISentence): IPerform => {
blockingNext: () => false,
blockingAuto: () => !keep,
stopTimeout: undefined, // 暂时不用,后面会交给自动清除
isParallel: parallel,
};
};
16 changes: 9 additions & 7 deletions packages/webgal/src/Core/gameScripts/setTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import { baseTransform, ITransform } from '@/store/stageInterface';
import { AnimationFrame, IUserAnimation } from '../Modules/animations';
import { generateTransformAnimationObj } from '@/Core/controller/stage/pixi/animations/generateTransformAnimationObj';
import { WebGAL } from '@/Core/WebGAL';
import { getAnimateDuration, getAnimationObject } from '../Modules/animationFunctions';

import { getAnimateDurationFromObj, getAnimationObject } from '../Modules/animationFunctions';
import { v4 as uuid } from 'uuid';
/**
* 设置变换
* @param sentence
*/
export const setTransform = (sentence: ISentence): IPerform => {
const startDialogKey = webgalStore.getState().stage.currentDialogKey;
const animationName = (Math.random() * 10).toString(16);
const animationName = uuid();
const animationString = sentence.content;
let animationObj: AnimationFrame[];

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

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

WebGAL.gameplay.performController.unmountPerform(performInitName, true);
if (!parallel) WebGAL.gameplay.performController.unmountPerform(performInitName, true);

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

const newAnimation: IUserAnimation = { name: animationName, effects: animationObj };
WebGAL.animationManager.addAnimation(newAnimation);
const animationDuration = getAnimateDuration(animationName);

const animationDuration = getAnimateDurationFromObj(newAnimation);
const key = `${target}-${animationName}-${animationDuration}`;
let keepAnimationStopped = false;
setTimeout(() => {
Expand Down Expand Up @@ -82,5 +83,6 @@ export const setTransform = (sentence: ISentence): IPerform => {
blockingNext: () => false,
blockingAuto: () => !keep,
stopTimeout: undefined, // 暂时不用,后面会交给自动清除
isParallel: parallel,
};
};
3 changes: 2 additions & 1 deletion packages/webgal/src/Stage/MainStage/useSetEffects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { baseTransform, IEffect, IStageState, ITransform } from '@/store/stageIn

import { WebGAL } from '@/Core/WebGAL';
import PixiStage from '@/Core/controller/stage/pixi/PixiController';
import { isUndefined, omitBy } from 'lodash';

export function setStageObjectEffects(stageState: IStageState) {
const effects = stageState.effects;
Expand Down Expand Up @@ -42,5 +43,5 @@ function convertTransform(transform: ITransform | undefined) {
return {};
}
const { position, ...rest } = transform;
return { ...rest, x: position.x, y: position.y };
return omitBy({ ...rest, x: position?.x, y: position?.y },isUndefined);
}
Loading