UNPKG

pxt-common-packages

Version:
177 lines (154 loc) 5.09 kB
/* Animation library for sprites */ namespace animation { //Handles all the updates let animations: Animation[]; let animationStateStack: { state: Animation[], scene: scene.Scene }[]; game.addScenePushHandler(oldScene => { if (animations) { if (!animationStateStack) animationStateStack = []; animationStateStack.push({ state: animations, scene: oldScene }); animations = undefined; } }); game.addScenePopHandler(() => { const scene = game.currentScene(); animations = undefined; if (animationStateStack && animationStateStack.length) { const nextState = animationStateStack.pop(); if (nextState.scene == scene) { animations = nextState.state; } else { animationStateStack.push(nextState); } } }); export class Animation { sprites: Sprite[]; frames: Image[]; index: number; interval: number; action: number; lastTime: number; constructor(action: number, interval: number) { this.interval = interval; this.index = -1; this.action = action; this.frames = []; this.sprites = []; this.lastTime = control.millis(); this._init(); } _init() { if (!animations) { animations = []; game.eventContext().registerFrameHandler(scene.ANIMATION_UPDATE_PRIORITY, () => { animations.forEach(anim => anim.update()); }); } animations.push(this); } update() { let currentTime = control.millis(); let dt = currentTime - this.lastTime; if (dt >= this.interval && this.frames.length) { this.index = (this.index + 1) % this.frames.length; this.lastTime = currentTime; } this.sprites = this.sprites.filter(sprite => !(sprite.flags & sprites.Flag.Destroyed)); this.sprites.forEach(sprite => { if (sprite._action === this.action) { let newImage = this.getImage(); //Update only if the image has changed if (sprite.image !== newImage) { sprite.setImage(newImage); } } }); } getImage() { return this.frames[this.index]; } getAction() { return this.action; } getInterval() { return this.interval; } setInterval(interval: number) { this.interval = interval; } /** * Add an image frame to an animation */ //% blockId=addAnimationFrame //% block="add frame $frame=screen_image_picker to $this=variables_get(anim)" //% group="Advanced" //% weight=40 //% help=animation/add-animation-frame addAnimationFrame(frame: Image) { this.frames[++this.index] = frame; } registerSprite(sprite: Sprite) { if (this.sprites.indexOf(sprite) === -1) { this.sprites.push(sprite); } } } //% shim=ENUM_GET //% blockId=action_enum_shim //% block="%arg" //% group="Advanced" //% enumName="ActionKind" //% enumMemberName="action" //% enumPromptHint="e.g. Walking, Idle, Jumping, ..." //% enumInitialMembers="Walking, Idle, Jumping" //% weight=10 export function _actionEnumShim(arg: number) { // This function should do nothing, but must take in a single // argument of type number and return a number value. return arg; } /** * Create an animation */ //% blockId=createAnimation //% block="create animation of $action=action_enum_shim with interval $interval ms" //% group="Advanced" //% interval.defl=1000 //% blockSetVariable="anim" //% weight=50 //% help=animation/create-animation export function createAnimation(action: number, interval: number) { return new Animation(action, interval); } /** * Attach an animation to a sprite */ //% blockId=attachAnimation //% block="attach animation $set=variables_get(anim) to sprite $sprite=variables_get(mySprite)" //% group="Advanced" //% weight=30 //% help=animation/attach-animation export function attachAnimation(sprite: Sprite, set: Animation) { set.registerSprite(sprite); } /** * Set an animation action to a sprite */ //% blockId=setAction //% block="activate animation $action=action_enum_shim on $sprite=variables_get(mySprite)" //% group="Advanced" //% weight=20 //% help=animation/set-action export function setAction(sprite: Sprite, action: number) { sprite._action = action; } }