~alva/bee

d6be878897a191784ef7998e5f07f0c538dd7218 — Alva 4 years ago 43075de
Basic animations work; added tests file
12 files changed, 223 insertions(+), 124 deletions(-)

D assets/bee16x16.gif
D assets/bee16x16goingup.png
D assets/beeshootums32x16.png
R assets/{bee16x16.png => bullet.png}
A assets/tandblomma64x64prototype.png
M build.zig
M src/assets.zig
M src/c.zig
M src/main.zig
M src/objects.zig
D src/objman.zig
A src/tests.zig
D assets/bee16x16.gif => assets/bee16x16.gif +0 -0
D assets/bee16x16goingup.png => assets/bee16x16goingup.png +0 -0
D assets/beeshootums32x16.png => assets/beeshootums32x16.png +0 -0
R assets/bee16x16.png => assets/bullet.png +0 -0
A assets/tandblomma64x64prototype.png => assets/tandblomma64x64prototype.png +0 -0
M build.zig => build.zig +9 -0
@@ 18,9 18,18 @@ pub fn build(b: *Builder) void {
    exe.linkSystemLibrary("SDL2");
    exe.linkSystemLibrary("SDL2_image");

//    exe.linkSystemLibrary("csfml-window");
//    exe.linkSystemLibrary("csfml-graphics");
//    exe.linkSystemLibrary("csfml-audio");

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

    const tests = b.addTest("src/tests.zig");

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

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


M src/assets.zig => src/assets.zig +1 -0
@@ 1,3 1,4 @@
pub const bee = @embedFile("../assets/bee-sheet.png");
pub const bullet = @embedFile("../assets/bullet.png");
pub const flower = @embedFile("../assets/flower-sheet.png");
pub const tooth_flower = @embedFile("../assets/tandblomma64x64prototype.png");

M src/c.zig => src/c.zig +2 -0
@@ 1,4 1,6 @@
usingnamespace @cImport({
    @cInclude("SDL2/SDL.h");
    @cInclude("SDL2/SDL_image.h");
//    @cInclude("SFML/Graphics.h");
//    @cInclude("SFML/Window.h");
});

M src/main.zig => src/main.zig +70 -29
@@ 31,38 31,32 @@ pub fn main() !void {
    stage.textures[1] = try createSdlTexture(renderer, assets.flower);
    stage.textures[2] = try createSdlTexture(renderer, assets.tooth_flower);

    stage.player = Player{
        .attribute = 0,
    };
//    _ = c.SDL_ShowCursor(0);
    stage.attributes[0] = Attributes{
        .enabled = true,
        .size = Size.Sixteen.toInt(),
        .position = .{0.0, resolution[1] / 2.0 - Size.Sixteen.toFloat() / 2.0},
        .speed = .{0.0, 0.0},
        .direction = 0,
    stage.sprites[0] = Sprite{
        .attributes = 0,
        .texture = 0,
        .whatever = undefined,
        .frames = 2,
        .frame_counter = 0,
        .animation_speed = 4,
        .frame_offset = 0,
    };

    stage.attributes[1] = Attributes{
        .enabled = true,
        .size = Size.Sixteen.toInt(),
        .position = .{resolution[1] / 2.0 + 8.0, resolution[1] - Size.Sixteen.toFloat()},
        .speed = .{0.0, 0.0},
        .direction = 0,
    stage.sprites[1] = Sprite{
        .attributes = 1,
        .texture = 1,
        .whatever = undefined,
        .frames = 4,
        .frame_counter = 0,
        .animation_speed = 6,
        .frame_offset = 0,
    };

    stage.attributes[2] = Attributes{
        .enabled = true,
        .size = Size.Sixtyfour.toInt(),
        .position = .{resolution[1] / 2.0 + 32.0, resolution[1] - Size.Sixtyfour.toFloat()},
        .speed = .{0.0, 0.0},
        .direction = 0,
    stage.sprites[2] = Sprite{
        .attributes = 2,
        .texture = 2,
        .whatever = undefined,
        .frames = 4,
        .frame_counter = 0,
        .animation_speed = 8,
        .frame_offset = 0,
    };

//    var dmode: c.SDL_DisplayMode = undefined;


@@ 77,7 71,19 @@ pub fn main() !void {
    _ = c.SDL_RenderFillRect(renderer, null);

    const pf = @intToFloat(f64, c.SDL_GetPerformanceFrequency());
    stage.tick_now = @intToFloat(f64, c.SDL_GetPerformanceCounter());
    stage.tick_last = @intToFloat(f64, c.SDL_GetPerformanceCounter());

    stage.attributes[0] = Attributes.init(Size.Sixteen);
    stage.attributes[0].position = .{0.0, resolution[1] / 2.0 - Size.Sixteen.toFloat() / 2.0};

    stage.attributes[1] = Attributes.init(Size.Sixteen);
    stage.attributes[1].position = .{resolution[1] / 2.0 + 8.0, resolution[1] - Size.Sixteen.toFloat()};
    stage.attributes[1].texture = 1;

    stage.attributes[2] = Attributes.init(Size.Sixtyfour);
    stage.attributes[2].position = .{resolution[1] - 32.0, resolution[1] - Size.Sixtyfour.toFloat() + 2};
    stage.attributes[2].texture = 2;
    stage.attributes[2].speed = .{-4.0, 0.0};

    var event: c.SDL_Event = undefined;



@@ 90,24 96,25 @@ pub fn main() !void {
            continue;
        }

        stage.tick_last = stage.tick_now;

        while (c.SDL_PollEvent(&event) != 0) {
            switch (event.type) {
                c.SDL_QUIT => {
                    break :loop;
                },
                c.SDL_KEYUP => {
                    stage.player.handleKeyUp(event.key.keysym.sym);
                    stage.sprites[0].handleKeyUp(event.key.keysym.sym);
                },
                c.SDL_KEYDOWN => {
                    stage.player.handleKeyDown(event.key.keysym.sym);
                    stage.sprites[0].handleKeyDown(event.key.keysym.sym);
                },
                else => {
                    continue;
                },
            }
        }

        stage.tick_last = stage.tick_now;

        _ = c.SDL_RenderFillRect(renderer, null);
        stage.update(delta);
        stage.render(renderer);


@@ 115,6 122,40 @@ pub fn main() !void {
    }
}

extern const V2f = struct {
    x: f32,
    y: f32,
};

pub fn sfmlMain() !void {
    const vidmode: c.sfVideoMode = .{
        .width = resolution[0],
        .height = resolution[1],
        .bitsPerPixel = 32,
    };
    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};

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

    var event: c.sfEvent = undefined;

    while (c.sfRenderWindow_isOpen(win) != 0) {
        while (c.sfRenderWindow_pollEvent(win, &event) != 0) {
            if (event.type == .sfEvtClosed)
                c.sfRenderWindow_close(win);
        }

        c.sfRenderWindow_drawSprite(win, beesprt, 0);
    }
}

fn initSdl() !void {
    if (c.SDL_Init(c.SDL_INIT_EVERYTHING) != 0) {
//        warn("Unable to initialize SDL: {s}", .{c.SDL_GetError()});

M src/objects.zig => src/objects.zig +120 -92
@@ 22,8 22,9 @@ pub const Size = enum {
    Sixteen,
    Thirtytwo,
    Sixtyfour,
    const Self = @This();

    pub fn toInt(   self: @This()) u8 {
    pub fn toInt(self: Self) u8 {
        return switch (self) {
            .Four => 4,
            .Eight => 8,


@@ 33,7 34,7 @@ pub const Size = enum {
        };
    }

    pub fn toFloat(self: @This()) f64 {
    pub fn toFloat(self: Self) f64 {
        return @intToFloat(f64, self.toInt());
    }
};


@@ 45,61 46,68 @@ pub const Attributes = struct {
    speed: Vec2,
    direction: u8,
    texture: u8,
    whatever: u8,
};

const Direction = enum(u8) {
    None = 0,
    Up = 1 << 0,
    Down = 1 << 1,
    Left = 1 << 2,
    Right = 1 << 3,
};

pub const Player = struct {
    attribute: u8,
    const Self = @This();
    const acc = 7.5;
    const dec = 2.5;
    const smax = 60.0;

    fn update(self: *Self, delta: f64) void {
        const a = &stage.attributes[self.attribute];
    pub fn init(size: Size) Self {
        return Self{
            .enabled = true,
            .size = size.toInt(),
            .position = .{0.0, 0.0},
            .speed = .{0.0, 0.0},
            .direction = 0,
            .texture = 0,
        };
    }

        if (a.direction & @enumToInt(Direction.Up) != 0)
            a.speed[1] = max(a.speed[1] - acc, -smax);
    pub fn overlaps(self: *Self, other: *Self) bool {
        return if (self.overlapsCrude(other))
            self.overlapsPrecise(other)
            else false;
    }

        if (a.direction & @enumToInt(Direction.Down) != 0)
            a.speed[1] = min(a.speed[1] + acc, smax);
    fn overlapsCrude(self: *Self, other: *Self) bool {
        return (self.position[0] < other.position[0] + @intToFloat(f64, other.size)
            and other.position[0] < self.position[0] + @intToFloat(f64, self.size)
            and self.position[1] < other.position[1] + @intToFloat(f64, other.size)
            and other.position[1] < self.position[1] + @intToFloat(f64, self.size));
    }

        if (a.direction & @enumToInt(Direction.Left) != 0)
            a.speed[0] = max(a.speed[0] - acc, -smax);
    fn overlapsPrecise(self: *Self, other: *Attributes) bool {
        return true;
    }
};

        if (a.direction & @enumToInt(Direction.Right) != 0)
            a.speed[0] = min(a.speed[0] + acc, smax);
pub const Sprite = struct {
    attributes: u8,
    texture: u8,
    frames: u8,
    frame_counter: u8,
    animation_speed: u8,
    frame_offset: u16,
    const Self = @This();

        if (a.direction &
                (@enumToInt(Direction.Up) | @enumToInt(Direction.Down)) == 0) {
            if (a.speed[1] < 0.0) {
                a.speed[1] = min(a.speed[1] + dec, 0.0);
            } else if (0.0 < a.speed[1])
                a.speed[1] = max(a.speed[1] - dec, 0.0);
        }
    fn update(self: *Self, delta: f64) void {
        const a = &stage.attributes[self.attributes];
//        warn("Speed {}\n", .{mo.speed});
        self.updateAnimation();
        a.position[0] += a.speed[0] * delta;
        a.position[1] += a.speed[1] * delta;
    }

        if (a.direction &
                (@enumToInt(Direction.Right) | @enumToInt(Direction.Left)) == 0) {
            if (a.speed[0] < 0.0) {
                a.speed[0] = min(a.speed[0] + dec, 0.0);
            } else if (0.0 < a.speed[0])
                a.speed[0] = max(a.speed[0] - dec, 0.0);
        }
    fn updateAnimation(self: *Self) void {
        if (1 < self.frames) {
        if (self.frame_counter == self.animation_speed) {
            self.frame_offset = (self.frame_offset + 1) % self.frames;
            self.frame_counter = 0;
        } else
            self.frame_counter += 1;

//        warn("Speed {}\n", .{mo.speed});
        a.whatever +%= 32;
//            warn("off {} {}\n", .{self.frame_counter, self.frame_offset});
        }
    }

    fn handleKeyUp(self: *Self, sym: c.SDL_Keycode) void {
        const a = &stage.attributes[self.attribute];
        const a = &stage.attributes[self.attributes];
        a.direction &= ~@enumToInt(switch (sym) {
            c.SDLK_UP, c.SDLK_w => Direction.Up,
            c.SDLK_DOWN, c.SDLK_s => Direction.Down,


@@ 115,7 123,7 @@ pub const Player = struct {
            return;
        }

        const a = &stage.attributes[self.attribute];
        const a = &stage.attributes[self.attributes];
        a.direction |= @enumToInt(switch (sym) {
            c.SDLK_UP, c.SDLK_w => Direction.Up,
            c.SDLK_DOWN, c.SDLK_s => Direction.Down,


@@ 124,35 132,22 @@ pub const Player = struct {
            else => Direction.None,
        });
    }

    fn render(self: *Self, renderer: *c.SDL_Renderer) void {
        const a = &stage.attributes[self.attribute];
        _ = c.SDL_RenderCopy(renderer, stage.textures[a.texture],
            &c.SDL_Rect{
                .x = a.whatever >> 7 << 4,
                .y = 0,
                .w = 16,
                .h = 16
            },
            &c.SDL_Rect{
                .x = @floatToInt(c_int, a.position[0]),
                .y = @floatToInt(c_int, a.position[1]),
                .w = 16,
                .h = 16
            });
    }
};

pub const Sprite = struct {
    texture: *c.SDL_Texture,
pub const Direction = enum(u8) {
    None = 0,
    Up = 1 << 0,
    Down = 1 << 1,
    Left = 1 << 2,
    Right = 1 << 3,
};

pub const Stage = struct {
    tick_now: f64,
    tick_last: f64,
    player: Player,
    attributes: [128]Attributes,
    textures: [64]?*c.SDL_Texture,
    attributes: [64]Attributes,
    textures: [32]?*c.SDL_Texture,
    sprites: [32]Sprite,

    const Self = @This();



@@ 160,7 155,6 @@ pub const Stage = struct {
        return Self{
            .tick_now = 0,
            .tick_last = 0,
            .player = undefined,
            .attributes = [_]Attributes{
                Attributes{
                    .enabled = false,


@@ 169,10 163,19 @@ pub const Stage = struct {
                    .speed = undefined,
                    .direction = undefined,
                    .texture = undefined,
                    .whatever = undefined,
                }
            } ** 128,
            .textures = [_]?*c.SDL_Texture{null} ** 64,
            } ** 64,
            .textures = [_]?*c.SDL_Texture{null} ** 32,
            .sprites = [_]Sprite{
                Sprite{
                    .attributes = 63,
                    .texture = undefined,
                    .frames = undefined,
                    .frame_counter = 0,
                    .animation_speed = undefined,
                    .frame_offset = undefined,
                }
            } ** 32,
        };
    }



@@ 184,25 187,61 @@ pub const Stage = struct {
    }

    pub fn update(self: *Self, delta: f64) void {
        self.player.update(delta);
        for (self.attributes) |*a| {
            a.position[0] += a.speed[0] * delta;
            a.position[1] += a.speed[1] * delta;
        self.updatePlayer(delta);
        for (self.sprites) |*s| {
            const a = &self.attributes[s.attributes];
            if (!a.enabled)
                continue;
            s.update(delta);
        }
    }

    pub fn render(self: *Self, renderer: *c.SDL_Renderer) void {
        self.player.render(renderer);
    fn updatePlayer(self: *Self, delta: f64) void {
        const acc = 7.5;
        const dec = 2.5;
        const smax = 60.0;
        const a = &self.attributes[0];

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

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

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

        for (self.attributes[1..]) |*a| {
        if (a.direction & @enumToInt(Direction.Right) != 0)
            a.speed[0] = min(a.speed[0] + acc, smax);

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

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

    pub fn render(self: *Self, renderer: *c.SDL_Renderer) void {
        for (self.sprites) |*s, i| {
            const a = &self.attributes[s.attributes];
            if (!a.enabled)
                continue;
            if (boundingBoxesOverlap(&self.attributes[0], a))
            if (i != 0 and self.attributes[0].overlaps(a))
                warn("Boom!\n", .{});
//            warn("txtidx: {}\n", .{a.texture});
            _ = c.SDL_RenderCopy(renderer, stage.textures[a.texture],
                &c.SDL_Rect{
                    .x = 0,
                    .x = s.frame_offset * a.size,
                    .y = 0,
                    .w = a.size,
                    .h = a.size,


@@ 216,14 255,3 @@ pub const Stage = struct {
        }
    }
};

fn boundingBoxesOverlap(as1: *Attributes, as2: *Attributes) bool {
    return (as1.position[0] < as2.position[0] + @intToFloat(f64, as2.size) - 2.0
        and as2.position[0] < as1.position[0] + @intToFloat(f64, as1.size) - 2.0
        and as1.position[1] < as2.position[1] + @intToFloat(f64, as2.size) - 2.0
        and as2.position[1] < as1.position[1] + @intToFloat(f64, as1.size) - 2.0);
}

fn pixelsOverlap(as1: *Attributes, as2: *Attributes) bool {
    return false;
}

D src/objman.zig => src/objman.zig +0 -3
@@ 1,3 0,0 @@
const std = @import("std");



A src/tests.zig => src/tests.zig +21 -0
@@ 0,0 1,21 @@
const std = @import("std");
usingnamespace @import("objects.zig");
const expect = std.testing.expect;

test "Attributes overlapsCrude" {
    var a1 = Attributes.init(Size.Eight);
    var a2 = Attributes.init(Size.Eight);

    a2.position = .{8.0, 8.0};
    expect(!a1.overlapsCrude(&a2));

    a2.position = .{7.0, 7.0};
    expect(a1.overlapsCrude(&a2));

    a2.position = .{-8.0, -8.0};
    expect(!a1.overlapsCrude(&a2));

    a2.position = .{-7.0, -7.0};
    expect(a1.overlapsCrude(&a2));
}