recursive tree
There is no browser build of this example yet.
Is it the same as C?
- Desktop:verified The Zig version renders a final frame that is byte-identical to the C example.
- Browser:verified In headless Chrome, the Zig version gives a final frame byte-identical to the C example built for the web.
//! raylib [shapes] example - recursive tree
//!
//! Zig-API translation of examples/shapes/shapes_recursive_tree.c (raylib 6.2).
//! Example contributed by Jopestpe (@jopestpe)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2025 Jopestpe (@jopestpe)
const std = @import("std");
const rl = @import("raylib");
const gui = @import("raygui");
const Branch = struct {
start: rl.Vector2,
end: rl.Vector2,
angle: f32,
length: f32,
/// The branch growing from `start` at `angle` (radians from vertical).
fn grow(start: rl.Vector2, angle: f32, length: f32) Branch {
return .{
.start = start,
.end = .{ .x = start.x + length * @sin(angle), .y = start.y - length * @cos(angle) },
.angle = angle,
.length = length,
};
}
};
pub fn main() void {
// Initialization
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [shapes] example - recursive tree");
defer rl.closeWindow(); // Close window and OpenGL context
const start: rl.Vector2 = .{ .x = (screen_width / 2.0) - 125.0, .y = screen_height };
var angle: f32 = 40.0;
var thick: f32 = 1.0;
var tree_depth: f32 = 10.0;
var branch_decay: f32 = 0.66;
var length: f32 = 120.0;
var bezier = false;
rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
const theta = angle * rl.deg2rad;
const max_branches = std.math.pow(usize, 2, @intFromFloat(@floor(tree_depth)));
var buffer: [1030]Branch = undefined;
var branches: std.ArrayList(Branch) = .initBuffer(&buffer);
branches.appendAssumeCapacity(.grow(start, 0.0, length));
// Breadth-first: the list grows while it is being walked
var i: usize = 0;
while (i < branches.items.len) : (i += 1) {
const branch = branches.items[i];
if (branch.length < 2) continue;
const next_length = branch.length * branch_decay;
if (branches.items.len < max_branches and next_length >= 2) {
branches.appendAssumeCapacity(.grow(branch.end, branch.angle + theta, next_length));
branches.appendAssumeCapacity(.grow(branch.end, branch.angle - theta, next_length));
}
}
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.ray_white);
for (branches.items) |branch| {
if (branch.length >= 2) {
if (bezier) {
rl.drawLineBezier(branch.start, branch.end, thick, .red);
} else {
rl.drawLineEx(branch.start, branch.end, thick, .red);
}
}
}
rl.drawLine(580, 0, 580, rl.getScreenHeight(), .{ .r = 218, .g = 218, .b = 218, .a = 255 });
rl.drawRectangle(580, 0, rl.getScreenWidth(), rl.getScreenHeight(), .{ .r = 232, .g = 232, .b = 232, .a = 255 });
// Draw GUI controls
_ = gui.sliderBar(.{ .x = 640, .y = 40, .width = 120, .height = 20 }, "Angle", rl.textFormat("{d:.0}", .{angle}), &angle, 0, 180);
_ = gui.sliderBar(.{ .x = 640, .y = 70, .width = 120, .height = 20 }, "Length", rl.textFormat("{d:.0}", .{length}), &length, 12.0, 240.0);
_ = gui.sliderBar(.{ .x = 640, .y = 100, .width = 120, .height = 20 }, "Decay", rl.textFormat("{d:.2}", .{branch_decay}), &branch_decay, 0.1, 0.78);
_ = gui.sliderBar(.{ .x = 640, .y = 130, .width = 120, .height = 20 }, "Depth", rl.textFormat("{d:.0}", .{tree_depth}), &tree_depth, 1.0, 10.0);
_ = gui.sliderBar(.{ .x = 640, .y = 160, .width = 120, .height = 20 }, "Thick", rl.textFormat("{d:.0}", .{thick}), &thick, 1, 8);
_ = gui.checkBox(.{ .x = 640, .y = 190, .width = 20, .height = 20 }, "Bezier", &bezier);
rl.drawFPS(10, 10);
}
}/*******************************************************************************************
*
* raylib [shapes] example - recursive tree
*
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 6.0, last time updated with raylib 6.0
*
* Example contributed by Jopestpe (@jopestpe)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2025 Jopestpe (@jopestpe)
*
********************************************************************************************/
#include "raylib.h"
#include <math.h>
#define RAYGUI_IMPLEMENTATION
#include "raygui.h" // Required for GUI controls
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef struct {
Vector2 start;
Vector2 end;
float angle;
float length;
} Branch;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [shapes] example - recursive tree");
Vector2 start = { (screenWidth/2.0f) - 125.0f, (float)screenHeight };
float angle = 40.0f;
float thick = 1.0f;
float treeDepth = 10.0f;
float branchDecay = 0.66f;
float length = 120.0f;
bool bezier = false;
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
float theta = angle*DEG2RAD;
int maxBranches = (int)(powf(2, floorf(treeDepth)));
Branch branches[1030] = { 0 };
int count = 0;
Vector2 initialEnd = { start.x + length*sinf(0.0f), start.y - length*cosf(0.0f) };
branches[count++] = (Branch){start, initialEnd, 0.0f, length};
for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
if (branch.length < 2) continue;
float nextLength = branch.length*branchDecay;
if (count < maxBranches && nextLength >= 2)
{
Vector2 branchStart = branch.end;
float angle1 = branch.angle + theta;
Vector2 branchEnd1 = { branchStart.x + nextLength*sinf(angle1), branchStart.y - nextLength*cosf(angle1) };
branches[count++] = (Branch){branchStart, branchEnd1, angle1, nextLength};
float angle2 = branch.angle - theta;
Vector2 branchEnd2 = { branchStart.x + nextLength*sinf(angle2), branchStart.y - nextLength*cosf(angle2) };
branches[count++] = (Branch){branchStart, branchEnd2, angle2, nextLength};
}
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(RAYWHITE);
for (int i = 0; i < count; i++)
{
Branch branch = branches[i];
if (branch.length >= 2)
{
if (bezier) DrawLineBezier(branch.start, branch.end, thick, RED);
else DrawLineEx(branch.start, branch.end, thick, RED);
}
}
DrawLine(580, 0, 580, GetScreenHeight(), (Color){ 218, 218, 218, 255 });
DrawRectangle(580, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 232, 232, 232, 255 });
// Draw GUI controls
//------------------------------------------------------------------------------
GuiSliderBar((Rectangle){ 640, 40, 120, 20}, "Angle", TextFormat("%.0f", angle), &angle, 0, 180);
GuiSliderBar((Rectangle){ 640, 70, 120, 20 }, "Length", TextFormat("%.0f", length), &length, 12.0f, 240.0f);
GuiSliderBar((Rectangle){ 640, 100, 120, 20}, "Decay", TextFormat("%.2f", branchDecay), &branchDecay, 0.1f, 0.78f);
GuiSliderBar((Rectangle){ 640, 130, 120, 20 }, "Depth", TextFormat("%.0f", treeDepth), &treeDepth, 1.0f, 10.0f);
GuiSliderBar((Rectangle){ 640, 160, 120, 20}, "Thick", TextFormat("%.0f", thick), &thick, 1, 8);
GuiCheckBox((Rectangle){ 640, 190, 20, 20 }, "Bezier", &bezier);
//------------------------------------------------------------------------------
DrawFPS(10, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}From raylib 6.2. The original on GitHub.