Sonolus Wiki

12. 输入管理器

在本章中,我们将介绍并实现输入管理器。

输入管理器

音符的输入逻辑中还缺少最后一件事:如果有两个音符彼此非常接近,当玩家点击时,我们只希望点击只记录在一个音符上,而不是同时记录在两个音符上。

这需要一个作为中介的实体来协调所有的音符:输入管理器。

让我们构建一个输入管理器:

export class InputManager extends Archetype {}
export class InputManager extends Archetype {}
export const archetypes = defineArchetypes({
    // ...
    InputManager,
    // ...
})
export const archetypes = defineArchetypes({
    // ...
    InputManager,
    // ...
})
export const data: LevelData = {
    // ...
    entities: [
        // ...
        {
            archetype: 'InputManager',
            data: [],
        },
        // ...
    ],
}
export const data = {
    // ...
    entities: [
        // ...
        {
            archetype: 'InputManager',
            data: [],
        },
        // ...
    ],
}

已经用过的触摸

为了阻塞输入,我们可以用一个集合存储已经使用过的触摸数据,让音符在使用前检查触摸数据是否已经使用过。

那如何共享可变数据呢?我们可以使用关卡内存(Level Memory)块来做到这一点:

const usedTouchIds = levelMemory(Collection(16, TouchId))
const usedTouchIds = levelMemory(Collection(16, TouchId))

现在我们可以实现并导出两个函数来与之交互:

export const isUsed = (touch: Touch) => usedTouchIds.has(touch.id)

export const markAsUsed = (touch: Touch) => usedTouchIds.add(touch.id)
export const isUsed = (touch) => usedTouchIds.has(touch.id)

export const markAsUsed = (touch) => usedTouchIds.add(touch.id)

最后,我们应该清除每一帧使用过的触摸,这样这个集合就不会无限增长:

export class InputManager extends Archetype {
    // ...

    touch() {
        usedTouchIds.clear()
    }
}
export class InputManager extends Archetype {
    // ...

    touch() {
        usedTouchIds.clear()
    }
}

阻塞输入

有了输入管理器,我们现在可以将阻塞输入添加到音符的输入逻辑中。

但首先,我们需要确保音符的touch在输入管理器的之后执行,我们可以通过给出更高的顺序来实现:

export class Note extends Archetype {
    // ...

    touchOrder = 1
    // ...
}
export class Note extends Archetype {
    // ...

    touchOrder = 1
    // ...
}

现在阻塞输入简单地在使用前检查触摸是否已经被使用过,并在使用时将其标记为已使用:

export class Note extends Archetype {
    // ...
    touch() {
        // ...

        for (const touch of touches) {
            // ...
            if (isUsed(touch)) continue

            markAsUsed(touch)

            // ...
        }
    }

    // ...
}
export class Note extends Archetype {
    // ...
    touch() {
        // ...

        for (const touch of touches) {
            // ...
            if (isUsed(touch)) continue

            markAsUsed(touch)

            // ...
        }
    }

    // ...
}