Skip to content

Commit

Permalink
Merge pull request #481 from OpenWebGAL/dev
Browse files Browse the repository at this point in the history
4.4.13
  • Loading branch information
MakinoharaShoko committed Mar 24, 2024
2 parents ff29415 + daf5232 commit f33258d
Show file tree
Hide file tree
Showing 30 changed files with 440 additions and 220 deletions.
5 changes: 3 additions & 2 deletions packages/webgal/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "webgal",
"private": true,
"version": "4.4.12",
"version": "4.4.13",
"scripts": {
"dev": "vite --host --port 3000",
"build": "cross-env NODE_ENV=production tsc && vite build --base=./",
Expand All @@ -13,7 +13,7 @@
"@icon-park/react": "^1.4.2",
"@reduxjs/toolkit": "^1.8.1",
"angular-expressions": "^1.1.5",
"axios": "^0.26.1",
"axios": "^0.28.0",
"cloudlogjs": "^1.0.9",
"i18next": "^22.4.15",
"localforage": "^1.10.0",
Expand All @@ -22,6 +22,7 @@
"modern-css-reset": "^1.4.0",
"pixi-filters": "^4.2.0",
"pixi-live2d-display": "^0.4.0",
"pixi-spine": "^3.1.2",
"pixi.js": "^6.3.0",
"popmotion": "^11.0.5",
"react": "^17.0.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/webgal/public/game/template/template.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name":"Default Template",
"webgal-version":"4.4.12"
"webgal-version":"4.4.13"
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const whenChecker = (whenValue: string | undefined): boolean => {
return true;
}
// 先把变量解析出来
const valExpArr = whenValue.split(/([+\-*\/()><!]|>=|<=|==)/g);
const valExpArr = whenValue.split(/([+\-*\/()><!]|>=|<=|==|&&|\|\||!=)/g);
const valExp = valExpArr
.map((e) => {
if (e.match(/[a-zA-Z]/)) {
Expand Down
110 changes: 103 additions & 7 deletions packages/webgal/src/Core/controller/stage/pixi/PixiController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { logger } from '@/Core/util/logger';
import { isIOS } from '@/Core/initializeScript';
import { WebGALPixiContainer } from '@/Core/controller/stage/pixi/WebGALPixiContainer';
import { WebGAL } from '@/Core/WebGAL';
import 'pixi-spine'; // Do this once at the very start of your code. This registers the loader!
import { Spine } from 'pixi-spine';
// import { figureCash } from '@/Core/gameScripts/vocal/conentsCash'; // 如果要使用 Live2D,取消这里的注释
// import { Live2DModel, SoundManager } from 'pixi-live2d-display'; // 如果要使用 Live2D,取消这里的注释

Expand Down Expand Up @@ -70,7 +72,7 @@ export default class PixiStage {
// 注册到 Ticker 上的函数
private stageAnimations: Array<IStageAnimationObject> = [];
private assetLoader = new PIXI.Loader();
private loadQueue: { url: string; callback: () => void }[] = [];
private loadQueue: { url: string; callback: () => void; name?: string }[] = [];
private live2dFigureRecorder: Array<ILive2DRecord> = [];

// 锁定变换对象(对象可能正在执行动画,不能应用变换)
Expand Down Expand Up @@ -512,6 +514,93 @@ export default class PixiStage {
}
}

/**
* 添加 Spine 立绘
* @param key 立绘的标识,一般和立绘位置有关
* @param url 立绘图片url
* @param presetPosition
*/
public addSpineFigure(key: string, url: string, presetPosition: 'left' | 'center' | 'right' = 'center') {
const spineId = `spine-${url}`;
const loader = this.assetLoader;
// 准备用于存放这个立绘的 Container
const thisFigureContainer = new WebGALPixiContainer();

// 是否有相同 key 的立绘
const setFigIndex = this.figureObjects.findIndex((e) => e.key === key);
const isFigSet = setFigIndex >= 0;

// 已经有一个这个 key 的立绘存在了
if (isFigSet) {
this.removeStageObjectByKey(key);
}

// 挂载
this.figureContainer.addChild(thisFigureContainer);
const figureUuid = uuid();
this.figureObjects.push({ uuid: figureUuid, key: key, pixiContainer: thisFigureContainer, sourceUrl: url });

// 完成图片加载后执行的函数
const setup = () => {
console.log(this.assetLoader.resources);
const spineResource: any = this.assetLoader.resources?.[spineId];
// TODO:找一个更好的解法,现在的解法是无论是否复用原来的资源,都设置一个延时以让动画工作正常!
setTimeout(() => {
if (spineResource && this.getStageObjByUuid(figureUuid)) {
const figureSpine = new Spine(spineResource.spineData);
const transY = spineResource?.spineData?.y ?? 0;
/**
* 重设大小
*/
console.log(figureSpine);
const originalWidth = figureSpine.width;
const originalHeight = figureSpine.height;
const scaleX = this.stageWidth / originalWidth;
const scaleY = this.stageHeight / originalHeight;
// 我也不知道为什么啊啊啊啊
figureSpine.y = -(scaleY * transY) / 2;
console.log(figureSpine.state);
figureSpine.state.setAnimation(0, '07', true);
const targetScale = Math.min(scaleX, scaleY);
const figureSprite = new PIXI.Sprite();
figureSprite.addChild(figureSpine);
figureSprite.scale.x = targetScale;
figureSprite.scale.y = targetScale;
figureSprite.anchor.set(0.5);
figureSprite.position.y = this.stageHeight / 2;
const targetWidth = originalWidth * targetScale;
const targetHeight = originalHeight * targetScale;
thisFigureContainer.setBaseY(this.stageHeight / 2);
if (targetHeight < this.stageHeight) {
thisFigureContainer.setBaseY(this.stageHeight / 2 + this.stageHeight - targetHeight / 2);
}
if (presetPosition === 'center') {
thisFigureContainer.setBaseX(this.stageWidth / 2);
}
if (presetPosition === 'left') {
thisFigureContainer.setBaseX(targetWidth / 2);
}
if (presetPosition === 'right') {
thisFigureContainer.setBaseX(this.stageWidth - targetWidth / 2);
}
thisFigureContainer.pivot.set(0, this.stageHeight / 2);
thisFigureContainer.addChild(figureSprite);
}
}, 0);
};

/**
* 加载器部分
*/
this.cacheGC();
if (!loader.resources?.[url]) {
this.loadAsset(url, setup, spineId);
} else {
// 复用
setup();
}
}

/**
* Live2d立绘,如果要使用 Live2D,取消这里的注释
* @param jsonPath
Expand Down Expand Up @@ -751,11 +840,11 @@ export default class PixiStage {
}
}

private loadAsset(url: string, callback: () => void) {
private loadAsset(url: string, callback: () => void, name?: string) {
/**
* Loader 复用疑似有问题,转而采用先前的单独方式
*/
this.loadQueue.unshift({ url, callback });
this.loadQueue.unshift({ url, callback, name });
/**
* 尝试启动加载
*/
Expand All @@ -771,10 +860,17 @@ export default class PixiStage {
front.callback();
this.callLoader();
} else {
this.assetLoader.add(front.url).load(() => {
front.callback();
this.callLoader();
});
if (front.name) {
this.assetLoader.add(front.name, front.url).load(() => {
front.callback();
this.callLoader();
});
} else {
this.assetLoader.add(front.url).load(() => {
front.callback();
this.callLoader();
});
}
}
} catch (error) {
logger.fatal('PIXI Loader 故障', error);
Expand Down
22 changes: 9 additions & 13 deletions packages/webgal/src/Core/controller/storage/fastSaveLoad.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { webgalStore } from '@/store/store';
import { setFastSave } from '@/store/userDataReducer';
import { getStorageAsync, setStorageAsync } from '@/Core/controller/storage/storageController';
import { ISaveData } from '@/store/userDataInterface';
import { loadGameFromStageData } from '@/Core/controller/storage/loadGame';
import { generateCurrentStageData } from '@/Core/controller/storage/saveGame';
import cloneDeep from 'lodash/cloneDeep';
import { WebGAL } from '@/Core/WebGAL';
import { saveActions } from '@/store/savesReducer';
import { dumpFastSaveToStorage, getFastSaveFromStorage } from '@/Core/controller/storage/savesController';

export let fastSaveGameKey = '';
export let isFastSaveKey = '';
Expand All @@ -21,15 +22,10 @@ export function initKey() {
* 用于紧急回避时的数据存储 & 快速保存
*/
export async function fastSaveGame() {
const saveData: ISaveData = generateCurrentStageData(-1);
const saveData: ISaveData = generateCurrentStageData(-1, false);
const newSaveData = cloneDeep(saveData);
// localStorage.setItem(fastSaveGameKey, JSON.stringify(newSaveData));
// localStorage.setItem(isFastSaveKey, JSON.stringify(true));
// localStorage.setItem('currentSentenceId', JSON.stringify(runtime_currentSceneData.currentSentenceId));
// await localforage.setItem(fastSaveGameKey, newSaveData);
// await localforage.setItem(isFastSaveKey, true);
webgalStore.dispatch(setFastSave(newSaveData));
await setStorageAsync();
webgalStore.dispatch(saveActions.setFastSave(newSaveData));
await dumpFastSaveToStorage();
}

/**
Expand All @@ -38,7 +34,7 @@ export async function fastSaveGame() {
export async function hasFastSaveRecord() {
// return await localforage.getItem(isFastSaveKey);
await getStorageAsync();
return webgalStore.getState().userData.quickSaveData !== null;
return webgalStore.getState().saveData.quickSaveData !== null;
}

/**
Expand All @@ -47,8 +43,8 @@ export async function hasFastSaveRecord() {
export async function loadFastSaveGame() {
// 获得存档文件
// const loadFile: ISaveData | null = await localforage.getItem(fastSaveGameKey);
await getStorageAsync();
const loadFile: ISaveData | null = webgalStore.getState().userData.quickSaveData;
await getFastSaveFromStorage();
const loadFile: ISaveData | null = webgalStore.getState().saveData.quickSaveData;
if (!loadFile) {
return;
}
Expand All @@ -59,7 +55,7 @@ export async function loadFastSaveGame() {
* 移除紧急回避的数据
*/
export async function removeFastSaveGameRecord() {
webgalStore.dispatch(setFastSave(null));
webgalStore.dispatch(saveActions.resetFastSave());
await setStorageAsync();
// await localforage.setItem(isFastSaveKey, false);
// await localforage.setItem(fastSaveGameKey, null);
Expand Down
2 changes: 1 addition & 1 deletion packages/webgal/src/Core/controller/storage/loadGame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { WebGAL } from '@/Core/WebGAL';
* @param index 要读取的存档的档位
*/
export const loadGame = (index: number) => {
const userDataState = webgalStore.getState().userData;
const userDataState = webgalStore.getState().saveData;
// 获得存档文件
const loadFile: ISaveData = userDataState.saveData[index];
logger.debug('读取的存档数据', loadFile);
Expand Down
35 changes: 17 additions & 18 deletions packages/webgal/src/Core/controller/storage/saveGame.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,47 @@
import { logger } from '../../util/logger';
import { ISaveData } from '@/store/userDataInterface';
import { syncStorageFast } from './storageController';
import { dumpToStorageFast } from './storageController';
import { webgalStore } from '@/store/store';
import { setUserData } from '@/store/userDataReducer';
import cloneDeep from 'lodash/cloneDeep';

import { WebGAL } from '@/Core/WebGAL';
import { saveActions } from '@/store/savesReducer';
import { dumpSavesToStorage } from '@/Core/controller/storage/savesController';

/**
* 保存游戏
* @param index 游戏的档位
*/
export const saveGame = (index: number) => {
const userDataState = webgalStore.getState().userData;
const saveData: ISaveData = generateCurrentStageData(index);
logger.debug('存档数据:', saveData);
const newSaveData = cloneDeep(userDataState.saveData);
logger.debug('newSaveData:', newSaveData);
newSaveData[index] = saveData;
webgalStore.dispatch(setUserData({ key: 'saveData', value: [...newSaveData] }));
logger.debug('存档完成,存档结果:', newSaveData);
syncStorageFast();
webgalStore.dispatch(saveActions.saveGame({ index, saveData }));
dumpSavesToStorage(index, index);
};

/**
* 生成现在游戏的数据快照
* @param index 游戏的档位
*/
export function generateCurrentStageData(index: number) {
export function generateCurrentStageData(index: number, isSavePreviewImage = true) {
const stageState = webgalStore.getState().stage;
const saveBacklog = cloneDeep(WebGAL.backlogManager.getBacklog());

/**
* 生成缩略图
*/

const canvas: HTMLCanvasElement = document.getElementById('pixiCanvas')! as HTMLCanvasElement;
const canvas2 = document.createElement('canvas');
const context = canvas2.getContext('2d');
canvas2.width = 480;
canvas2.height = 270;
context!.drawImage(canvas, 0, 0, 480, 270);
const urlToSave = canvas2.toDataURL('image/webp', 0.5);
canvas2.remove();
let urlToSave = '';
if (isSavePreviewImage) {
const canvas: HTMLCanvasElement = document.getElementById('pixiCanvas')! as HTMLCanvasElement;
const canvas2 = document.createElement('canvas');
const context = canvas2.getContext('2d');
canvas2.width = 480;
canvas2.height = 270;
context!.drawImage(canvas, 0, 0, 480, 270);
urlToSave = canvas2.toDataURL('image/webp', 0.5);
canvas2.remove();
}
const saveData: ISaveData = {
nowStageState: cloneDeep(stageState),
backlog: saveBacklog, // 舞台数据
Expand Down
36 changes: 36 additions & 0 deletions packages/webgal/src/Core/controller/storage/savesController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import localforage from 'localforage';
import { WebGAL } from '@/Core/WebGAL';
import { logger } from '@/Core/util/logger';
import { webgalStore } from '@/store/store';
import { saveActions } from '@/store/savesReducer';
import { ISaveData } from '@/store/userDataInterface';

export function dumpSavesToStorage(startIndex: number, endIndex: number) {
for (let i = startIndex; i <= endIndex; i++) {
const save = webgalStore.getState().saveData.saveData[i];
localforage.setItem(`${WebGAL.gameKey}-saves${i}`, save).then(() => {
logger.info(`存档${i}写入本地存储`);
});
}
}

export function getSavesFromStorage(startIndex: number, endIndex: number) {
for (let i = startIndex; i <= endIndex; i++) {
localforage.getItem(`${WebGAL.gameKey}-saves${i}`).then((save) => {
webgalStore.dispatch(saveActions.saveGame({ index: i, saveData: save as ISaveData }));
logger.info(`存档${i}读取自本地存储`);
});
}
}

export async function dumpFastSaveToStorage() {
const save = webgalStore.getState().saveData.quickSaveData;
await localforage.setItem(`${WebGAL.gameKey}-saves-fast`, save);
logger.info(`快速存档写入本地存储`);
}

export async function getFastSaveFromStorage() {
const save = await localforage.getItem(`${WebGAL.gameKey}-saves-fast`);
webgalStore.dispatch(saveActions.setFastSave(save as ISaveData));
logger.info(`快速存档读取自本地存储`);
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function debounce<T, K>(func: (...args: T[]) => K, wait: number) {
return context;
}

export const syncStorageFast = () => {
export const dumpToStorageFast = () => {
const userDataState = webgalStore.getState().userData;
localforage.setItem(WebGAL.gameKey, userDataState).then(() => {
localforage.getItem(WebGAL.gameKey).then((newUserData) => {
Expand Down
8 changes: 4 additions & 4 deletions packages/webgal/src/Core/gameScripts/end.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { webgalStore } from '@/store/store';
import { setVisibility } from '@/store/GUIReducer';
import { playBgm } from '@/Core/controller/stage/playBgm';
import { WebGAL } from '@/Core/WebGAL';
import { resetFastSave } from '@/store/userDataReducer';
import { syncStorageFast } from '@/Core/controller/storage/storageController';
import { dumpToStorageFast } from '@/Core/controller/storage/storageController';
import { saveActions } from '@/store/savesReducer';

/**
* 结束游戏
Expand All @@ -24,8 +24,8 @@ export const end = (sentence: ISentence): IPerform => {
setTimeout(() => {
WebGAL.sceneManager.resetScene();
}, 5);
dispatch(resetFastSave());
syncStorageFast();
dispatch(saveActions.resetFastSave());
dumpToStorageFast();
sceneFetcher(sceneUrl).then((rawScene) => {
// 场景写入到运行时
WebGAL.sceneManager.sceneData.currentScene = sceneParser(rawScene, 'start.txt', sceneUrl);
Expand Down
Loading

0 comments on commit f33258d

Please sign in to comment.