How should you do matrix transformations?
You are correct that Transform2D
does not allow these kinds of "additional transforms on top" -- mostly because the transform matrix gets recalculated whenever any underlying property changes. However, you can create a derived class, overriding the transformMatrix
getter so that it applies additional transformations.
I'm not sure what's the best way for implementing isometric games in Flame, but you could try the following approach:
[World]
+--[Ground]
| +--[Tile]s
|
+--[Overground]
+--[Character]
+--[Enemy]s
+--[Structure]s
+--...
Here, Ground
would be a component that applies isometric projection before rendering its children Tile
s (which are just regular PositionComponents). Thus, there's no need to multiply the transform matrix: you are just applying an extra canvas transform.
The Overground
component is a bit trickier. It has many children, each of which is a regular PositionComponent
with (x, y)
position given in the world coordinates. The job of the Overground
then is to apply the isometric projection to that position, converting it into the screen coordinates, and then translate the canvas accordingly before rendering each component. Also, Overground
would need to constantly re-sort the children according to their distance from the camera.
anonymous-dev
Updated on January 03, 2023Comments
-
anonymous-dev over 1 year
We are rendering a isometric grid with flame where each tile is a component but we found this comment in the source code of the Transform2D
The returned matrix must not be modified by the user.
/// The total transformation matrix for the component. This matrix combines /// translation, rotation, reflection and scale transforms into a single /// entity. The matrix is cached and gets recalculated only as necessary. /// /// The returned matrix must not be modified by the user. Matrix4 get transformMatrix { if (_recalculate) { // The transforms below are equivalent to: // _transformMatrix = Matrix4.identity() // .. translate(_position.x, _position.y) // .. rotateZ(_angle) // .. scale(_scale.x, _scale.y, 1) // .. translate(_offset.x, _offset.y); final m = _transformMatrix.storage; final cosA = math.cos(_angle); final sinA = math.sin(_angle); m[0] = cosA * _scale.x; m[1] = sinA * _scale.x; m[4] = -sinA * _scale.y; m[5] = cosA * _scale.y; m[12] = _position.x + m[0] * _offset.x + m[4] * _offset.y; m[13] = _position.y + m[1] * _offset.x + m[5] * _offset.y; _recalculate = false; } return _transformMatrix; }
It does seem to work, with all tiles being its own component, where each component just renders a colored rectangle. (Matrix4.isometric() is our extension).
IsometricGrid extends PositionComponent
IsometricGrid({ this.tiles = const [], this.rows = 1, this.columns = 1, this.tileWidth = 1, this.tileHeight = 1, }) : super() { final isometricMatrix = Matrix4.isometric(); transformMatrix.multiply(isometricMatrix); projectionMatrix = isometricMatrix; inverseProjectionMatrix = Matrix4.inverted(projectionMatrix); }
And we get
But we later wanted to add a actor to the grid with IsometricGrid.addActor
addActor(PositionComponent actor) { actor.transform.transformMatrix.multiply(inverseProjectionMatrix); add(actor); }
Which ads the character standing up right to the grid. But once we move the actor to column 2 row 3 by changing its position the matrix seems to be reset for the actor.
What is the idiomatic way of modifying a matrix on the transform in the flame engine? It seems that under some conditions the matrix just resets. I think this happens because it just recalculates the matrix when you do a transformation such as rotation, position or scale.
We are building this with flutter web and we also notice that sometimes when alt tabed the matrix is reset.
-
anonymous-dev over 2 yearsHi, great answer. We did think of a solution like this, and since this seems like the only option we will try this. We hope the transform will allow these kind of transformations in a future update.
-
anonymous-dev over 2 yearsBut could you explain what you mean by "Ground would be a component that applies isometric projection before rendering its children Tiles (which are just regular PositionComponents). Thus, there's no need to multiply the transform matrix"? Without a matrix? Could you elaborate how this projection should be done without a matrix?