Game Development 13 min read

Build an Angry‑Birds‑Style Game in Under 100 Lines with Dora SSR and TSX

This tutorial shows how front‑end developers can use the Dora SSR game engine’s TSX support to create a simple Angry‑Birds‑like game in fewer than 100 lines of code, covering scene setup, physics, UI components, touch controls, scoring logic, and cross‑platform deployment.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Build an Angry‑Birds‑Style Game in Under 100 Lines with Dora SSR and TSX

Overview

Dora SSR is a cross‑platform game engine that mirrors the DOM tree and lets front‑end developers write game logic with TSX. TSX is compiled to Lua via TypeScriptToLua, running on a Lua/WASM VM.

Setup

Install the Dora SSR package, open the Web IDE and start coding. Quick‑start guide: https://dora-ssr.net/zh-Hans/docs/tutorial/quick-start

1. Minimal scene

Add preview comment for hot‑reload: // @preview-file on Import core modules:

import { React, toNode, useRef } from 'DoraX';
import { Body, BodyMoveType, Ease, Label, Line, Scale, TypeName, Vec2, tolua } from 'Dora';

Show a sprite:

toNode(<sprite file='Image/logo.png' scaleX={0.2} scaleY={0.2}/>);

2. Box component

Reusable component that creates a dynamic physics body, a rectangular fixture, visual rectangle and a score label.

interface BoxProps {
  num: number;
  x?: number;
  y?: number;
  children?: any | any[];
}
const Box = (props: BoxProps) => {
  const numText = props.num.toString();
  return (
    <body type={BodyMoveType.Dynamic} scaleX={0} scaleY={0} x={props.x} y={props.y} tag={numText}>
      <rect-fixture width={100} height={100}/>
      <draw-node>
        <rect-shape width={100} height={100} fillColor={0x8800ffff} borderWidth={1} borderColor={0xff00ffff}/>
      </draw-node>
      <label fontName='sarasa-mono-sc-regular' fontSize={40}>{numText}</label>
      {props.children}
    </body>
  );
};
tag

: stores the box’s score. rect-fixture: defines collision shape. draw-node: draws rectangle. label: displays score.

3. References

useRef to keep handles to the bird body and the score label:

const bird = useRef<Body.Type>();
const score = useRef<Label.Type>();

4. Launch line

Track touch/mouse drag to draw a line and set bird velocity on release.

let start = Vec2.zero;
let delta = Vec2.zero;
const line = Line();

toNode(
  <physics-world
    onTapBegan={(touch) => { start = touch.location; line.clear(); }}
    onTapMoved={(touch) => { delta = delta.add(touch.delta); line.set([start, start.add(delta)]); }}
    onTapEnded={() => {
      if (!bird.current) return;
      bird.current.velocity = delta.mul(Vec2(10, 10));
      start = Vec2.zero; delta = Vec2.zero; line.clear();
    }}>
    {/* other game objects */}
  </physics-world>
);

onTapBegan records start point and clears line.

onTapMoved updates line.

onTapEnded applies velocity to bird.

5. Game objects

5.1 Ground

<body type={BodyMoveType.Static}>
  <rect-fixture centerY={-200} width={2000} height={10}/>
  <draw-node>
    <rect-shape centerY={-200} width={2000} height={10} fillColor={0xfffbc400}/>
  </draw-node>
</body>

5.2 Boxes

Instantiate five boxes with scores 10‑50 and staggered entrance animation:

{[10,20,30,40,50].map((num,i) => (
  <Box num={num} x={200} y={-150 + i*100}>
    <sequence>
      <delay time={i*0.2}/>
      <scale time={0.3} start={0} stop={1}/>
    </sequence>
  </Box>
))}

5.3 Bird

<body ref={bird} type={BodyMoveType.Dynamic} x={-200} y={-150}
      onContactStart={(other) => {
        if (other.tag && score.current) {
          const sc = parseFloat(score.current.text) + parseFloat(other.tag);
          score.current.text = sc.toString();
          const label = tolua.cast(other.children?.last, TypeName.Label);
          if (label) label.text = '';
          other.tag = '';
          other.perform(Scale(0.2, 0.7, 1.0));
        }
      }}>
  <disk-fixture radius={50}/>
  <draw-node>
    <dot-shape radius={50} color={0xffff0088}/>
  </draw-node>
  <label ref={score} fontName='sarasa-mono-sc-regular' fontSize={40}>0</label>
  <scale time={0.4} start={0.3} stop={1.0} easing={Ease.OutBack}/>
</body>

6. Full demo

The code above produces a functional Angry‑Birds‑style game. Extend it with more levels or UI as needed.

Full source: https://github.com/IppClub/Dora-SSR/blob/main/Assets/Script/Test/Birdy.tsx

Game screenshot
Game screenshot
Drag to launch the bird
Drag to launch the bird

Technical details

Dora SSR runs on a Lua/WASM virtual machine. TypeScript support is provided by the TypeScriptToLua compiler, which translates TS/TSX into Lua bytecode. The current engine builds the scene once; there is no virtual‑DOM diffing, so TSX is used only for static scene construction.

Future work may add React‑like state synchronization or Solid‑style fine‑grained updates for game UI.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Front-endTypeScriptGame DevelopmentTutorialDora SSRTSXPhysics
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

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.