inital work on pong
This commit is contained in:
parent
1482e6e679
commit
b0f31f40c1
2 changed files with 160 additions and 7 deletions
|
|
@ -2,11 +2,21 @@ const std = @import("std");
|
||||||
const gpa = std.heap.page_allocator;
|
const gpa = std.heap.page_allocator;
|
||||||
|
|
||||||
const Conway = @import("conway.zig");
|
const Conway = @import("conway.zig");
|
||||||
|
const Pong = @import("pong.zig");
|
||||||
|
|
||||||
const games = enum(u16) {
|
const games = enum(u16) {
|
||||||
@"Conways Game of Life",
|
@"Conways Game of Life",
|
||||||
|
// Pong,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn run_game(game: i64, width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
|
switch (game) {
|
||||||
|
@intFromEnum(games.@"Conways Game of Life") => try Conway.play(width, height, writer),
|
||||||
|
// @intFromEnum(games.Pong) => try Pong.play(width, height, writer),
|
||||||
|
else => @panic("Game does not exist."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ui(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
fn ui(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
var fd = [_]std.posix.pollfd{.{
|
var fd = [_]std.posix.pollfd{.{
|
||||||
.fd = std.posix.STDIN_FILENO,
|
.fd = std.posix.STDIN_FILENO,
|
||||||
|
|
@ -42,7 +52,7 @@ fn ui(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
cursor_y = @intCast(std.math.clamp(cursor_y, 0, @typeInfo(games).@"enum".fields.len - 1));
|
cursor_y = @intCast(std.math.clamp(cursor_y, 0, @typeInfo(games).@"enum".fields.len - 1));
|
||||||
inline for (@typeInfo(games).@"enum".fields, 0..) |f, i| {
|
inline for (@typeInfo(games).@"enum".fields, 0..) |f, i| {
|
||||||
try writer.print("\x1B[{};{}H", .{ // y, x
|
try writer.print("\x1B[{};{}H", .{ // y, x
|
||||||
((height + i) / 2) + 3,
|
((height) / 2) + 3 + i,
|
||||||
(width - f.name.len) / 2,
|
(width - f.name.len) / 2,
|
||||||
});
|
});
|
||||||
try writer.print("{s} {s} \x1B[0m\n", .{
|
try writer.print("{s} {s} \x1B[0m\n", .{
|
||||||
|
|
@ -65,7 +75,7 @@ fn ui(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
'k' => cursor_y -= 1,
|
'k' => cursor_y -= 1,
|
||||||
'g' => cursor_y = 1,
|
'g' => cursor_y = 1,
|
||||||
'G' => cursor_y = @intFromEnum(games.@"Conways Game of Life"),
|
'G' => cursor_y = @intFromEnum(games.@"Conways Game of Life"),
|
||||||
' ' => {
|
' ', '\n' => {
|
||||||
// reset the terminal state for the game
|
// reset the terminal state for the game
|
||||||
try std.posix.tcsetattr(std.posix.STDIN_FILENO, std.posix.TCSA.NOW, oldios);
|
try std.posix.tcsetattr(std.posix.STDIN_FILENO, std.posix.TCSA.NOW, oldios);
|
||||||
_ = try writer.write("\x1B[?25h"); // show cursor
|
_ = try writer.write("\x1B[?25h"); // show cursor
|
||||||
|
|
@ -73,10 +83,7 @@ fn ui(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
// not much we can do
|
// not much we can do
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (cursor_y) {
|
try run_game(cursor_y, width, height, writer);
|
||||||
@intFromEnum(games.@"Conways Game of Life") => try Conway.play(width, height, writer),
|
|
||||||
else => @panic("Game does not exist."),
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = try writer.write("\x1B[?25l"); // hide cursor
|
_ = try writer.write("\x1B[?25l"); // hide cursor
|
||||||
try writer.flush();
|
try writer.flush();
|
||||||
|
|
|
||||||
146
src/subcmds/arcade/pong.zig
Normal file
146
src/subcmds/arcade/pong.zig
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
const Pong = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const gpa = std.heap.page_allocator;
|
||||||
|
|
||||||
|
width: u64,
|
||||||
|
height: u64,
|
||||||
|
writer: *std.io.Writer,
|
||||||
|
players: []Player,
|
||||||
|
ball: Ball,
|
||||||
|
mode: Mode,
|
||||||
|
cps: f32,
|
||||||
|
|
||||||
|
const Player = struct {
|
||||||
|
score: u8 = 0,
|
||||||
|
/// top y position
|
||||||
|
paddle_y: u64,
|
||||||
|
paddle_x: u64,
|
||||||
|
|
||||||
|
const paddle_height = 4;
|
||||||
|
};
|
||||||
|
const Ball = struct { x: f32, y: f32, vx: f16, vy: f16 };
|
||||||
|
const Mode = enum{ easy, hard };
|
||||||
|
|
||||||
|
pub fn init(mode: Mode, width: u64, height: u64, writer: *std.Io.Writer) !Pong {
|
||||||
|
std.debug.assert(width > 0);
|
||||||
|
std.debug.assert(height > 0);
|
||||||
|
|
||||||
|
const self: Pong = .{
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.writer = writer,
|
||||||
|
|
||||||
|
.players = try gpa.alloc(Player, 2),
|
||||||
|
.mode = mode,
|
||||||
|
.ball = .{
|
||||||
|
.x = @as(f32, @floatFromInt(width)) / 2.0,
|
||||||
|
.y = @as(f32, @floatFromInt(height)) / 2.0,
|
||||||
|
.vx = 0.5,
|
||||||
|
.vy = 0.2,
|
||||||
|
},
|
||||||
|
.cps = switch (mode) {
|
||||||
|
Mode.easy => @as(f32, @floatFromInt(width)) / 1.3,
|
||||||
|
Mode.hard => @as(f32, @floatFromInt(width)) / 0.65,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.players[0] = Player{
|
||||||
|
.paddle_y = height / 2,
|
||||||
|
.paddle_x = 0,
|
||||||
|
.score = 0,
|
||||||
|
};
|
||||||
|
self.players[1] = .{
|
||||||
|
.paddle_y = height / 2,
|
||||||
|
.paddle_x = width - 1,
|
||||||
|
.score = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// must be called self.cps times per second
|
||||||
|
pub fn step(self: *Pong) !void {
|
||||||
|
const next_x = self.ball.x + 1 / self.ball.vx;
|
||||||
|
const next_y = self.ball.y + 1 / self.ball.vy;
|
||||||
|
|
||||||
|
if (next_y < 0 or next_y > @as(f32, @floatFromInt(self.height - 1))) self.ball.vy = -self.ball.vy;
|
||||||
|
for (self.players) |p| {
|
||||||
|
if ((@floor(next_x) == @as(f32, @floatFromInt(p.paddle_x))) and
|
||||||
|
(@floor(next_y) >= @as(f32, @floatFromInt(p.paddle_y)) and
|
||||||
|
@floor(next_y) <= @as(f32, @floatFromInt(p.paddle_y + Player.paddle_height)))) {
|
||||||
|
self.ball.vx = -self.ball.vx;
|
||||||
|
|
||||||
|
// The paddle is 4 high but divided into 8 sections.
|
||||||
|
// This is done so that we may change the vy of the ball after its
|
||||||
|
// hit the paddle which allows the ball to traverse an arbitrary
|
||||||
|
// path.
|
||||||
|
//
|
||||||
|
// I've encoded it in the struct below which allows us to generate
|
||||||
|
// the if branching at comptime.
|
||||||
|
const strong = 0.8;
|
||||||
|
const medium = 0.4;
|
||||||
|
const weak = 0.2;
|
||||||
|
const zero = 0;
|
||||||
|
const result_vy = .{
|
||||||
|
.{ 0.5, strong },
|
||||||
|
.{ 1, medium },
|
||||||
|
.{ 1.5, weak },
|
||||||
|
.{ 2, zero },
|
||||||
|
.{ 2.5, zero },
|
||||||
|
.{ 3, weak },
|
||||||
|
.{ 3.5, medium },
|
||||||
|
.{ 4, strong },
|
||||||
|
};
|
||||||
|
self.ball.vy = vy: {
|
||||||
|
inline for (result_vy) |f| {
|
||||||
|
if (next_y <= @as(f32, @floatFromInt(p.paddle_y)) + f[0]) {
|
||||||
|
break: vy f[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable; // it should be impossible to be outside of the paddle
|
||||||
|
};
|
||||||
|
} else if (@floor(next_x) == @as(f32, @floatFromInt(p.paddle_x))) {
|
||||||
|
// scored
|
||||||
|
var mult: f16 = 1;
|
||||||
|
if (std.meta.eql(p, self.players[0])) {
|
||||||
|
self.players[1].score += 1;
|
||||||
|
mult = -mult;
|
||||||
|
} else {
|
||||||
|
self.players[0].score += 1;
|
||||||
|
mult = mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ball = .{
|
||||||
|
.x = @as(f32, @floatFromInt(self.width)) / 2.0,
|
||||||
|
.y = @as(f32, @floatFromInt(self.height)) / 2.0,
|
||||||
|
.vx = 0.5 * mult,
|
||||||
|
.vy = self.ball.vy,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ball.x += self.ball.vx;
|
||||||
|
self.ball.y += self.ball.vy;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn play(width: u32, height: u32, writer: *std.Io.Writer) !void {
|
||||||
|
var pong = try Pong.init(.hard, width, height, writer);
|
||||||
|
|
||||||
|
// var fd = [_]std.posix.pollfd{.{
|
||||||
|
// .fd = std.posix.STDIN_FILENO,
|
||||||
|
// .events = std.posix.POLL.IN,
|
||||||
|
// .revents = 0
|
||||||
|
// }};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try pong.writer.print("\x1B[{}A", .{height});
|
||||||
|
|
||||||
|
try pong.writer.print("\x1B[{};{}H", .{pong.ball.y, pong.ball.x});
|
||||||
|
try pong.writer.writeAll("o");
|
||||||
|
try pong.writer.flush();
|
||||||
|
try pong.step();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue