particles blending
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:not checked yet The browser comparison does not cover this example yet.
//! raylib [textures] example - particles blending
//!
//! Zig-API translation of examples/textures/textures_particles_blending.c (raylib 6.2).
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2017-2025 Ramon Santamaria (@raysan5)
const rl = @import("raylib");
const max_particles = 200;
const Particle = struct {
position: rl.Vector2,
color: rl.Color,
alpha: f32,
size: f32,
rotation: f32,
active: bool, // NOTE: Use it to activate/deactive particle
};
pub fn main() !void {
// Initialization
const screen_width = 800;
const screen_height = 450;
rl.initWindow(screen_width, screen_height, "raylib [textures] example - particles blending");
defer rl.closeWindow(); // Close window and OpenGL context
// Particles pool, reuse them!
var mouse_tail: [max_particles]Particle = undefined;
// Initialize particles
for (&mouse_tail) |*particle| {
const r: u8 = @intCast(rl.getRandomValue(0, 255));
const g: u8 = @intCast(rl.getRandomValue(0, 255));
const b: u8 = @intCast(rl.getRandomValue(0, 255));
const size = @as(f32, @floatFromInt(rl.getRandomValue(1, 30))) / 20.0;
const rotation: f32 = @floatFromInt(rl.getRandomValue(0, 360));
particle.* = .{
.position = .{ .x = 0, .y = 0 },
.color = .{ .r = r, .g = g, .b = b, .a = 255 },
.alpha = 1.0,
.size = size,
.rotation = rotation,
.active = false,
};
}
const gravity: f32 = 3.0;
const smoke = try rl.loadTexture("resources/spark_flame.png");
defer rl.unloadTexture(smoke);
const smoke_width: f32 = @floatFromInt(smoke.width);
const smoke_height: f32 = @floatFromInt(smoke.height);
var blending: rl.BlendMode = .alpha;
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
// Activate one particle every frame and Update active particles
// NOTE: Particles initial position should be mouse position when activated
// NOTE: Particles fall down with gravity and rotation... and disappear after 2 seconds (alpha = 0)
// NOTE: When a particle disappears, active = false and it can be reused
for (&mouse_tail) |*particle| {
if (!particle.active) {
particle.active = true;
particle.alpha = 1.0;
particle.position = rl.getMousePosition();
break;
}
}
for (&mouse_tail) |*particle| {
if (particle.active) {
particle.position.y += gravity / 2;
particle.alpha -= 0.005;
if (particle.alpha <= 0.0) particle.active = false;
particle.rotation += 2.0;
}
}
if (rl.isKeyPressed(.space)) {
blending = if (blending == .alpha) .additive else .alpha;
}
// Draw
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.dark_gray);
rl.beginBlendMode(blending);
// Draw active particles
for (mouse_tail) |particle| {
if (!particle.active) continue;
const width = smoke_width * particle.size;
const height = smoke_height * particle.size;
rl.drawTexturePro(
smoke,
.{ .x = 0.0, .y = 0.0, .width = smoke_width, .height = smoke_height },
.{ .x = particle.position.x, .y = particle.position.y, .width = width, .height = height },
.{ .x = width / 2.0, .y = height / 2.0 },
particle.rotation,
rl.fade(particle.color, particle.alpha),
);
}
rl.endBlendMode();
rl.drawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, .black);
if (blending == .alpha) {
rl.drawText("ALPHA BLENDING", 290, screen_height - 40, 20, .black);
} else {
rl.drawText("ADDITIVE BLENDING", 280, screen_height - 40, 20, .ray_white);
}
}
}/*******************************************************************************************
*
* raylib [textures] example - particles blending
*
* Example complexity rating: [★☆☆☆] 1/4
*
* Example originally created with raylib 1.7, last time updated with raylib 3.5
*
* 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) 2017-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#define MAX_PARTICLES 200
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Particle structure
typedef struct {
Vector2 position;
Color color;
float alpha;
float size;
float rotation;
bool active; // NOTE: Use it to activate/deactive particle
} Particle;
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [textures] example - particles blending");
// Particles pool, reuse them!
Particle mouseTail[MAX_PARTICLES] = { 0 };
// Initialize particles
for (int i = 0; i < MAX_PARTICLES; i++)
{
mouseTail[i].position = (Vector2){ 0, 0 };
mouseTail[i].color = (Color){ GetRandomValue(0, 255), GetRandomValue(0, 255), GetRandomValue(0, 255), 255 };
mouseTail[i].alpha = 1.0f;
mouseTail[i].size = (float)GetRandomValue(1, 30)/20.0f;
mouseTail[i].rotation = (float)GetRandomValue(0, 360);
mouseTail[i].active = false;
}
float gravity = 3.0f;
Texture2D smoke = LoadTexture("resources/spark_flame.png");
int blending = BLEND_ALPHA;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
// Activate one particle every frame and Update active particles
// NOTE: Particles initial position should be mouse position when activated
// NOTE: Particles fall down with gravity and rotation... and disappear after 2 seconds (alpha = 0)
// NOTE: When a particle disappears, active = false and it can be reused
for (int i = 0; i < MAX_PARTICLES; i++)
{
if (!mouseTail[i].active)
{
mouseTail[i].active = true;
mouseTail[i].alpha = 1.0f;
mouseTail[i].position = GetMousePosition();
i = MAX_PARTICLES;
}
}
for (int i = 0; i < MAX_PARTICLES; i++)
{
if (mouseTail[i].active)
{
mouseTail[i].position.y += gravity/2;
mouseTail[i].alpha -= 0.005f;
if (mouseTail[i].alpha <= 0.0f) mouseTail[i].active = false;
mouseTail[i].rotation += 2.0f;
}
}
if (IsKeyPressed(KEY_SPACE))
{
if (blending == BLEND_ALPHA) blending = BLEND_ADDITIVE;
else blending = BLEND_ALPHA;
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
ClearBackground(DARKGRAY);
BeginBlendMode(blending);
// Draw active particles
for (int i = 0; i < MAX_PARTICLES; i++)
{
if (mouseTail[i].active) DrawTexturePro(smoke, (Rectangle){ 0.0f, 0.0f, (float)smoke.width, (float)smoke.height },
(Rectangle){ mouseTail[i].position.x, mouseTail[i].position.y, smoke.width*mouseTail[i].size, smoke.height*mouseTail[i].size },
(Vector2){ (float)(smoke.width*mouseTail[i].size/2.0f), (float)(smoke.height*mouseTail[i].size/2.0f) }, mouseTail[i].rotation,
Fade(mouseTail[i].color, mouseTail[i].alpha));
}
EndBlendMode();
DrawText("PRESS SPACE to CHANGE BLENDING MODE", 180, 20, 20, BLACK);
if (blending == BLEND_ALPHA) DrawText("ALPHA BLENDING", 290, screenHeight - 40, 20, BLACK);
else DrawText("ADDITIVE BLENDING", 280, screenHeight - 40, 20, RAYWHITE);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadTexture(smoke);
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}From raylib 6.2. The original on GitHub.