Blog post: Gameplay Optimisation Challenges (2023-07-26)

Sourced from *Gameplay Optimisation Challenges*, a blog post on the game's official website by Lapper.

```
The original games use a grid of Solid Tiles to build up terrain.

Sonic Studio, on the other hand, uses free flowing vector lines to build up terrain. One is more restrictive than the other... but that one is easier to deal with than the other.

Tile vs Vector Collision Setups

I'm going to try and explain how both the original game's collision setup works, and how Sonic Studio's works. If you are a seasoned programmer, this post will come as no surprise, but I mainly want to express the challenges faced in Sonic Studio to those who may assume how things work based on what they are used to. Such as the tiles like those in the classic games, be it in hacking tools, or other level editors like SMM.

Below is a sample of the Solid Tiles the original Sonic games use to build terrain. These are 16x16 height arrays combined with precalculated angle values, and are smartly combined in multiple different ways to create the recognisable slopes and curves we are used to.

When you use a grid to build any sort of map, collision or otherwise, the process for finding and reacting to any given tile is easy.

Let's go through the process for the original game:

What tile is Sonic currently within? Well, all the tiles are in a neatly organised grid, so the "tile coordinate" is simply the tile at Sonic's position divided by the tile size. Once you know the tile coordinate, you know what tile is at that position. It's easy to react to because that tile already "exists". It's part of a small set, the data can be instantly analysed.

Then the tile can be reacted to. Minimal work needed.

Vectors are a different story.

In the example of this loop, multiple small terrain edges, which are lines (or vectors), are used to construct the solid surface. Curves are also are split into these individual terrain edge lines. Sonic Studio works this way to allow you to create terrain with any vector polygons you wish to. It has incredible benefits, but  a few extra challenges.

Something to note is that Sonic Studio is a fan game created with GameMaker. GameMaker has no automatic built in vector/polygon collision system (it has a 2D physics engine, but that's not helpful for us at all). What little built in collision functions it does have is no use to us, because the classic Sonic games don't use complex sprite based collision.

Everything has to be built from scratch using pure math, and that includes solving the issues that will be explained ahead.

Let's go through the process for vector terrain edges:

What terrain edge is Sonic currently within? Urm. Ok, already, we hit a problem. These terrain edges aren't constructed using a grid, they can be literally anywhere, any angle, and any size. All we have is a list of them from when they are generated in a random order. So, thanks to all of that, we can't automatically find them using Sonic's position like with tiles. Darn.

To find it using the most direct approach, we would have to loop through all of them, checking the position, size, and rotation of all of them until we find a match. Each frame. That... is slow. Each stage could have thousands of these terrain edges.

At the very start of Sonic Studio's development, me being new to this stuff, that's exactly what it did. But obviously if you try to make a stage of any reasonable size, this breaks fast.

It's looking bleak. But not for long. So what's the solution?

Solution

​Let's look back to that grid that the original games use.

Hmmm. Seems simple. Seems nice.

Let's copy it. Let's steal it.😈

Wait. Sonic Studio uses a grid too?
Yes.

Does it use collision tiles?
No.

When the stage is edited or loaded, all of those terrain edges are of course, generated. The terrain shapes are "built", and their collision edges are calculated along with the angles. As they are created they are all added to a big list.

Here's where the copycat magic happens. We will cycle through this large list of terrain edgers, once. The first frame of gameplay. As it does this, for each one it can check the terrain edge's size and position and compare it to an imaginary grid. This imaginary grid will be our equivalent of the original game's tile grid (though in practice, the grid used in Sonic Studio is a little bigger than the original). We will call this grid the "edge grid".

The imaginary edge grid cell that the vector overlaps will become a real edge grid cell, and that cell is given a list which contains references to that and any other terrain edges overlapping it. If a terrain edge overlaps 2 or more these edge grid cells, that same edge will be referenced in each edge grid cell.

With that done, let's go through our new process:

What terrain edge is Sonic currently within? Well, let's use our new grid. All the edge grid cells are in a neatly organised grid, so the "cell coordinate" is simply the cell at Sonic's position divided by the grid size. Once we know the tile coordinate, we know if that cell exists, and if it does we know the list of terrain edges that it contains. All we need to do now is cycle through that very small list of terrain edges within that cell, rather than ALL of them.

Tadaa

I have greatly simplified things here in my explanations, but I think the core idea comes across. This kind of optimisation is a must when it comes to collision, drawing shapes, processing objects, and much much more.

Bye bye.
```