Skip to content

v20.11.0

Choose a tag to compare

@github-actions github-actions released this 27 Oct 10:13
· 35 commits to master since this release
bc478c1

Added

  • Effects: colors take an alpha. Every color option and setColor takes [r, g, b] or [r, g, b, a], the alpha being the color's opacity ([r, g, b] stays opaque), RadialGradientEffect honours the alpha of its Color, and DropShadowEffect gains the setColor the others have. Four values used to break an effect (WebGL rejected them, and on WebGPU the fourth overwrote the next setting, such as an outline's width); a color of any other length now throws a TypeError saying so
  • Effects: SwayEffect leans a sprite or a layer from side to side, as if in a breeze, its top swaying most and everything from its anchor row down staying put. It is a WaveEffect, which now takes an anchor for the row its wave fades out at, and it wraps its own time so it never stutters on a phone's medium-precision floats
  • Rendering: Renderable#sortOffset lines a renderable up as if it stood that many pixels lower (or higher) when its container sorts on "y" or "x", without moving it: a torch drawn over the wall it hangs on, dust sorted with the door it rises from, or art of different heights sorted by its base
  • Lighting: Light2d#softness (0 to 1) fades the edge of a light's hole in the stage's ambient darkness, from a hard rim (0, the default, as before) to a darkness that thins straight from the center (1), along the same falloff as the glow. Hard and soft lights mix in one scene, overlapping lights multiply, and it works on every renderer
  • Particles: tintOverLife gives the tints a particle takes over its life, evenly spaced and blended from the first at birth to the last at the end, such as a flame turning from white hot to deep red. It sets the color only (the fade still sets the opacity), and the blend is taken in 32 steps, which keeps the Canvas renderer to 32 tinted copies of the texture
  • Animation: setCurrentAnimation(name, { onFrame }) calls back with each frame index as playback reaches it, from frame 0 when the animation starts, so a footstep or a hit can land on its frame. It applies to the frame animations of a Sprite or a Sprite3d
  • Audio: playTrack(name, { volume, sprite }) plays one region of a clip as the track and loops on it. A region of a loop's exact length keeps an MP3 loop gapless in Safari, which plays the padding an MP3 encoder adds to the end of the file
  • Tiled: a tile object with no class of its own is built by the class registered under its tile's class, as Tiled shows it, so a class set once on a tile in the tileset applies to every object placed from it, and TMXTileset#getTileClass() returns that class. The object's own class or registered name still comes first, and a tile classed like a built-in (Sprite, Trigger, shape...) stays a plain tile
  • Tiled: TMXObject#resolvedProperty() and resolvedProperties() return an object's custom properties together with those it inherits from its tile, the object's own winning, as the methods of the same names in Tiled's scripting API do. Only the object's own properties are set on it by name, as before
  • Tiled: a tileset, a tile of an image collection or an image layer whose image has a transparent color (trans in TMX, transparentcolor in JSON) is drawn with that color transparent, as Tiled shows it. The color is cleared once when the map loads, on a copy of the image
  • Typings: TMXObject, the settings a class registered with registerTiledObjectClass (or a factory registered with registerTiledObjectFactory) receives, is exported as a type, and both functions are typed with it. A class or factory typed with its own settings still compiles
  • Rendering: textureFilter: "linear-mipmap" samples a texture's mipmaps wherever it is drawn smaller than its size, so a zoomed-out camera, a minimap or a scaled-down sprite no longer shimmers as it moves; it covers sprites, text and tile layers on WebGL and WebGPU. A sprite cut from an atlas or a tileset keeps its samples inside its own frame, so its neighbours no longer streak along its edges, and a texture draws as under "linear" at its size or larger
  • Camera: Renderable#visibilityLayer and Camera2d#cullMask choose what each camera draws: a camera draws a renderable only if they share a bit, so a minimap can leave out the particles, or a Light2d can show in one camera only. By default every renderable is on layer 1 and every camera draws every layer; a container left out is left out with everything in it, and the layer can be set on a Tiled object as an int custom property
  • Application: the syncToDisplay setting keeps motion steady on a display that refreshes at maxfps (60 by default) or a whole multiple of it, such as 60 or 120 Hz. Frame times are counted in whole display frames, so a frame no longer runs no update and the next one two, which made scrolling stutter; it is off by default, and timer.syncToDisplay switches it at any time

Changed

  • Rendering: renderer.uvOffset and the textureSeamFix setting are removed. The Canvas renderer drew tiles a pixel larger to hide the seams between them, which no longer appear; code that added uvOffset to a size should drop it
  • Rendering: a container sorted on "x" or "y" keeps its children in order as they move. With autoSort on, the default, it checks the order at the end of every update and re-sorts when anything is out of place, so a walking character no longer needs a sort() call to pass in front of and behind things. A frame where nothing moved costs one pass over the children and causes no redraw; turn autoSort off to keep the order you set. A "z" sort is unchanged

