~alva/bee

e045190b76ca35292c835f2aaeae93294d790a65 — owl 2 months ago 98eafdb trunk
fix the bee
21 files changed, 164 insertions(+), 205 deletions(-)

M LICENSE
M README.md
M build.zig
A build.zig.zon
M src/assets.zig
R assets/bee-sheet.png => src/assets/bee-sheet.png
R assets/bg1.png => src/assets/bg1.png
R assets/bluebird32x32bobbin.png => src/assets/bluebird32x32bobbin.png
R assets/bullet.png => src/assets/bullet.png
R assets/explosion32x32.png => src/assets/explosion32x32.png
R assets/flower-sheet.png => src/assets/flower-sheet.png
R assets/puff.png => src/assets/puff.png
R assets/slimeexplosion16x16.png => src/assets/slimeexplosion16x16.png
R assets/tandblomma64x64prototype.png => src/assets/tandblomma64x64prototype.png
R assets/wasp.png => src/assets/wasp.png
M src/c.zig
M src/constants.zig
M src/main.zig
M src/objects.zig
M src/sdl.zig
M src/tests.zig
M LICENSE => LICENSE +1 -1
@@ 1,4 1,4 @@
Copyright (c) 2019 Alva
Copyright (c) 2019 Owl

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

M README.md => README.md +1 -1
@@ 13,5 13,5 @@ Using Zig 0.6.0:

```shell
# build it [optimised] [and run it]
zig build [-Drelease-fast] [run]
zig build [-Doptimize=ReleaseFast] [run]
```

M build.zig => build.zig +19 -49
@@ 1,65 1,35 @@
const builtin = @import("builtin");
const std = @import("std");
const path = std.fs.path;
const Builder = std.build.Builder;

const name = "Bee";

