diff --git a/spx-gui/src/models/animation.test.ts b/spx-gui/src/models/animation.test.ts index 91f09112e..e107a080e 100644 --- a/spx-gui/src/models/animation.test.ts +++ b/spx-gui/src/models/animation.test.ts @@ -81,7 +81,7 @@ describe('Animation', () => { expect(animation.sound).toBeNull() }) - it('should load correctly', async () => { + it('should work correctly while project loads', async () => { const project = makeProject() project.sprites[0].animations[0].setSound(project.sounds[0].name) diff --git a/spx-gui/src/models/animation.ts b/spx-gui/src/models/animation.ts index df006ad20..0eb2b0e1f 100644 --- a/spx-gui/src/models/animation.ts +++ b/spx-gui/src/models/animation.ts @@ -10,13 +10,6 @@ import type { Files } from './common/file' import type { Costume, RawCostumeConfig } from './costume' import type { Sprite } from './sprite' -enum AniType { - frame = 0, - move = 1, - turn = 2, - glide = 3 -} - type ActionConfig = { /** Sound name to play */ play?: string @@ -27,19 +20,26 @@ type ActionConfig = { export const defaultFps = 10 export type AnimationInits = { + /** Duration for animation to be played once */ duration?: number onStart?: ActionConfig // not supported by builder: - fps?: number isLoop?: boolean // TODO onPlay?: ActionConfig } -export type RawAnimationConfig = AnimationInits & { +export type RawAnimationConfig = Omit & { anitype?: number + frameFrom?: number | string + frameTo?: number | string + frameFps?: number + + // legacy APIs, for compatibility only: from?: number | string to?: number | string + fps?: number + duration?: number } export class Animation extends Disposable { @@ -103,7 +103,7 @@ export class Animation extends Disposable { this.duration = inits?.duration ?? 0 this.sound = inits?.onStart?.play ?? null - for (const field of ['fps', 'isLoop', 'onPlay'] as const) { + for (const field of ['isLoop', 'onPlay'] as const) { if (inits?.[field] != null) console.warn(`unsupported field: ${field} for sprite ${name}`) } @@ -120,12 +120,31 @@ export class Animation extends Disposable { return animation } - static load(name: string, { from, to, ...inits }: RawAnimationConfig, sprite: Sprite) { - if (from == null || to == null) throw new Error(`from and to expected for Animation ${name}`) - const fromIndex = getCostumeIndex(sprite.costumes, from) - const toIndex = getCostumeIndex(sprite.costumes, to) + static load( + name: string, + { + frameFrom, + frameTo, + frameFps, + from, + to, + fps, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + duration: _spxDuration, // drop spx `duration`, which is different from ours + ...inits + }: RawAnimationConfig, + sprite: Sprite + ) { + frameFrom = frameFrom ?? from + frameTo = frameTo ?? to + frameFps = frameFps ?? fps + if (frameFrom == null || frameTo == null) + throw new Error(`from and to expected for Animation ${name}`) + const fromIndex = getCostumeIndex(sprite.costumes, frameFrom) + const toIndex = getCostumeIndex(sprite.costumes, frameTo) const costumes = sprite.costumes.slice(fromIndex, toIndex + 1) - const animation = new Animation(name, inits) + const duration = costumes.length / (frameFps ?? defaultFps) + const animation = new Animation(name, { ...inits, duration }) animation.setCostumes(costumes.map((costume) => costume.clone())) for (const costume of costumes) { sprite.removeCostume(costume.name) @@ -145,10 +164,9 @@ export class Animation extends Disposable { Object.assign(files, costumeFiles) } const config: RawAnimationConfig = { - from: costumeConfigs[0]?.name, - to: costumeConfigs[costumeConfigs.length - 1]?.name, - duration: this.duration, - anitype: AniType.frame, + frameFrom: costumeConfigs[0]?.name, + frameTo: costumeConfigs[costumeConfigs.length - 1]?.name, + frameFps: Math.ceil(this.costumes.length / this.duration), onStart: this.sound == null ? undefined : { play: this.sound } } return [config, costumeConfigs, files] diff --git a/tools/ispx/go.mod b/tools/ispx/go.mod index 3b00544cf..f7a933565 100644 --- a/tools/ispx/go.mod +++ b/tools/ispx/go.mod @@ -45,6 +45,7 @@ require ( ) replace ( + github.com/goplus/spx => github.com/JiepengTan/spx v0.0.0-20240719133620-feffaabdead7 github.com/hajimehoshi/oto => github.com/hajimehoshi/oto v1.0.1 github.com/srwiley/oksvg => github.com/qiniu/oksvg v0.2.0-no-charset golang.org/x/image => golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d diff --git a/tools/ispx/go.sum b/tools/ispx/go.sum index 5bf088881..57a96472c 100644 --- a/tools/ispx/go.sum +++ b/tools/ispx/go.sum @@ -1,5 +1,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/JiepengTan/spx v0.0.0-20240719133620-feffaabdead7 h1:1ao1rWUNLiVADvDobtydL1BoYwComcePTbTKBZV3kTg= +github.com/JiepengTan/spx v0.0.0-20240719133620-feffaabdead7/go.mod h1:mFopcoTwo/IhdWUhQD1SmQfNdJyY7NPKnCcy5O1W9pc= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20210927141636-6d70534b1098 h1:iiPTCsr/y6MEke5leED5Bi/0zlznD44tlHQvTgLOJcE= @@ -38,16 +40,6 @@ github.com/goplus/mod v0.13.9 h1:B9zZoHi2AzMltTSOFqZNVjqGlSMlhhNTWwEzVqhTQzg= github.com/goplus/mod v0.13.9/go.mod h1:MibsLSftGmxaQq78YzUzNviyFwB9RtpMaoscufvEKH4= github.com/goplus/reflectx v1.2.2 h1:T1p20OIH/HcnAvQQNnDLwl6AZOjU34icsfc6migD6L8= github.com/goplus/reflectx v1.2.2/go.mod h1:wHOS9ilbB4zrecI0W1dMmkW9JMcpXV7VjALVbNU9xfM= -github.com/goplus/spx v1.0.1-0.20240625013919-ea894f504455 h1:/E/joCS3nu+VbxBsRt1j3OqQtACqO1nbMAf4yOVD0o0= -github.com/goplus/spx v1.0.1-0.20240625013919-ea894f504455/go.mod h1:eP0Yfbt31hSgnVmfmVeSRnq/kRoDyhwz+mI3VeXb/Vo= -github.com/goplus/spx v1.0.1-0.20240703050621-72b5b4f2242e h1:nlVcudZPaahpF7mn/HgHgIcNdqmbQP/ky5gF5UlLkWs= -github.com/goplus/spx v1.0.1-0.20240703050621-72b5b4f2242e/go.mod h1:8HjcFxmoksU4fxQF0Kc4hBuRLpW2FkEJHmLuyMhY5w8= -github.com/goplus/spx v1.0.1-0.20240708105507-8f9159acc876 h1:sV6oNNakUbjgCMC4PFjj/TvCbTGxCGaJIdUfFU3d4mw= -github.com/goplus/spx v1.0.1-0.20240708105507-8f9159acc876/go.mod h1:mFopcoTwo/IhdWUhQD1SmQfNdJyY7NPKnCcy5O1W9pc= -github.com/hajimehoshi/ebiten/v2 v2.7.5 h1:jN6FnhCd9NGYCsm5GtrweuikrlyVGCSUpH5YgL+7UKA= -github.com/hajimehoshi/ebiten/v2 v2.7.5/go.mod h1:H2pHVgq29rfm5yeQ7jzWOM3VHsjo7/AyucODNLOhsVY= -github.com/hajimehoshi/ebiten/v2 v2.7.6 h1:dKM/BdPZP+I/I0ElcqfQ1d06W+kA0nwhUOWzEdEBIbY= -github.com/hajimehoshi/ebiten/v2 v2.7.6/go.mod h1:Ulbq5xDmdx47P24EJ+Mb31Zps7vQq+guieG9mghQUaA= github.com/hajimehoshi/ebiten/v2 v2.7.7 h1:FyiuIOZqKU4aefYVws/lBDhTZu2WY2m/eWI3PtXZaHs= github.com/hajimehoshi/ebiten/v2 v2.7.7/go.mod h1:Ulbq5xDmdx47P24EJ+Mb31Zps7vQq+guieG9mghQUaA= github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= @@ -163,8 +155,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -175,8 +165,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= -golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= -golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=