2D engine design/architecture: transformations

Hello! I'm working on this hobby little 2D engine in JavaScript because I want to learn how all this things are implemented and architectured in general. Internet is full of resources but most things are mathematical or theoretical stuff, there is very little about implementation or architecture for small 2D engines like the one I'm working in. So, this is my context and at the end are some questions I hope you can help me with:

I have a Body object that has different properties like (pseudo-code):

Body {
angle: float
scale: float
acceleration: 2d vector
velocity: 2d vector
position: 2d vector
update: function()
}


A Body object also has a Model object, which has (pseudo-code):

Model {
points: Array of [x, y] points
fillColor: string (hex)
transform: function(rotate, scale, translate)
}


The transform function receives Angle, Scale and Translate, and returns a new transformed instance of the model.

On every frame I will update the Body object to represent the current state: adding accelerator vector to velocity, velocity to location (and some similar stuff to update the angle and scale if required):

Body {
update() {
this.acceleration.reset()
}
}


Once the Body object is updated I must do a world-transform of the model so that I can start doing physics related stuff (like collision detection/resolving, interaction forces between bodies, etc). After that I will do a view-transform, to transform the world-objects into the "perspective" of some other object.

At the moment this is my solution is based in keeing three instances of the Model object withing the Body object, like this:

Body {
model: the original *Model* with no transformations
model_world: result of *Model.transform(body.angle, body.scale, body.location)*
model_view: the result of transforming **model_world** instance with viewport properties
}


Questions:

• Do you think there is a better way to handle model transformations? Like maybe one the do not require the Body object to mantain the three instances of the three transformations itself, perhaps.

• Can you please give me some suggestions on how to better organize this functionality for a simple 2D engine?

Thank you very much in advance!

• I highly suggest looking into the book HTML5 Games: Novice to Ninja. Its github is (here)[github.com/spbooks/html5games1]. It describes how to make a JS game engine from scratch. Do I agree with every decision ever? No. Is it an amazing resource? Yes! Absolutely. Apr 22, 2020 at 5:34
• Is this for the web? What are you using for rendering? If this is for the web, I'd advice to use WebGL, and have the GPU handle the transformations with GLSL. If this is server side code with Node.js... Hmm… No, that can't be right. Apr 22, 2020 at 6:49

In my humble opinion, the way you are currently tackling this problem is quite smart! That said, my concern with your current method is that the amount of memory you will be using to store 3 unique transformations of an object will increase dramatically for each object you add to your game. In fact, I'm pretty sure later on you will wish you didn't keep the 3 transformations separate!

I looked back at some code I wrote previously, and the process I'm using is the same as you are. I am simply doing it sequentially and not using separate objects/models.

• Determine how much the object's position will increment before collisions
• Determine how much the object's position is allowed to increment based on its collisions
• Transform the object's position based on its allowed amount
• Render the object

You can optionally pass the object to your viewport transform and pass the result to the renderer. You ask how to organize this, so I will give you an example to illustrate my approach more clearly.

I have a player class - you may call it a body. This is it's update function:

update() {
// update velocity
if (*condition*) {
this.decelerate(dt);
}
else if (*condition*) {
this.velocity.x += controls.x * dt * this.acceleration;
} else {
...
}

let x_offset = this.velocity.x;
let y_offset = 0;
// if jumping I set the y_offset

// returns edges collided and a valid x and y increment
const position = collision(this, this.map, x_offset, y_offset);

// logic based on edges collided if needed

// increment position
this.x += position.x;
this.y += position.y;

// logic after you have the "world" model
}


I don't know how your main game loop works or how this integrates with your renderer, so I can't really give specifics on how to construct your view-transform, but I think you could create a function that just takes your objects, makes a transformation, and passes it to the renderer. Or maybe you just want to make a camera, I'm not too sure from your descriptions. Anyway, feel free to ask me any questions. I hope this helps some!

• "my concern with your current method is that the amount of memory you will be using to store 3 unique transformations of an object will increase dramatically for each object you add" - I don't think that's the case, because the OP isn't storing transform matrices, he's just using 2 floats and a 2D vector (so 4 floats, I assume, as opposed to 9 for a single homogeneous transform matrix); but yeah, using a single matrix and leveraging linear algebra might make the code simpler in certain places, once you get past the math. Jan 17, 2021 at 14:52