pub fn build(b: *Builder) !void {
    const mode = b.standardReleaseOptions();
    const exe = b.addExecutable("bee", "src/main.zig");
    const tests = b.addTest("src/tests.zig");

//     exe.setTarget(b.standardTargetOptions(.{
//         .default_target = .{
//             .cpu_arch = builtin.cpu.arch,
//             .os_tag = builtin.os.tag,
//             .abi = switch (builtin.cpu.arch) {
//                 .aarch64 => .musleabi,
//                 .arm => .musleabihf,
//                 else => .musl,
//             },
//         },
//     }));
    exe.setBuildMode(mode);

    if (mode != .Debug)
        exe.strip = true;

    if (mode == .ReleaseSafe)
        exe.force_pic = true;

    exe.linkLibC();
//    tests.linkLibC();

    exe.addIncludeDir(try path.join(b.allocator,
        &[_][]const u8{ b.build_root, "usr", "include", "SDL2" }));
//     exe.addLibPath(try path.join(b.allocator,
//         &[_][]const u8{ b.build_root, "usr", "local", "lib" }));
//     exe.addLibPath(try path.join(b.allocator,
//         &[_][]const u8{ "usr", "lib" }));

//     exe.linkSystemLibraryName("./usr/lib/libSDL2main.a");
//     exe.linkSystemLibraryName("./usr/local/lib/libSDL2_image.a");
    exe.linkSystemLibrary("SDL2");
    exe.linkSystemLibrary("SDL2_image");
//    exe.linkSystemLibrary("SDL2_image");
    //     exe.addLibPath("/usr/lib");
//     inline for (libs) |lib| {
//         exe.linkSystemLibrary(lib);
//         tests.linkSystemLibrary(lib);
//     }
//    exe.linkSystemLibrary("csfml-window");
//    exe.linkSystemLibrary("csfml-graphics");
//    exe.linkSystemLibrary("csfml-audio");
pub fn build(b: *std.Build) !void {
    const optimize = b.standardOptimizeOption(.{});
    const target = b.standardTargetOptions(.{});
    const exe = b.addExecutable(.{
        .name = "bee",
        .root_source_file = .{ .path = "src/main.zig" },
        .optimize = optimize,
        .target = target,
        .strip = optimize != .Debug,
    });
    const tests = b.addTest(.{ .root_source_file = .{ .path = "src/tests.zig" } });

    inline for (.{ exe, tests }) |t| {
        t.linkLibC();
        t.linkSystemLibrary("SDL2");
        t.linkSystemLibrary("SDL2_image");
    }

    b.default_step.dependOn(&exe.step);

    b.installArtifact(exe);

    const test_step = b.step("test", "Run all " ++ name ++ " tests");
    test_step.dependOn(&tests.step);

    const run_cmd = exe.run();
    const run_cmd = b.addRunArtifact(exe);
    const run_step = b.step("run", "Run " ++ name);

    run_step.dependOn(&run_cmd.step);

A build.zig.zon => build.zig.zon +5 -0
@@ 0,0 1,5 @@
.{
    .name = "bee",
    .version = "0.0.1",
    .paths = .{ "src", "assets" },
}

M src/assets.zig => src/assets.zig +1 -1
@@ 1,6 1,6 @@
const HitBox = @import("objects.zig").HitBox;

const path = "../assets/";
const path = "./assets/";

pub const bee = @embedFile(path ++ "bee-sheet.png");
pub const bee_box = HitBox.init(0, 2, 16, 11);

R assets/bee-sheet.png => src/assets/bee-sheet.png +0 -0
R assets/bg1.png => src/assets/bg1.png +0 -0
R assets/bluebird32x32bobbin.png => src/assets/bluebird32x32bobbin.png +0 -0
R assets/bullet.png => src/assets/bullet.png +0 -0
R assets/explosion32x32.png => src/assets/explosion32x32.png +0 -0
R assets/flower-sheet.png => src/assets/flower-sheet.png +0 -0
R assets/puff.png => src/assets/puff.png +0 -0
R assets/slimeexplosion16x16.png => src/assets/slimeexplosion16x16.png +0 -0
R assets/tandblomma64x64prototype.png => src/assets/tandblomma64x64prototype.png +0 -0
R assets/wasp.png => src/assets/wasp.png +0 -0
M src/c.zig => src/c.zig +2 -2
@@ 1,7 1,7 @@
usingnamespace @cImport({
pub usingnamespace @cImport({
    @cInclude("SDL.h");
    @cInclude("SDL_image.h");
    @cInclude("SDL_video.h");
    //    @cInclude("SFML/Graphics.h");
//    @cInclude("SFML/Window.h");
    //    @cInclude("SFML/Window.h");
});

M src/constants.zig => src/constants.zig +1 -1
@@ 1,7 1,7 @@
const builtin = @import("builtin");
const std = @import("std");

pub const resolution = [2]comptime_int{256, 224};
pub const resolution = [2]comptime_int{ 256, 224 };

pub fn warn(comptime fmt: []const u8, args: anytype) void {
    if (builtin.mode == .Debug)

M src/main.zig => src/main.zig +25 -30
@@ 2,8 2,8 @@ const builtin = @import("builtin");
const std = @import("std");
const c = @import("c.zig");
const assets = @import("assets.zig");
usingnamespace @import("constants.zig");
usingnamespace @import("objects.zig");
const consts = @import("constants.zig");
const o = @import("objects.zig");
const sdl = @import("sdl.zig");

const assert = std.debug.assert;


@@ 11,16 11,13 @@ const assert = std.debug.assert;
var memory: [1 * 1024 * 1024]u8 = undefined;

pub fn main() !void {
    var fixed_alloc = std.heap.FixedBufferAllocator.init(&memory);
    const allocator = &fixed_alloc.allocator;

    try sdl.init();
    defer c.SDL_Quit();

    var dmode: c.SDL_DisplayMode = undefined;
    if (c.SDL_GetCurrentDisplayMode(0, &dmode) != 0)
        return error.SdlInitFailed;
//     warn("Refresh rate: {} Hz\n", .{dmode.refresh_rate});
    //     warn("Refresh rate: {} Hz\n", .{dmode.refresh_rate});

    const win = try sdl.createWindow(&dmode);
    defer c.SDL_DestroyWindow(win);


@@ 30,10 27,10 @@ pub fn main() !void {

    try sdl.configureRenderer(renderer);

//    _ = c.SDL_SetWindowFullscreen(win, c.SDL_WINDOW_FULLSCREEN);
    //    _ = c.SDL_SetWindowFullscreen(win, c.SDL_WINDOW_FULLSCREEN);

    stage = Stage.init();
    defer stage.deinit();
    o.stage = o.Stage.init();
    defer o.stage.deinit();

    _ = c.SDL_SetRenderDrawColor(renderer, 0, 0, 0, c.SDL_ALPHA_OPAQUE);
    _ = c.SDL_RenderClear(renderer);


@@ 42,25 39,25 @@ pub fn main() !void {

    const pf = c.SDL_GetPerformanceFrequency();

    stage.tick_last = c.SDL_GetPerformanceCounter();
    try stage.prepare(renderer);
    
    o.stage.tick_last = c.SDL_GetPerformanceCounter();
    try o.stage.prepare(renderer);

    var event: c.SDL_Event = undefined;

    const bg1t = try sdl.createTexture(renderer, assets.bg1);
    defer c.SDL_DestroyTexture(bg1t);

    loop: while (true) {
        stage.tick_now = c.SDL_GetPerformanceCounter();
        const delta = stage.tick_now - stage.tick_last;
        o.stage.tick_now = c.SDL_GetPerformanceCounter();
        const delta = o.stage.tick_now - o.stage.tick_last;

        if (delta < pf / @intCast(u64, dmode.refresh_rate) + 1) {
        if (delta < pf / @as(u64, @intCast(dmode.refresh_rate)) + 1) {
            if (builtin.mode == .Debug)
                std.time.sleep(pf / @intCast(u64, dmode.refresh_rate) + 1 - delta);
                std.time.sleep(pf / @as(u64, @intCast(dmode.refresh_rate)) + 1 - delta);
            continue;
        }

        stage.tick_last = stage.tick_now;
        o.stage.tick_last = o.stage.tick_now;

        while (c.SDL_PollEvent(&event) != 0) {
            switch (event.type) {


@@ 68,10 65,10 @@ pub fn main() !void {
                    break :loop;
                },
                c.SDL_KEYUP => {
                    stage.handleKeyUp(event);
                    o.stage.handleKeyUp(event);
                },
                c.SDL_KEYDOWN => {
                    stage.handleKeyDown(event);
                    o.stage.handleKeyDown(event);
                },
                else => {
                    continue;


@@ 79,17 76,15 @@ pub fn main() !void {
            }
        }

        _ = c.SDL_RenderCopy(renderer, bg1t,
            null,
            comptime &c.SDL_Rect{
                .x = 0,
                .y = 0,
                .w = resolution[0],
                .h = resolution[1],
            });
        stage.update(@intToFloat(f32, delta) / @intToFloat(f32, pf));
        stage.checkCollisions();
        stage.render(renderer);
        _ = c.SDL_RenderCopy(renderer, bg1t, null, comptime &c.SDL_Rect{
            .x = 0,
            .y = 0,
            .w = consts.resolution[0],
            .h = consts.resolution[1],
        });
        o.stage.update(@as(f32, @floatFromInt(delta)) / @as(f32, @floatFromInt(pf)));
        o.stage.checkCollisions();
        o.stage.render(renderer);
        c.SDL_RenderPresent(renderer);
    }
}

M src/objects.zig => src/objects.zig +82 -92
@@ 1,11 1,9 @@
const std = @import("std");
const c = @import("c.zig");
const assets = @import("assets.zig");
usingnamespace @import("constants.zig");
usingnamespace @import("sdl.zig");
const consts = @import("constants.zig");
const sdl = @import("sdl.zig");
const math = std.math;
const max = math.max;
const min = math.min;

pub var stage: Stage = undefined;
pub var game: Game = undefined;


@@ 60,7 58,7 @@ pub const Attributes = struct {
};

fn f(x: anytype) f32 {
    return @intToFloat(f32, x);
    return @floatFromInt(x);
}

pub const Sprite = struct {


@@ 94,13 92,10 @@ pub const Sprite = struct {

        self.position.x = @mulAdd(f32, a.speed.x, delta, self.position.x);
        self.position.y = @mulAdd(f32, a.speed.y, delta, self.position.y);
        

        // TODO: Run this less frequently.
        if (resolution[0] * 2 < self.position.x
            or self.position.x < -resolution[0]
            or resolution[1] * 2 < self.position.y
            or self.position.y < -resolution[1]) {
            warn("Going inactive\n", .{});
        if (consts.resolution[0] * 2 < self.position.x or self.position.x < -consts.resolution[0] or consts.resolution[1] * 2 < self.position.y or self.position.y < -consts.resolution[1]) {
            std.log.warn("Going inactive\n", .{});
            self.enabled = false;
        }
    }


@@ 115,8 110,7 @@ pub const Sprite = struct {
                return;
            }
            self.frame_counter = 0;
        } else
            self.frame_counter += delta;
        } else self.frame_counter += delta;
    }

    pub fn overlaps(a: *Self, b: *Self) bool {


@@ 124,10 118,7 @@ pub const Sprite = struct {
        const ba = stage.attributes[b.attributes];
        const ax = aa.hit_box;
        const bx = ba.hit_box;
        return a.position.x + f(ax.offset.x) < b.position.x + f(bx.rect.width) + f(bx.offset.x)
            and b.position.x + f(bx.offset.x) < a.position.x + f(ax.rect.width) + f(ax.offset.x)
            and a.position.y + f(ax.offset.y) < b.position.y + f(bx.rect.height) + f(bx.offset.y)
            and b.position.y + f(bx.offset.y) < a.position.y + f(ax.rect.height) + f(ax.offset.y);
        return a.position.x + f(ax.offset.x) < b.position.x + f(bx.rect.width) + f(bx.offset.x) and b.position.x + f(bx.offset.x) < a.position.x + f(ax.rect.width) + f(ax.offset.x) and a.position.y + f(ax.offset.y) < b.position.y + f(bx.rect.height) + f(bx.offset.y) and b.position.y + f(bx.offset.y) < a.position.y + f(ax.rect.height) + f(ax.offset.y);
    }
};



@@ 168,8 159,8 @@ pub const Stage = struct {
            .tick_now = 0,
            .tick_last = 0,
            .attributes = undefined,
            .textures = [_]?*c.SDL_Texture{ null } ** 32,
            .sprites = [_]Sprite{ std.mem.zeroes(Sprite) } ** 128,
            .textures = [_]?*c.SDL_Texture{null} ** 32,
            .sprites = [_]Sprite{std.mem.zeroes(Sprite)} ** 128,
            .bullet_idx = 0,
            .is_firing = false,
            .firing_wait = 10,


@@ 185,15 176,15 @@ pub const Stage = struct {
    }

    pub fn prepare(self: *Self, renderer: *c.SDL_Renderer) !void {
        self.textures[0] = try createTexture(renderer, assets.bee);
        self.textures[29] = try createTexture(renderer, assets.boom);
        self.textures[30] = try createTexture(renderer, assets.slime_explosion);
        self.textures[31] = try createTexture(renderer, assets.bullet);
        self.textures[1] = try createTexture(renderer, assets.flower);
        self.textures[2] = try createTexture(renderer, assets.tooth_flower);
        self.textures[3] = try createTexture(renderer, assets.blue_bird);
        self.textures[4] = try createTexture(renderer, assets.wasp);
        
        self.textures[0] = try sdl.createTexture(renderer, assets.bee);
        self.textures[29] = try sdl.createTexture(renderer, assets.boom);
        self.textures[30] = try sdl.createTexture(renderer, assets.slime_explosion);
        self.textures[31] = try sdl.createTexture(renderer, assets.bullet);
        self.textures[1] = try sdl.createTexture(renderer, assets.flower);
        self.textures[2] = try sdl.createTexture(renderer, assets.tooth_flower);
        self.textures[3] = try sdl.createTexture(renderer, assets.blue_bird);
        self.textures[4] = try sdl.createTexture(renderer, assets.wasp);

        // Player
        self.sprites[0] = Sprite{
            .enabled = true,


@@ 265,41 256,41 @@ pub const Stage = struct {
        };

        self.attributes[0] = Attributes.init(16);
        self.sprites[0].position = .{.x = 0.0, .y = resolution[1] / 2 - 8};
        self.sprites[0].position = .{ .x = 0.0, .y = consts.resolution[1] / 2 - 8 };
        self.attributes[0].hit_box = assets.bee_box;

        self.attributes[62] = Attributes.init(32);
        self.attributes[62].speed = .{.x = 0, .y = 0};
        self.attributes[62].speed = .{ .x = 0, .y = 0 };

        self.attributes[63] = Attributes.init(8);
        self.attributes[63].speed = .{.x = 150.0, .y = 0.0};
        self.attributes[63].speed = .{ .x = 150.0, .y = 0.0 };

        self.attributes[1] = Attributes.init(16);
        self.sprites[1].position = .{.x = resolution[0] / 2 + 8, .y = resolution[1] - 16 - 16};
        self.sprites[1].position = .{ .x = consts.resolution[0] / 2 + 8, .y = consts.resolution[1] - 16 - 16 };
        self.attributes[1].hit_box = assets.flower_box;

        self.attributes[2] = Attributes.init(64);
        self.sprites[2].position = .{.x = resolution[0] - 64, .y = resolution[1] - 64 - 16 + 2};
        self.attributes[2].speed = .{.x = -1, .y = 0};
        self.sprites[2].position = .{ .x = consts.resolution[0] - 64, .y = consts.resolution[1] - 64 - 16 + 2 };
        self.attributes[2].speed = .{ .x = -1, .y = 0 };
        self.attributes[2].hit_box = assets.tooth_flower_box;

        self.attributes[3] = Attributes.init(32);
        self.sprites[3].position = .{.x = resolution[0] - 1, .y = resolution[1] / 2 - 16};
        self.attributes[3].speed = .{.x = -20.0, .y = 0};
        self.sprites[3].position = .{ .x = consts.resolution[0] - 1, .y = consts.resolution[1] / 2 - 16 };
        self.attributes[3].speed = .{ .x = -20.0, .y = 0 };
        self.attributes[3].hit_box = assets.blue_bird_box;

        self.attributes[4] = Attributes.init(16);
        self.sprites[4].position = .{.x = resolution[0] -1, .y = resolution[1] / 3 - 8};
        self.attributes[4].speed = .{.x = -40.0, .y = 0};
        self.sprites[4].position = .{ .x = consts.resolution[0] - 1, .y = consts.resolution[1] / 3 - 8 };
        self.attributes[4].speed = .{ .x = -40.0, .y = 0 };
        self.attributes[4].hit_box = assets.wasp_box;
    }

    pub fn update(self: *Self, delta: f32) void {
//        warn("pos: {}, pos + speed * delta: {}\n", .{self.sprites[2].position.x, @mulAdd(f16, self.attributes[2].speed.x, @floatCast(f16, delta), self.sprites[2].position.x)});
        //        warn("pos: {}, pos + speed * delta: {}\n", .{self.sprites[2].position.x, @mulAdd(f16, self.attributes[2].speed.x, @floatCast(f16, delta), self.sprites[2].position.x)});
        self.updatePlayer(delta);
        self.updateShootums();

        for (self.sprites) |*s| {
        for (&self.sprites) |*s| {
            if (s.enabled)
                s.update(delta);
        }


@@ 313,72 304,73 @@ pub const Stage = struct {
                self.addBullet();
            } else if (self.is_firing)
                self.addBullet();
        } else
            self.firing_wait -= 1;
        } else self.firing_wait -= 1;
    }

    fn updatePlayer(self: *Self, delta: f32) void {
        _ = delta;
        const acc = 6;
        const dec = 2;
        const smax = 60;
        const a = &self.attributes[0];

        if (a.direction & @enumToInt(Direction.Up) != 0)
            a.speed.y = max(a.speed.y - acc, -smax);
        if (a.direction & @intFromEnum(Direction.Up) != 0)
            a.speed.y = @max(a.speed.y - acc, -smax);

        if (a.direction & @enumToInt(Direction.Down) != 0)
            a.speed.y = min(a.speed.y + acc, smax);
        if (a.direction & @intFromEnum(Direction.Down) != 0)
            a.speed.y = @min(a.speed.y + acc, smax);

        if (a.direction & @enumToInt(Direction.Left) != 0)
            a.speed.x = max(a.speed.x - acc, -smax);
        if (a.direction & @intFromEnum(Direction.Left) != 0)
            a.speed.x = @max(a.speed.x - acc, -smax);

        if (a.direction & @enumToInt(Direction.Right) != 0)
            a.speed.x = min(a.speed.x + acc, smax);
        if (a.direction & @intFromEnum(Direction.Right) != 0)
            a.speed.x = @min(a.speed.x + acc, smax);

        if (a.direction &
                (@enumToInt(Direction.Up) | @enumToInt(Direction.Down)) == 0) {
            (@intFromEnum(Direction.Up) | @intFromEnum(Direction.Down)) == 0)
        {
            if (a.speed.y < 0) {
                a.speed.y = min(a.speed.y + dec, 0);
                a.speed.y = @min(a.speed.y + dec, 0);
            } else if (0 < a.speed.y)
                a.speed.y = max(a.speed.y - dec, 0);
                a.speed.y = @max(a.speed.y - dec, 0);
        }

        if (a.direction &
                (@enumToInt(Direction.Right) | @enumToInt(Direction.Left)) == 0) {
            (@intFromEnum(Direction.Right) | @intFromEnum(Direction.Left)) == 0)
        {
            if (a.speed.x < 0) {
                a.speed.x = min(a.speed.x + dec, 0);
                a.speed.x = @min(a.speed.x + dec, 0);
            } else if (0 < a.speed.x)
                a.speed.x = max(a.speed.x - dec, 0);
                a.speed.x = @max(a.speed.x - dec, 0);
        }
    }

    pub fn checkCollisions(self: *Self) void {
        for (self.sprites) |*s| {
        for (&self.sprites) |*s| {
            switch (s.kind) {
                .Player => {
                },
                .Player => {},
                .PlayerBullet => {
                    for (self.sprites) |*e, i| {
                    for (&self.sprites, 0..) |*e, i| {
                        if (!s.enabled or !e.enabled or e.kind != .Enemy or !s.overlaps(e))
                            continue;

                        warn("Enemy took {} damage.\n", .{s.health});
                        std.log.warn("Enemy took {} damage.\n", .{s.health});
                        s.enabled = false;
                        e.health -= s.health;
                        if (e.health == 0) {
                            warn("Enemy died!\n", .{});
                            std.log.warn("Enemy died!\n", .{});
                            self.replaceWithExplosion(i);
                        }                        
                        }
                    }
                },
                .Enemy, .EnemyBullet => {
                    const player = &self.sprites[0];
                    if (s.overlaps(player)) {
                        const damage = min(player.health, s.health);
                        warn("Player took {} damage.\n", .{damage});
                        const damage = @min(player.health, s.health);
                        std.log.warn("Player took {} damage.\n", .{damage});
                        player.health -= damage;
                        if (player.health == 0) {
                            warn("Player died!\n", .{});
                            std.log.warn("Player died!\n", .{});
                        }
                    }
                },


@@ 402,7 394,7 @@ pub const Stage = struct {
                .x = old_sprite.position.x,
                .y = old_sprite.position.y,
            },
            .health = undefined,            
            .health = undefined,
        };
    }



@@ 411,7 403,7 @@ pub const Stage = struct {
        const ps = &self.sprites[0];
        const pa = &self.attributes[ps.attributes];
        const ba = &self.attributes[63];
        var bs = Sprite{
        const bs = Sprite{
            .enabled = true,
            .attributes = 63,
            .texture = 31,


@@ 421,8 413,8 @@ pub const Stage = struct {
            .frame_offset = 0,
            .kind = .PlayerBullet,
            .position = .{
                .x = ps.position.x + @intToFloat(f32, pa.size - ba.size / 2),
                .y = ps.position.y + @intToFloat(f32, pa.size / 2 - ba.size / 2),
                .x = ps.position.x + @as(f32, @floatFromInt(pa.size - ba.size / 2)),
                .y = ps.position.y + @as(f32, @floatFromInt(pa.size / 2 - ba.size / 2)),
            },
            .health = 1,
        };


@@ 436,10 428,10 @@ pub const Stage = struct {
        const a = &self.attributes[0];
        switch (sym) {
            c.SDLK_SPACE => self.is_firing = false,
            c.SDLK_UP, c.SDLK_w => a.direction &= ~@enumToInt(Direction.Up),
            c.SDLK_DOWN, c.SDLK_s => a.direction &= ~@enumToInt(Direction.Down),
            c.SDLK_LEFT, c.SDLK_a => a.direction &= ~@enumToInt(Direction.Left),
            c.SDLK_RIGHT, c.SDLK_d => a.direction &= ~@enumToInt(Direction.Right),
            c.SDLK_UP, c.SDLK_w => a.direction &= ~@intFromEnum(Direction.Up),
            c.SDLK_DOWN, c.SDLK_s => a.direction &= ~@intFromEnum(Direction.Down),
            c.SDLK_LEFT, c.SDLK_a => a.direction &= ~@intFromEnum(Direction.Left),
            c.SDLK_RIGHT, c.SDLK_d => a.direction &= ~@intFromEnum(Direction.Right),
            else => {},
        }
    }


@@ 459,34 451,32 @@ pub const Stage = struct {
                    self.is_firing = true;
                }
            },
            c.SDLK_UP, c.SDLK_w => a.direction |= @enumToInt(Direction.Up),
            c.SDLK_DOWN, c.SDLK_s => a.direction |= @enumToInt(Direction.Down),
            c.SDLK_LEFT, c.SDLK_a => a.direction |= @enumToInt(Direction.Left),
            c.SDLK_RIGHT, c.SDLK_d => a.direction |= @enumToInt(Direction.Right),
            c.SDLK_UP, c.SDLK_w => a.direction |= @intFromEnum(Direction.Up),
            c.SDLK_DOWN, c.SDLK_s => a.direction |= @intFromEnum(Direction.Down),
            c.SDLK_LEFT, c.SDLK_a => a.direction |= @intFromEnum(Direction.Left),
            c.SDLK_RIGHT, c.SDLK_d => a.direction |= @intFromEnum(Direction.Right),
            else => {},
        }
    }

    pub fn render(self: *Self, renderer: *c.SDL_Renderer) void {
        for (self.sprites) |*s, i| {
        for (&self.sprites) |*s| {
            if (!s.enabled)
                continue;

            const a = &self.attributes[s.attributes];

            _ = c.SDL_RenderCopy(renderer, stage.textures[s.texture],
                &c.SDL_Rect{
                    .x = @intCast(c_int, s.frame_offset * a.size),
                    .y = 0,
                    .w = a.size,
                    .h = a.size,
                },
                &c.SDL_Rect{
                    .x = @floatToInt(c_int, @round(s.position.x)),
                    .y = @floatToInt(c_int, @round(s.position.y)),
                    .w = a.size,
                    .h = a.size,
                });
            _ = c.SDL_RenderCopy(renderer, stage.textures[s.texture], &c.SDL_Rect{
                .x = @intCast(s.frame_offset * a.size),
                .y = 0,
                .w = a.size,
                .h = a.size,
            }, &c.SDL_Rect{
                .x = @intFromFloat(@round(s.position.x)),
                .y = @intFromFloat(@round(s.position.y)),
                .w = a.size,
                .h = a.size,
            });
        }
    }
};

M src/sdl.zig => src/sdl.zig +20 -20
@@ 1,24 1,24 @@
const c = @import("c.zig");
const std = @import("std");
usingnamespace @import("constants.zig");
const consts = @import("constants.zig");
const assets = @import("assets.zig");
const assert = std.debug.assert;

pub fn sfmlMain() !void {
    const vidmode: c.sfVideoMode = .{
        .width = resolution[0],
        .height = resolution[1],
        .width = consts.resolution[0],
        .height = consts.resolution[1],
        .bitsPerPixel = 32,
    };
    const win = c.sfRenderWindow_create(vidmode, "Bee", c.sfDefaultStyle, null)
        orelse return error.Sfml;
    const win = c.sfRenderWindow_create(vidmode, "Bee", c.sfDefaultStyle, null) orelse return error.Sfml;
    defer c.sfRenderWindow_destroy(win);

    const beetxt = c.sfTexture_createFromMemory(assets.bee, assets.bee.len, null);
    const beesprt = c.sfSprite_create();
    const pos = V2f{.x = 10.0, .y = 10.0};
    const pos = c.V2f{ .x = 10.0, .y = 10.0 };

    c.sfSprite_setTexture(beesprt, beetxt, 0);
    c.sfSprite_setPosition(beesprt, @bitCast(c.Vector2f, pos));
    c.sfSprite_setPosition(beesprt, @bitCast(pos));

    var event: c.sfEvent = undefined;



@@ 35,59 35,59 @@ pub fn sfmlMain() !void {
pub fn init() !void {
    const opts = c.SDL_INIT_TIMER | c.SDL_INIT_AUDIO | c.SDL_INIT_VIDEO;
    if (c.SDL_Init(opts) != 0) {
        warn("Unable to initialize SDL: {s}", .{c.SDL_GetError()});
        std.log.err("Unable to initialize SDL: {s}", .{c.SDL_GetError()});
        return error.SdlInitFailed;
    }
}

pub fn createWindow(display_mode: *c.SDL_DisplayMode) !*c.SDL_Window {
    const scale = @divFloor(display_mode.h, @intCast(c_int, resolution[1]));
    const scale = @divFloor(display_mode.h, @as(c_int, @intCast(consts.resolution[1])));
    return c.SDL_CreateWindow(
        "Bee",
        0,
        0,
        resolution[0] * scale,
        resolution[1] * scale,
        consts.resolution[0] * scale,
        consts.resolution[1] * scale,
        c.SDL_WINDOW_OPENGL | c.SDL_WINDOW_RESIZABLE,
    ) orelse {
//        warn("Failed to create window: {s}\n", .{c.SDL_GetError()});
        //        warn("Failed to create window: {s}\n", .{c.SDL_GetError()});
        return error.SdlCreateWindowFailed;
    };
}

pub fn createRenderer(window: *c.SDL_Window) !*c.SDL_Renderer {
    return c.SDL_CreateRenderer(window, -1, 0) orelse {
//        warn("Failed to create renderer: {s}\n", .{c.SDL_GetError()});
        //        warn("Failed to create renderer: {s}\n", .{c.SDL_GetError()});
        return error.SdlCreateRendererFailed;
    };
}

pub fn configureRenderer(renderer: *c.SDL_Renderer) !void {
    if (c.SDL_RenderSetLogicalSize(renderer, resolution[0], resolution[1]) != 0)
    if (c.SDL_RenderSetLogicalSize(renderer, consts.resolution[0], consts.resolution[1]) != 0)
        return error.SdlRenderSetLogicalSizeFailed;

    if (c.SDL_RenderSetIntegerScale(renderer, .SDL_TRUE) != 0)
    if (c.SDL_RenderSetIntegerScale(renderer, c.SDL_TRUE) != 0)
        return error.SdlRenderSetIntegerScaleFailed;
}

pub fn createTexture(renderer: *c.SDL_Renderer, data: []const u8) !*c.SDL_Texture {
    const rw = c.SDL_RWFromConstMem(
        &data[0],
        @intCast(c_int, data.len),
        @intCast(data.len),
    ) orelse {
//        warn("SDL_RWFromConstMem: {s}\n", .{c.SDL_GetError()});
        //        warn("SDL_RWFromConstMem: {s}\n", .{c.SDL_GetError()});
        return error.SdlRwFromConstMemFailed;
    };
    defer assert(c.SDL_RWclose(rw) == 0);

    const surface = c.IMG_Load_RW(rw, 0) orelse {
//        warn("IMG_Load_RW: {s}\n", .{c.SDL_GetError()});
        //        warn("IMG_Load_RW: {s}\n", .{c.SDL_GetError()});
        return error.ImgLoadRwFailed;
    };
    defer c.SDL_FreeSurface(surface);

    return c.SDL_CreateTextureFromSurface(renderer, surface) orelse {
//        warn("SDL_CreateTextureFromSurface: {s}\n", .{c.SDL_GetError()});
        //        warn("SDL_CreateTextureFromSurface: {s}\n", .{c.SDL_GetError()});
        return error.SdlCreateTextureFromSurfaceFailed;
    };
} 
}

M src/tests.zig => src/tests.zig +7 -8
@@ 1,25 1,24 @@
const std = @import("std");
usingnamespace @import("objects.zig");
const o = @import("objects.zig");
const expect = std.testing.expect;

test "Sprite overlaps" {
    var a1 = Sprite.init();
    var a2 = Sprite.init();
    var a1 = o.Sprite.init();
    var a2 = o.Sprite.init();

    a2.position.x = 8;
    a2.position.y = 8;
    expect(!a1.overlaps(&a2));
    try expect(!a1.overlaps(&a2));

    a2.position.x = 7;
    a2.position.y = 7;
    expect(a1.overlaps(&a2));
    try expect(a1.overlaps(&a2));

    a2.position.x = -8;
    a2.position.y = -8;
    expect(!a1.overlaps(&a2));
    try expect(!a1.overlaps(&a2));

    a2.position.x = -7;
    a2.position.y = -7;
    expect(a1.overlaps(&a2));
    try expect(a1.overlaps(&a2));
}