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
Markdown
# 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', ..