Migration
Migrating from v0.32.x to v1.0.0
v1.0.0 is a major version and carries every breaking change that was deferred during the v0.x line. Most of them are renames in service of a consistent API, the rest are behavior fixes. The full list is in the CHANGELOG, this page summarizes them and shows the codemod that does the bulk of the work.
Run the codemod first
The ex upgrade command in create-excalibur chains every migration from v0.29.3 onward and rewrites your source with formatting-preserving edits. It classifies call sites against the Excalibur types you currently have installed, so run it before you bump the dependency:
sh# preview the full plan, writes nothingnpx create-excalibur@latest upgrade --dry-run# apply the rewrites and bump package.jsonnpx create-excalibur@latest upgrade# then install the new versionnpm install
sh# preview the full plan, writes nothingnpx create-excalibur@latest upgrade --dry-run# apply the rewrites and bump package.jsonnpx create-excalibur@latest upgrade# then install the new versionnpm install
Options: --to next targets the prerelease line, --migrate-only rewrites code but leaves package.json alone, --allow-dirty skips the clean-git-tree requirement (a clean tree is your undo button, so prefer committing first). With the CLI installed globally the same command is ex upgrade (alias ex up).
Every migration is one of three kinds:
- Automated: rewritten for you, no review needed.
- Manual: a
// ex-upgrade(<id>): …breadcrumb comment is inserted at each site with a link and a recipe, because the right fix depends on what your code meant. - Notification: no code change, a heads up about a behavior change printed in the plan.
After running it, search your project for ex-upgrade( and work through the breadcrumbs, then build and type-check. If a migration is missing for something in your project, open an issue on create-excalibur.
Naming (automated)
Synchronous boolean state is always an isX/hasX getter, side-effecting calls are verb methods, and async state is a promise property.
- Zero-argument
isX()/hasX()methods became getters, drop the parentheses:entity.isKilled,engine.isRunning,engine.isDisposed,clock.isRunning,scene.isCurrentScene,sound.isPlaying/isPaused/isStopped,resource.isLoaded(everyLoadable),matrix.isIdentity,transform.isMirrored,boundingBox.hasZeroDimensions,camera.hasChanged,animation.isComplete,timer.isComplete,transition.isComplete,gamepad.isConnected, and more. - Methods that do real work stay verbs:
PolygonCollider.isConvex→checkConvex(),SparseHashGrid.hasChanged→refreshAndCheckChanged(), every inputtoggleEnabled(enabled)→setEnabled(enabled),Engine.toggleInputEnabled→setInputEnabled. - Option keys:
visible→isVisibleonActorOptions,TriggerOptions,GraphicsComponentOptions;solid→isSolidon tiles; graph edgedirected→isDirected;Slide({ easingFunction })→Slide({ easing });Timer({ fcn })→Timer({ action }). - Renames:
Engine.loadingComplete→isLoaded,Engine.ready(boolean) →isReady,Engine.isReady()(promise) →await engine.ready,Animation.done→isComplete,Gamepads.enabled→pollingEnabled,PointerEvent.active→isActive,Transition.started→hasStarted,isOffScreen→isOffscreen,isHiDpi→isHiDPI,Future.isCompleted→isComplete,Color.equal→equals,Screen.isFullScreen/goFullScreen/exitFullScreen→isFullscreen/enterFullscreen/exitFullscreen,Direction(text) →TextDirection,EnterViewPortEvent/ExitViewPortEvent→EnterViewportEvent/ExitViewportEvent. - Pausing:
Actor.paused(aPauseComponent) is now the read-onlypauseComponent; useactor.isPausedandactor.canPause.PauseComponentInterface→PauseComponentOptions. - System lifecycle hooks match the rest of the engine:
initialize/update/preupdate/postupdate→onInitialize/onUpdate/onPreUpdate/onPostUpdate.
Time units (automated, check sound code by hand)
Everything is milliseconds and nothing carries an Ms suffix: Engine.currentFrameElapsedMs → currentFrameElapsed, FrameStats.elapsedMs → elapsed, GifFrame.delayMs → delay, ClockOptions.defaultUpdateMs → defaultUpdate, Animation.durationPerFrameMs → durationPerFrame.
Sound, SoundTrack, and PlayOptions position/duration, seek(), getPlaybackPosition(), getTotalPlaybackDuration(), and scheduledStartTime are now milliseconds (previously seconds). The codemod cannot know whether a literal was seconds, so audit these:
typescript// Before: secondssound.play({ duration: 0.5 });sound.seek(2);// After: millisecondssound.play({ duration: 500 });sound.seek(2000);
typescript// Before: secondssound.play({ duration: 0.5 });sound.seek(2);// After: millisecondssound.play({ duration: 500 });sound.seek(2000);
Sound (mostly automated, play/resume is manual)
-
The audio abstraction is gone, Web Audio is the only implementation.
ex.WebAudioInstance→ex.SoundTrack;ex.Audio,ex.AudioImplementation,ex.ExResponse,ex.ExResponseTypeare removed (pass the response type string tonew ex.Resource(path, 'arraybuffer')). -
Sound.play()always starts a new track and never changes the sound's configuration. Previouslyplay()resumed paused tracks andplay(volume)permanently setSound.volume.typescript// Beforesound.play(0.5); // set volume forever AND resumed if paused// Aftersound.play({ volume: 0.5 }); // one-off volume for this track, multiplies sound.volumesound.resume(); // continue a paused or seeked tracksound.volume = 0.5; // change the configurationtypescript// Beforesound.play(0.5); // set volume forever AND resumed if paused// Aftersound.play({ volume: 0.5 }); // one-off volume for this track, multiplies sound.volumesound.resume(); // continue a paused or seeked tracksound.volume = 0.5; // change the configuration -
SoundManageris a real mixer. A sound routes through a singlechannel(SoundConfig.channel, notchannels),soundsis an array of named configs,addChannel/removeChannel/defaultVolumeare removed,SoundManager.volumeis the master volume, andplay()resolves to aboolean(false when dropped by a concurrency cap).typescript// Beforenew ex.SoundManager({channels: ['fx', 'music'],sounds: { jump: { sound: jump, volume: 0.4, channels: ['fx'] } }});// Afternew ex.SoundManager({channels: ['fx', 'music'],sounds: [{ name: 'jump', sound: jump, volume: 0.4, channel: 'fx' }]});typescript// Beforenew ex.SoundManager({channels: ['fx', 'music'],sounds: { jump: { sound: jump, volume: 0.4, channels: ['fx'] } }});// Afternew ex.SoundManager({channels: ['fx', 'music'],sounds: [{ name: 'jump', sound: jump, volume: 0.4, channel: 'fx' }]}); -
Muting is gain-based.
mute()no longer pauses andunmute()no longer starts playback, a muted sound keeps advancing and is mid-clip when unmuted.mute()/unmute()/toggle()with no argument act on the master output.
Screen space (manual, only clipping display modes)
Screen space is rooted at the top-left of the safe content area everywhere: CoordPlane.Screen entities, pointer events, Screen.worldToScreenCoordinates, and Screen.contentArea all agree. Previously worldToScreenCoordinates returned raw canvas coordinates and contentArea.left/top carried the canvas inset in the FitScreenAndFill, FitContainerAndFill, FitScreenAndZoom, and FitContainerAndZoom modes. Fixed, FitScreen, FillScreen, FitContainer, and FillContainer are unaffected.
typescript// Before: canvas-rooted, for example to position an HTML overlayconst canvasPos = engine.screen.worldToScreenCoordinates(actor.pos);// After: add the inset back if you really want canvas coordinatesconst canvasPos = engine.screen.worldToScreenCoordinates(actor.pos).add(engine.screen.contentAreaOffset);
typescript// Before: canvas-rooted, for example to position an HTML overlayconst canvasPos = engine.screen.worldToScreenCoordinates(actor.pos);// After: add the inset back if you really want canvas coordinatesconst canvasPos = engine.screen.worldToScreenCoordinates(actor.pos).add(engine.screen.contentAreaOffset);
Materials and post processors (manual)
-
Material.update()passes aMaterialContextinstead of the composite shader:typescript// Beforematerial.update((shader) => shader.trySetUniformFloatVector('iMouse', pos));// Aftermaterial.update((context) => (context.uniforms.iMouse = pos));// or skip update() entirelymaterial.uniforms.iMouse = pos;typescript// Beforematerial.update((shader) => shader.trySetUniformFloatVector('iMouse', pos));// Aftermaterial.update((context) => (context.uniforms.iMouse = pos));// or skip update() entirelymaterial.uniforms.iMouse = pos; -
MaterialOptionsis a union type (fragmentSourceonly,passesonly, or both), interfaces thatextends MaterialOptionsmust become type intersections. -
PostProcessor.process(source, destination)is required; the single-passgetShader()/getLayout()path,ex.ScreenShader, and thev_texcoordvarying are removed. Useex.ShaderPipelinePostProcessorwithpasses, orex.ShaderPass, andv_uv.
Behavior changes
rotateBy({ angleRadiansOffset, duration })with norotationTyperotates by exactly the signed offset. Offsets larger than π go the long way, and2 * Math.PIis a full revolution (previously a no-op). Pass an explicitrotationTypefor the old shortest-path behavior.TileMapdefaults tocompositeStrategy: 'separate'. The codemod writes the old'together'default explicitly onto existing tilemaps so nothing changes until you opt in.Scenedeactivation flushes pending entity and component removals synchronously.- Realistic physics bodies sleep by default (since v0.32).
- Font and text render more accurately with smaller textures, so text looks slightly different.
Engine.plugins/addPlugin,Scene.pause/resume,Actor.pauseComponent/isPaused/canPause, and thelightingengine option are new engine members. Subclass fields with those names now override engine behavior.
Removed (automated where a replacement exists)
ex.Shape→ex.Colliders(Colliders.Box/Polygon/Circle/Edge/Capsule)ColliderComponent.set()→use()ActorArgs/ParticleEmitterArgs→ActorOptions/ParticleEmitterOptions,ex.Pool→ex.ArenaPoolEasingFunctions.*and the 4-argument easing form → the(t: number) => numbereasings;EaseTo/EaseByandactions.easeTo/easeBy→MoveTo/MoveBywitheasingbody.sleeping→isSleeping,body.setSleeping(x)→body.isSleeping = x,body.center→globalPosentity.active→isActive,graphics.visible→isVisibleactor.getGlobalPos()/getGlobalRotation()/getGlobalScale()→globalPos/globalRotation/globalScaleBoundingBox.draw→debug,Vector.size→magnitude,engine.isFullScreen→isFullscreenworld.queryTags(...)→world.query({ tags: { all: [...] } }),TagsComponentGamepad.isButtonPressed→isButtonHeldActor.draggable: handlepointerdragstart/pointerdragmove/pointerdragendyourselfFlags.useLegacyImageRenderer()and the legacy image rendererex.EventTypes, the lowercaseex.Events.*aliases,AddedComponent/RemovedComponent@obsoletedecorator,Util.addItemToArray,CapturePointerConfig,Particle.DefaultConfig, theGifParser/Stream/LegacyWebAudioSourceexports, rAF/cAF/AudioContext polyfills- The UMD bundle: Excalibur is ESM-only,
require('excalibur')no longer works
Build
- The engine
tsconfigusesmodule: "esnext"withmoduleResolution: "bundler"; consumers importing source directly need bundler-compatible tooling.
Migrating from v0.28.x to v0.29.0
-
ex.Entity.tagsis now a javascriptSetinstead of anArraythis will affect methods that inspected tags as an array before. -
ex.SpriteSheet.getSprite(...)will now throw on invalid sprite coordinates, this is likely always an error and a warning is inappropriate. This also has the side benefit that you will always get a definite type out of the method. -
Changed the
Fontdefault base align toTopthis is more in line with user expectations. This does change the default rendering to the top left corner of the font instead of the bottom left. -
ex.Physicsstatic is marked as deprecated, configuring these setting will move to theex.Engine({...})constructortypescriptconst engine = new ex.Engine({...physics: {solver: ex.SolverStrategy.Realistic,gravity: ex.vec(0, 20),arcade: {contactSolveBias: ex.ContactSolveBias.VerticalFirst},}})typescriptconst engine = new ex.Engine({...physics: {solver: ex.SolverStrategy.Realistic,gravity: ex.vec(0, 20),arcade: {contactSolveBias: ex.ContactSolveBias.VerticalFirst},}}) -
ex.Engine.goToScene's second argument now takesGoToOptionsinstead of just scene activation datatypescriptgame.goToScene('myscene', {/*** Optionally supply scene activation data passed to Scene.onActivate*/sceneActivationData?: TActivationData,/*** Optionally supply destination scene "in" transition, this will override any previously defined transition*/destinationIn?: Transition,/*** Optionally supply source scene "out" transition, this will override any previously defined transition*/sourceOut?: Transition,/*** Optionally supply a different loader for the destination scene, this will override any previously defined loader*/loader?: DefaultLoader});typescriptgame.goToScene('myscene', {/*** Optionally supply scene activation data passed to Scene.onActivate*/sceneActivationData?: TActivationData,/*** Optionally supply destination scene "in" transition, this will override any previously defined transition*/destinationIn?: Transition,/*** Optionally supply source scene "out" transition, this will override any previously defined transition*/sourceOut?: Transition,/*** Optionally supply a different loader for the destination scene, this will override any previously defined loader*/loader?: DefaultLoader}); -
ECS components and system are now simplified to not require a string type name, now they just use the runtime type name instead.
- On your components remove the type argument
class MyComponent extends Component<'mycomponent'>toclass MyComponent extends Component - On your systems remove the type arguments
class MySystem extends System<MyComponent>toclass MySystem extends System - Systems no longer get magically passed the entities in
System.update()you now must create an explicitquery. Queries automatically get updatedtypescriptexport class MyComponent extends Component {data = 'foo';}class MySystem extends System {systemType = SystemType.Update;query: Query<typeof MyComponent>;constructor(world: World) {super();this.query = world.query([MyComponent]);}update(elapsed: number): void {for (let entity of this.query.entities) {const myComponent = entity.get(MyComponent);console.log(myComponent.data);}}}typescriptexport class MyComponent extends Component {data = 'foo';}class MySystem extends System {systemType = SystemType.Update;query: Query<typeof MyComponent>;constructor(world: World) {super();this.query = world.query([MyComponent]);}update(elapsed: number): void {for (let entity of this.query.entities) {const myComponent = entity.get(MyComponent);console.log(myComponent.data);}}}
- On your components remove the type argument
-
Graphics components no longer support layering built in, they now ONLY hold 1 graphic at a time. With this
actor.graphics.show()is now deprecatedgraphics.use()replaces the functionality. This change simplifies usage of graphics for folks building games and removes complexity caused by supporting layering and multiple graphics in Excalibur.- To use layering use
- A GraphicsGroup, you can specify a list of graphics in painter order (first is draw first, then so on)
typescriptconst actor = new ex.Actor({...});const graphicsGroup = new ex.GraphicsGroup({members: [new ex.Rectangle({width: 100, height: 100, color: ex.Color.Red}),{ offset: ex.vec(100, 100), graphic: new ex.Circle({radius: 100, color: ex.Color.Blue})}]});actor.graphics.use(graphicsGroup);typescriptconst actor = new ex.Actor({...});const graphicsGroup = new ex.GraphicsGroup({members: [new ex.Rectangle({width: 100, height: 100, color: ex.Color.Red}),{ offset: ex.vec(100, 100), graphic: new ex.Circle({radius: 100, color: ex.Color.Blue})}]});actor.graphics.use(graphicsGroup);
- Child actors if you need more control over graphic movement, transform, or behavior
typescriptconst actor = new ex.Actor({...});const child = new ex.Actor({pos: ex.vec(100, 100),rotation: Math.PI / 4,scale: ex.vec(3, 3)});actor.addChild(child);actor.graphics.use(new ex.Rectangle({width: 100, height: 100, color: ex.Color.Red}));child.graphics.use(new ex.Rectangle({width: 10, height: 10, color: ex.Color.Blue}));typescriptconst actor = new ex.Actor({...});const child = new ex.Actor({pos: ex.vec(100, 100),rotation: Math.PI / 4,scale: ex.vec(3, 3)});actor.addChild(child);actor.graphics.use(new ex.Rectangle({width: 100, height: 100, color: ex.Color.Red}));child.graphics.use(new ex.Rectangle({width: 10, height: 10, color: ex.Color.Blue}));
- A GraphicsGroup, you can specify a list of graphics in painter order (first is draw first, then so on)
- To use layering use
Migrating from v0.26.0 to v0.27.0
-
ex.Engine.snapToPixelnow defaults tofalse, it was unexpected to have pixel snapping on by default it has now been switched. You may need to explicitly switch it depending on your desired effect. -
The
ex.Physics.useRealisticPhysics()physics solver has been updated to fix a bug in bounciness to be more physically accurate, this does change how physics behaves. Settingex.Body.bounciness = 0will simulate the old behavior. -
ex.TransformComponent.getGlobalMatrix()has been removed, use this insteadtypescriptconst actor = new ex.Actor({...});const transform = actor.get(TransformComponent);const matrix = transform.get().matrix;typescriptconst actor = new ex.Actor({...});const transform = actor.get(TransformComponent);const matrix = transform.get().matrix; -
ex.TransformComponent.posChanged$has been removed, it incurs a steep performance cost. -
ex.EventDispatchermeta events 'subscribe' and 'unsubscribe' were unused and undocumented and have been removed. -
ex.TileMaptiles are now drawn from the lower left by default to match withex.IsometricMapand Tiled, but can be configured withrenderFromTopOfGraphicto restore the previous behavior.typescriptconst tilemap = new ex.TileMap({...renderFromTopOfGraphic: true})typescriptconst tilemap = new ex.TileMap({...renderFromTopOfGraphic: true}) -
Scene
onActivateandonDeactivatemethods have been changed to receive a single context parameter, an object containing thepreviousScene,nextScene, and optionaldatapassed in fromgoToScene(). Update anyonActivateoronDeactivatehandlerstypescriptonActivate(ctx: SceneActivationContext<TActivationData>) {...}typescriptonActivate(ctx: SceneActivationContext<TActivationData>) {...}
Migrating from v0.25.3 to v0.26.0
The old drawing API had been removed from excalibur, this should not affect you unless you were using the ex.Flags.useLegacyDrawing(). If so you must switch to the new graphics api.
ex.TileMap has several breaking changes around naming, but brings it consistent with Tiled terminology and the new ex.IsometricMap. Additionally the new names are easier to follow.
- Constructor has been changed to the following
typescriptnew ex.TileMap({pos: ex.vec(100, 100),tileWidth: 64,tileHeight: 48,rows: 20,columns: 20,})typescriptnew ex.TileMap({pos: ex.vec(100, 100),tileWidth: 64,tileHeight: 48,rows: 20,columns: 20,})
ex.Cellhas been renamed toex.Tileex.Tilenow usesaddGraphic(...),removeGraphic(...),clearGraphics()andgetGraphics()instead of having an accessibleex.Tile.graphicsarray.
ex.TileMap.datahas been renamed toex.TileMap.tilesex.TileMap.getCell(..)has been renamed toex.TileMap.getTile(...)ex.TileMap.getCellByIndex(...)has been renamed toex.TileMap.getTileByIndex(...)ex.TileMap.getCellByPoint(...)has been renamed toex.TileMap.getTileByPoint(...)
The following types have been removed:
ex.SortedListold sorted list is removed, use the built in browser Array.sortex.Collectionold collection type is removed, use the built in browser Arrayex.Utilimport site, exported code promotedex.*ex.DisplayMode.Positionis removed, use CSS to position the canvasex.Traitinterface, traits are not longer supportedex.Promisesold promise implementation is removed in favor of browser promises
Notable method & property removals
ex.Actor.getZIndex()and.setZIndex()removed use.z
ex.Scene.screenElementsremoved in favor of.entities.addScreenElement(...)removed use.add(...).addTileMap(...)removed use.add(...).removeTileMap(...)removed use.remove(...)
ex.Timer.unpause()removed use.resume()
ex.Camera.rxremoved use.angularVelocity
ex.BodyComponent.sxremoved use.scaleFactor.rxremoved use.angularVelocity
ex.ActionsComponent.asPromise()removed use.toPromise()
ex.ActionContext.asPromise()removed use.toPromise()
ex.Color- Misspellings corrected
Migrating from v0.25.1 to v0.25.2
- EventEmitter no longer tampers with
thison the event callbacks which may be a breaking change for some people. Change callbacks's to be an arrow function to capturethis
typescriptclass MyActor extends ex.Actor {constructor() {super()// Change from thisthis.on('precollision', this.onPreCollision)// To thisthis.on('precollision', (evt) => this.onPreCollision(evt))}}
typescriptclass MyActor extends ex.Actor {constructor() {super()// Change from thisthis.on('precollision', this.onPreCollision)// To thisthis.on('precollision', (evt) => this.onPreCollision(evt))}}
Migrating from v0.24.5 to v0.25.0
Graphics
-
Replace
ex.Texturewithex.ImageSource -
Replace
ex.Texture.asSprite()withex.ImageSource.toSprite()
typescriptconst image = new ex.ImageSource('./img/myimage.png')// keep in mind this wont work until the image source is loadedconst sprite = image.toSprite()
typescriptconst image = new ex.ImageSource('./img/myimage.png')// keep in mind this wont work until the image source is loadedconst sprite = image.toSprite()
- Update
ex.Spriteconstructor arguments
typescriptconst image = new ex.ImageSource('./path/to/image.png')const sprite = new ex.Sprite({image: image,sourceView: {// Take a small slice of the source image starting at pixel (10, 10) with dimension 20 pixels x 20 pixelsx: 10,y: 10,width: 20,height: 20,},destSize: {// Optionally specify a different projected size, otherwise use the sourcewidth: 100,height: 100,},})
typescriptconst image = new ex.ImageSource('./path/to/image.png')const sprite = new ex.Sprite({image: image,sourceView: {// Take a small slice of the source image starting at pixel (10, 10) with dimension 20 pixels x 20 pixelsx: 10,y: 10,width: 20,height: 20,},destSize: {// Optionally specify a different projected size, otherwise use the sourcewidth: 100,height: 100,},})
- Update
new ex.SpriteSheet()constructor withex.SpriteSheet.fromImageSource()
typescriptconst runImage = new ex.ImageSource(runImageSrc)const runSheet = ex.SpriteSheet.fromImageSource({image: runImage,grid: {rows: 1,columns: 21,spriteWidth: 96,spriteHeight: 96,},})
typescriptconst runImage = new ex.ImageSource(runImageSrc)const runSheet = ex.SpriteSheet.fromImageSource({image: runImage,grid: {rows: 1,columns: 21,spriteWidth: 96,spriteHeight: 96,},})
-
Replace Legacy Drawing Usage
ex.Actor.addDrawing()withex.Actor.graphics.add()ex.Actor.setDrawing()withex.Actor.graphics.use()orex.Actor.graphics.show()
-
Replace Legacy
ex.Actor.onPostDrawandex.Actor.onPreDrawwithactor.graphicsorex.Canvas
typescriptconst canvas = new ex.Canvas({cache: true,draw: (ctx: CanvasRenderingContext2D) => {// custom drawing with CanvasRenderingContext2D},})actor.use(canvas)actor.graphics.onPreDraw = (exctx: ExcaliburGraphicsContext) => {// custom drawing with ExcaliburGraphicsContext}actor.graphics.onPostDraw = (exctx: ExcaliburGraphicsContext) => {// custom drawing with ExcaliburGraphicsContext}
typescriptconst canvas = new ex.Canvas({cache: true,draw: (ctx: CanvasRenderingContext2D) => {// custom drawing with CanvasRenderingContext2D},})actor.use(canvas)actor.graphics.onPreDraw = (exctx: ExcaliburGraphicsContext) => {// custom drawing with ExcaliburGraphicsContext}actor.graphics.onPostDraw = (exctx: ExcaliburGraphicsContext) => {// custom drawing with ExcaliburGraphicsContext}
Actors
- Actor only supports the option bag constructor
new ex.Actor({...}) - Label only supports the option bag constructor
new ex.Label({...}) - Replace
ex.Actor.rxwithex.Actor.angularVelocity
Camera
ex.Camera.zhas been renamed to propertyex.Camera.zoomwhich is the zoom factorex.Camera.zoom(...)has been renamed to functionex.Camera.zoomOverTime()
Engine
-
DisplayMode's have changed (#1733) & (#1928):DisplayMode.FitContainerfits the screen to the available width/height in the canvas parent element, while maintaining aspect ratio and resolutionDisplayMode.FillContainerupdate the resolution and viewport dynamically to fill the available space in the canvas parent element, DOES NOT preserveaspectRatioDisplayMode.FitScreenfits the screen to the available browser window space, while maintaining aspect ratio and resolutionDisplayMode.FillScreennow does whatDisplayMode.FullScreenused to do, the resolution and viewport dynamically adjust to fill the available space in the window, DOES NOT preserveaspectRatio(#1733)DisplayMode.FullScreenis now removed, useScreen.goFullScreen().
Physics
- Rename
ex.Edgetoex.EdgeColliderandex.ConvexPolygontoex.PolygonCollider
Timer
- Timers must be added to a scene and
Timer.start()called for them to start Timer.unpause()has be deprecated in favor ofTimer.resume()(#1864)
Actions
- Rewrite
ex.Actor.actions.repeat()andex.Actor.actions.repeatForever()to use thectxto define the set of repeating actions
typescriptconst actor = new ex.Actor()actor.actions// Move up in a zig-zag by repeating 5 times.repeat((ctx) => {ctx.moveBy(10, 0, 10)ctx.moveBy(0, 10, 10)}, 5).callMethod(() => {console.log('Done repeating!')})
typescriptconst actor = new ex.Actor()actor.actions// Move up in a zig-zag by repeating 5 times.repeat((ctx) => {ctx.moveBy(10, 0, 10)ctx.moveBy(0, 10, 10)}, 5).callMethod(() => {console.log('Done repeating!')})
TileMap
- TileMap no longer needs registered SpriteSheets,
Sprite's can be added directly toCell's withaddGraphic- The confusing
TileSpritetype is removed (Related to TileMap plugin updates https://github.com/excaliburjs/excalibur-tiled/issues/4, https://github.com/excaliburjs/excalibur-tiled/issues/23, https://github.com/excaliburjs/excalibur-tiled/issues/108)
- The confusing