Fixed

  • Loader: a data: URI is decoded in place instead of fetched, so it loads on a page whose Content-Security-Policy connect-src does not allow data: (sandboxed embeds, hardened sites), where the browser refused it. The default loading screen's logo, inlined as a data: URI, showed nothing on such pages; this covers a data: URI given to any asset type
  • Effects: a colored drop shadow below full opacity is no longer too bright, nor are the soft edges of an outline. Both added their color at full strength whatever its opacity
  • TextureAtlas: drawing part of an image, a bitmap font glyph or a repeating pattern no longer adds a region to the atlas for every new source rectangle, and on an atlas with pages of different sizes no longer reuses the UVs worked out for the same rectangle on another page. Those regions piled up for as long as the atlas lived, and turned up among the frames an animation is built from (#1281, thanks @snowyukitty)
  • Tiled: objects on isometric maps are placed where Tiled draws them. Positions are measured in tile heights on both axes, which changes maps whose tiles are not 2:1, and tile objects are anchored at their bottom center, so a game that offset them to compensate should drop that offset (thanks @vtxe02023274)
  • Tiled: a tile object resized or flipped in Tiled is drawn on its own box, its tile stretched to fill it, and collides at that size. One from a tileset image was drawn and collided at the size of its tile, and one from an image collection was drawn above and to the left of its box when resized, and a whole tile width to the right when flipped (thanks @vtxe02023274)
  • Tiled: tile objects are placed by their tileset's object alignment, and a rotated one turns about that point, as in Tiled: the bottom left, or the bottom center on isometric maps, unless the tileset sets another. They were always anchored at the bottom left (bottom center on isometric maps), and a rotated one turned about another point, so it was drawn and collided away from where Tiled shows it
  • Tiled: a map with an animated tile object loads, and the object plays its animation. One from a tileset image threw "string parameters for addAnimation are not allowed for standard spritesheet based Texture", and one from an image collection threw a TypeError
  • Tiled: in a tile layer, tiles from an image collection whose images are not all the same height each sit on the bottom of their cell, as in Tiled. Every tile was placed as if it were as tall as the tallest image of the collection
  • Tiled: a collision object whose shape reaches left of or above its position, like every rectangle on an isometric map, is found by collision checks, queryAABB and raycast wherever its shape is. Parts of it were missed, so a character could walk through walls; such an object's pos is now the top left corner of its shape
  • Tiled: the collision shapes of objects on isometric maps are projected with the map's tile ratio, as Tiled does. Rectangles, polygons and polylines were projected as if the tiles were 2:1, squeezed or stretched across on a map with wider or narrower tiles so they no longer lined up with the walls they outline, and ellipses were not projected at all; a circle stays an Ellipse, and any other ellipse, which comes out tilted, becomes a polygon around it (thanks @vtxe02023274)
  • Tiled: a tile object on an isometric map collides over its image, as on other maps. Its default body was its image's box projected onto the map grid, a slanted shape hanging off the image
  • Physics: the builtin raycast measures a body from the frame its renderable draws in, as collisions have since 20.7. On a body whose anchor is not its top left corner, such as a Sprite's default centre, a ray hit half the body's size away from where it collides, or missed it
  • Camera: a zoomed camera follows its target, stays within its bounds and centres on focusOn in world units, and localToWorld and worldToLocal take its zoom and its place on the screen (screenX, screenY) into account. Zoomed out, it kept the target off centre and scrolled past its bounds, zoomed in it stopped short of them, and a pointer on a zoomed camera, or on one drawn in a corner of the screen, hit the world somewhere else than it pointed
  • Effects: a glow, outline, blur, drop shadow, chromatic aberration, wave, squish, pixelate or bloom on a sprite cut from an atlas or a tileset keeps to the sprite's own frame. Along the frame's edges it picked up the neighbouring frames, and drew a glow or a line from pixels that are not part of the sprite
  • Effects: a glow, outline, blur, drop shadow, chromatic aberration, pixelate or bloom measures its width, offset or size in pixels of the texture it draws, as documented, with no textureSize to pass: a sprite's texture, the screen for a camera's effect, a mesh's texture. Each assumed a 256x256 texture (the screen for an outline or a bloom), so on any other texture it came out thinner or thicker than asked; a game that tuned its widths around that should check them, and an effect given a textureSize keeps it
  • Tiled: a tile layer drawn with smooth filtering, scaled or off the pixel grid, shows no seams between its tiles on WebGL and WebGPU. Along each tile's edge, filtering blended in the next tile of the tileset, or the spacing around it
  • Tiled: a pre-rendered tile layer holds every tile it draws, on hexagonal, staggered and oblique maps and with tiles larger than their cell or offset from it, and shows the tiles setTile and clearTile change. It was baked at an orthogonal layer's size, which cut off the last column of a hexagonal map, what an oblique map draws left of or above its origin and the parts of large tiles reaching past the edge; setTile left it as it was, and clearTile erased a rectangle placed as on an orthogonal map, cutting into the tiles around it
  • Tiled: an orthogonal tile layer with an opacity below 1, or inside a faded container, is drawn faded on WebGL and WebGPU. Its colors were drawn at full strength over what lies behind it, as bright as an opaque layer or brighter, and the container's fade was ignored
  • Rendering: on the Canvas renderer, a game created with antiAlias: false still draws unsmoothed after the canvas is resized, with no seams between its tiles. A resize reset the canvas's drawing state, which turned smoothing back on, and also reset the blend mode, the color and the line width, join and dash
  • Camera: a zoomed camera draws its floating renderables, such as a HUD or a ColorLayer, and a ColorLayer fills all of its view. It skipped them all, as a minimap does, on every renderer
  • Application: a maxfps above 120 no longer stops the game. Updates ran every 60 / maxfps frames rounded to a whole number, which came out as 0, so none ran
  • Effects: changing the texture filter after an effect's texture was replaced with setTexture, or after the effect was destroyed, no longer raises a WebGL error. The deleted texture was still listed as bound, and the filter change bound it again
  • Camera: the follow deadzone has its edges on whole pixels, so a camera following a target on a whole pixel comes to rest on one. Its size, a sixth of the view by default, was kept as a fraction, so with subPixel on a camera following its target right or down stopped between two pixels
  • Camera: offset can shift the view for good, such as to look above the hero, and not only for a shake: a shake adds its jitter to the offset and gives it back when it ends, where it used to reset it to zero. Culling, the pointer (localToWorld, worldToLocal), tile layers and parallax ImageLayers all count it, so a parallax background now shakes with the world, by its ratio
  • Lighting: on the Canvas renderer, a light's hole in the ambient darkness is cut where the light is, under a scrolled or zoomed camera and one drawn at an offset such as a minimap. Under a scrolled camera the mask kept the darkness inside the light and cleared it around it, and the holes of a zoomed or offset camera were cut as if it were neither
  • Lighting: the ambient darkness covers the whole view of a camera. Zoomed out, it covered only as much of the world as the camera is wide, and at a fractional position, such as a camera following its target with damping, it left the first column and row lit unless subPixel was set
  • Lighting: on the Canvas renderer, a lit game whose sprites have no normal map no longer warns that normal-map lighting needs a GPU backend. It warned as soon as a Light2d existed, though a sprite without a normal map is drawn unlit on every renderer; it now warns once, when it draws a sprite with a normal map under a light
  • Audio: a sprite region declared looping ([start, duration, true]) loops when played with audio.play(name, { sprite }). It played only once unless loop: true was passed as well
  • Text: a label whose text is empty or only spaces no longer blanks the whole frame on WebGPU. Its canvas was sized 0 pixels wide, which WebGPU refuses to upload
  • Typings: TextureAtlas#getAnimationSettings() is typed as the settings it returns, so they pass to a Sprite constructor from TypeScript without a cast. It returned object, and Sprite3d typed the named animations an aseprite atlas carries as an array
  • Typings: CanvasRenderTarget#destroy(renderer) is typed and documented with its renderer, which frees the copy of the canvas uploaded to the GPU as well. It was hidden, so only the parent's destroy() showed, and TypeScript refused the argument

Performance

  • Effects: sprites drawn one after the other through the same ShaderEffect share one draw call, as plain sprites do, even from different frames of an atlas. A uniform set to a new value draws the sprites queued before it first, so each sprite still draws with the values it was given; a screen_texture effect still draws each sprite on its own
  • Rendering: drawing a sprite, a glyph or a pattern computes its UVs from the image size instead of looking them up, with no string built and nothing allocated or kept. On the platformer, text and Jungle Rabbit examples a lookup took 34 to 58 ns and now takes 6 to 10, in Chrome and WebKit: 1 to 2% of a frame's CPU time on the text example, and too little to measure on the platformer

Contributors

@snowyukitty

  • TextureAtlas: compute quad UVs instead of adding a region for every drawn rectangle (#1734) (f4c5793)

New Contributors

  • @vtxe02023274 made their first contribution
    • Project isometric collision shapes with the map's tile ratio (#1766) (6ecf5bd)
    • Tiled: place objects on isometric maps where Tiled draws them (#1759) (5f037e0)

Full Changelog: 20.10.1...20.11.0