任天堂DS代码编辑器和可编程游戏引擎
Nintendo DS code editor and scriptable game engine

原始链接: https://crl.io/ds-game-engine/

## DS游戏引擎:掌上复古开发 该项目旨在重现早期游戏开发体验——例如在TI-82计算器上开发游戏——通过为任天堂DS构建一个可编写脚本的3D游戏引擎。引擎使用C语言和libnds编写,生成一个紧凑(约100KB)的.nds ROM,运行速度流畅,达到60 FPS。 DS的上屏幕显示彩色立方体的实时3D渲染,并配有可控制的摄像头。与此同时,下方的触摸屏托管一个自定义的软件渲染代码编辑器。用户可以使用一种简单的语言编写脚本,该语言具有变量(A-Z)、循环和条件语句,然后直接在控制台上执行它们。 该引擎由三个部分组成:3D渲染、基于触摸的编辑器和脚本解释器。脚本使用寄存器来处理输入(十字键、按钮)和系统数据。一个默认的3D Pong游戏展示了引擎的功能。 虽然脚本限制为128行、26个变量和简单的立方体模型,但该项目展示了一个功能齐全的掌上游戏开发环境。源代码和编译后的ROM可供实验使用。

## 任天堂DS代码编辑器和脚本引擎受到关注 一款新的任天堂DS代码编辑器和可脚本化游戏引擎在Hacker News上引起了关注。该工具允许开发者使用自定义脚本语言创建游戏,每帧执行大约60行代码。 讨论强调了DS的持久吸引力,许多人赞扬其便携性——这是现代掌机如Switch和Steam Deck所失去的特性。用户们分享着个人项目,例如基于精灵的应用程序和手写日记,并讨论了在极端限制下工作以培养创造力的好处。 对话还涉及了破解DS/3DS主机进行自制软件开发的简易性,以及与PS Vita和Steam Deck等其他掌机的比较。一些用户推荐Brick Hammer用于便携式复古游戏,而另一些用户则提到了现有的DS工具,如Petit Computer。最终,这篇帖子引发了人们对DS独特功能和可破解性的怀旧之情。
相关文章

原文

2026


TL;DR

I built a scriptable 3D game engine for the Nintendo DS so you can write and run games directly on the console itself. Written in C using libnds, it compiles to a ~100KB .nds ROM that runs at 60 FPS. Features a touch-based code editor on the bottom screen and real-time 3D rendering on the top screen. Ships with a working 3D pong game as the default script.

What is it?

I felt nostalgic for when I made my first games on an old TI-82 graphing calculator. So I tried bringing that whole experience to my Nintendo DS. A complete programming environment you can hold in your hands.

What you see is a scriptable game engine with a custom programming language featuring variables, loops, and conditionals. You write code using the bottom touchscreen, click play, and the game will execute in real-time on the top screen with full 3D rendering.


How it works

At a high level, the engine breaks down into three parts:


1. Top screen: 3D rendering (hardware accelerated)

Uses the DS's 3D hardware to render colored cubes at 60 FPS. Each model has position (X, Y, Z), rotation angle, and color. The camera is fully controllable with position and yaw/pitch angles.

// DS 3D rendering code (C + libnds)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(camX, camY, camZ,  // camera position
          camX + lookX, camY + lookY, camZ + lookZ,  // look target
          0, 1, 0);  // up vector

Each model is drawn with a transform (position + Y-axis rotation), then the cube geometry: one color, six quads (24 vertices).

