Excalibur, the popular open-source 2D game engine for TypeScript, has unveiled its latest release: version 0.30.0. This update is packed with powerful new features, performance enhancements, and critical bug fixes that significantly elevate the game development experience. With advanced GPU particle rendering capabilities and more interactive tile maps, this release aims to deliver a richer, more flexible toolkit for developers looking to build engaging, visually striking games.
New Features
Advanced GPU Particle Implementation
Excalibur now boasts a GPU-accelerated particle system capable of handling 10,000+ particles. This enhancement allows for highly detailed and dynamic visual effects without compromising performance.
const 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
}
});
Enhanced Sprite Management
- SpriteSheet Tiling: Utilize
ex.SpriteSheet.getTiledSprite(...)
to effortlessly extract tiling sprites from a sprite sheet. - Alias for Screen Dimensions: Access
engine.screen.width
andengine.screen.height
as aliases forengine.screen.drawWidth
andengine.screen.drawHeight
.
Convenience Types for Tiling Sprites and Animations
Excalibur introduces ex.TiledSprite
and ex.TiledAnimation
to simplify the integration of tiled graphics and animations.
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
});
SVG Image Support
Manage vector graphics more efficiently with inline SVG support via ex.ImageSource.fromSvgString('<svg>...</svg>')
. This feature ensures crisp scaling and a reduced asset footprint.
const svgImage = ex.ImageSource.fromSvgString('<svg>...</svg>');
Scene Transitions with Slide Effect
Introduce smooth and dynamic scene transitions using the new ex.Slide
transition. Scenes can elegantly slide in from any direction, enhancing the narrative flow.
game.goToScene('otherScene', {
destinationIn: new ex.Slide({
duration: 1000,
easingFunction: ex.EasingFunctions.EaseInOutCubic,
slideDirection: 'up'
})
});
Nine-Slice Graphics for Responsive UI
Create scalable and responsive UI elements effortlessly with ex.NineSlice
, perfect for menus, panels, and HUD components.
const 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);
Enhanced Action System
- New Actions:
actor.actions.curveTo(...)
andactor.actions.curveBy(...)
enable curved motion paths for more natural and complex movements. - Flash Action:
actor.actions.flash(...)
allows actors to flash a color for a specified duration, useful for visual feedback.
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'
});
});
Mathematical Utilities
New utility functions for numerical and vector operations enhance the precision and flexibility of game mechanics:
ex.lerpAngle(...)
ex.lerp(...)
,ex.inverseLerp(...)
,ex.remap(...)
ex.lerpVector(...)
,ex.inverseLerpVector(...)
,ex.remapVector(...)
Interactive Tile Maps
ex.TileMap
and ex.IsometricMap
now support pointerenter
and pointerleave
events, enabling more interactive and responsive game worlds.
Bezier Curve Support
Introducing ex.BezierCurve
for drawing cubic bezier curves, allowing for more sophisticated graphic designs and animations.
Graphics Enhancements
- Force On Screen:
ex.GraphicsComponent.forceOnScreen
ensures certain graphics remain visible within the viewport. - Inline Canvas Image Creation:
ex.ImageSource.fromHtmlCanvasElement(...)
allows creating images directly from HTML canvas elements.
Developer Tools
- Assertion Utility:
ex.assert()
can be used to enforce conditions during development, aiding in debugging and maintaining code integrity. - Improved Coroutine Management: Enhanced coroutine support with
ex.coroutine(...)
, allowing for better control over asynchronous operations, including nested coroutines and manual start/cancel options.
TypeScript Enhancements
- TypeScript Strictness: Increased TypeScript strictness across various APIs ensures better type safety and developer experience.
Improvements
Action System Enhancements
- Precise Timing: Actions now accept durations in milliseconds, allowing for more accurate timing and synchronization.
- Easing Options: Added easing functions to actions like
moveTo(...)
for smoother transitions.
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 });
Angle Interpolation
The new ex.lerpAngle
function facilitates smooth transitions between angles, enhancing rotational animations and directional changes.
Debugging Tools
- Refined Debug Methods: New
ex.Debug
static methods provide enhanced capabilities for visualizing and diagnosing game elements, such as collision boxes and layout constraints.
Performance Optimizations
- WebGL Texture Management: Excalibur now automatically cleans up unused WebGL textures, improving memory usage and stability during long game sessions.
- Image Rendering: Upgraded to
ImageRendererV2
, doubling the performance of image rendering tasks. - Component Retrieval: Enhanced
ex.Entity.get()
method significantly boosts engine performance by optimizing component access. - Collision Processing: Introduction of
ex.SparseHashGridCollisionProcessor
offers a faster, more efficient collision pair generation mechanism. - Pointer System: Improved
PointerSystem
using a new spatial hash grid data structure enhances pointer event processing speed. - General Allocations Reduction: Numerous optimizations reduce memory allocations in hot paths, such as state/transform stacks and collision calculations, leading to smoother performance.
Coroutine Enhancements
- Coroutine Instances:
ex.CoroutineInstance
provides better control and management of coroutine lifecycles. - Autostart Control: Option to disable autostart for coroutines, allowing manual initiation and cancellation.
- Nested Coroutines: Support for nested coroutines enables more complex asynchronous workflows.
API Enhancements
- World to Page Pixel Ratio:
ex.Screen.worldToPagePixelRatio
API returns the ratio between Excalibur pixels and HTML pixels, facilitating seamless scaling of HTML UIs to match game dimensions.
.ui-container {
pointer-events: none;
position: absolute;
transform-origin: 0 0;
transform: scale(
calc(var(--ex-pixel-ratio)),
calc(var(--ex-pixel-ratio))
);
}
Additional Utilities
- RentalPool: A new
RentalPool
type for efficient sparse object pooling. - Vector Utilities:
Vector.angleBetween(...)
method added to calculate angles between vectors, aiding in directional calculations and rotations.
const point = ex.vec(100, 100);
const destinationDirection = Math.PI / 4;
const angleToRotate = point.angleBetween(destinationDirection, RotationType.ShortestPath);
expect(point.rotate(angleToRotate).toAngle()).toEqual(destinationDirection);
Bug Fixes
Excalibur v0.30.0 addresses numerous bugs to enhance stability and reliability:
- Particle Emitter: Fixed
ex.ParticleEmitter.clearParticles()
to function correctly. - Pointer Positioning: Corrected the pointer’s
lastWorldPos
to update accurately when the camera moves. - Collision Events: Standardized collision event targets to consistently reference entities instead of colliders or other types.
- Screenshot Timing: Improved
ex.Engine.screenshot()
to ensure images are fully loaded before use in transitions. - Scene Transition Visuals: Resolved a background color inconsistency that occurred briefly during scene transitions.
- Input Handling: Fixed issues where
blockInput: true
only blocked input events but not state queries likewasHeld(...)
. - Renderer Plugin: Allowed easier definition of custom
RendererPlugin
by exposing necessary types. - Fade Transition: Ensured
ex.Fade
transitions complete reliably regardless of elapsed time. - Collider Stability: Fixed infinite loops in
ex.PolygonColliders
for degenerate polygons and improvedCircleCollider
raycasts. - Loader Stability: Prevented the engine from locking up when using an empty loader in
ex.Scene.onPreLoad(loader: ex.DefaultLoader)
. - Input Events: Addressed issues with scoped input events preserving state incorrectly when switching scenes.
- Key Handling: Ensured all physical keys, including
ex.Keys.Tab
, are recognized and handled correctly. - Graphics Opacity: Corrected multiplicative opacity issues when setting actor opacity via
ex.Label
. - Loader Resolution: Fixed low-resolution logos in the loader for smaller configured resolutions.
- GIF Parsing: Enhanced
ex.Gif
to correctly parse certain binary formats. - Pixel Ratio Overrides: Fixed the boot
ex.Loader
to prevent removal of pixel ratio overrides. - Raster Options: Ensured
ex.RasterOptions
extendsex.GraphicsOptions
for consistent behavior. - RayCasting Order: Fixed inconsistent ordering in raycasts when using the
ex.SparseHashGridCollisionProcessor
. - Scene Transitions: Ensured that providing a loader without a transition does not cause errors.
- Vector Normalization: Updated
ex.Vector.normalize()
to return a zero-vector instead of(0,1)
when normalizing a zero-magnitude vector. - API Refinements: Various API refinements to disallow invalid combinations of collider parameters and improve type safety.
Breaking Changes
Version 0.30.0 introduces several breaking changes aimed at streamlining the API and improving overall consistency. Developers upgrading to this version should review these changes to adjust their code accordingly.
- Method Renaming and Removal:
ex.Engine.goto(...)
has been removed. Useex.Engine.goToScene(...)
instead.ex.GraphicsComponent.show(...)
has been removed. Useex.GraphicsComponent.use(...)
instead.ex.EventDispatcher
has been removed. Useex.EventEmitter
instead.
- Configuration Adjustments:
ex.Engine.getAntialiasing()
andex.Engine.setAntialiasing(bool)
have been removed. Configure antialiasing via the engine constructor:
const engine = new ex.Engine({
antialiasing: true
});
Or set it directly on the screen:
engine.screen.antialiasing = true;
ex.Physics.*
configuration statics have been removed. Configure physics settings through the engine constructor:
const engine = new ex.Engine({
physics: { /* physics config */ }
});
- Namespace and Type Promotions:
ex.Input.*
namespace has been removed. Types have been promoted toex.*
.
- Collision Events Targeting:
- Collision events now exclusively target
ex.Collider
types instead of sometimes emittingex.Entity
objects.
- Collision events now exclusively target
- API Parameter Changes:
ex.Timer
now only accepts an option bag constructor.PreDrawEvent
,PostDrawEvent
,PreTransformDrawEvent
,PostTransformDrawEvent
,PreUpdateEvent
, andPostUpdateEvent
now useelapsedMs
instead ofdelta
for the time between frames.
- Trigger API Modifications:
action
now returns the triggeringEntity
instead ofActor
.target
now works in conjunction withfilter
instead of overwriting it.EnterTriggerEvent
andExitTriggerEvent
now contain anentity: Entity
property instead ofactor: Actor
.
- Vector and GIF Handling:
ex.Vector.normalize()
returns a zero-vector instead of(0,1)
when normalizing a vector with zero magnitude.- The
transparentColor
constructor argument forex.Gif
has been removed in favor of built-in GIF file mechanisms.
- Dependency Removal:
- Removed the
core-js
dependency, which is no longer necessary for modern browsers. This is a breaking change for projects targeting older browsers.
- Removed the
- API Consistency and Renaming:
ex.Particle
andex.ParticleEmitter
APIs have been modernized to align with the latest Excalibur conventions.- Renamed properties for clarity and consistency:
particleSprite
→graphic
particleRotationalVelocity
→angularVelocity
fadeFlag
→fade
acceleration
→acc
particleLife
→life
minVel
→minSpeed
maxVel
→maxSpeed
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,
minSpeed: 100,
maxSpeed: 200,
minAngle: 5.1,
maxAngle: 6.2,
fade: true,
maxSize: 10,
graphic: swordImg.toSprite(),
randomRotation: true,
minSize: 1
}
});
Performance Improvements
Excalibur v0.30.0 introduces numerous performance optimizations to ensure smoother and more efficient game execution:
- PolygonCollider Performance: Enhanced
PolygonCollider.contains(...)
by keeping geometry tests in local space. - Image Rendering: Upgraded to
ImageRendererV2
, approximately doubling image rendering performance. - Component Retrieval: Optimized
ex.Entity.get()
method for faster component access. - Particle Emitter: Significant performance gains in
ex.ParticleEmitter
operations. - Collision Processing: Improved collision narrowphase and solver steps with the
ex.SparseHashGridCollisionProcessor
. - Pointer System: Enhanced with a new spatial hash grid data structure for quicker pointer event processing.
- Loop Optimization: Switched from iterators to C-style loops where possible to increase execution speed.
- Object Pooling: Leveraged object pools to reduce allocations and improve memory management.
- Hot Path Allocations: Reduced allocations in critical paths, such as state/transform stacks and collision calculations, to minimize performance bottlenecks.
Developer Experience Enhancements
- Assertions: Introduced
ex.assert()
for enforcing conditions during development, aiding in debugging. - TypeScript Strictness: Increased TypeScript strictness across various APIs, enhancing type safety and reducing potential runtime errors.
- Development Warnings: Display warnings when an
Entity
hasn’t been added to a scene after a few seconds, preventing potential issues in game logic. - Enhanced Coroutines: Improved coroutine management with better control over execution flow, including support for nested coroutines.
Raw Changes
- Removal of Units: Parameters no longer include units by default, streamlining API usage and reducing potential confusion.
- Improved Type Definitions: Enhanced type definitions to disallow invalid combinations of collider parameters and ensure only default color graphics are added for respective colliders.
- Graphical Consistency: Ensured
ex.SpriteFont
respects scale when measuring text and fixed negative transform issues affecting collision detection.
Conclusion
Excalibur v0.30.0 marks a significant advancement in the engine’s capabilities, offering developers a more powerful, efficient, and flexible toolkit for creating engaging 2D games. The introduction of GPU-accelerated particles, enhanced sprite management, robust performance optimizations, and numerous bug fixes collectively contribute to a more stable and feature-rich development environment.
Developers are highly encouraged to upgrade to Excalibur v0.30.0 to leverage these enhancements and streamline their game development workflows. For more detailed documentation, and migration guides, please refer to the official release notes on GitHub.