Wrote initial game objects
This commit is contained in:
parent
d7ac70b78d
commit
b951f4de71
5 changed files with 243 additions and 0 deletions
57
build.zig
Normal file
57
build.zig
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.build.Builder) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard release options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||||
|
const mode = b.standardReleaseOptions();
|
||||||
|
|
||||||
|
const exe = b.addExecutable("grenade-brothers", "src/main.zig");
|
||||||
|
exe.addPackagePath("spoon", "lib/spoon/import.zig");
|
||||||
|
exe.setTarget(target);
|
||||||
|
exe.setBuildMode(mode);
|
||||||
|
exe.install();
|
||||||
|
|
||||||
|
const run_cmd = exe.run();
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const coverage = b.option(bool, "test-coverage", "Generate test coverage") orelse false;
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
const exe_tests = b.addTest("src/main.zig");
|
||||||
|
exe_tests.addPackagePath("spoon", "lib/spoon/import.zig");
|
||||||
|
exe_tests.setTarget(target);
|
||||||
|
exe_tests.setBuildMode(mode);
|
||||||
|
|
||||||
|
// Code coverage with kcov, we need an allocator for the setup
|
||||||
|
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
defer _ = general_purpose_allocator.deinit();
|
||||||
|
const gpa = general_purpose_allocator.allocator();
|
||||||
|
// We want to exclude the $HOME/.zig path
|
||||||
|
const home = std.process.getEnvVarOwned(gpa, "HOME") catch "";
|
||||||
|
defer gpa.free(home);
|
||||||
|
const exclude = std.fmt.allocPrint(gpa, "--exclude-path={s}/.zig/,/usr", .{home}) catch "";
|
||||||
|
defer gpa.free(exclude);
|
||||||
|
if (coverage) {
|
||||||
|
exe_tests.setExecCmd(&[_]?[]const u8{
|
||||||
|
"kcov",
|
||||||
|
exclude,
|
||||||
|
//"--path-strip-level=3", // any kcov flags can be specified here
|
||||||
|
"kcov-output", // output dir for kcov
|
||||||
|
null, // to get zig to use the --test-cmd-bin flag
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&exe_tests.step);
|
||||||
|
}
|
46
src/brothers.zig
Normal file
46
src/brothers.zig
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const spoon = @import("spoon");
|
||||||
|
|
||||||
|
pub const Side = enum(u1) {
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
};
|
||||||
|
|
||||||
|
const startingX = [2]f64{ 15, 60 };
|
||||||
|
const colors = [2]spoon.Attribute.Colour{ .blue, .red };
|
||||||
|
|
||||||
|
pub const Brother = struct {
|
||||||
|
side: Side,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
dx: f64,
|
||||||
|
dy: f64,
|
||||||
|
pub fn reset(self: *Brother, side: ?Side) void {
|
||||||
|
if (side) |s| {
|
||||||
|
self.side = s;
|
||||||
|
}
|
||||||
|
self.x = startingX[@enumToInt(self.side)];
|
||||||
|
self.y = 17;
|
||||||
|
self.dx = 0;
|
||||||
|
self.dy = 0;
|
||||||
|
}
|
||||||
|
pub fn draw(self: Brother, rc: *spoon.Term.RenderContext) !void {
|
||||||
|
try rc.setAttribute(.{ .fg = colors[@enumToInt(self.side)] });
|
||||||
|
var iter = std.mem.split(u8, brother, "\n");
|
||||||
|
var y = @floatToInt(usize, std.math.round(self.y));
|
||||||
|
var x = @floatToInt(usize, std.math.round(self.x));
|
||||||
|
while (iter.next()) |line| : (y += 1) {
|
||||||
|
try rc.moveCursorTo(y, x);
|
||||||
|
_ = try rc.buffer.writer().write(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const brother =
|
||||||
|
\\█ █
|
||||||
|
\\█ █ █
|
||||||
|
\\█████
|
||||||
|
\\█████
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
;
|
22
src/game.zig
Normal file
22
src/game.zig
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const spoon = @import("spoon");
|
||||||
|
|
||||||
|
const brothers = @import("brothers.zig");
|
||||||
|
const playfield = @import("playfield.zig");
|
||||||
|
|
||||||
|
pub const Game = struct {
|
||||||
|
brothers: [2]brothers.Brother = undefined,
|
||||||
|
character: ?brothers.Side = undefined,
|
||||||
|
pub fn draw(self: Game, rc: *spoon.Term.RenderContext) !void {
|
||||||
|
try playfield.draw(rc);
|
||||||
|
try self.brothers[0].draw(rc);
|
||||||
|
try self.brothers[1].draw(rc);
|
||||||
|
}
|
||||||
|
pub fn reset(self: *Game) void {
|
||||||
|
self.resetRound();
|
||||||
|
}
|
||||||
|
pub fn resetRound(self: *Game) void {
|
||||||
|
self.brothers[0].reset(brothers.Side.left);
|
||||||
|
self.brothers[1].reset(brothers.Side.right);
|
||||||
|
}
|
||||||
|
};
|
80
src/main.zig
Normal file
80
src/main.zig
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const spoon = @import("spoon");
|
||||||
|
|
||||||
|
const game = @import("game.zig");
|
||||||
|
|
||||||
|
var term: spoon.Term = undefined;
|
||||||
|
var done: bool = false;
|
||||||
|
|
||||||
|
//----- Game State -----------------------------------------------------------
|
||||||
|
var gs: game.Game = undefined;
|
||||||
|
|
||||||
|
//----- Main -----------------------------------------------------------------
|
||||||
|
pub fn main() !void {
|
||||||
|
try term.init();
|
||||||
|
defer term.deinit();
|
||||||
|
|
||||||
|
std.os.sigaction(std.os.SIG.WINCH, &std.os.Sigaction{
|
||||||
|
.handler = .{ .handler = handleSigWinch },
|
||||||
|
.mask = std.os.empty_sigset,
|
||||||
|
.flags = 0,
|
||||||
|
}, null);
|
||||||
|
|
||||||
|
var fds: [1]std.os.pollfd = undefined;
|
||||||
|
fds[0] = .{
|
||||||
|
.fd = term.tty.handle,
|
||||||
|
.events = std.os.POLL.IN,
|
||||||
|
.revents = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
try term.uncook(.{});
|
||||||
|
defer term.cook() catch {};
|
||||||
|
|
||||||
|
try term.fetchSize();
|
||||||
|
try term.setWindowTitle("Grenade Brothers", .{});
|
||||||
|
|
||||||
|
gs.reset();
|
||||||
|
try renderAll();
|
||||||
|
|
||||||
|
var buf: [16]u8 = undefined;
|
||||||
|
while (!done) {
|
||||||
|
_ = try std.os.poll(&fds, 100);
|
||||||
|
|
||||||
|
const read = try term.readInput(&buf);
|
||||||
|
var it = spoon.inputParser(buf[0..read]);
|
||||||
|
while (it.next()) |in| {
|
||||||
|
if (in.eqlDescription("escape") or in.eqlDescription("q")) {
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderAll() !void {
|
||||||
|
var rc = try term.getRenderContext();
|
||||||
|
defer rc.done() catch {};
|
||||||
|
|
||||||
|
try rc.clear();
|
||||||
|
|
||||||
|
if (term.width < 80 or term.width < 24) {
|
||||||
|
try rc.setAttribute(.{ .fg = .red, .bold = true });
|
||||||
|
try rc.writeAllWrapping("Terminal too small!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try gs.draw(&rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleSigWinch(_: c_int) callconv(.C) void {
|
||||||
|
term.fetchSize() catch {};
|
||||||
|
renderAll() catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Custom panic handler, so that we can try to cook the terminal on a crash,
|
||||||
|
/// as otherwise all messages will be mangled.
|
||||||
|
pub fn panic(msg: []const u8, trace: ?*std.builtin.StackTrace) noreturn {
|
||||||
|
@setCold(true);
|
||||||
|
term.cook() catch {};
|
||||||
|
std.builtin.default_panic(msg, trace);
|
||||||
|
}
|
38
src/playfield.zig
Normal file
38
src/playfield.zig
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const spoon = @import("spoon");
|
||||||
|
|
||||||
|
pub fn draw(rc: *spoon.Term.RenderContext) !void {
|
||||||
|
var iter = std.mem.split(u8, field, "\n");
|
||||||
|
var y: usize = 0;
|
||||||
|
while (iter.next()) |line| : (y += 1) {
|
||||||
|
try rc.moveCursorTo(y, 0);
|
||||||
|
_ = try rc.buffer.writer().write(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const field =
|
||||||
|
\\████████████████████████████████████████████████████████████████████████████████
|
||||||
|
\\█ ██ █
|
||||||
|
\\████████████████████████████████████████████████████████████████████████████████
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\█ ██ █
|
||||||
|
\\████████████████████████████████████████████████████████████████████████████████
|
||||||
|
;
|
Loading…
Add table
Reference in a new issue