Cascading / tumbling reels
TL;DR
После выигрыша победившие символы взрываются (анимация исчезновения), верхние падают вниз, на пустоты сверху приходят новые символы из той же reelstrip-полоски. Заново evaluate. Цикл до прекращения выигрышей. Один base-spin может породить длинную цепочку tumble-ов с возрастающим global multiplier-ом — это и есть «комбо».
Названия-синонимы: cascade, tumble, avalanche (NetEnt), rolling reels (Microgaming). Геометрически разные имена, механика одинаковая.
Как работает
Алгоритм tumble loop
while win_data.totalWin > 0 and not wincap_triggered:
отметить win_positions как explode
tumble_board():
для каждого reel:
удалить explode-позиции
сдвинуть оставшиеся вниз
на пустоты сверху насыпать символы из reelstrip
(top-symbol сохраняется!)
evaluate_wins(board) → новый win_data
wallet.update_spin_win(win_data.totalWin)
if global_mult_increments_on_tumble:
global_mult += 1
emit update_global_mult_event
emit tumble_board_event, tumble_win_event
Top-symbol сохраняется
Если в config include_padding = True, фронт показывает «padding-символы» сверху и снизу board (часть в-кадре). При tumble top-symbol сохраняется, не приходит новый — это важно для UX «полностью видимой полоски» reelstrip-а. Иначе первые позиции сразу после tumble могли бы выглядеть «телепортацией».
Реализация: на каждый tumble-step сохраняем индекс reelstrip-стопа (reel_pos); новые символы берутся из позиций выше изначального стопа, top-symbol = reelstrip[reel_pos - 1] остаётся неизменным.
Мат-эффект
- Hit frequency на base-spin не меняется (триггерится первой evaluate). Но расширенный hit frequency «спин с хотя бы одной выплатой за tumble» заметно выше.
- Volatility растёт за счёт длинных tumble-цепочек с multiplier-инкрементом.
- Average win за раунд выше — суммируются tumble-ы.
- RTP контролируется через
paytable × probabilitiesдля board ДО первого tumble. Tumble-цепочка считается рекурсивно при симуляции.
Варианты и подвиды
Global multiplier инкремент
- +1 на каждый tumble в freegame — стандарт (Pragmatic Play Gates of Olympus, Sweet Bonanza).
- +1 на каждый tumble в base — реже.
- Persistent через freegame (не сбрасывается на каждый freespin) vs сбрасывается (стандарт «сбрасывается»).
Position-multiplier grid
- В freegame каждая cell board может иметь multiplier (накапливается с каждым tumble на этой позиции, обычно 2× → 4× → 8× → … → 512×). Sweet Bonanza, Sugar Rush.
- Multiplier-grid сохраняется через retrigger.
Multiplier-symbols на board
- Особый символ M с написанным multiplier-значением (типа «3×»).
- Не «взрывается» при tumble.
- В конце цепочки tumble-ов суммируется и применяется к итогу. Gates of Olympus.
Без multiplier
Чистый tumble без множителей — Bonanza (NetEnt), Reactoonz (Play’n GO).
Реализационные заметки
Бэк (TS)
function runTumbleLoop(ctx: GameContext) {
let winData = evaluateWins(ctx);
emitWinInfoEvent(ctx, winData);
ctx.wallet.updateSpinWin(winData.totalWin);
ctx.wallet.tumbleWin += winData.totalWin;
while (winData.totalWin > 0 && !ctx.wincapTriggered) {
markExplode(ctx.board, winData.wins);
tumbleBoard(ctx); // mutate board, emit tumbleBoard event
if (ctx.config.globalMultIncrementOnTumble && ctx.gametype === "freegame") {
ctx.globalMult += 1;
emit({type: "updateGlobalMult", value: ctx.globalMult});
}
winData = evaluateWins(ctx);
if (winData.totalWin > 0) {
ctx.wallet.updateSpinWin(winData.totalWin);
ctx.wallet.tumbleWin += winData.totalWin;
emitWinInfoEvent(ctx, winData);
}
evaluateWincap(ctx);
}
// emit cumulative tumble banner
emit({type: "tumbleBanner", amount: ctx.wallet.tumbleWin, globalMult: ctx.globalMult});
ctx.wallet.tumbleWin = 0n;
}
function tumbleBoard(ctx) {
for (let reel = 0; reel < ctx.board.length; reel++) {
const explodedRows = collectExplodedRows(ctx.board[reel]);
if (explodedRows.length === 0) continue;
const remaining = ctx.board[reel].filter(s => !s.explode);
const newSyms = nextSymbolsFromReelstrip(ctx.reelstrip[reel], ctx.reelPos[reel], explodedRows.length);
ctx.board[reel] = [...newSyms, ...remaining];
ctx.reelPos[reel] -= explodedRows.length;
}
emit({type: "tumbleBoard", removed: explodedPositions, newSymbols: newSymbolsByReel});
}Edge cases
- Wincap во время tumble —
wincapTriggeredобрезает loop. Дополнительные tumble-ы не запускаются. - Бесконечный tumble — теоретически возможно (вся reelstrip из одинаковых символов). На практике reelstrip-композиция гарантирует прекращение. Должна быть hard-cap на число tumble-ов в loop (например, 50) как fail-safe против infinite loop, с error-метрикой.
- Position-multiplier через retrigger — multiplier-grid между freespin-ами должен сохраняться.
Фронт
Эмитятся подряд:
winInfo— что выиграло.tumbleBoard— какие позиции исчезают, какие приходят.- (опц.)
updateGlobalMult— multiplier увеличился. - …повтор…
tumbleBanner— итоговый banner с total-tumble-win и global mult.
Фронт делает анимацию win-highlight → explode → fall → reveal, потом повторяет evaluate ивента. Каждый шаг — отдельный animation pipeline.
Compliance / cert
- Help раскрывает: «After a winning combination, winning symbols are removed and replaced by symbols falling from above. Multipliers may apply.»
- Если global multiplier инкрементируется — это раскрывается явно.
- Должны соблюдаться правила responsible product design про auto-play лимиты — длинные tumble-цепочки не должны заглушать «paused» state для игрока.
Примеры реализаций
- NetEnt Gonzo’s Quest (avalanche, родоначальник tumble-механики в онлайне, 2010).
- NetEnt Bonanza (Megaways + tumble).
- Pragmatic Play Gates of Olympus (scatter-pays + tumble + global mult + multiplier-symbols).
- Pragmatic Play Sweet Bonanza (cluster + tumble + multiplier-symbols).
- Pragmatic Play Sugar Rush (cluster + tumble + position-multiplier-grid).
- Stake math-sdk sample:
games/0_0_cluster/,games/0_0_scatter/.