UNPKG

excalibur

Version:

Excalibur.js is a simple JavaScript game engine with TypeScript bindings for making 2D games in HTML5 Canvas. Our mission is to make web game development as simple as possible.

1,087 lines (919 loc) • 176 kB
# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Breaking Changes - ### Deprecated - ### Added - New PostProcessor.onDraw() hook to handle uploading textures - Adds contact solve bias to RealisticSolver, this allows customization on which direction contacts are solved first. By default there is no bias set to 'none'. ### Fixed - Fixed false positive warning when adding timers - Fixed issue where gamepad buttons wouldn't progress the default loader play button - Add defense around middling Safari fullscreen support and update documentation - Fixed issue where non-standard gamepad buttons would not be emitted by Excalibur - Added an additional param to the `ex.GamepadButtonEvent` `index`to disabiguate between `ex.Buttons.Unknown` - Fixed issue where Realistic solver would not sort contacts by distance causing some artifacts on seams - Fixed issue with CompositeCollider where large TileMaps would sometimes causes odd collision behavior in the Realistic Solver when the body & collider components are far apart in a TileMap. - Fixed crash on Xiaomi Redmi Phones by lazy loading the GPU particle renderer, GPU particles still do not work on these phones - Add warning if World.add() falls through! This is caused by multiple versions of Excalibur usually - Fixed CollidePolygonPolygon crash with some defense against invalid separation - Fixed issue with PostProcessor where it would not run correctly if no actors present ### Updates - ### Changed - <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> ## [v0.30.0] ### Breaking Changes - `ex.Engine.goto(...)` removed, use `ex.Engine.goToScene(...)` - `ex.GraphicsComponent.show(...)` removed, use `ex.GraphicsComponent.use(...)` - `ex.EventDispatcher` removed, use `ex.EventEmitter` instead. - `ex.Engine.getAntialiasing()` and `ex.Engine.setAntialiasing(bool)` have been removed, use the engine constructor parameter to configure `new ex.Engine({antialiasing: true})` or set on the screen `engine.screen.antialiasing = true` - `ex.Physics.*` configuration statics removed, use the engine constructor parameter to configure `new ex.Engine({physics: ...})` - `ex.Input.*` namespace removed and types promoted to `ex.*` - Removed legacy `ex.Configurable` function type used for doing dark magic to allow types to be configured by instances of that same type :boom: - Collision events now only target `ex.Collider` types, this previously would sometimes emit an `ex.Entity` if you attached to the `ex.ColliderComponent` * `ex.PreCollisionEvent` * `ex.PostCollisionEvent` * `ex.ContactStartEvent` * `ex.ContactEndEvent` * `ex.CollisionPreSolveEvent` * `ex.CollisionPostSolveEvent` * `ex.CollisionStartEvent` * `ex.CollisionEndEvent` - `System.priority` is refactored to be static. - `ex.Timer` now only takes the option bag constructor - `PreDrawEvent`, `PostDrawEvent`, `PreTransformDrawEvent`, `PostTransformDrawEvent`, `PreUpdateEvent`, `PostUpdateEvent` now use `elapsedMs` instead of `delta` for the elapsed milliseconds between the last frame.460696 - `Trigger` API has been slightly changed: - `action` now returns the triggering entity: `(entity: Entity) => void` - `target` now works in conjunction with `filter` instead of overwriting it. - `EnterTriggerEvent` and `ExitTriggerEvent` now contain a `entity: Entity` property instead of `actor: Actor` - `ex.Vector.normalize()` return zero-vector (`(0,0)`) instead of `(0,1)` when normalizing a vector with a magnitude of 0 - `ex.Gif` transparent color constructor arg is removed in favor of the built in Gif file mechanism - Remove core-js dependency, it is no longer necessary in modern browsers. Technically a breaking change for older browsers - `ex.Particle` and `ex.ParticleEmitter` now have an API that looks like modern Excalibur APIs * `particleSprite` is renamed to `graphic` * `particleRotationalVelocity` is renamed to `angularVelocity` * `fadeFlag` is renamed to `fade` * `acceleration` is renamed to `acc` * `particleLife` is renamed to `life` * `minVel` is renamed to `minSpeed` * `maxVel` is renamed to `maxSpeed` * `ParticleEmitter` now takes a separate `particle: ParticleConfig` parameter to disambiguate between particles parameters and emitter ones ```typescript const emitter = new ex.ParticleEmitter({ width: 10, height: 10, radius: 5, emitterType: ex.EmitterType.Rectangle, emitRate: 300, isEmitting: true, particle: { transform: ex.ParticleTransform.Global, opacity: 0.5, life: 1000, acc: ex.vec(10, 80), beginColor: ex.Color.Chartreuse, endColor: ex.Color.Magenta, startSize: 5, endSize: 100, minVel: 100, maxVel: 200, minAngle: 5.1, maxAngle: 6.2, fade: true, maxSize: 10, graphic: swordImg.toSprite(), randomRotation: true, minSize: 1 } }); ``` ### Deprecated - `easeTo(...)` and `easeBy(...)` actions marked deprecated, use `moveTo({easing: ...})` instead - `Vector.size` is deprecated, use `Vector.magnitude` instead - `ScreenShader` v_texcoord is deprecated, use v_uv. This is changed to match the materials shader API - `actor.getGlobalPos()` - use `actor.globalPos` instead - `actor.getGlobalRotation()` - use `actor.globalRotation` instead - `actor.getGlobalScale()` - use `actor.globalScale` instead ### Added - Added `ex.SpriteSheet.getTiledSprite(...)` to help pulling tiling sprites out of a sprite sheet - Alias the `engine.screen.drawWidth/drawHeight` with `engine.screen.width/height`; - Added convenience types `ex.TiledSprite` and `ex.TiledAnimation` for Tiling Sprites and Animations ```typescript const tiledGroundSprite = new ex.TiledSprite({ image: groundImage, width: game.screen.width, height: 200, wrapping: { x: ex.ImageWrapping.Repeat, y: ex.ImageWrapping.Clamp } }); const tilingAnimation = new ex.TiledAnimation({ animation: cardAnimation, sourceView: {x: 20, y: 20}, width: 200, height: 200, wrapping: ex.ImageWrapping.Repeat }); ``` - Added new static builder for making images from canvases `ex.ImageSource.fromHtmlCanvasElement(image: HTMLCanvasElement, options?: ImageSourceOptions)` - Added GPU particle implementation for MANY MANY particles in the simulation, similar to the existing CPU particle implementation. Note `maxParticles` is new for GPU particles. ```typescript var particles = new ex.GpuParticleEmitter({ pos: ex.vec(300, 500), maxParticles: 10_000, emitRate: 1000, radius: 100, emitterType: ex.EmitterType.Circle, particle: { beginColor: ex.Color.Orange, endColor: ex.Color.Purple, focus: ex.vec(0, -400), focusAccel: 1000, startSize: 100, endSize: 0, life: 3000, minSpeed: -100, maxSpeed: 100, angularVelocity: 2, randomRotation: true, transform: ex.ParticleTransform.Local } }); ``` - Added `ex.assert()` that can be used to throw in development builds - Added `easing` option to `moveTo(...)` - Added new option bag style input to actions with durations in milliseconds instead of speed ```typescript player.actions.rotateTo({angleRadians: angle, duration: 1000, rotationType}); player.actions.moveTo({pos: ex.vec(100, 100), duration: 1000}); player.actions.scaleTo({scale: ex.vec(2, 2), duration: 1000}); player.actions.repeatForever(ctx => { ctx.curveTo({ controlPoints: [cp1, cp2, dest], duration: 5000, mode: 'uniform' }); ctx.curveTo({ controlPoints: [cp2, cp1, start1], duration: 5000, mode: 'uniform' }); }); ``` - Added `ex.lerpAngle(startAngleRadians: number, endAngleRadians: number, rotationType: RotationType, time: number): number` in order to lerp angles between each other - Added `pointerenter` and `pointerleave` events to `ex.TileMap` tiles! - Added `pointerenter` and `pointerleave` events to `ex.IsometricMap` tiles! - Added new `ex.BezierCurve` type for drawing cubic bezier curves - Added 2 new actions `actor.actions.curveTo(...)` and `actor.actions.curveBy(...)` - Added new `ex.lerp(...)`, `ex.inverseLerp(...)`, and `ex.remap(...)` for numbers - Added new `ex.lerpVector(...)`,` ex.inverseLerpVector(...)`, and `ex.remapVector(...)` for `ex.Vector` - Added new `actor.actions.flash(...)` `Action` to flash a color for a period of time - Added a new `ex.NineSlice` `Graphic` for creating arbitrarily resizable rectangular regions, useful for creating UI, backgrounds, and other resizable elements. ```typescript var nineSlice = new ex.NineSlice({ width: 300, height: 100, source: inputTile, sourceConfig: { width: 64, height: 64, topMargin: 5, leftMargin: 7, bottomMargin: 5, rightMargin: 7 }, destinationConfig: { drawCenter: true, horizontalStretch: ex.NineSliceStretch.Stretch, verticalStretch: ex.NineSliceStretch.Stretch } }); actor.graphics.add(nineSlice); ``` - Added a method to force graphics on screen `ex.GraphicsComponent.forceOnScreen` - Added new `ex.Slide` scene transition, which can slide a screen shot of the current screen: `up`, `down`, `left`, or `right`. Optionally you can add an `ex.EasingFunction`, by default `ex.EasingFunctions.Linear` ```typescript game.goToScene('otherScene', { destinationIn: new ex.Slide({ duration: 1000, easingFunction: ex.EasingFunctions.EaseInOutCubic, slideDirection: 'up' }) }); ``` - Added inline SVG image support `ex.ImageSource.fromSvgString('<svg>...</svg>')`, note images produced this way still must be loaded. - Added ability to optionally specify sprite options in the `.toSprite(options:? SpriteOptions)` - The `ex.Engine` constructor had a new `enableCanvasContextMenu` arg that can be used to enable the right click context menu, by default the context menu is disabled which is what most games seem to want. - Child `ex.Actor` inherits opacity of parents - `ex.Engine.timeScale` values of 0 are now supported - `ex.Trigger` now supports all valid actor constructor parameters from `ex.ActorArgs` in addition to `ex.TriggerOptions` - `ex.Gif` can now handle default embedded GIF frame timings - New `ex.Screen.worldToPagePixelRatio` API that will return the ratio between excalibur pixels and the HTML pixels. * Additionally excalibur will now decorate the document root with this same value as a CSS variable `--ex-pixel-ratio` * Useful for scaling HTML UIs to match your game ```css .ui-container { pointer-events: none; position: absolute; transform-origin: 0 0; transform: scale( calc(var(--pixel-conversion)), calc(var(--pixel-conversion))); } ``` - New updates to `ex.coroutine(...)` * New `ex.CoroutineInstance` is returned (still awaitable) * Control coroutine autostart with `ex.coroutine(function*(){...}, {autostart: false})` * `.start()` and `.cancel()` coroutines * Nested coroutines! - Excalibur will now clean up WebGL textures that have not been drawn in a while, which improves stability for long game sessions * If a graphic is drawn again it will be reloaded into the GPU seamlessly - You can now query for colliders on the physics world ```typescript const scene = ...; const colliders = scene.physics.query(ex.BoundingBox.fromDimensions(...)); ``` - `actor.oldGlobalPos` returns the globalPosition from the previous frame - create development builds of excalibur that bundlers can use in dev mode - show warning in development when Entity hasn't been added to a scene after a few seconds - New `RentalPool` type for sparse object pooling - New `ex.SparseHashGridCollisionProcessor` which is a simpler (and faster) implementation for broadphase pair generation. This works by bucketing colliders into uniform sized square buckets and using that to generate pairs. - CollisionContact can be biased toward a collider by using `contact.bias(collider)`. This adjusts the contact so that the given collider is colliderA, and is helpful if you are doing mtv adjustments during precollision. - `angleBetween` medhod added to Vector class, to find the angle for which a vector needs to be rotated to match some given angle: ```typescript const point = vec(100, 100) const destinationDirection = Math.PI / 4 const angleToRotate = point.angleBetween(destinationDirection, RotationType.ShortestPath) expect(point.rotate(angleToRotate).toAngle()).toEqual(destinationDirection) ``` ### Fixed - Fixed issue where `ex.ParticleEmitter.clearParticles()` did not work - Fixed issue where the pointer `lastWorldPos` was not updated when the current `Camera` moved - Fixed issue where `cancel()`'d events still bubbled to the top level input handlers - Fixed issue where unexpected html HTML content from an image would silently hang the loader - Fixed issue where Collision events ahd inconsistent targets, sometimes they were Colliders and sometimes they were Entities - Fixed issue where `ex.Engine.screenshot()` images may not yet be loaded in time for use in `ex.Transition`s - Fixed issue where there would be an incorrect background color for 1 frame when transitioning to a new scene - Fixed issue where `blockInput: true` on scene transition only blocked input events, not accessors like `wasHeld(...)` etc. - Fixed issue where users could not easily define a custom `RendererPlugin` because the type was not exposed - Fixed issue where `ex.Fade` sometimes would not complete depending on the elapsed time - Fixed issue where `ex.PolygonColliders` would get trapped in infinite loop for degenerate polygons (< 3 vertices) - Fixed issue where certain devices that support large numbers of texture slots exhaust the maximum number of if statements (complexity) in the shader. - Fixed issue where `ex.Label` where setting the opacity of caused a multiplicative opacity effect when actor opacity set - Fixed issue where the `ex.Loader` would have a low res logo on small configured resolution sizes - Fixed issue where `ex.Gif` was not parsing certain binary formats correctly - Fixed issue where the boot `ex.Loader` was removing pixelRatio override - Fixed `ex.RasterOptions`, it now extends `ex.GraphicsOptions` which is the underlying truth - Fixed issue where rayCast `filter` would not be called in hit order - Fixed issue where rayCasts would return inconsistent orderings with the `ex.SparseHashGridCollisionProcessor` strategy - Fixed issue where CircleCollider tangent raycast did not work correctly - Fixed issue where you were required to provide a transition if you provided a loader in the `ex.Engine.start('scene', { loader })` - Fixed issue where `ex.Scene.onPreLoad(loader: ex.DefaultLoader)` would lock up the engine if there was an empty loader - Fixed issue where `ex.Scene` scoped input events would preserve state and get stuck causing issues when switching back to the original scene. - Fixed issue where not all physical keys from the spec were present in `ex.Keys` including the reported `ex.Keys.Tab` - Fixed invalid graphics types around `ex.Graphic.tint` - improve types to disallow invalid combo of collider/width/height/radius in actor args - only add default color graphic for the respective collider used - Fixed issue where `ex.SpriteFont` did not respect scale when measuring text - Fixed issue where negative transforms would cause collision issues because polygon winding would change. - Fixed issue where removing and re-adding an actor would cause subsequent children added not to function properly with regards to their parent/child transforms - Fixed issue where `ex.GraphicsSystem` would crash if a parent entity did not have a `ex.TransformComponent` - Fixed a bug in the new physics config merging, and re-arranged to better match the existing pattern - Fixed a bug in `canonicalizeAngle`, don't allow the result to be 2PI, now it will be in semi-open range [0..2PI) - Removed circular dependency between `Actions` and `Math` packages by moving `RotationType` into `Math` package. ### Updates - Remove units by default from parameters - Perf improve PolygonCollider.contains(...) perf by keeping geometry tests in local space. - Perf improvement to image rendering! with ImageRendererV2! Roughly doubles the performance of image rendering - Perf improvement to retrieving components with `ex.Entity.get()` which widely improves engine performance - Non-breaking parameters that reference `delta` to `elapsedMs` to better communicate intent and units - Perf improvements to `ex.ParticleEmitter` * Use the same integrator as the MotionSystem in the tight loop * Leverage object pools to increase performance and reduce allocations - Perf improvements to collision narrowphase and solver steps * Working in the local polygon space as much as possible speeds things up * Add another pair filtering condition on the `SparseHashGridCollisionProcessor` which reduces pairs passed to narrowphase * Switching to c-style loops where possible * Caching get component calls * Removing allocations where it makes sense - Perf Side.fromDirection(direction: Vector): Side - thanks @ikudrickiy! - Perf improvements to PointerSystem by using new spatial hash grid data structure - Perf improvements: Hot path allocations * Reduce State/Transform stack hot path allocations in graphics context * Reduce Transform allocations * Reduce AffineMatrix allocations - Perf improvements to `CircleCollider` bounds calculations - Switch from iterators to c-style loops which bring more speed * `Entity` component iteration * `EntityManager` iteration * `EventEmitter`s * `GraphicsSystem` entity iteration * `PointerSystem` entity iteration - Perf improvements to `GraphicsGroup` by reducing per draw allocations in bounds calculations ### Changed - Applied increased TS strictness: * Director API subtree * Resource API subtree * Graphics API subtree * TileMap API subtree ## [v0.29.3] ### Breaking Changes - `ex.Action` now requires a unique `id` property - Z-indexes are now relative to the parent's Z-index. You can get the global Z-index with the `globalZ` property on the Actor or TransformComponent. ### Deprecated ### Added - Built in actions now have a unique `id` property - `globalZ` property to Actor and TransformComponent ### Fixed - Fixed animation glitch caused by uninitialized state in `ImageRenderer` - Fixed issue where `ex.Loader.suppressPlayButton = true` did not work. Only using the `ex.Engine({suppressPlayButton: true})` worked ### Updates - ### Changed - `ex.Vector.toAngle()` now returns angles from `[0 - 2 PI)` ## [v0.29.2] ### Breaking Changes - ### Deprecated - ` ### Added - Added ability to configure image wrapping on `ex.ImageSource` with the new `ex.ImageWrapping.Clamp` (default), `ex.ImageWrapping.Repeat`, and `ex.ImageWrapping.Mirror`. ```typescript const image = new ex.ImageSource('path/to/image.png', { filtering: ex.ImageFiltering.Pixel, wrapping: { x: ex.ImageWrapping.Repeat, y: ex.ImageWrapping.Repeat, } }); ``` - Added pointer event support to `ex.TileMap`'s and individual `ex.Tile`'s - Added pointer event support to `ex.IsometricMap`'s and individual `ex.IsometricTile`'s - Added `useAnchor` parameter to `ex.GraphicsGroup` to allow users to opt out of anchor based positioning, if set to false all graphics members will be positioned with the top left of the graphic at the actor's position. ```typescript const graphicGroup = new ex.GraphicsGroup({ useAnchor: false, members: [ { graphic: heartImage.toSprite(), offset: ex.vec(0, 0), }, { graphic: heartImage.toSprite(), offset: ex.vec(0, 16), }, { graphic: heartImage.toSprite(), offset: ex.vec(16, 16), }, { graphic: heartImage.toSprite(), offset: ex.vec(16, 0), }, ], }); ``` - Added simplified `ex.coroutine` overloads, you need not pass engine as long as you are in an Excalibur lifecycle ```typescript const result = ex.coroutine(function* () {...}); ``` - Added way to bind 'this' to `ex.coroutine` overloads, you need not pass engine as long as you are in an Excalibur lifecycle ```typescript const result = ex.coroutine({myThis: 'cool'}, function* () {...}); ``` - Added optional `ex.coroutine` timing parameter to schedule when they are updated ```typescript const result = ex.coroutine(engine, function * () {...}, { timing: 'postupdate' }) ``` - Added `GraphicsComponent.bounds` which will report the world bounds of the graphic if applicable! - Added `ex.Vector.EQUALS_EPSILON` to configure the `ex.Vector.equals(v)` threshold - Added way to add custom WebGL context lost/recovered handlers for your game ```typescript const game = new ex.Engine({ handleContextLost: (e) => {...}, handleContextRestored: (e) => {...} }) ``` ### Fixed - Fixed issue where `ex.TileMap` culling did not work properly when using fixed updates lower than refresh rate - Fixed incomplete types for font options in `ex.FontSource().toFont(options)` - Fixed issue with `ex.Loader` start button position when using CSS transforms - Fixed issue where adding scenes with the same name did not work when it was previously removed - Fixed issue when WebGL context lost occurs where there was no friendly output to the user - Fixed issue where HiDPI scaling could accidentally scale past the 4k mobile limit, if the context would scale too large it will now attempt to recover by backing off. - Fixed issue where logo was sometimes not loaded during `ex.Loader` - Fixed issue where unbounded containers would grow infinitely when using the following display modes: * `DisplayMode.FillContainer` * `DisplayMode.FitContainer` * `DisplayMode.FitContainerAndFill` * `DisplayMode.FitContainerAndZoom` - Fixed issue where `ex.ParticleEmitter` z-index did not propagate to particles - Fixed incongruent behavior as small scales when setting `transform.scale = v` and `transform.scale.setTo(x, y)` - Fixed `ex.coroutine` TypeScript type to include yielding `undefined` - Fixed issue where Firefox on Linux would throw an error when using custom Materials due to unused attributes caused by glsl compiler optimization. - Fixed issue where start transition did not work properly if deferred - Fixed issue where transitions did not cover the whole screen if camera was zoomed - Fixed issue where `Color.toHex()` produced invalid strings if the channel values are negative or fractional, or if the alpha channel was different than 1 ### Updates - ### Changed - Significant 2x performance improvement to image drawing in Excalibur - Simplified `ex.Loader` viewport/resolution internal configuration ## [v0.29.0] ### Breaking Changes - `ex.Entity.tags` is now a javascript `Set` instead of an `Array` this will affect methods that inspected tags as an array before. - `ex.Engine.goToScene`'s second argument now takes `GoToOptions` instead of just scene activation data ```typescript { /** * 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 } ``` - `ex.Physics` static is marked as deprecated, configuring these setting will move to the `ex.Engine({...})` constructor ```typescript const engine = new ex.Engine({ ... physics: { solver: ex.SolverStrategy.Realistic, gravity: ex.vec(0, 20), arcade: { contactSolveBias: ex.ContactSolveBias.VerticalFirst }, } }) ``` - Changed the `Font` default base align to `Top` this 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. - Remove confusing Graphics Layering from `ex.GraphicsComponent`, recommend we use the `ex.GraphicsGroup` to manage this behavior * Update `ex.GraphicsGroup` to be consistent and use `offset` instead of `pos` for graphics relative positioning - ECS implementation has been updated to remove the "stringly" typed nature of components & systems * For average users of Excalibur folks shouldn't notice any difference * For folks leveraging the ECS, Systems/Components no longer have type parameters based on strings. The type itself is used to track changes. * `class MySystem extends System<'ex.component'>` becomes `class MySystem extends System` * `class MyComponent extends Component<'ex.component'>` becomes `class MyComponent extends Component` * `ex.System.update(elapsedMs: number)` is only passed an elapsed time - Prevent people from inadvertently overriding `update()` in `ex.Scene` and `ex.Actor`. This method can still be overridden with the `//@ts-ignore` pragma - `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. ### Deprecated - ### Added - Added new `ex.Tilemap.getOnScreenTiles()` method to help users access onscreen tiles for logic or other concerns. - Added `ex.FontSource` resource type ```typescript const fontSource = new ex.FontSource('/my-font.ttf', 'My Font') loader.addResource(fontSource) game.start(loader).then(() => { const font = fontSource.toFont() // returns ex.Font }) ``` Font options can be defined either at the source or at the `toFont()` call. If defined in both, `toFont(options)` will override the options in the `FontSource`. ```typescript const fontSource = new ex.FontSource('/my-font.ttf', 'My Font', { filtering: ex.ImageFiltering.Pixel, size: 16, // set a default size }) const font = fontSource.toFont({ // override just the size size: 20, }) ``` - Added fullscreen after load feature! You can optionally provide a `fullscreenContainer` with a string id or an instance of the `HTMLElement` ```typescript new ex.Loader({ fullscreenAfterLoad: true, fullscreenContainer: document.getElementById('container') }); ``` - Added new `ex.Debug` static for more convenient debug drawing where you might not have a graphics context accessible to you. This works by batching up all the debug draw requests and flushing them during the debug draw step. * `ex.Debug.drawRay(ray: Ray, options?: { distance?: number, color?: Color })` * `ex.Debug.drawBounds(boundingBox: BoundingBox, options?: { color?: Color })` * `ex.Debug.drawCircle(center: Vector, radius: number, options?: ...)` * `ex.Debug.drawPolygon(points: Vector[], options?: { color?: Color })` * `ex.Debug.drawText(text: string, pos: Vector)` * `ex.Debug.drawLine(start: Vector, end: Vector, options?: LineGraphicsOptions)` * `ex.Debug.drawLines(points: Vector[], options?: LineGraphicsOptions)` * `drawPoint(point: Vector, options?: PointGraphicsOptions)` - Experimental `ex.coroutine` for running code that changes over time, useful for modeling complex animation code. Coroutines return a promise when they are complete. You can think of each `yield` as a frame. * The result of a yield is the current elapsed time * You can yield a number in milliseconds and it will wait that long before resuming * You can yield a promise and it will wait until it resolves before resuming ```typescript const completePromise = coroutine(engine, function * () { let elapsed = 0; elapsed = yield 200; // frame 1 wait 200 ms before resuming elapsed = yield fetch('./some/data.json'); // frame 2 elapsed = yield; // frame 3 }); ``` - Added additional options in rayCast options * `ignoreCollisionGroupAll: boolean` will ignore testing against anything with the `CollisionGroup.All` which is the default for all * `filter: (hit: RayCastHit) => boolean` will allow people to do arbitrary filtering on raycast results, this runs very last after all other collision group/collision mask decisions have been made - Added additional data `side` and `lastContact` to `onCollisionEnd` and `collisionend` events - Added configuration option to `ex.PhysicsConfig` to configure composite collider onCollisionStart/End behavior - Added configuration option to `ex.TileMap({ meshingLookBehind: Infinity })` which allows users to configure how far the TileMap looks behind for matching colliders (default is 10). - Added Arcade Collision Solver bias to help mitigate seams in geometry that can cause problems for certain games. - `ex.ContactSolveBias.None` No bias, current default behavior collisions are solved in the default distance order - `ex.ContactSolveBias.VerticalFirst` Vertical collisions are solved first (useful for platformers with up/down gravity) - `ex.ContactSolveBias.HorizontalFirst` Horizontal collisions are solved first (useful for games with left/right predominant forces) ```typescript const engine = new ex.Engine({ ... physics: { solver: ex.SolverStrategy.Realistic, arcade: { contactSolveBias: ex.ContactSolveBias.VerticalFirst }, } }) ``` - Added Graphics `opacity` on the Actor constructor `new ex.Actor({opacity: .5})` - Added Graphics pixel `offset` on the Actor constructor `new ex.Actor({offset: ex.vec(-15, -15)})` - Added new `new ex.Engine({uvPadding: .25})` option to allow users using texture atlases in their sprite sheets to configure this to avoid texture bleed. This can happen if you're sampling from images meant for pixel art - Added new antialias settings for pixel art! This allows for smooth subpixel rendering of pixel art without shimmer/fat-pixel artifacts. - Use `new ex.Engine({pixelArt: true})` to opt in to all the right defaults to make this work! - Added new antialias configuration options to deeply configure how Excalibur does any antialiasing, or you can provide `antialiasing: true`/`antialiasing: false` to use the old defaults. - Example; ```typescript const game = new ex.Engine({ antialiasing: { pixelArtSampler: false, filtering: ex.ImageFiltering.Pixel, nativeContextAntialiasing: false, canvasImageRendering: 'pixelated' } }) ``` - Added new `lineHeight` property on `SpriteFont` and `Font` to manually adjust the line height when rendering text. - Added missing dual of `ex.GraphicsComponent.add()`, you can now `ex.GraphicsComponent.remove(name)`; - Added additional options to `ex.Animation.fromSpriteSheetCoordinates()` you can now pass any valid `ex.GraphicOptions` to influence the sprite per frame ```typescript const anim = ex.Animation.fromSpriteSheetCoordinates({ spriteSheet: ss, frameCoordinates: [ {x: 0, y: 0, duration: 100, options: { flipHorizontal: true }}, {x: 1, y: 0, duration: 100, options: { flipVertical: true }}, {x: 2, y: 0, duration: 100}, {x: 3, y: 0, duration: 100} ], strategy: ex.AnimationStrategy.Freeze }); ``` - Added additional options to `ex.SpriteSheet.getSprite(..., options)`. You can pass any valid `ex.GraphicOptions` to modify a copy of the sprite from the spritesheet. ```typescript const sprite = ss.getSprite(0, 0, { flipHorizontal: true, flipVertical: true, width: 200, height: 201, opacity: .5, scale: ex.vec(2, 2), origin: ex.vec(0, 1), tint: ex.Color.Red, rotation: 4 }); - New simplified way to query entities `ex.World.query([MyComponentA, MyComponentB])` - New way to query for tags on entities `ex.World.queryTags(['A', 'B'])` - Systems can be added as a constructor to a world, if they are the world will construct and pass a world instance to them ```typescript world.add(MySystem); ... class MySystem extends System { query: Query; constructor(world: World) { super() this.query = world.query([MyComponent]); } update } ``` - Added `RayCastHit`as part of every raycast not just the physics world query! * Additionally added the ray distance and the contact normal for the surface - Added the ability to log a message once to all log levels * `debugOnce` * `infoOnce` * `warnOnce` * `errorOnce` * `fatalOnce` - Added ability to load additional images into `ex.Material`s! ```typescript const noise = new ex.ImageSource('./noise.avif'); loader.addResource(noise); var waterMaterial = game.graphicsContext.createMaterial({ name: 'water', fragmentSource: waterFrag, color: ex.Color.fromRGB(55, 0, 200, .6), images: { u_noise: noise } }); ``` - Scene Transition & Loader API, this gives you the ability to have first class support for individual scene resource loading and scene transitions. * Add or remove scenes by constructor * Add loaders by constructor * New `ex.DefaultLoader` type that allows for easier custom loader creation * New `ex.Transition` type for building custom transitions * New scene lifecycle to allow scene specific resource loading * `onTransition(direction: "in" | "out") {...}` * `onPreLoad(loader: DefaultLoader) {...}` * New async `goToScene()` API that allows overriding loaders/transitions between scenes * Scenes now can have `async onInitialize` and `async onActivate`! * New scenes director API that allows upfront definition of scenes/transitions/loaders * Example: Defining scenes upfront ```typescript const game = new ex.Engine({ scenes: { scene1: { scene: scene1, transitions: { out: new ex.FadeInOut({duration: 1000, direction: 'out', color: ex.Color.Black}), in: new ex.FadeInOut({duration: 1000, direction: 'in'}) } }, scene2: { scene: scene2, loader: ex.DefaultLoader, // Constructor only option! transitions: { out: new ex.FadeInOut({duration: 1000, direction: 'out'}), in: new ex.FadeInOut({duration: 1000, direction: 'in', color: ex.Color.Black }) } }, scene3: ex.Scene // Constructor only option! } }) // Specify the boot loader & first scene transition from loader game.start('scene1', { inTransition: new ex.FadeInOut({duration: 500, direction: 'in', color: ex.Color.ExcaliburBlue}) loader: boot, }); ``` - Scene specific input API so that you can add input handlers that only fire when a scene is active! ```typescript class SceneWithInput extends ex.Scene { onInitialize(engine: ex.Engine<any>): void { this.input.pointers.on('down', () => { console.log('pointer down from scene1'); }); } } class OtherSceneWithInput extends ex.Scene { onInitialize(engine: ex.Engine<any>): void { this.input.pointers.on('down', () => { console.log('pointer down from scene2'); }); } } ``` ### Fixed - Performance improvement in `ex.TileMap` finding onscreen tiles is now BLAZINGLY FAST thanks to a suggestion from Kristen Maeyvn in the Discord. - TileMaps no longer need a quad tree, we can calculate the onscreen tiles with math by converting the screen into tilemap space 😎 - Fixed bug where `ex.TileMap.getTileByPoint()` did not take into account the rotation/scale of the tilemap. - Fixes issue where mis-matched coordinate planes on parent/children caused bizarre issues. Now children are forced to inherit their parent's coordinate plane, it will always be the coordinate plane of the top most parent. - Fixed issue with Log ScreenAppender utility where it was not positioned correctly, you can now deeply configure it! ```typescript export interface ScreenAppenderOptions { engine: Engine; /** * Optionally set the width of the overlay canvas */ width?: number; /** * Optionally set the height of the overlay canvas */ height?: number; /** * Adjust the text offset from the left side of the screen */ xPos?: number; /** * Provide a text color */ color?: Color; /** * Optionally set the CSS zindex of the overlay canvas */ zIndex?: number; } ``` - Fixed errant warning about resolution when using `pixelRatio` on low res games to upscale - Fixes an issue where a collider that was part of a contact that was deleted did not fire a collision end event, this was unexpected - Fixes an issue where you may want to have composite colliders behave as constituent colliders for the purposes of start/end collision events. A new property is added to physics config, the current behavior is the default which is `'together'`, this means the whole composite collider is treated as 1 collider for onCollisionStart/onCollisionEnd. Now you can configure a `separate` which will fire onCollisionStart/onCollisionEnd for every separate collider included in the composite (useful if you are building levels or things with gaps that you need to disambiguate). You can also configure this on a per composite level to mix and match `CompositeCollider.compositeStrategy` - Fixed issue where particles would have an errant draw if using a particle sprite - Fixed issue where a null/undefined graphics group member graphic would cause a crash, now logs a warning. - Fixed issue where Actor built in components could not be extended because of the way the Actor based type was built. - Actors now use instance properties for built-ins instead of getters - With the ECS refactor you can now subtype built-in `Components` and `.get(Builtin)` will return the correct subtype. ```typescript class MyBodyComponent extends ex.BodyComponent {} class MyActor extends ex.Actor { constructor() { super({}) this.removeComponent(ex.BodyComponent); this.addComponent(new MyBodyComponent()) } } const myActor = new MyActor(); const myBody = myActor.get(ex.BodyComponent); // Returns the new MyBodyComponent subtype! ``` - Fixed issue with `snapToPixel` where the `ex.Camera` was not snapping correctly - Fixed issue where using CSS transforms on the canvas confused Excalibur pointers - Fixed issue with *AndFill suffixed [[DisplayModes]]s where content area offset was not accounted for in world space - Fixed issue where `ex.Sound.getTotalPlaybackDuration()` would crash if not loaded, now logs friendly warning - Fixed issue where an empty constructor on `new ex.Label()` would crash - ### Updates - ### Changed - ## [v0.28.7] ### Breaking Changes - ### Deprecated - ### Added - ### Fixed - Fixed issue where pointer events did not work properly when using [[ScreenElement]]s - Fixed issue where debug draw was not accurate when using *AndFill suffixed [[DisplayMode]]s ### Updates - ### Changed - Changed the default `ex.PointerComponent.useGraphicsBounds = true`, users expect this to just work by default. - Changed a rough edge in the `ex.Material` API, if a material was created with a constructor it was lazily initialized. However this causes confusion because now the two ways of creating a material behave differently (the shader is not available immediately on the lazy version). Now `ex.Material` requires the GL graphics context to make sure it always works the same. - Changed a rough edge in the `ex.Material` API, if a material was created with a constructor it was lazily initialized. However this causes confusion because now the two ways of creating a material behave differently (the shader is not available immediately on the lazy version). Now `ex.Material` requires the GL graphics context to make sure it always works the same. <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> <!--------------------------------- DO NOT EDIT BELOW THIS LINE ---------------------------------> ## [v0.28.6] ### Breaking Changes - ### Deprecated - ### Added - Added arbitrary data storage in isometric tiles, `ex.IsometricTile.data` this brings it into feature parity with normal `ex.Tile.data` - New graphics events and hooks that allow you to hook into graphics drawing before or after any drawing transformations have been applied * `Actor.graphics.onPreTransformDraw` with the corresponding event `.on('pretransformdraw')` * `Actor.graphics.onPostTransformDraw` with the corresponding event `.on('posttransformdraw')` - New property and methods overloads to `ex.Animation` * `ex.Animation.currentFrameTimeLeft` will return the current time in milliseconds left in the current * `ex.Animation.goToFrame(frameNumber: number, duration?: number)` now accepts an optional duration for the target frame * `ex.Animation.speed` can set the speed multiplier on an animation 1 = 1x speed, 2 = 2x speed. ### Fixed - Fixed issue where nesting `ex.CompositeColliders` inside one another would cause a crash on collision - Fixed issue where `ex.CompositeColliders` did not respect collider offset - Fixed issue where parenting a entity with fixed updates on would cause a drawing flicker, transform interpolation now is aware of changing parents so it interpolates drawing continuously to prevent any flickering - `ex.Animation.reset()` did not properly reset all internal state ### Updates - ### Changed - ## [v0.28.5] ### Breaking Changes - ### Deprecated - ### Added - Added collision lifecycle convenience methods to `Actor`, you can now override the following events ```typescript class MyActor extends ex.Actor { constructor(args: ex.ActorArgs) { super(args); } onPreCollisionResolve(self: ex.Collider, other: ex.Collider, side: ex.Side, contact: ex.CollisionContact): void { } onPostCollisionResolve(self: ex.Collider, other: ex.Collider, side: ex.Side, contact: ex.CollisionContact): void { } onCollisionStart(self: ex.Collider, other: ex.Collider, side: ex.Side, contact: ex.CollisionContact): void { } onCollisionEnd(self: ex.Collider, other: ex.Collider): void { } } ``` - Added Scene specific background color - Added ability to apply draw offset to `ex.IsometricMap` and `ex.Tilemap` - Added `visibility` and `opacity` to `ex.IsometricMap` - Added base elevation for `ex.IsometricMap` so multiple maps can sort correctly - Added method to suppress convex polygon warning for library code usage - Added more configuration options to debug draw flags, including isometric map controls - Added `actionstart` and `actioncomplete` events to the Actor that are fired when an action starts and completes ### Fixed - Fixed issue where the `Camera` wasn't interpolated during fixed update, which is very noticeable when using camera locked strategies - Fixed issue where `IsometricMap` would debug draw collision geometry on non-solid tiles - Fixed issue where `CompositeCollider` offset was undefined if not set - Fixed Actor so it receives `predraw`/`postdraw` events per the advertised strongly typed events - Fixed infinite loop :bomb: when certain degenerate polygons were attempted to be triangulated! - Fixed incorrect type on `ex.Tilemap.getTileByPoint()` - Fixed TS type on `GraphicsComponent` and allow `.material` to be null to unset, current workaround is using `.material = null as any` ### Updates - ### Changed - All debug geometry settings are controlled from debug.collider now - Removed dunder prefixed parameters from overrideable methods - Tweaked debug draw to be less noisy by default - Removed dependency on `ex.IsometricMap` in the `ex.IsometricEntityComponent`, this allows for greater flexibility when using the component when a map may not be known or constructed. ## [v0.28.4] ### Breaking Changes - ### Deprecated - ### Added - Ability to configure TileMap debug drawing with the `ex.Engine.debug.tilemap` property. - Materials have a new convenience method for updating uniforms ```typescript game.input.pointers.primary.on('move', evt => { heartActor.pos = evt.worldPos; swirlMaterial.update(shader => { shader.trySetUniformFloatVector('iMouse', evt.worldPos); }); }); ``` ### Fixed - Fixed issue where TileMap solid tiles tile packing algorithm would incorrectly merge tiles in certain situations. - Sprite tint was not respected when supplied in the constructor, this has been fixed! - Adjusted the `FontCache` font timeout to 400 ms and makes it configurable as a static `FontCache.FONT_TIMEOUT`. This is to help prevent a downward spiral on mobile devices that might take a long while to render a few starting frames causing the cache to repeatedly clear and never recover. ### Updates - Materials can now reference a new uniform for the screen texture and a screen uv attribute in their fragment shaders * `u_screen_texture` - This is the texture of the screen right before the material draw call * `a_screenuv` - The vertex attribute corresponding to the screen uv relative to the current graphic * `v_screenuv` - The fragment varying corresponding to the screen uv relative to the current graphic - Materials can now reference the current time in their shaders * `u_time_ms` - This is the ms since page navigation (performance.now() under the hood) ### Changed - TileMap debug draw is now less verbose by default to save draw cycles when toggling to debug ## [v0.28.3] ### Breaking Changes - ### Deprecated - ### Added - Added new feature to collision group raycasting, directly provide a `collisionMask` that you want to search for. ```typescript const playerGroup = ex.CollisionGroupManager.create('playerGroup'); const notPlayersMask = ~playersGroup.category; const hits = engine.currentScene.physics.rayCast( new ex.Ray(player.pos, playerDir), { maxDistance: playerSightDistance, // Search for all categories that match the mask collisionMask: notPlayers, searchAllColliders: false }); ``` ### Fixed - Fixed issue where rendering multiple materials at once would crash the renderer - Fixed issue where raycasting with more complex collision groups was not working as expected ### Updates - ### Changed - ## [v0.28.2] ### Breaking Changes - ### Deprecated - ### Added - Added `ex.Engine.version` to report the current excalibur version build string - Added new `ex.Screen.events` - `screen.events.on('resize', (evt) => )` Will emit when the screen is resized - `screen.events.on('fullscreen', (evt) => )` Will emit when the screen is changed into browser fullscreen mode - `screen.events.on('pixelratio', (evt) => )` Will emit when the screen's pixel ratio changes (moving from a hidpi screen to a non, or vice versa) ### Fixed - Fixed issue where removing handlers by function reference only removed the first registered one - Fixed issue where play button was hidden when going fullscreen mode - Fixed issue where screen resizing caused artifacts on the loading screen - Fixed bug in `useCanvas2DFallback()` where `antialiasing` settings could be lost - Fixed bug in `useCanvas2DFallback()` where opacity was not respected in `save - Fixed typo in trigger event signature `entertrigger` should have been `enter` - Fixed typo in trigger event signature `exittrigger` should have been `exit` - Fixed typo in animation event signature `ended` should have been `end` - Fixed issue where some excalibur `clear()` implementations modified the collection they were iterating over - Fixed async issue where sound could not be stopped if `stop()`/`start()` were called in rapid succession - Fixed issue with input mapper where `keyboard.wasPressed(...)` did not fire - Fixed issue issue where TileMaps would not properly draw Tiles when setup in screen space coordinates - Fixed issue where the ex.Line graphics bounds were incorrect causing erroneous offscreen culling - Fixed event type signature on `ex.Engine.input.pointers.primary.on('wheel', ..