New Transform Aliases (Kiwi.js v1.1.0)

Hello, and welcome to the second in a series of in-depth articles about Kiwi.js v1.1.0, now available for use at www.kiwijs.org. Today we’re talking about transform aliases and how they make your life easier. I’m Ben Richards, and I’ve spent time with the biggest games being made in Kiwi.js, figuring out how to accelerate the coding process. I’m looking forward to sharing these improvements with you.

Who Needs to Read This Post?

All users. Kiwi.js is all about moving objects around the screen, and transform aliases make this quicker and more flexible than ever.

Lexicon

What’s a Transform?

Before discussing aliases, we must first understand the Transform object to which they refer.

The prototype Kiwi.Geom.Transform holds and implements information about transformation. This includes the following fundamental properties:

  • x
  • y
  • rotation
  • anchorPointX
  • anchorPointY
  • scaleX
  • scaleY

This tells you everything you need to position and lay out an image.

These properties are combined to create a transformation matrix, an efficient method for applying hierarchical transformations. The matrix is beyond the scope of this discussion, but it is the ultimate destination for transformation information.

Rotation and Anchor Points

If you’re used to degrees, I’ve got bad news. Mathematics and computer graphics don’t use degrees; they use radians. One radian is simply the distance along a circle’s circumference equal to the radius of that circle. It’s about 57.3 degrees. Because circumference equals 2 * pi * radius, a full circle of 360 degrees is precisely 2 * pi radians. A half circle is precisely pi radians, and a quarter circle or right angle is precisely pi / 2 radians.

You can either learn to love radians, or use built-in conversion functions in Kiwi.js. Simply call Kiwi.Utils.GameMath.degreesToRadians( degrees ) or Kiwi.Utils.GameMath.radiansToDegrees( radians ) to convert an angle back and forth.

Rotation does not occur about the x,y position of the object. That coordinate actually maps the top left corner. Rotation (and scaling) happens on an offset, usually set to the middle of the object. This behaviour looks right. The offset is described by anchorPointX,anchorPointY. You can change it, and this is useful for some desired effects.

Diagram explaining anchorPoint paradigm

NOTE: anchorPointX,anchorPointY nomenclature is actually an alias. We will discuss this later in the article.

Object Space Transforms

Kiwi.js has a hierarchical scene graph. This means you can add game objects to a Group, and then transform the Group to transform all the objects inside it as well.

How does this affect the object transform? For example, if you rotate the parent Group by 3, does the child’s rotation also equal 3?

Actually, the child’s rotation remains unchanged. Only the parent transform is altered. Kiwi.js preserves the child’s transform data, and compiles the parent data into the transform matrix behind the scenes. We call this child’s data object space transformation, because it doesn’t care about the wider world. It is an extremely useful model. You just need to worry about where your object is standing relative to its parent; you can change that context by transforming the parent, and the object need never know.

For example, you could create a pirate and a pirate ship, add them to the same Group, and then animate the Group to bob and sway with the high seas; the pirate will appear to be fixed to the deck of the ship. In fact, if you move the pirate left and right, they will appear to walk along the deck even if the ship is swaying back and forth. You could go further, and add the bobbing ship to another group to represent ocean currents, add that to another group to represent the tides, another group to represent the Earth spinning, yet another group for the Earth moving round the Sun, and so on. This is getting a bit silly, but the point remains: even if you do all this astronomical transformation, you can still just move the pirate left and right, without accounting for solar peregrinations and epicycles. Isn’t that handy?

What are Aliases?

They’re shortcuts to frequently-used data.

Many objects in Kiwi.js have a Transform object. This manages transformation: position, rotation, and scaling in space. However, it is not always intuitive for you to have to call pirate.transform.x every time you want to move a character. Accordingly, shortcuts or aliases are implemented on several game objects. Now you may simply call pirate.x. Kiwi.js automatically transfers that information to the Transform, and your pirate moves left and right.

Old Aliases

Previous versions of Kiwi.js did not provide consistent access to aliases. The Sprite object had rotPointX and rotPointY properties, while the Group object did not. The TextField object had width and height properties, but did not define them. The Transform object itself had a simple scale alias, but this was not accessible elsewhere. And so on.

All the information was there, but sometimes you had to dig a little to get at it. We needed to make it easier and more intuitive.

New Alias Standard

