12. 输入管理器
在本章中,我们将介绍并实现输入管理器。
输入管理器
音符的输入逻辑中还缺少最后一件事:如果有两个音符彼此非常接近,当玩家点击时,我们只希望点击只记录在一个音符上,而不是同时记录在两个音符上。
这需要一个作为中介的实体来协调所有的音符:输入管理器。
让我们构建一个输入管理器。由于输入管理器只在游玩模式中出现,因此我们将其定义为一个可生成的原型并让其在初始化中生成。我们可以扩展 SpawnableArchetype({})
来使其变为可生成原型并且不需要任何数据来生成:
export class InputManager extends SpawnableArchetype({}) {}
export class InputManager extends SpawnableArchetype({}) {}
export const archetypes = defineArchetypes({
// ...
InputManager,
// ...
})
export const archetypes = defineArchetypes({
// ...
InputManager,
// ...
})
我们能在初始化原型中生成输入管理器:
export class Initialization extends Archetype {
// ...
updateSequential() {
archetypes.InputManager.spawn({})
// ...
}
}
export class Initialization extends Archetype {
// ...
updateSequential() {
archetypes.InputManager.spawn({})
// ...
}
}
已经用过的触摸
为了阻塞输入,我们可以用一个集合存储已经使用过的触摸数据,让音符在使用前检查触摸数据是否已经使用过。
那如何共享可变数据呢?我们可以使用关卡内存(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)
// ...
}
}
// ...
}