// Per-model draw calls (from main.c)
for (i = 0; i  glColor3b, then 6 faces as GL_QUADS
glColor3b(r * 255/31, g * 255/31, b * 255/31);
glBegin(GL_QUADS);
    /* +Z face */
    glVertex3f(-1.0f,  1.0f,  1.0f);
    glVertex3f( 1.0f,  1.0f,  1.0f);
    glVertex3f( 1.0f, -1.0f,  1.0f);
    glVertex3f(-1.0f, -1.0f,  1.0f);
    /* -Z, +Y, -Y, +X, -X ... (24 vertices total) */
glEnd();

2. Bottom screen: Script editor (software rendered)

A touch-based code editor with a custom UI drawn pixel-by-pixel to a 256x192 bitmap. Features include:

  • Token picker: tap to insert commands (SET, ADD, LOOP, IF_GT, etc.)
  • Numpad: edit number parameters for each command
  • Register selector: choose which variable (A-Z) to use
  • Play/Pause/Stop/Step: control script execution
  • 6 script slots: save and load different programs
// Software rendering to bottom screen
u16 *subBuffer = (u16*)BG_BMP_RAM_SUB(0);  // 256x192 framebuffer
subBuffer[y * 256 + x] = RGB15(31, 31, 31);  // white pixel

3. Script interpreter

Executes one line of script per frame (~60 lines/sec). Scripts can use 26 variables (A-Z) plus 9 read-only registers for input (D-pad, buttons) and system state (elapsed time, camera direction).

// Script execution (simplified)
if (tokenEquals(script[scriptIP], "add")) {
    int r = scriptReg[scriptIP];  // which register (A-Z)
    registers[r] += getNumberParamValue(scriptIP, 0);
    scriptIP++;  // next line
}

The scripting language

Scripts are built from tokens (commands) with numeric parameters. Each line executes instantly, with no parsing overhead, just a series of if-checks against token names.


Available commands

Variables & Math

  • SET A 5 — set register A to 5
  • ADD A 1 — add 1 to A
  • SUBTRACT A 2 — subtract 2 from A
  • MULTIPLY B -1 — multiply B by -1

Control Flow

  • LOOP / END_LOOP — infinite loop
  • IF_GT A 10 — if A > 10
  • IF_LT A 0 — if A < 0
  • IF_TRUE kA — if A button pressed
  • END_IF — close conditional

3D Objects

  • MODEL 0 — create model at index 0
  • POSITION 0 X Y Z — set position
  • ANGLE 0 45 — set rotation angle
  • NEXT_COLOR 0 — cycle color

Camera & Rendering

  • CAM_POS X Y Z — set camera position
  • CAM_ANGLE yaw pitch — set look direction
  • BACKGROUND 2 — set bg color (0-3)
  • BEEP — play 0.1s sound
  • SLEEP 0.016 — pause (60 FPS = 0.016s/frame)

Read-only registers (input & state)

  • LEFT, UP, RGT, DN: D-pad (1.0 when held, 0.0 when released)
  • KA, KB: A and B buttons
  • TIME: elapsed seconds since script started
  • LOOKX, LOOKZ: camera forward direction (normalized X and Z)

Example: 3D pong (default script)

The engine ships with a playable pong game. Here's a simplified excerpt:

MODEL 0           ; create ball
MODEL 1           ; create paddle
CAM_POS 0 8 18    ; position camera
SET A 0           ; ball X position
SET B 1           ; ball velocity
SET C 0           ; paddle Z position
LOOP
  ADD A B         ; move ball
  IF_GT A 10      ; hit right wall?
    MULTIPLY B -1 ; reverse velocity
  END_IF
  IF_TRUE Up      ; up button pressed?
    ADD C -0.5    ; move paddle up
  END_IF
  POSITION 0 A 0 0     ; update ball position
  POSITION 1 -13 0 C   ; update paddle position
  SLEEP 0.016          ; ~60 FPS
END_LOOP

The full script includes collision detection, game-over logic, and beep sounds on miss, all done with simple register math and conditionals.

Technical details

Language & toolchain

  • Language: C
  • Library: libnds (Nintendo DS development library)
  • Toolchain: devkitPro (ARM cross-compiler)
  • Source size: ~3,100 lines of C (main.c)
  • Binary size: ~100 KB (.nds ROM)
  • Performance: 60 FPS on DS Lite (2006 hardware)

Capabilities & limitations

  • Up to 128 script lines per program
  • 26 variables (A-Z) + 9 read-only registers
  • Up to 16 3D models (simple cubes with color/position/rotation)
  • 6 save slots for different scripts
  • No dynamic memory allocation, all arrays are statically sized
  • No string variables, numbers only (floats)
  • No function calls or subroutines (yet!)

How to build & run

Compilation (on your computer)

  1. Install devkitPro (includes devkitARM and libnds)
  2. Download the source code (main.c + Makefile)
  3. Run make in the project directory
  4. Output: program.nds (~100 KB ROM file)

Running on real hardware

You need a flashcart (e.g. R4, DSTT, Acekard) with a microSD card:

  1. Copy program.nds to the microSD card
  2. Insert the microSD into the flashcart
  3. Insert the flashcart into your DS
  4. Boot the DS and select the ROM from the flashcart menu

Note: I got my R4 cart + SD card from a friend years ago, so I don't have detailed setup instructions for the cart itself. Most modern flashcarts just need you to copy their firmware to the SD root, then add ROMs in a folder.

Try it in your browser (Nintendo DS emulator)

You can test the DS game engine build directly below. The emulator loads ds-game-engine.nds. Loads a more basic pong game than the one in the video.

Nintendo DS emulator (Desmond). If the game doesn’t start, ensure JavaScript is enabled and the page has finished loading.

Download

Source (ds-game-engine.zip)

Compiled ROM (ds-game-engine.nds)

Discussion

Feel free to ask or discuss in this Reddit thread

联系我们 contact @ memedata.com