Files
simvx/examples/ports/heartbeast_rpg

HeartBeast Action RPG: SimVX Port

A SimVX re-implementation of HeartBeast's Action RPG tutorial, whose canonical source is the Action RPG folder of uheartbeast/youtube-tutorials.

What it is

The complete combat loop of the tutorial: movement with acceleration and friction, a sword that swings in the facing direction, a roll that dashes and grants invincibility frames, bats driven by an Idle to Wander to Chase state machine, soft collision so bats push each other apart instead of stacking, destructible grass, and a heart HUD.

No upstream art is redistributed (see ATTRIBUTION.md), so every visual is drawn at runtime with the immediate-mode 2D API.

Running

uv run python examples/ports/heartbeast_rpg/main.py           # desktop
uv run python examples/ports/heartbeast_rpg/main.py --test    # headless smoke run

Controls

Action Keyboard Pointer / touch
Start Space or Enter Tap anywhere
Move W/A/S/D or the arrow keys Drag from the lower-left half
Attack J or Z Tap ATK
Roll / dodge K or X Tap ROLL
Quit Escape --

Architecture

nodes/
├── effects.py     HitEffect, EnemyDeathEffect, GrassEffect (self-destructing)
├── enemy.py       Bat: Idle/Wander/Chase state machine plus soft collision
├── grass.py       Destructible grass tufts
├── hud.py         Heart health bar and the bottom controls strip
├── player.py      Movement physics, sword, roll, invincibility frames
├── stats.py       Signal-based health tracker (mirrors the upstream Stats scene)
├── ui.py          Title card and the on-screen stick / action buttons
└── world.py       Playfield, camera, decorations, collision dispatcher

What it shows off in SimVX

  • Signals carry health changes and effect spawns: Stats emits health_changed / no_health, the bats emit hit and death signals that the world turns into particle bursts, and the HUD only ever listens.
  • Camera2D does the following and the clamping: the port sets target, zoom and the four limit_* properties from the window size, rather than reimplementing them.
  • CanvasLayer keeps the HUD, the title card and the pointer controls in screen space above a camera-transformed world.
  • The retained 2D contract: nodes that animate every frame declare dynamic, and nodes that change on an event (the hearts) call queue_redraw() instead.
  • Procedural 2D drawing throughout: draw_rect, draw_circle, draw_polygon and draw_text, with no textures at all.

Feature parity with upstream

Feature Status Notes
Player movement (accel/friction) Yes Matches the upstream speed values
8-directional movement Yes Normalised diagonals
Sword attack with rotation Yes Hitbox swings along the facing
Roll/dodge with i-frames Yes 0.3s, 250 px/s dash
Enemy AI (Idle/Wander/Chase) Yes Detection radius of 120 px
Soft collision Yes Push-apart between overlapping bats
Destructible grass Yes 80 tufts, leaf burst on destruction
Invincibility frames plus blink Yes Player and bats both blink
Health system (signals) Yes Stats node with health_changed / no_health
Heart HUD Yes 6 hearts, updated from signals
Bounded camera Yes Camera2D target plus limits, clamped to the map
Death/respawn Yes 2s delay, then full health
Hit/death/grass effects Yes Fading particle bursts that self-destruct
Tree/bush decorations Yes Drawn procedurally
Terrain Partial A drawn ground rect and a polygon path, not a TileMap
Sprite animation Partial Wing flap is procedural, no sprite sheets
Audio No Upstream SFX are not redistributable

Web export

uv run simvx export web examples/ports/heartbeast_rpg/main.py -o /tmp/heartbeast_rpg.html

The exporter auto-detects GameRoot; no extra flags are needed.

Licence

The upstream tutorial code is MIT (Copyright (c) 2020 Heart GameDev); the notice is preserved in UPSTREAM_LICENSE.md. The upstream pixel art and audio are not covered by that licence and are not bundled here. See ATTRIBUTION.md for the full provenance.