Skip to content

Commit f2a41bf

Browse files
author
Builder
committed
Merge branch '4589-sdk-spriteanimation-needs-a-pause-function' into 'master'
[FEAT][sdk] spriteanimation needs a pause function See merge request codingame/game-engine!129
2 parents b158f0b + 497ddae commit f2a41bf

File tree

7 files changed

+86
-58
lines changed

7 files changed

+86
-58
lines changed

engine/modules/entities/src/main/java/com/codingame/gameengine/module/entities/Serializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ class Serializer {
5858
keys.put("zIndex", "z");
5959
keys.put("blendMode", "b");
6060
keys.put("images", "I");
61-
keys.put("started", "p");
61+
keys.put("restarted", "rs");
62+
keys.put("playing", "p");
6263
keys.put("loop", "l");
6364
keys.put("duration", "d");
6465
keys.put("baseWidth", "bw");

engine/modules/entities/src/main/java/com/codingame/gameengine/module/entities/SpriteAnimation.java

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ public class SpriteAnimation extends TextureBasedEntity<SpriteAnimation> impleme
1313

1414
@Inject GraphicEntityModule entityModule;
1515

16-
private int START_INDEX = 0;
16+
private int RESTART_INDEX = 0;
1717

1818
private String[] images = new String[] {};
1919

2020
private boolean loop;
21-
private boolean started;
21+
private boolean playing = true;
2222
private int duration = 1000;
2323

2424
SpriteAnimation() {
@@ -37,65 +37,57 @@ private static void requireValidDuration(int duration) {
3737
}
3838

3939
/**
40-
* Returns whether the animation is flagged to have the graphical counterpart start animating if it hasn't yet.
40+
* Returns whether the animation is flagged to have the graphical counterpart play the animation or to pause it.
4141
* <p>
42-
* Default is false.
42+
* Default is true.
4343
* </p>
4444
*
45-
* @return true if the animation has been started.
45+
* @return true if the animation is playing.
4646
*
4747
*/
48-
public boolean isStarted() {
49-
return started;
48+
public boolean isPlaying() {
49+
return playing;
5050
}
5151

5252
/**
53-
* Begins or restarts the animation, it will always begin at the first image.
54-
* <p>
55-
* Setting this to false will stop the animation, but it may not be resumed without restarting.
56-
* </p>
53+
* Plays or pause the animation
5754
*
5855
* @param started
59-
* true to begin or restart animation, false to stop animation
56+
* true to play animation, false to pause animation
6057
* @return this animation.
6158
*/
62-
public SpriteAnimation setStarted(boolean started) {
63-
this.started = started;
64-
65-
if (started) {
66-
set("started", START_INDEX, null);
67-
} else {
68-
set("started", "", null);
69-
}
59+
public SpriteAnimation setPlaying(boolean playing) {
60+
this.playing = playing;
61+
set("playing", playing, null);
7062
return this;
7163
}
7264

7365
/**
74-
* Calls setStarted(true) and forces the animation to play from the start;
66+
* Reset the progress of the animation
7567
*
7668
* @return this animation.
7769
*/
7870
public SpriteAnimation reset() {
79-
START_INDEX++;
80-
return setStarted(true);
71+
set("restarted", RESTART_INDEX++, null);
72+
return this;
8173
}
8274

8375
/**
84-
* Calls setStarted(true);
76+
* Calls setPlaying(true);
8577
*
8678
* @return this animation.
8779
*/
88-
public SpriteAnimation start() {
89-
return setStarted(true);
80+
public SpriteAnimation play() {
81+
return setPlaying(true);
9082
}
9183

9284
/**
93-
* Calls setStarted(false);
85+
* Calls setPlaying(false);
9486
*
9587
* @return this animation.
9688
*/
97-
public SpriteAnimation stop() {
98-
return setStarted(false);
89+
public SpriteAnimation pause() {
90+
return setPlaying(false);
9991
}
10092

10193
/**

engine/modules/entities/src/main/resources/view/entity-module/Command.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ const PROPERTY_KEY_MAP = {
3434
z: 'zIndex',
3535
b: 'blendMode',
3636
I: 'images',
37-
p: 'started',
37+
rs: 'restarted',
38+
p: 'playing',
3839
l: 'loop',
3940
d: 'duration',
4041
bw: 'baseWidth',
@@ -47,7 +48,7 @@ export class CreateCommand {
4748
this.type = args[0]
4849
}
4950

50-
apply (entities, frameNumber) {
51+
apply (entities) {
5152
let entity = EntityFactory.create(this.type)
5253
entity.id = this.id
5354
entities.set(this.id, entity)
@@ -61,8 +62,8 @@ export class CreateCommands {
6162
this.type = args[0]
6263
}
6364

64-
apply (entities, frameNumber) {
65-
this.commands.forEach(command => command.apply(entities, frameNumber))
65+
apply (entities, frameInfo) {
66+
this.commands.forEach(command => command.apply(entities, frameInfo.number, frameInfo))
6667
}
6768
}
6869

@@ -142,20 +143,20 @@ export class PropertiesCommand {
142143
}
143144
}
144145

145-
apply (entities, frameNumber) {
146+
apply (entities, frameInfo) {
146147
let entity = entities.get(this.id)
147-
entity.addState(this.t, {values: this.params, curve: this.curve}, frameNumber)
148+
entity.addState(this.t, {values: this.params, curve: this.curve}, frameInfo.number, frameInfo)
148149
}
149150
}
150151
export class WorldCommitCommand {
151152
constructor (args, globalData) {
152153
this.times = args.map(v => +v)
153154
}
154155

155-
apply (entities, frameNumber) {
156+
apply (entities, frameInfo) {
156157
entities.forEach(entity => {
157158
this.times.forEach(time => {
158-
entity.addState(time, {values: {}, curve: {}}, frameNumber)
159+
entity.addState(time, {values: {}, curve: {}}, frameInfo.number, frameInfo)
159160
})
160161
})
161162
}

engine/modules/entities/src/main/resources/view/entity-module/EntityFactory.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { BufferedGroup } from './BufferedGroup.js'
88
import { SpriteAnimation } from './SpriteAnimation.js'
99

1010
export class EntityFactory {
11-
static create(type) {
11+
static create (type) {
1212
var entity
1313
switch (type) {
1414
case 'C':

engine/modules/entities/src/main/resources/view/entity-module/GraphicEntityModule.js

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import { CommandParser } from './CommandParser.js'
22
import { fitAspectRatio } from '../core/utils.js'
33
import { WIDTH, HEIGHT } from '../core/constants.js'
44
import { ContainerBasedEntity } from './ContainerBasedEntity.js'
5-
import { Entity } from './Entity.js'
6-
75
export const api = {}
86

97
export class GraphicEntityModule {
@@ -38,12 +36,11 @@ export class GraphicEntityModule {
3836
}
3937

4038
handleFrameData (frameInfo, frameData) {
41-
const number = frameInfo.number
4239
if (frameData) {
4340
const commands = CommandParser.parse(frameData, this.globalData, frameInfo)
4441
if (commands) {
4542
commands.forEach(command => {
46-
const loadPromise = command.apply(this.entities, number)
43+
const loadPromise = command.apply(this.entities, frameInfo)
4744
if (loadPromise) {
4845
this.loadingAssets++
4946
loadPromise.then(() => {
@@ -54,11 +51,12 @@ export class GraphicEntityModule {
5451
}
5552
}
5653

57-
this.extrapolate(number)
58-
5954
const parsedFrame = {...frameInfo}
6055

6156
parsedFrame.previous = this.frames[this.frames.length - 1] || parsedFrame
57+
58+
this.extrapolate(parsedFrame)
59+
6260
if (parsedFrame !== parsedFrame.previous) {
6361
parsedFrame.previous.next = parsedFrame
6462
}
@@ -72,7 +70,9 @@ export class GraphicEntityModule {
7270
return arr[arr.length - 1]
7371
}
7472

75-
extrapolate (frameNumber) {
73+
extrapolate (frameInfo) {
74+
const frameNumber = frameInfo.number
75+
const previousFrameNumber = frameInfo.previous.number
7676
this
7777
.entities.forEach(entity => {
7878
// Create empty substate array if none
@@ -90,15 +90,23 @@ export class GraphicEntityModule {
9090
// Sort on t to begin extrapolation
9191
subStates.sort((a, b) => a.t - b.t)
9292

93+
if (!subStates.length || this.lastElementOf(subStates).t !== 1) {
94+
// Create a subState at t=1
95+
entity.addState(1, {}, frameNumber, frameInfo)
96+
}
97+
let prevState = currentState
98+
// If the entity had a state in the previous frame get the last one of them
99+
if (entity.states[previousFrameNumber] && previousFrameNumber !== frameNumber) {
100+
prevState = entity.states[previousFrameNumber][entity.states[previousFrameNumber].length - 1]
101+
}
93102
for (const state of subStates) {
94103
// Extrapolate through existing substates, updating the extrapolationMap in the process (currentState)
95104
Object.assign(currentState, state)
96105
Object.assign(state, currentState)
97-
}
98-
99-
if (!subStates.length || this.lastElementOf(subStates).t !== 1) {
100-
// Create a subState at t=1
101-
subStates.push(Entity.createState(1, currentState))
106+
if (typeof entity.computeAnimationProgressTime === 'function') {
107+
entity.computeAnimationProgressTime(prevState, state)
108+
}
109+
prevState = state
102110
}
103111
})
104112
}

engine/modules/entities/src/main/resources/view/entity-module/SpriteAnimation.js

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ export class SpriteAnimation extends TextureBasedEntity {
1212
images: '',
1313
loop: false,
1414
duration: 1000,
15-
started: null
15+
playing: true,
16+
restarted: null,
17+
animationProgressTime: 0,
18+
date: 0
1619
})
1720
}
1821

@@ -21,16 +24,21 @@ export class SpriteAnimation extends TextureBasedEntity {
2124
this.graphics = new PIXI.Sprite(PIXI.Texture.EMPTY)
2225
}
2326

27+
addState (t, params, frame, frameInfo) {
28+
super.addState(t, params, frame)
29+
const toModify = this.states[frame].find(v => v.t === t)
30+
const date = frameInfo.date + frameInfo.frameDuration * t
31+
toModify.date = date
32+
}
33+
2434
updateDisplay (state, changed, globalData, frame, progress) {
2535
super.updateDisplay(state, changed, globalData)
2636

27-
if (state.images && state.started) {
37+
if (state.images) {
2838
const duration = state.duration
29-
const date = frame.date + progress * frame.frameDuration
30-
const startDate = state.started.date
3139
const images = state.images.split(',')
3240

33-
const animationProgress = (state.loop ? unlerpUnclamped : unlerp)(startDate, startDate + duration, date)
41+
const animationProgress = (state.loop ? unlerpUnclamped : unlerp)(0, duration, state.animationProgressTime)
3442
if (animationProgress >= 0) {
3543
const animationIndex = Math.floor(images.length * animationProgress)
3644
const image = state.loop ? images[animationIndex % images.length] : (images[animationIndex] || images[images.length - 1])
@@ -44,4 +52,15 @@ export class SpriteAnimation extends TextureBasedEntity {
4452
this.graphics.texture = PIXI.Texture.EMPTY
4553
}
4654
}
55+
56+
computeAnimationProgressTime (prevState, currState) {
57+
if (currState.restarted && currState.restarted.date === currState.date) {
58+
currState.animationProgressTime = 0
59+
} else {
60+
currState.animationProgressTime = prevState.animationProgressTime
61+
if (prevState.playing) {
62+
currState.animationProgressTime += currState.date - prevState.date
63+
}
64+
}
65+
}
4766
}

engine/modules/entities/src/main/resources/view/entity-module/properties.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {lerp, lerpColor, lerpAngle} from '../core/utils.js'
22

33
const noLerp = (a, b, u) => u < 1 ? a : b
4+
const timeLerp = (a, b, u) => b < a ? b : lerp(a, b, u)
45

56
const colorOpts = {
67
type: Number,
@@ -37,6 +38,10 @@ const boolOpts = {
3738
},
3839
lerpMethod: noLerp
3940
}
41+
const timeOpts = {
42+
type: Number,
43+
lerpMethod: timeLerp
44+
}
4045

4146
export const PROPERTIES = {
4247
default: {
@@ -53,12 +58,14 @@ export const PROPERTIES = {
5358
strokeColor: colorOpts,
5459
tint: colorOpts,
5560

61+
animationProgressTime: timeOpts,
62+
5663
mask: constOpts,
5764
baseWidth: constOpts,
5865
baseHeight: constOpts,
5966
image: stringOpts,
6067
images: stringOpts,
61-
started: {
68+
restarted: {
6269
type: String,
6370
convert (value, globalData, frameInfo, t) {
6471
if (value) {
@@ -70,7 +77,7 @@ export const PROPERTIES = {
7077
},
7178
lerpMethod: noLerp
7279
},
73-
80+
playing: boolOpts,
7481
duration: constOpts,
7582
blendMode: constOpts,
7683

0 commit comments

Comments
 (0)