Snake (raylib classic)

Grid logic, a drawn D-pad, resize-aware HUD.

▶ Run in browser

Upstream: https://github.com/raysan5/raylib-games/tree/master/classics/src

Licence: this port's own code is offered under Zlib, not the SimVX Examples Licence the rest of the gallery carries. See ATTRIBUTION.md for the upstream it re-implements, the terms of anything it bundles, and the credit each one requires.

Ports live in the repository only, not in the simvx-examples distribution, because each is a derivative work licensed individually against the game it re-implements. Read it with git clone https://git.simvx.com/simvx/simvx.

Tags: port tier-0

Snake (raylib classic): SimVX port

A re-implementation of snake.c from raylib-games/classics by Ian Eito, Albert Martos and Ramon Santamaria. The gameplay follows the C original: a snake that grows on fruit pickup, the allow_move latch that blocks 180-degree reversals, and a step every five physics frames. The board here is 31 by 24 cells.

Everything is drawn procedurally, so the port bundles no upstream art, audio or fonts. See ATTRIBUTION.md and UPSTREAM_LICENSE.md.

What it shows

  • The whole game is one Node2D: grid state, the menu / play / game-over flow and the drawing all live in nodes/snake_game.py.

  • Fixed-timestep logic in on_fixed_update, so the snake steps at the same cadence whatever the frame rate.

  • Immediate-mode 2D drawing: the board, the snake and the HUD come out of one on_draw on a dynamic node, with no scene node per cell.

  • One typed move action instead of four opposed ones: the arrow keys, WASD, a controller’s D-pad and its left stick all feed it, and the game takes the dominant axis so the snake still turns four ways.

  • input_context declared on the scene root rather than from main(), where InputMap has no tree yet, so the actions arrive with the scene under a web export and in a test.

  • A TouchController in the D-pad layout, added when the machine reports a coarse pointer. It publishes itself as a real controller, so the Controller button and D-pad bindings above are the whole of the touch support.

  • Resize-aware layout: the cell size, the board origin and every text scale are recomputed from viewport_size each frame, fitted with renderer.fit_scale. The board is laid out above whatever the drawn pad is covering, measured off the pad’s own controls, so a thumb never hides the snake.

  • died and ate signals, so a scoreboard or an audio node can react without the game node knowing about it.

Run

# the export runs in a copy made by `simvx examples copy ports_raylib_snake`
simvx examples run ports_raylib_snake

Controls

Action

Keyboard

Controller

Touch

Steer

Arrow keys or WASD

D-pad or left stick

The on-screen D-pad, or tap ahead of the head

Pause / resume

P

B or Start

The on-screen B, or tap the middle of the score strip

Start / restart

SPACE or ENTER (also a direction to start)

A or Start

Tap anywhere, or the on-screen A

Quit

ESC

Back

-

The on-screen pad appears when the machine reports that its primary pointer is a finger, and takes itself away again while a real controller is in use.

Web export

simvx export web main.py \
    -o raylib_snake.html

Source files

File

Summary

Lines

main.py

Snake (raylib classic): Grid logic, a drawn D-pad, resize-aware HUD.

54

__init__.py

0

nodes/__init__.py

0

nodes/snake_game.py

Snake: gameplay node.

488

Source

 1#!/usr/bin/env python3
 2# /// script
 3# requires-python = ">=3.14"
 4# dependencies = ["simvx-core", "simvx-graphics"]
 5# ///
 6
 7# /// simvx
 8# tags = ["port", "tier-0"]
 9# upstream = "https://github.com/raysan5/raylib-games/tree/master/classics/src"
10# web = { width = 620, height = 480, responsive = true }
11# ///
12"""Snake (raylib classic): Grid logic, a drawn D-pad, resize-aware HUD.
13
14A re-implementation of raylib's classic ``snake.c`` as a single SimVX
15``Node2D``. It follows the upstream design (the ``allow_move`` latch that
16blocks 180-degree reversals, a step every five physics frames) on a 31 by 24
17board, and
18around that shows fixed-timestep logic in ``on_fixed_update``, immediate-mode
19board drawing in ``on_draw`` on a ``dynamic`` node, one typed ``move`` action
20the keys, a controller and a drawn D-pad all feed, text that fits itself to the
21window with ``renderer.fit_scale``, and ``died`` / ``ate`` signals other nodes
22can connect to.
23
24Controls: arrow keys, WASD, a controller's D-pad or its left stick steer; P or
25(B) pauses; SPACE, ENTER or (A) starts and restarts; ESC quits. By touch, tap
26to start and restart, tap ahead of the head to steer, tap the middle of the
27score strip to pause, and use the on-screen D-pad, which appears on a touch
28screen and publishes itself as a real controller.
29
30Run::
31
32    simvx examples run ports_raylib_snake
33
34Web export::
35
36    simvx export web main.py -o raylib_snake.html
37
38Attribution and upstream licence: see ``ATTRIBUTION.md`` and
39``UPSTREAM_LICENSE.md`` beside this file.
40"""
41
42from nodes.snake_game import SnakeGame  # noqa: E402
43
44from simvx.graphics import App  # noqa: E402
45
46WIDTH, HEIGHT = 620, 480
47
48
49def main():
50    App(title="Snake (raylib classic)", width=WIDTH, height=HEIGHT).run(SnakeGame())
51
52
53if __name__ == "__main__":
54    main()