Hello everyone, I am a game engine technology explorer and a programmer who has done a lot of front-end development work. If you want to know how to go from writing web pages to developing games, you've come to the right place!
Today we talk about how to use Dora SSR, a game engine that supports TSX and runs cross-platform natively, to help you easily enter the world of game development. Don’t worry, when it comes to game engines, they are not unattainable technologies. Instead, they are surprisingly similar to the front-end development tools we are familiar with.
1. Game client development can also be a kind of front-end development
First, let's explain what a game engine is. Simply put, a game engine is a collection of tools and libraries that help developers build games and manage graphics, sound, physics calculations or collision detection, etc. For front-end developers, you can think of it as a special browser designed to run games.
The game scene management of Dora SSR uses a tree structure similar to HTML DOM, which is very familiar to us. Imagine replacing the div elements with various objects in the game, and replacing the CSS animations with game animations. The concept is almost the same, and the code writing may be similar. Doesn’t it sound interesting?
2. From TypeScript to TSX: Application of front-end technology in games
Many front-end developers are familiar with TypeScript and React's JSX syntax. In the Dora SSR open source game engine, we provide a game development interface similar to the front-end development programming model by supporting TSX. Yes, you heard it right, that TSX.
Using TSX to develop games means that you can leverage your existing front-end technology stack—components, modules, and other modern front-end technologies—and reuse these concepts directly in game development. Moreover, Dora SSR's performance optimization ensures smooth operation even in complex game scenarios.
3. Challenge yourself to write an “Angry Birds”-like game within 100 lines of code.
Okay, enough theory, let’s get into the practical stuff. Let's take a look at how to write a small game similar to "Angry Birds" in Dora SSR with less than 100 lines of TSX code. Of course, you still need to prepare a development environment before starting. Doing this with Dora SSR is very simple: I have an installation package , I have a browser and I open it . Well, let’s start writing code and running it. For installation and startup, see: Dora Start!
不小心装成了APK包在手机上?那就在同局域网下访问,直接在手机上进行开发调试吧
1. Write the simplest game scenario
Before writing the actual code, we can first write a comment with a special function, which can tell Dora SSR's Web IDE to automatically hot update the running code when we press Ctrl + S to save the file, so as to realize the code running results. Real-time preview function.
// @preview-file on
Then, we introduce the necessary libraries and components. Of course, our code editor will also prompt us to automatically introduce the required modules, which can be completed later in the coding process:
import { React, toNode, useRef } from 'dora-x';
import { Body, BodyMoveType, Ease, Label, Line, Scale, TypeName, Vec2, tolua } from 'dora';
Displaying an image in Dora SSR is very simple, just use <sprite>
a label, and finally toNode()
instantiate the label into a game object through a function.
toNode(<sprite file='Image/logo.png' scaleX={0.2} scaleY={0.2}/>);
Okay, now you have basically mastered most of the tricks of Dora SSR game development, let's start making your own game (seriously).
2. Write game box components
Next, the boxes we collide with in the game will Box
be defined by the component, which accepts attributes such as num
, x
, y
and :children
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>
);
};
We use React-like function component writing to complete the definition of our box component, where:
-
body
Property of the componenttag
: used to store the score of the box. -
rect-fixture
: Defines the collision shape of the box. -
draw-node
: Used to draw the appearance of the box. -
label
: Used to display the score of the box.
3. Create an object reference after TSX instantiation
Use useRef to create two reference variables for backup, pointing to the small page and score labels respectively:
const bird = useRef<Body.Type>();
const score = useRef<Label.Type>();
4. Create emission lines
The emission line is created from line
the variable, and event handling for touch (also mouse click) is added:
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();
}}
>
{/* ...在物理世界下创建其它游戏元素 ... */}
</physics-world>
);
-
In
onTapBegan
the event, record where the touch started and clear the emission line. -
In
onTapMoved
the event, calculate the distance the touch moved and update the emission line. -
In
onTapEnded
the event, set the bird's launch speed and clear the launch line based on the distance moved by the touch.
5. Create other game elements
Next, we use <physics-world>
the parent tag of the game scene and continue to create various elements in the game scene below it:
5.1 Ground
First, we body
create a ground using the component and set it as a static rigid body:
<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>
-
type={BodyMoveType.Static}
: Indicates that this is a static rigid body and will not be affected by physical simulation. -
rect-fixture
: Define the ground collision shape as a rectangle. -
draw-node
: Used to draw the appearance of the ground. -
rect-shape
:Draw a rectangle with the color yellow.
5.2 Box
Next, we use the component we wrote before Box
to create 5 boxes, set different initial positions and scores, and play the exit animation when creating:
{
[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>
))
}
-
map
Function: Used to iterate through the score array from 10 to 50 and create a box for each score that requires a bird to hit. -
Box
Component: used to create a box and pass in the following properties:-
num={num}
: The score of the box, corresponding to the number in the array. -
x={200}
: The initial x-axis position of the box, which is 200. -
y={-150 + i * 100}
: The initial y-axis position of the box, incremented according to the creation sequence number.
-
-
sequence
Component: used to create an animation sequence to be played on the parent node, including the following animations:-
delay time={i * 0.2}
: Delay the animation playback, and the delay time increases according to the creation sequence number. -
scale time={0.3} start={0} stop={1}
: Zoom animation, from not displayed to fully displayed, takes 0.3 seconds.
-
5.3 Birdie
Finally, we body
create the bird using the component and set the collision shape, appearance, and score labels:
<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>
-
ref={bird}
: Use toref
create reference variables to facilitate subsequent manipulation of the bird. -
type={BodyMoveType.Dynamic}
: Indicates that this is a dynamic rigid body and will be affected by physical simulation. -
onContactStart={(other) => {}}
: The callback processing function triggered when the bird's physical body touches other objects. -
disk-fixture
: Define the shape of the bird as a disk. -
draw-node
: Used to draw the appearance of the bird. -
label
: Used to display the cumulative score of the bird. -
scale
: Used to play the bird’s appearance animation.
6. Complete the game logic
At this point, we have completed the core logic of the mini-game. You can further improve the game logic and add functions according to your own ideas. The complete demo code can be found at this link: Dora-SSR/Assets/Script/Test/Birdy.tsx . Below are some screenshots of the running effects.
<p align=center>Drag the screen to launch "Angry Birds"</p>
<p align=center>My superb skills allowed me to score all the points in one strike</p>
4. Briefly reveal the secrets
1. Deer or horse
In fact, the game code we wrote can ensure consistent running results across Linux, Android, iOS, macOS and Windows with the power of the Dora SSR engine. But in order to run this code, our Dora SSR engine does not even support JavaScript runtime environment... (What did you say?)
Yes, the underlying technology implementation of Dora SSR is actually based on Lua and WASM virtual machine as the scripting language running environment. Support for TypeScript is actually provided by integrating the TypescriptToLua ( https://github.com/TypeScriptToLua/TypeScriptToLua ) compiler. TSTL rewrites the backend of the TypeScript language compiler to compile the TS and TSX codes into equivalent running Lua codes, so that the TS code can be loaded and run on Dora. Under the code editor of Dora's own Web IDE, it can help you do TS language checking and completion as well as Dora built-in library API prompts. For the final user experience, you don’t have to worry about whether it is a deer or a horse in the end. As long as the code can pass the TS compilation check, it will run the same when it is pulled out.
2. Is it related to React?
The answer to this question is currently: yes (so not as of the time of publishing). The most important capability of React is to synchronize the status of rendering components and business data through Virtual DOM and the process of executing Tree Diff processing. Currently, this mechanism has not been implemented in Dora SSR, so what you currently see written using TSX is similar to The VDOM construction code will only build a one-time game rendering object at runtime, and the engine functions implemented in the underlying C++ will be responsible for continued processing. Maybe one day we will provide game UI development with the ability to imitate React for state synchronization by executing Tree Diff, or imitate SolidJS to implement other rendering component state synchronization mechanisms based on TSX. Therefore, we sincerely invite front-end development friends to join us, play the Dora SSR project together, study how to use front-end development technology ideas, and introduce more easy-to-use and convenient wheels for game development.
Finally, our Q group is here, welcome to come and play: 512620381
I decided to give up on open source Hongmeng. Wang Chenglu, the father of open source Hongmeng: Open source Hongmeng is the only architectural innovation industrial software event in the field of basic software in China - OGG 1.0 is released, Huawei contributes all source code Google Reader is killed by the "code shit mountain" Fedora Linux 40 is officially released Former Microsoft developer: Windows 11 performance is "ridiculously bad" Ma Huateng and Zhou Hongyi shake hands to "eliminate grudges" Well-known game companies have issued new regulations: employee wedding gifts must not exceed 100,000 yuan Ubuntu 24.04 LTS officially released Pinduoduo was sentenced for unfair competition Compensation of 5 million yuan