In Kiwi.js v1.1.0, we’ve implemented a robust new standard for aliases. All transformable objects except cameras have the following properties:

  • x
  • y
  • rotation
  • anchorPointX
  • anchorPointY
  • rotPointX
  • rotPointY
  • scale (SET only)
  • scaleX
  • scaleY
  • worldX (GET only)
  • worldY (GET only)

Anchor Point

The anchorPointX, anchorPointY properties alias to the original properties rotPointX, rotPointY. The term “rotPoint” or “rotation point” is potentially confusing, because it describes both rotation and scale. Alternative names were discussed, including “transformPoint”. However, transformPoint implied that it would also affect x, y; and there was already a method on Transform called transformPoint(), used for projecting coordinates via a matrix. In the end, “anchorPoint” was determined to be most logical and accessible. The terminology was inspired by Adobe After Effects, where it serves an identical function.

rotPointX, Y still works, but will be deprecated in favour of anchorPoint nomenclature in future major version.

Scale and worldXY: Set/Get Only Aliases

These aliases do not correspond to persistent, singular values.

scale sets both scaleX and scaleY. Most of the time you will want these to be paired. However, because we cannot guarantee that they are the same, scale does not have a value that you can read. You can only use it to set values.

worldX and worldY break out of object space and tell you precisely where in the world your object is located. These are calculated behind the scenes using matrix operations. You cannot set world values in Kiwi.js v1.1.0.

We only provide world location, not world scale or world rotation. This is because of the nature of transformation matrices. While they are created from location, rotation, and scale data, they can quickly twist into shapes that are simply too complicated for simple rotation and scale values to describe. It’s a stroke of luck that the laws of mathematics yield even position values.

New Functionality

We have added several functions that are not standard aliases, but nevertheless allow you to perform useful functions. These include width and height properties, scaleTo methods, and the centerAnchorPoint method. We also discuss the camera and the use of shear.

Width and Height

This applies to Entity-type objects: Sprite, StaticImage, TextField and TileMapLayer. It does not apply to Groups or Cameras.

All entities now have a width and height. By default, these refer to the pixel dimensions of their source image. They do not change when the entity is scaled.

TileMapLayer is an Exception

While TileMapLayer objects have width and height, they do not give pixel dimensions. Instead these properties refer to the number of tiles in the map. You can get pixel width and height values akin to those of other entities using the properties TileMapLayer.widthInPixels and TileMapLayer.heightInPixels. This was implemented early and unfortunately cannot be changed without breaking the current API.

scaleToWidth and scaleToHeight

This applies to Entity-type objects: Sprite, StaticImage, TextField and TileMapLayer. It does not apply to Groups or Cameras.

All entities now have the methods scaleToWidth( value ) and scaleToHeight( value ). These set the scale of the entity so it matches that width or height. This is based on the ratio between value and (width or height). You can call one of these methods once, to uniformly scale an Entity to a desired dimension. This does not alter the width or height properties. As it affects scale, this transformation remains persistent after one call. It is useful when setting up objects.

centerAnchorPoint

This applies to Entity-type objects: Sprite, StaticImage, TextField and TileMapLayer. It does not apply to Groups or Cameras.

All Entities have a new method: centerAnchorPoint(). This moves the anchorPoint (rotPoint) to the geometric center of the object: [width/2, height/2]. This is a convenience method for quickly aligning objects.

On TileMapLayer, this method functions as expected, but it uses widthInPixels and heightInPixels instead.

Shear/Skew

We discussed implementing a shear function on Transform or Matrix. This would permit some new visual possibilities. However, it would do two undesirable things.

  • Adding this parameter would increase the cost of matrix operations.
  • We plan to implement glMatrix.js for high performance matrix mathematics in future releases, and this does not have a shear function. Adding shear now would entail taking it out later.

Ultimately we decided against implementing shear.

You can create your own shear effects by placing an object inside a group, rotating the object, and scaling the group in one axis.

Camera

The Camera has a Transform, but it has no aliases. Because the Camera is not frequently animated, and its default values are largely unchanging, we can consider any transformation of the camera to be an advanced topic. Users should therefore know exactly what they’re doing if they access Camera.Transform.

In Review

You should now understand the principles of object space transformation. You can use a wide range of aliases to manipulate objects, and use new methods to configure their transformation. These were much-demanded features, so I know you’ll find them useful!

Benjamin D. Richards

Share the joy

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">