add key repeat
This commit is contained in:
parent
d91fd0f4dc
commit
a153a3f04a
24
src/app.zig
24
src/app.zig
@ -280,16 +280,16 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
const input = plt.input;
|
const input = plt.input;
|
||||||
|
|
||||||
var dir: Vec2 = .init(0, 0);
|
var dir: Vec2 = .init(0, 0);
|
||||||
if (input.isKeyPressed(.S)) {
|
if (input.isKeyPressedOrRepeat(.S)) {
|
||||||
dir.y += 1;
|
dir.y += 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyPressed(.W)) {
|
if (input.isKeyPressedOrRepeat(.W)) {
|
||||||
dir.y -= 1;
|
dir.y -= 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyPressed(.D)) {
|
if (input.isKeyPressedOrRepeat(.D)) {
|
||||||
dir.x += 1;
|
dir.x += 1;
|
||||||
}
|
}
|
||||||
if (input.isKeyPressed(.A)) {
|
if (input.isKeyPressedOrRepeat(.A)) {
|
||||||
dir.x -= 1;
|
dir.x -= 1;
|
||||||
}
|
}
|
||||||
if (dir.x != 0) {
|
if (dir.x != 0) {
|
||||||
@ -297,13 +297,8 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
self.player_pos = self.player_pos.add(dir);
|
self.player_pos = self.player_pos.add(dir);
|
||||||
|
|
||||||
if (input.isKeyPressed(.F)) {
|
if (dir.x != 0 or dir.y != 0) {
|
||||||
Audio.stop(self.footstep_sound);
|
self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .bus = self.sfx_bus });
|
||||||
}
|
|
||||||
|
|
||||||
if (input.isKeyPressed(.E)) {
|
|
||||||
Audio.stop(self.footstep_sound);
|
|
||||||
self.footstep_sound = Audio.play(.{ .buffer = self.footstep_buffer, .loop = true, .bus = self.sfx_bus });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var new_direction = self.player_direction;
|
var new_direction = self.player_direction;
|
||||||
@ -325,7 +320,7 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
const frames = self.player_sprites.getDirection(self.player_direction);
|
const frames = self.player_sprites.getDirection(self.player_direction);
|
||||||
|
|
||||||
if (dir.x != 0 or dir.y != 0) {
|
if (dir.x != 0 or dir.y != 0) {
|
||||||
self.animation_timer += plt.dt;
|
self.animation_timer += plt.input.delta_time;
|
||||||
const animatin_time = std.time.ns_per_s / 5;
|
const animatin_time = std.time.ns_per_s / 5;
|
||||||
while (self.animation_timer >= animatin_time) {
|
while (self.animation_timer >= animatin_time) {
|
||||||
self.player_frame_index = (self.player_frame_index + 1) % @as(u32, @intCast(frames.len));
|
self.player_frame_index = (self.player_frame_index + 1) % @as(u32, @intCast(frames.len));
|
||||||
@ -354,11 +349,6 @@ pub fn frame(self: *App, plt: Platform.Frame) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Gfx.drawSprite(frames[self.player_frame_index], self.player_pos.multiply(tile_size), tile_size, .white);
|
Gfx.drawSprite(frames[self.player_frame_index], self.player_pos.multiply(tile_size), tile_size, .white);
|
||||||
Gfx.drawText(self.roboto_font, .{
|
|
||||||
.pos = .init(300, 100),
|
|
||||||
.text = try std.fmt.allocPrint(plt.frame, "Hello, World! {:.0}", .{ plt.time() }),
|
|
||||||
.height = 64,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
pub fn deinit(self: *App, plt: Platform.Deinit) void {
|
||||||
|
|||||||
@ -6,9 +6,16 @@ const sokol = @import("sokol");
|
|||||||
const Math = @import("math");
|
const Math = @import("math");
|
||||||
const Vec2 = Math.Vec2;
|
const Vec2 = Math.Vec2;
|
||||||
|
|
||||||
|
const Nanoseconds = @import("./root.zig").Nanoseconds;
|
||||||
|
|
||||||
const Input = @This();
|
const Input = @This();
|
||||||
|
|
||||||
key_code_mapping: std.EnumMap(KeyCode, u21),
|
// TODO: Make this configurable from the app
|
||||||
|
const key_repeat_first: Nanoseconds = 0.4 * std.time.ns_per_s;
|
||||||
|
const key_repeat_delay: Nanoseconds = 0.2 * std.time.ns_per_s;
|
||||||
|
|
||||||
|
now: Nanoseconds,
|
||||||
|
delta_time: Nanoseconds,
|
||||||
|
|
||||||
window_size: Vec2,
|
window_size: Vec2,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
@ -18,8 +25,13 @@ mouse_position: ?Vec2,
|
|||||||
mouse_delta: Vec2,
|
mouse_delta: Vec2,
|
||||||
mouse_scroll: Vec2,
|
mouse_scroll: Vec2,
|
||||||
|
|
||||||
|
key_code_mapping: std.EnumMap(KeyCode, u21),
|
||||||
|
last_key_repeat_at: std.EnumMap(KeyCode, Nanoseconds),
|
||||||
|
|
||||||
pub fn init(window_size: Vec2) Input {
|
pub fn init(window_size: Vec2) Input {
|
||||||
return Input{
|
return Input{
|
||||||
|
.now = 0,
|
||||||
|
.delta_time = 0,
|
||||||
.key_code_mapping = .{},
|
.key_code_mapping = .{},
|
||||||
.focused = false,
|
.focused = false,
|
||||||
.keyboard = .empty,
|
.keyboard = .empty,
|
||||||
@ -27,7 +39,8 @@ pub fn init(window_size: Vec2) Input {
|
|||||||
.mouse_position = null,
|
.mouse_position = null,
|
||||||
.mouse_delta = .init(0, 0),
|
.mouse_delta = .init(0, 0),
|
||||||
.mouse_scroll = .init(0, 0),
|
.mouse_scroll = .init(0, 0),
|
||||||
.window_size = window_size
|
.window_size = window_size,
|
||||||
|
.last_key_repeat_at = .{}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +53,33 @@ pub fn isKeyReleased(self: Input, key: KeyCode) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn isKeyDown(self: Input, key: KeyCode) bool {
|
pub fn isKeyDown(self: Input, key: KeyCode) bool {
|
||||||
return self.keyboard.down.contains(key);
|
return self.keyboard.pressed_at.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getKeyDown(self: Input, key: KeyCode) ?Nanoseconds {
|
||||||
|
return self.keyboard.getDown(key, self.now);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isKeyRepeat(self: *Input, key: KeyCode) bool {
|
||||||
|
const pressed_at = self.keyboard.pressed_at.get(key) orelse return false;
|
||||||
|
|
||||||
|
var next_repeat_at: Nanoseconds = undefined;
|
||||||
|
if (self.last_key_repeat_at.get(key)) |last_repeat_at| {
|
||||||
|
next_repeat_at = last_repeat_at + key_repeat_delay;
|
||||||
|
} else {
|
||||||
|
next_repeat_at = pressed_at + key_repeat_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.now >= next_repeat_at) {
|
||||||
|
self.last_key_repeat_at.put(key, next_repeat_at);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isKeyPressedOrRepeat(self: *Input, key: KeyCode) bool {
|
||||||
|
return self.isKeyPressed(key) or self.isKeyRepeat(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isMousePressed(self: Input, button: MouseButton) bool {
|
pub fn isMousePressed(self: Input, button: MouseButton) bool {
|
||||||
@ -52,7 +91,11 @@ pub fn isMouseReleased(self: Input, button: MouseButton) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn isMouseDown(self: Input, button: MouseButton) bool {
|
pub fn isMouseDown(self: Input, button: MouseButton) bool {
|
||||||
return self.mouse_buttons.down.contains(button);
|
return self.mouse_buttons.pressed_at.contains(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMouseDown(self: Input, button: MouseButton) ?Nanoseconds {
|
||||||
|
return self.mouse_buttons.getDown(button, self.now);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const KeyCode = enum(std.math.IntFittingRange(0, sokol.app.max_keycodes-1)) {
|
pub const KeyCode = enum(std.math.IntFittingRange(0, sokol.app.max_keycodes-1)) {
|
||||||
@ -212,28 +255,35 @@ fn KeyStateType(T: type) type {
|
|||||||
return struct {
|
return struct {
|
||||||
pressed: std.EnumSet(T),
|
pressed: std.EnumSet(T),
|
||||||
released: std.EnumSet(T),
|
released: std.EnumSet(T),
|
||||||
down: std.EnumSet(T),
|
pressed_at: std.EnumMap(T, Nanoseconds),
|
||||||
|
|
||||||
pub const empty = @This(){
|
pub const empty = @This(){
|
||||||
.pressed = .empty,
|
.pressed = .empty,
|
||||||
.released = .empty,
|
.released = .empty,
|
||||||
.down = .empty,
|
.pressed_at = .{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn press(self: *@This(), key: T) void {
|
pub fn press(self: *@This(), key: T, now: Nanoseconds) void {
|
||||||
self.pressed.insert(key);
|
self.pressed.insert(key);
|
||||||
self.down.insert(key);
|
self.pressed_at.put(key, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self: *@This(), key: T) void {
|
pub fn release(self: *@This(), key: T) void {
|
||||||
self.released.insert(key);
|
self.released.insert(key);
|
||||||
self.down.remove(key);
|
self.pressed_at.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDown(self: @This(), key: T, now: Nanoseconds) ?Nanoseconds {
|
||||||
|
if (self.pressed_at.get(key)) |pressed_at| {
|
||||||
|
return now - pressed_at;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn releaseAll(self: *@This()) void {
|
pub fn releaseAll(self: *@This()) void {
|
||||||
var iter = self.down.iterator();
|
var iter = self.pressed_at.iterator();
|
||||||
while (iter.next()) |key| {
|
while (iter.next()) |e| {
|
||||||
self.release(key);
|
self.release(e.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -105,10 +105,11 @@ fn PlatformType(App: type) type {
|
|||||||
_ = self.frame_arena.reset(.free_all); // TODO: make arena reset mode configurable
|
_ = self.frame_arena.reset(.free_all); // TODO: make arena reset mode configurable
|
||||||
|
|
||||||
const now = Io.Timestamp.now(self.io, .awake);
|
const now = Io.Timestamp.now(self.io, .awake);
|
||||||
const t = self.started_at.durationTo(now);
|
|
||||||
const dt = self.last_frame_at.durationTo(now);
|
|
||||||
self.last_frame_at = now;
|
self.last_frame_at = now;
|
||||||
|
|
||||||
|
self.input.now = @intCast(self.started_at.durationTo(now).nanoseconds);
|
||||||
|
self.input.delta_time = @intCast(self.last_frame_at.durationTo(now).nanoseconds);
|
||||||
|
|
||||||
if (self.input.keyboard.pressed.contains(.F4)) {
|
if (self.input.keyboard.pressed.contains(.F4)) {
|
||||||
self.show_imgui = !self.show_imgui;
|
self.show_imgui = !self.show_imgui;
|
||||||
}
|
}
|
||||||
@ -126,8 +127,6 @@ fn PlatformType(App: type) type {
|
|||||||
|
|
||||||
if (@hasDecl(App, "frame")) {
|
if (@hasDecl(App, "frame")) {
|
||||||
const plt = Frame{
|
const plt = Frame{
|
||||||
.t = t.nanoseconds,
|
|
||||||
.dt = dt.nanoseconds,
|
|
||||||
.gpa = self.gpa,
|
.gpa = self.gpa,
|
||||||
.arena = self.arena.allocator(),
|
.arena = self.arena.allocator(),
|
||||||
.io = self.io,
|
.io = self.io,
|
||||||
@ -195,7 +194,9 @@ fn PlatformType(App: type) type {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.keyboard.press(key);
|
const now = self.started_at.durationTo(Io.Timestamp.now(self.io, .awake));
|
||||||
|
|
||||||
|
input.keyboard.press(key, @intCast(now.nanoseconds));
|
||||||
self.last_key_pressed = key;
|
self.last_key_pressed = key;
|
||||||
},
|
},
|
||||||
.key_released => |key| {
|
.key_released => |key| {
|
||||||
@ -204,13 +205,16 @@ fn PlatformType(App: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input.keyboard.release(key);
|
input.keyboard.release(key);
|
||||||
|
input.last_key_repeat_at.remove(key);
|
||||||
},
|
},
|
||||||
.mouse_pressed => |button| {
|
.mouse_pressed => |button| {
|
||||||
if (input.mouse_position == null or input.isMouseDown(button)) {
|
if (input.mouse_position == null or input.isMouseDown(button)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.mouse_buttons.press(button);
|
const now = self.started_at.durationTo(Io.Timestamp.now(self.io, .awake));
|
||||||
|
|
||||||
|
input.mouse_buttons.press(button, @intCast(now.nanoseconds));
|
||||||
},
|
},
|
||||||
.mouse_released => |button| {
|
.mouse_released => |button| {
|
||||||
if (input.mouse_position == null or !input.isMouseDown(button)) {
|
if (input.mouse_position == null or !input.isMouseDown(button)) {
|
||||||
@ -274,8 +278,8 @@ fn PlatformType(App: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(input.mouse_position == null);
|
assert(input.mouse_position == null);
|
||||||
assert(input.keyboard.down.eql(.empty));
|
assert(input.keyboard.pressed_at.count() == 0);
|
||||||
assert(input.mouse_buttons.down.eql(.empty));
|
assert(input.mouse_buttons.pressed_at.count() == 0);
|
||||||
input.focused = false;
|
input.focused = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,13 +310,13 @@ fn PlatformType(App: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (e == .unfocused) {
|
if (e == .unfocused) {
|
||||||
var key_iter = input.keyboard.down.iterator();
|
var key_iter = input.keyboard.pressed_at.iterator();
|
||||||
while (key_iter.next()) |key| {
|
while (key_iter.next()) |key_pressed_at| {
|
||||||
self.appendEvent(.{ .key_released = key });
|
self.appendEvent(.{ .key_released = key_pressed_at.key });
|
||||||
}
|
}
|
||||||
var mouse_buttons_iter = input.mouse_buttons.down.iterator();
|
var mouse_buttons_iter = input.mouse_buttons.pressed_at.iterator();
|
||||||
while (mouse_buttons_iter.next()) |button| {
|
while (mouse_buttons_iter.next()) |key_pressed_at| {
|
||||||
self.appendEvent(.{ .mouse_released = button });
|
self.appendEvent(.{ .mouse_released = key_pressed_at.key });
|
||||||
}
|
}
|
||||||
self.appendEvent(.{ .mouse_leave = {} });
|
self.appendEvent(.{ .mouse_leave = {} });
|
||||||
}
|
}
|
||||||
@ -566,12 +570,9 @@ pub const Deinit = struct {
|
|||||||
io: Io,
|
io: Io,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Nanoseconds = i96;
|
pub const Nanoseconds = i64;
|
||||||
|
|
||||||
pub const Frame = struct {
|
pub const Frame = struct {
|
||||||
t: Nanoseconds,
|
|
||||||
dt: Nanoseconds,
|
|
||||||
|
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
arena: Allocator,
|
arena: Allocator,
|
||||||
frame: Allocator,
|
frame: Allocator,
|
||||||
@ -580,16 +581,16 @@ pub const Frame = struct {
|
|||||||
input: *Input,
|
input: *Input,
|
||||||
input_events: []Input.Event,
|
input_events: []Input.Event,
|
||||||
|
|
||||||
fn nanosecondsToSeconds(nanoseconds: i96) f32 {
|
fn nanosecondsToSeconds(nanoseconds: Nanoseconds) f32 {
|
||||||
return @floatCast(@as(f64, @floatFromInt(nanoseconds)) / std.time.ns_per_s);
|
return @floatCast(@as(f64, @floatFromInt(nanoseconds)) / std.time.ns_per_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deltaTime(self: Frame) f32 {
|
pub fn deltaTime(self: Frame) f32 {
|
||||||
return nanosecondsToSeconds(self.dt);
|
return nanosecondsToSeconds(self.input.delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time(self: Frame) f32 {
|
pub fn time(self: Frame) f32 {
|
||||||
return nanosecondsToSeconds(self.t);
|
return nanosecondsToSeconds(self.input.now);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user