Game Development 16 min read

Inside Shopee Candy: Building a Scalable Match‑3 H5 Game Architecture

This article walks through the origin, architecture, and tooling of Shopee Candy, a multi‑region match‑3 H5 game, detailing the Algorithm SDK, animation system, map editor, score runner, replayer, and future plans for configurability, performance, anti‑cheat, and AI‑driven level design.

Shopee Tech Team
Shopee Tech Team
Shopee Tech Team
Inside Shopee Candy: Building a Scalable Match‑3 H5 Game Architecture

Project Overview

Shopee Candy is a multi‑region casual H5 match‑3 game that rewards players with platform coins and coupons. The game limits the number of moves per level and generates special elements based on elimination patterns. It launched in June 2020 on iOS and Android.

System Architecture

Algorithm SDK

The Algorithm SDK encapsulates all core elimination logic, scoring and level progression, and is completely decoupled from the animation and business layers.

Map

Manages level maps and element objects in three layers (top, middle, bottom) so that new special elements can be added without breaking existing logic.

export default class Grid {
  public middle: CellModel;
  public upper: Upper;
  public bottom: Bottom;

  constructor(info: ICellInfo) {
    const { type } = info;
    this.upper = new Upper(/* ... */);
    this.middle = new CellModel(/* ... */);
    this.bottom = new Bottom(/* ... */);
  }
}

Operator

Acts as the bridge between external input (swap, double‑click) and the algorithm, converting user actions into IAnimationData for the animation system.

// Element swap
export function exchange(startPos, endPos): IAnimationData {
  // ...logic process
  // returns animation data
}

// Element double‑click
export function doubleClick(pos): IAnimationData {
  // ...logic process
  // returns animation data
}

Logic Processing

Performs solvability checks, elimination, drop calculations and other core operations. To avoid frame drops during intensive loops, the logic is split into asynchronous segments and data is sent to the animation system ahead of time.

Unit Testing

Because the algorithm library is isolated, it can be unit‑tested without UI. Tests verify that identical board states produce the same score, element counts and step counts regardless of operation order.

describe('BOMB', () => {
  it('Exchange each other should be the same crush', () => {
    const source = { row: 0, col: 3 };
    const target = { row: 1, col: 3 };
    const wrapper = mapDecorator(operator);
    const data1 = wrapper({ key: CRUSH_TYPE.BOMB }, source, target);
    const data2 = wrapper({ key: CRUSH_TYPE.BOMB }, target, source);
    expect(JSON.stringify(data1.map)).to.equal(JSON.stringify(data2.map));
    expect(data1.score).to.equal(data2.score).to.equal(150);
    expect(data1.passStep).to.equal(data2.passStep).to.equal(14);
  });
});

Animation System

Separating animation from the algorithm yields high cohesion, low coupling, improved efficiency and flexibility (e.g., bonus skipping).

High cohesion, low coupling

High efficiency

High flexibility

Design

Algorithm emits animation data which is placed into a queue and processed recursively until empty. A Strategy pattern selects the appropriate animation handler based on element type.

const animStrategyCfg = new Map([
  [AElement, AStrategy],
  [BElement, BStrategy],
  [CElement, CStrategy],
]);

function getStrategy(elementType) {
  return animStrategyCfg.get(elementType);
}

function executeStrategy(elementType) {
  const strategy = getStrategy(elementType);
  return strategy.execute();
}

Promise‑based animation methods replace nested callbacks, allowing clear async/await flow.

async function animation() {
  await tweenA.promise();
  await tweenB.promise();
  await tweenC.promise();
  await sleep.promise();
}

Development Tools

Map Editor

Provides drag‑and‑drop level configuration with keyboard shortcuts. Enforces element coexistence rules (mutual, exclusive, global exclusive) via a relationship table fetched from the server.

Score Runner

Automates difficulty testing by constructing a graph of all possible player actions, traversing it to compute maximum and minimum possible scores. A “smartness” strategy prunes low‑value branches, improving performance.

Statistical analysis of average pass rates across thousands of levels reduces manual validation time for level designers.

Replayer

Records random seeds to enable deterministic replay of Score Runner simulations, supporting verification of algorithm correctness, reconnection handling and post‑mortem analysis with minimal storage.

Future Directions

Configurable development for new elements to lower implementation cost.

Performance optimizations for low‑end devices.

Operation‑behavior verification services to prevent cheating.

Machine‑learning models trained on Score Runner data to auto‑generate levels.

frontendanimationalgorithmgame developmentH5Tooling
Shopee Tech Team
Written by

Shopee Tech Team

How to innovate and solve technical challenges in diverse, complex overseas scenarios? The Shopee Tech Team will explore cutting‑edge technology concepts and applications with you.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.