Skip to content
Merged
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
37 changes: 17 additions & 20 deletions packages/webgal/src/Core/Modules/animationFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@ import cloneDeep from 'lodash/cloneDeep';
import { baseTransform } from '@/store/stageInterface';
import { generateTimelineObj } from '@/Core/controller/stage/pixi/animations/timeline';
import { WebGAL } from '@/Core/WebGAL';
import PixiStage from '@/Core/controller/stage/pixi/PixiController';
import PixiStage, { IAnimationObject } from '@/Core/controller/stage/pixi/PixiController';

export function getAnimationObject(animationName: string, target: string, duration: number) {
// eslint-disable-next-line max-params
export function getAnimationObject(animationName: string, target: string, duration: number, writeDefault: boolean) {
const effect = WebGAL.animationManager.getAnimations().find((ani) => ani.name === animationName);
if (effect) {
const mappedEffects = effect.effects.map((effect) => {
const targetSetEffect = webgalStore.getState().stage.effects.find((e) => e.target === target);
const newEffect = cloneDeep({ ...(targetSetEffect?.transform ?? baseTransform), duration: 0 });
let newEffect;

if (!writeDefault && targetSetEffect && targetSetEffect.transform) {
newEffect = cloneDeep({ ...targetSetEffect.transform, duration: 0, ease: '' });
} else {
newEffect = cloneDeep({ ...baseTransform, duration: 0, ease: '' });
}

PixiStage.assignTransform(newEffect, effect);
newEffect.duration = effect.duration;
newEffect.ease = effect.ease;
return newEffect;
});
logger.debug('装载自定义动画', mappedEffects);
Expand Down Expand Up @@ -44,27 +53,19 @@ export function getEnterExitAnimation(
realTarget?: string, // 用于立绘和背景移除时,以当前时间打上特殊标记
): {
duration: number;
animation: {
setStartState: () => void;
tickerFunc: (delta: number) => void;
setEndState: () => void;
} | null;
animation: IAnimationObject | null;
} {
if (type === 'enter') {
let duration = 500;
if (isBg) {
duration = 1500;
}
// 走默认动画
let animation: {
setStartState: () => void;
tickerFunc: (delta: number) => void;
setEndState: () => void;
} | null = generateUniversalSoftInAnimationObj(realTarget ?? target, duration);
let animation: IAnimationObject | null = generateUniversalSoftInAnimationObj(realTarget ?? target, duration);
const animarionName = WebGAL.animationManager.nextEnterAnimationName.get(target);
if (animarionName) {
logger.debug('取代默认进入动画', target);
animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName));
animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName), false);
duration = getAnimateDuration(animarionName);
// 用后重置
WebGAL.animationManager.nextEnterAnimationName.delete(target);
Expand All @@ -76,15 +77,11 @@ export function getEnterExitAnimation(
duration = 1500;
}
// 走默认动画
let animation: {
setStartState: () => void;
tickerFunc: (delta: number) => void;
setEndState: () => void;
} | null = generateUniversalSoftOffAnimationObj(realTarget ?? target, duration);
let animation: IAnimationObject | null = generateUniversalSoftOffAnimationObj(realTarget ?? target, duration);
const animarionName = WebGAL.animationManager.nextExitAnimationName.get(target);
if (animarionName) {
logger.debug('取代默认退出动画', target);
animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName));
animation = getAnimationObject(animarionName, realTarget ?? target, getAnimateDuration(animarionName), false);
duration = getAnimateDuration(animarionName);
// 用后重置
WebGAL.animationManager.nextExitAnimationName.delete(target);
Expand Down
4 changes: 3 additions & 1 deletion packages/webgal/src/Core/Modules/animations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import { ITransform } from '@/store/stageInterface';

export interface IUserAnimation {
name: string;
effects: Array<ITransform & { duration: number }>;
effects: Array<AnimationFrame>;
}

export type AnimationFrame = ITransform & { duration: number; ease: string };

export class AnimationManager {
public nextEnterAnimationName: Map<string, string> = new Map();
public nextExitAnimationName: Map<string, string> = new Map();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import { ITransform } from '@/store/stageInterface';
import { AnimationFrame } from '@/Core/Modules/animations';
import { webgalStore } from '@/store/store';
import isNull from 'lodash/isNull';

type AnimationFrame = ITransform & { duration: number };
type AnimationObj = Array<AnimationFrame>;

// eslint-disable-next-line max-params
export function generateTransformAnimationObj(
target: string,
applyFrame: AnimationFrame,
duration: number | string | boolean | null,
ease: string,
): AnimationObj {
let animationObj;
// 获取那个 target 的当前变换
const transformState = webgalStore.getState().stage.effects;
const targetEffect = transformState.find((effect) => effect.target === target);

applyFrame.duration = 500;
if (!isNull(duration) && typeof duration === 'number') {
applyFrame.duration = duration;
}
applyFrame.ease = ease;
animationObj = [applyFrame];

// 找到 effect
if (targetEffect) {
const effectWithDuration = { ...targetEffect!.transform!, duration: 0 };
const effectWithDuration = { ...targetEffect!.transform!, duration: 0, ease };
animationObj.unshift(effectWithDuration);
} else {
// 应用默认effect,也就是最终的 effect 的 alpha = 0 版本
const effectWithDuration = { ...applyFrame, alpha: 0, duration: 0 };
const effectWithDuration = { ...applyFrame, alpha: 0, duration: 0, ease };
animationObj.unshift(effectWithDuration);
}
return animationObj;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { ITransform } from '@/store/stageInterface';
import { animate } from 'popmotion';
import * as popmotion from 'popmotion';
import { WebGAL } from '@/Core/WebGAL';
import { webgalStore } from '@/store/store';
import { stageActions } from '@/store/stageReducer';
import omitBy from 'lodash/omitBy';
import isUndefined from 'lodash/isUndefined';
import PixiStage from '@/Core/controller/stage/pixi/PixiController';
import PixiStage, { IAnimationObject } from '@/Core/controller/stage/pixi/PixiController';
import { AnimationFrame } from '@/Core/Modules/animations';

/**
* 动画创建模板
Expand All @@ -14,10 +15,10 @@ import PixiStage from '@/Core/controller/stage/pixi/PixiController';
* @param duration 持续时间
*/
export function generateTimelineObj(
timeline: Array<ITransform & { duration: number }>,
timeline: Array<AnimationFrame>,
targetKey: string,
duration: number,
) {
): IAnimationObject {
for (const segment of timeline) {
// 处理 alphaL
// @ts-ignore
Expand All @@ -27,25 +28,32 @@ export function generateTimelineObj(
const target = WebGAL.gameplay.pixiStage!.getStageObjByKey(targetKey);
let currentDelay = 0;
const values = [];
const easeArray: Array<popmotion.Easing> = [];
const times: number[] = [];
for (const segment of timeline) {
for (let i = 0; i < timeline.length; i++) {
const segment = timeline[i];
const segmentDuration = segment.duration;
currentDelay += segmentDuration;
const { position, scale, ...segmentValues } = segment;
// 不能用 scale,因为 popmotion 不能用嵌套
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));
}
if (duration !== 0) {
times.push(currentDelay / duration);
} else times.push(0);
}
const container = target?.pixiContainer;
let animateInstance: ReturnType<typeof animate> | null = null;
let animateInstance: ReturnType<typeof popmotion.animate> | null = null;
// 只有有 duration 的时候才有动画
if (duration > 0) {
animateInstance = animate({
animateInstance = popmotion.animate({
to: values,
offset: times,
duration,
ease: easeArray,
onUpdate: (updateValue) => {
if (container) {
const { scaleX, scaleY, ...val } = updateValue;
Expand Down Expand Up @@ -134,3 +142,66 @@ export function generateTimelineObj(
getEndFilterEffect,
};
}

const stringToEasing = (ease: string): popmotion.Easing => {
let easeType = popmotion.easeInOut;
switch (ease) {
case 'easeInOut': {
easeType = popmotion.easeInOut;
break;
}
case 'easeIn': {
easeType = popmotion.easeIn;
break;
}
case 'easeOut': {
easeType = popmotion.easeOut;
break;
}
case 'circInOut': {
easeType = popmotion.circInOut;
break;
}
case 'circIn': {
easeType = popmotion.circIn;
break;
}
case 'circOut': {
easeType = popmotion.circOut;
break;
}
case 'backInOut': {
easeType = popmotion.backInOut;
break;
}
case 'backIn': {
easeType = popmotion.backIn;
break;
}
case 'backOut': {
easeType = popmotion.backOut;
break;
}
case 'bounceInOut': {
easeType = popmotion.bounceInOut;
break;
}
case 'bounceIn': {
easeType = popmotion.bounceIn;
break;
}
case 'bounceOut': {
easeType = popmotion.bounceOut;
break;
}
case 'linear': {
easeType = popmotion.linear;
break;
}
case 'anticipate': {
easeType = popmotion.anticipate;
break;
}
}
return easeType;
};
13 changes: 6 additions & 7 deletions packages/webgal/src/Core/gameScripts/changeBg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { unlockCgInUserData } from '@/store/userDataReducer';
import { logger } from '@/Core/util/logger';
import { ITransform } from '@/store/stageInterface';
import { generateTransformAnimationObj } from '@/Core/controller/stage/pixi/animations/generateTransformAnimationObj';
import { IUserAnimation } from '@/Core/Modules/animations';
import { AnimationFrame, IUserAnimation } from '@/Core/Modules/animations';
import cloneDeep from 'lodash/cloneDeep';
import { getAnimateDuration } from '@/Core/Modules/animationFunctions';
import { WebGAL } from '@/Core/WebGAL';
Expand Down Expand Up @@ -43,16 +43,15 @@ export const changeBg = (sentence: ISentence): IPerform => {
// 处理 transform 和 默认 transform
const transformString = getSentenceArgByKey(sentence, 'transform');
let duration = getSentenceArgByKey(sentence, 'duration');
let ease = getSentenceArgByKey(sentence, 'ease')?.toString() ?? '';
if (!duration || typeof duration !== 'number') {
duration = 1000;
}
let animationObj: (ITransform & {
duration: number;
})[];
let animationObj: AnimationFrame[];
if (transformString) {
try {
const frame = JSON.parse(transformString.toString()) as ITransform & { duration: number };
animationObj = generateTransformAnimationObj('bg-main', frame, duration);
const frame = JSON.parse(transformString.toString()) as AnimationFrame;
animationObj = generateTransformAnimationObj('bg-main', frame, duration, ease);
// 因为是切换,必须把一开始的 alpha 改为 0
animationObj[0].alpha = 0;
const animationName = (Math.random() * 10).toString(16);
Expand All @@ -71,7 +70,7 @@ export const changeBg = (sentence: ISentence): IPerform => {
function applyDefaultTransform() {
// 应用默认的
const frame = {};
animationObj = generateTransformAnimationObj('bg-main', frame as ITransform & { duration: number }, duration);
animationObj = generateTransformAnimationObj('bg-main', frame as AnimationFrame, duration, ease);
// 因为是切换,必须把一开始的 alpha 改为 0
animationObj[0].alpha = 0;
const animationName = (Math.random() * 10).toString(16);
Expand Down
13 changes: 6 additions & 7 deletions packages/webgal/src/Core/gameScripts/changeFigure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { setStage, stageActions } from '@/store/stageReducer';
import cloneDeep from 'lodash/cloneDeep';
import { getSentenceArgByKey } from '@/Core/util/getSentenceArg';
import { IFreeFigure, IStageState, ITransform } from '@/store/stageInterface';
import { IUserAnimation } from '@/Core/Modules/animations';
import { AnimationFrame, IUserAnimation } from '@/Core/Modules/animations';
import { generateTransformAnimationObj } from '@/Core/controller/stage/pixi/animations/generateTransformAnimationObj';
import { assetSetter, fileType } from '@/Core/util/gameAssetsAccess/assetSetter';
import { logger } from '@/Core/util/logger';
Expand Down Expand Up @@ -169,17 +169,16 @@ export function changeFigure(sentence: ISentence): IPerform {
// 处理 transform 和 默认 transform
const transformString = getSentenceArgByKey(sentence, 'transform');
const durationFromArg = getSentenceArgByKey(sentence, 'duration');
const ease = getSentenceArgByKey(sentence, 'ease')?.toString() ?? '';
if (durationFromArg && typeof durationFromArg === 'number') {
duration = durationFromArg;
}
let animationObj: (ITransform & {
duration: number;
})[];
let animationObj: AnimationFrame[];
if (transformString) {
console.log(transformString);
try {
const frame = JSON.parse(transformString.toString()) as ITransform & { duration: number };
animationObj = generateTransformAnimationObj(key, frame, duration);
const frame = JSON.parse(transformString.toString()) as AnimationFrame;
animationObj = generateTransformAnimationObj(key, frame, duration, ease);
// 因为是切换,必须把一开始的 alpha 改为 0
animationObj[0].alpha = 0;
const animationName = (Math.random() * 10).toString(16);
Expand All @@ -198,7 +197,7 @@ export function changeFigure(sentence: ISentence): IPerform {
function applyDefaultTransform() {
// 应用默认的
const frame = {};
animationObj = generateTransformAnimationObj(key, frame as ITransform & { duration: number }, duration);
animationObj = generateTransformAnimationObj(key, frame as AnimationFrame, duration, ease);
// 因为是切换,必须把一开始的 alpha 改为 0
animationObj[0].alpha = 0;
const animationName = (Math.random() * 10).toString(16);
Expand Down
8 changes: 7 additions & 1 deletion packages/webgal/src/Core/gameScripts/setAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@ export const setAnimation = (sentence: ISentence): IPerform => {
const animationName = sentence.content;
const animationDuration = getAnimateDuration(animationName);
const target = (getSentenceArgByKey(sentence, 'target')?.toString() ?? 'default_id').toString();
const writeDefault = (getSentenceArgByKey(sentence, 'writeDefault') as boolean) ?? false;
const key = `${target}-${animationName}-${animationDuration}`;
let stopFunction;
setTimeout(() => {
WebGAL.gameplay.pixiStage?.stopPresetAnimationOnTarget(target);
const animationObj: IAnimationObject | null = getAnimationObject(animationName, target, animationDuration);
const animationObj: IAnimationObject | null = getAnimationObject(
animationName,
target,
animationDuration,
writeDefault,
);
if (animationObj) {
logger.debug(`动画${animationName}作用在${target}`, animationDuration);
WebGAL.gameplay.pixiStage?.registerAnimation(animationObj, key, target);
Expand Down
8 changes: 7 additions & 1 deletion packages/webgal/src/Core/gameScripts/setTempAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ export const setTempAnimation = (sentence: ISentence): IPerform => {
WebGAL.animationManager.addAnimation(newAnimation);
const animationDuration = getAnimateDuration(animationName);
const target = (getSentenceArgByKey(sentence, 'target')?.toString() ?? '0') as string;
const writeDefault = (getSentenceArgByKey(sentence, 'writeDefault') as boolean) ?? false;
const key = `${target}-${animationName}-${animationDuration}`;
let stopFunction = () => {};
setTimeout(() => {
WebGAL.gameplay.pixiStage?.stopPresetAnimationOnTarget(target);
const animationObj: IAnimationObject | null = getAnimationObject(animationName, target, animationDuration);
const animationObj: IAnimationObject | null = getAnimationObject(
animationName,
target,
animationDuration,
writeDefault,
);
if (animationObj) {
logger.debug(`动画${animationName}作用在${target}`, animationDuration);
WebGAL.gameplay.pixiStage?.registerAnimation(animationObj, key, target);
Expand Down
Loading