Sonolus Wiki

05. Blocks and Sharing Immutable Data

In this chapter, we will go over the concept of blocks and how to share immutable data between archetypes.

Blocks

In previous chapter, Initialization has transformed our screen coordinate system to better suit our engine needs. However, the other archetypes now no longer know about how they should render. For example, Stage is responsible for rendering the judgment line, it would be simply drawing from x = screen.l to x = screen.r, but now it no longer knows how far left or right to draw.

Initialization holds those information and must be shared to other archetypes, but how do we do that?

Blocks are the memory sharing mechanism in Sonolus. Blocks are simply continuous blocks of memory that can be accessed by low level functions provided by Sonolus. For example, when we despawn using this.despawn = true, what it's doing under the hood is to call the low level Set function, with arguments pointing to despawn flag in the Entity Despawn block.

Sonolus.js abstracts these low level operations and wraps it in a nice developer friendly API.

Level Data Block

To do what we want, we can use a block that lets us write arbitrary values into, and read it out of. There are many blocks that serve the purpose of generic memory storage, however one in particular we should take note of is the Level Data block.

Level Data block can only be written to during preprocess callback, after that it is immutable and can only be read. This immutability allows optimizations to be performed, and all future read operations of Level Data block will be inlined as constants, making it extremely performant and suitable for sharing immutable data.

Declaring

We need to let Stage know the new left and right coordinate of the judgment line, as well as let Note know the new radius. Let's declare them:

export const judgeLine = levelData({
    l: Number,
    r: Number,
})
export const judgeLine = levelData({
    l: Number,
    r: Number,
})
export const note = levelData({
    radius: Number,
})
export const note = levelData({
    radius: Number,
})

Accessing

Now we can simply access them like regular variables:

export class Initialization extends Archetype {
    preprocess() {
        // ...

        judgeLine.l = screen.l / h
        judgeLine.r = screen.r / h

        note.radius = noteRadius / h

        // ...
    }

    // ...
}
export class Initialization extends Archetype {
    preprocess() {
        // ...

        judgeLine.l = screen.l / h
        judgeLine.r = screen.r / h

        note.radius = noteRadius / h

        // ...
    }

    // ...
}