ref: e3c2fff3fead8501068149464c2716ed5f06a594
dir: /examples/main.zig/
const std = @import("std"); const ld = @import("../src/libdraw.zig"); const SQUARELEN = 40; const SPACING = 15; const Point = ld.Point; const Rectangle = ld.Rectangle; const Ball = struct { const FPoint = struct { x: f32, y: f32, fn toPoint(self: @This()) Point { return .{ .x = @intFromFloat(self.x), .y = @intFromFloat(self.y) }; } }; pos: FPoint, vel: FPoint, fn collide(b: *Ball) void { var i: u16 = 0; while (i < numbricks_vert) : (i += 1) { var j: u16 = 0; while (j < numbricks_horiz) : (j += 1) { const val = bricks[i * numbricks_vert + j]; if (val == 0) continue; switch (b.testCollide(i, j)) { .horiz => { bricks[i * numbricks_vert + j] -|= 1; b.vel.y *= -1; return; }, .vert => { bricks[i * numbricks_vert + j] -|= 1; b.vel.x *= -1; return; }, .none => {}, } } } } fn testCollide(self: Ball, i: u16, j: u16) enum { horiz, vert, none } { const brick = getBrickRect(i, j); const p = self.pos.toPoint(); const brickcenter: Point = .{ .x = brick.min.x + @divFloor(brick.width(), 2), .y = @divFloor(brick.min.y + brick.height(), 2) }; if (p.x >= brick.min.x and p.x <= brick.max.x and p.y >= brick.min.y and p.y <= brick.max.y) { // const a = std.math.radiansToDegrees(f32, std.math.atan2(f32, @as(f32, @floatFromInt(brickcenter.y - p.y)), @as(f32, @floatFromInt(brickcenter.x - p.x)))); // if (@fabs(a) < 45 or @fabs(a) >= 135) return .horiz; // return .vert; if (std.math.absInt(p.x - brickcenter.x) catch unreachable < std.math.absInt(p.y - brickcenter.y) catch unreachable) return .vert; return .horiz; } return .none; } }; var bricks: []u32 = undefined; var screenr: ld.Rectangle = undefined; var balls: std.ArrayList(Ball) = undefined; var numbricks_vert: u32 = undefined; var numbricks_horiz: u32 = undefined; var colors: [15]*ld.Image = undefined; const cs: [15]u32 = .{ 0xff0000ff, 0xff3600ff, 0xff6d00ff, 0xffa400ff, 0xffda00ff, 0xdbff00ff, 0x6dff00ff, 0x00ff00ff, 0x00926dff, 0x0024dbff, 0x1500dbff, 0x3600a6ff, 0x540094ff, 0x7000c9ff, 0x8b00ffff, }; fn getBrickRect(i: u16, j: u16) Rectangle { return Rectangle.init(screenr.min.x + SQUARELEN * j, screenr.min.y + SQUARELEN * i, screenr.min.x + SQUARELEN * (j + 1) - SPACING, screenr.min.y + SQUARELEN * (i + 1) - SPACING); } pub fn main() !void { const ally = std.heap.page_allocator; const d = ld.initDraw(ally, null, "balls") catch |e| { std.debug.print("errstr: {s}\n", .{std.os.plan9.errstr()}); return e; }; defer d.close() catch {}; const screen = d.getScreen(); const width = screen.r.width(); const height = screen.r.height(); for (cs, &colors) |c, *color| { color.* = try d.allocImage(Rectangle.init(0, 0, 1, 1), .rgba32, true, c); } screenr = screen.r; numbricks_horiz = @intCast(@divFloor(width, SQUARELEN)); numbricks_vert = @intCast(@divFloor(height, SQUARELEN) - 3); bricks = try ally.alloc(u32, numbricks_horiz * numbricks_vert); for (bricks) |*square| { square.* = 14; } balls = try std.ArrayList(Ball).initCapacity(ally, 40); // var angle: f32 = std.math.degreesToRadians(f32, 80); // try balls.append(.{ .pos = .{ .x = @divFloor(screenr.min.x + screenr.max.x, 2), .y = screenr.max.y }, .vel = .{ .x = @cos(angle), .y = @sin(angle) } }); try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 3.4, .y = 2.8 } }); try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 1.4, .y = 7.8 } }); try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = 0.4, .y = 8.8 } }); try balls.append(.{ .pos = .{ .x = @as(f32, @floatFromInt(screenr.min.x + screenr.max.x)) / 2.0, .y = @as(f32, @floatFromInt(screenr.max.y)) }, .vel = .{ .x = -4.1, .y = 0.5 } }); while (true) { // clear the screen try screen.draw(screen.r, d.white, null, Point.Zero); // collide the balls // update the balls for (balls.items) |*ball| { ball.collide(); ball.pos.x += ball.vel.x; ball.pos.y += ball.vel.y; const p = ball.pos.toPoint(); if (p.x > screenr.max.x or p.x < screenr.min.x) { ball.vel.x *= -1; } if (p.y > screenr.max.y or p.y < screenr.min.y) { ball.vel.y *= -1; } } var quit = true; // draw the squares var i: u16 = 0; while (i < numbricks_vert) : (i += 1) { var j: u16 = 0; while (j < numbricks_horiz) : (j += 1) { const square = bricks[i * numbricks_vert + j]; if (square > 0) { quit = false; try screen.draw(getBrickRect(i, j), colors[square], null, Point.Zero); } } } if (quit) break; for (balls.items) |ball| { try screen.ellipse(ball.pos.toPoint(), 3, 3, 3, d.black, Point.Zero); } try d.flushImage(true); _ = std.os.plan9.syscall_bits.syscall1(.SLEEP, 10); } }