Docs/Examples/Hybrid Game

HybridGame

Score accumulation with random events every Nth tick — the Hybrid VRF pattern in action.


Overview

HybridGame demonstrates the Hybrid VRF pattern. Most ticks are cheap standard ticks that accumulate score. Every Nth tick triggers a VRF random event — bonus points, multipliers, or jackpots.

  • Base: AutoLoopHybridVRFCompatible
  • VRF: Every 10th tick (configurable)
  • Gas: ~90k standard / ~240k VRF
  • Use case: RPGs, roguelikes, loot systems, any game with occasional random events

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {AutoLoopHybridVRFCompatible} from
    "autoloop/AutoLoopHybridVRFCompatible.sol";

contract HybridGame is AutoLoopHybridVRFCompatible {
    uint256 public score;
    uint256 public lastRoll;
    uint256 public interval;
    uint256 public lastTimeStamp;
    uint256 public totalTicks;
    uint256 public totalVRFTicks;
    uint256 private _loopID;
    uint256 private _vrfFrequency;

    uint256 constant EVENT_BONUS = 1;
    uint256 constant EVENT_MULTIPLIER = 2;
    uint256 constant EVENT_JACKPOT = 3;

    constructor(uint256 _interval, uint256 vrfFrequency) {
        interval = _interval;
        _vrfFrequency = vrfFrequency;
        lastTimeStamp = block.timestamp;
    }

    function _needsVRF(uint256 loopID)
        internal view override returns (bool)
    {
        return loopID % _vrfFrequency == 0;
    }

    function _shouldProgress()
        internal view override
        returns (bool ready, bytes memory gameData)
    {
        ready = (block.timestamp - lastTimeStamp) > interval;
        gameData = abi.encode(score);
    }

    function _onTick(bytes memory) internal override {
        lastTimeStamp = block.timestamp;
        ++score;
        ++totalTicks;
        ++_loopID;
    }

    function _onVRFTick(
        bytes32 randomness,
        bytes memory
    ) internal override {
        lastRoll = (uint256(randomness) % 6) + 1;
        uint256 eventType = (uint256(randomness) >> 8) % 3;

        if (eventType == EVENT_BONUS) {
            score += 10;
        } else if (eventType == EVENT_MULTIPLIER) {
            score *= 2;
        } else {
            score += 100; // JACKPOT
        }

        lastTimeStamp = block.timestamp;
        ++totalTicks;
        ++totalVRFTicks;
        ++_loopID;
    }
}

Deploy

# 30 second interval, VRF every 10th tick
forge create examples/HybridGame.sol:HybridGame \
  --constructor-args 30 10 \
  --rpc-url $RPC_URL \
  --private-key $PRIVATE_KEY

Key Design Decisions

  • _vrfFrequency is set in the constructor — adjust per game (every 5th, 10th, 20th tick)
  • _onTick is cheap and fast — just increments score and advances state
  • _onVRFTick uses randomness for event types — bonus, multiplier, or jackpot
  • Both tick types advance _loopID and totalTicks
  • totalVRFTicks tracks how many VRF ticks have fired for analytics