diff options
| author | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-06-12 02:42:59 -0500 |
|---|---|---|
| committer | Nic Gaffney <gaffney_nic@protonmail.com> | 2024-06-12 02:42:59 -0500 |
| commit | e4e94ab41a0cfb64658c8b2fdec31dc41a12861b (patch) | |
| tree | 2dbd681cb7e45de793223b07be825b86da24ae3c /src | |
| parent | a80c55f308ed3337df9ab572df60297d7369196d (diff) | |
| download | particle-sim-e4e94ab41a0cfb64658c8b2fdec31dc41a12861b.tar.gz | |
Added rules matrix and 3 more colors
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.zig | 128 |
1 files changed, 110 insertions, 18 deletions
diff --git a/src/main.zig b/src/main.zig index 6ba4ff4..dcd6e41 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,20 +2,58 @@ const std = @import("std"); const rl = @import("raylib"); const particle = struct { - color: rl.Color, + colorId: u32, attrs: particleAttrs, x: i32, y: i32, - xvel: i32, - yvel: i32, + xvel: f32, + yvel: f32, }; const particleAttrs = struct {}; -const screenWidth = 1920; -const screenHeight = 1080; +const screenWidth = 2560; +const screenHeight = 1440; const particleMax = 5000; +const radius = 50.0; +const minDistance = 10.0; pub fn main() !void { + const colors = [_]rl.Color{ + rl.Color.red, + rl.Color.green, + rl.Color.blue, + rl.Color.yellow, + rl.Color.magenta, + rl.Color.brown, + }; + + const rules = ruleMatrix(colors.len); + std.debug.print( + \\| | R | G | B | Y + \\| R | {d:.1} | {d:.1} | {d:.1} | {d:.1} + \\| G | {d:.1} | {d:.1} | {d:.1} | {d:.1} + \\| B | {d:.1} | {d:.1} | {d:.1} | {d:.1} + \\| Y | {d:.1} | {d:.1} | {d:.1} | {d:.1} + \\ + , .{ + rules[0][0], + rules[0][1], + rules[0][2], + rules[0][3], + rules[1][0], + rules[1][1], + rules[1][2], + rules[1][3], + rules[2][0], + rules[2][1], + rules[2][2], + rules[2][3], + rules[3][0], + rules[3][1], + rules[3][2], + rules[3][3], + }); + rl.initWindow(screenWidth, screenHeight, "Particle Simulator"); defer rl.closeWindow(); @@ -24,7 +62,7 @@ pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); - var particles = try initParticles(gpa.allocator(), 1); + var particles = try initParticles(gpa.allocator(), 3000); defer particles.deinit(gpa.allocator()); while (!rl.windowShouldClose()) { @@ -33,40 +71,94 @@ pub fn main() !void { defer rl.endDrawing(); + updateVelocities(particles, rules); + for (particles.items(.y), particles.items(.yvel)) |*y, yvel| - y.* = @mod((y.* + yvel), screenHeight); + y.* = @mod(@as(i32, @intFromFloat(@round((@as(f32, @floatFromInt(y.*)) + yvel)))), screenHeight); for (particles.items(.x), particles.items(.xvel)) |*x, xvel| - x.* = @mod((x.* + xvel), screenWidth); - - for (particles.items(.y), particles.items(.x), particles.items(.color)) |*y, *x, color| - rl.drawRectangle(x.*, y.*, 1, 1, color); + x.* = @mod(@as(i32, @intFromFloat(@round((@as(f32, @floatFromInt(x.*)) + xvel)))), screenWidth); - if (particles.slice().len < particleMax) try particles.append(gpa.allocator(), createParticle(.{})); - std.debug.print("{}\n", .{particles.slice().len}); + for (particles.items(.y), particles.items(.x), particles.items(.colorId)) |*y, *x, colorId| + rl.drawRectangle(x.*, y.*, 5, 5, colors[colorId]); rl.clearBackground(rl.Color.black); } } +fn force(distance: f32, attraction: f32) f32 { + const beta = minDistance / radius; + const r: f32 = distance / radius; + if (r < beta) + return 3 * (r / beta - 1.0); + if (beta < r and r < 1) + return attraction * (1 - @abs(2.0 * r - 1.0 - beta) / (1.0 - beta)); + return 0; +} + +fn updateVelocities(particles: std.MultiArrayList(particle), rules: [6][6]f32) void { + const colors = particles.items(.colorId); + var xvel = particles.items(.xvel); + var yvel = particles.items(.yvel); + for (particles.items(.x), particles.items(.y), 0..) |x, y, i| { + var forceX: f32 = 0.0; + var forceY: f32 = 0.0; + + for (particles.items(.x), particles.items(.y), 0..) |x2, y2, j| { + if (i == j) continue; + const rx: f32 = @floatFromInt(x - x2); + const ry: f32 = @floatFromInt(y - y2); + var r = @sqrt(rx * rx + ry * ry); + if (r == 0) { + r = 0.1; + } + if (r > 0 and r < radius) { + const f = force(r, rules[colors[i]][colors[j]]); + forceX = forceX + rx / r * f; + forceY = forceY + ry / r * f; + } + } + + forceX = forceX * 2; + forceY = forceY * 2; + + xvel[i] = xvel[i] * 0.95 + forceX; + yvel[i] = yvel[i] * 0.95 + forceY; + } +} + /// Generates a particle with a random Color and Location pub fn createParticle(attrs: particleAttrs) particle { const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp())))); var prng = std.rand.DefaultPrng.init(seed); - const colors = [_]rl.Color{ rl.Color.red, rl.Color.blue, rl.Color.green }; const x = prng.random().uintLessThan(u32, screenWidth); const y = prng.random().uintLessThan(u32, screenHeight); - const color = colors[prng.random().uintLessThan(u32, 3)]; + const color = prng.random().uintLessThan(u32, 6); return particle{ - .color = color, + .colorId = color, .attrs = attrs, .x = @intCast(x), .y = @intCast(y), - .xvel = 5, - .yvel = -7, + .xvel = 0, + .yvel = 0, }; } +fn ruleMatrix(comptime size: u32) [size][size]f32 { + const seed = @as(u64, @truncate(@as(u128, @bitCast(std.time.nanoTimestamp())))); + var prng = std.rand.DefaultPrng.init(seed); + var rules: [size][size]f32 = undefined; + for (0..size) |i| { + for (0..size) |j| { + var val = prng.random().float(f32); + const isNeg = prng.random().uintAtMost(u8, 1); + if (isNeg == 1) val = 0 - val; + rules[i][j] = val; + } + } + return rules; +} + /// Initialize a MultiArrayList of size amnt with particles created by createParticle pub fn initParticles(allocator: std.mem.Allocator, amnt: u32) !std.MultiArrayList(particle) { var particles = std.MultiArrayList(particle){}; |
