From 834db8b1f1f6b0fd8ebe966936d08191358b2077 Mon Sep 17 00:00:00 2001 From: jack Date: Mon, 2 Dec 2024 23:33:34 +0800 Subject: [PATCH] enhance 2d animation system: add wait time --- build.zig.zon | 2 +- examples/animation_2d.zig | 25 ++++++++++++------------ src/j2d/AnimationSystem.zig | 39 +++++++++++++++++++++++++++++++------ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index cfd83b9a..9b32ed39 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = "jok", - .version = "0.24.2", + .version = "0.25.0", .paths = .{ "README.md", "build.zig", diff --git a/examples/animation_2d.zig b/examples/animation_2d.zig index f3454901..02a89a5a 100644 --- a/examples/animation_2d.zig +++ b/examples/animation_2d.zig @@ -43,7 +43,7 @@ pub fn init(ctx: jok.Context) !void { .{ .sp = player.getSubSprite(3 * 16, 0, 16, 16) }, }, 6, - false, + .{}, ); try as.addSimple( "player_up", @@ -53,7 +53,7 @@ pub fn init(ctx: jok.Context) !void { .{ .sp = player.getSubSprite(6 * 16, 0, 16, 16) }, }, 6, - false, + .{}, ); try as.addSimple( "player_down", @@ -63,18 +63,19 @@ pub fn init(ctx: jok.Context) !void { .{ .sp = player.getSubSprite(0 * 16, 0, 16, 16) }, }, 6, - false, + .{}, ); - var dcmds: [10]j2d.AnimationSystem.Frame.Data = undefined; - for (0..10) |i| { + var dcmds: [20]j2d.AnimationSystem.Frame.Data = undefined; + for (0..dcmds.len) |i| { dcmds[i] = .{ .dcmd = .{ .cmd = .{ - .circle_fill = .{ + .circle = .{ .p = .{ .x = 0, .y = 0 }, - .radius = @floatFromInt(i * 10), - .color = jok.Color.rgb(@intCast(i * 48 % 255), @intCast(i * 16 % 255), @intCast(i * 32 % 255)).toInternalColor(), - .num_segments = @intCast(i), + .radius = @floatFromInt(@abs(100 - @as(i32, @intCast(i)) * 10)), + .color = jok.Color.rgb(@intCast(i * 50 % 255), @intCast(i * 50 % 255), 0).toInternalColor(), + .num_segments = 20, + .thickness = 6, }, }, .depth = 0.5, @@ -84,8 +85,8 @@ pub fn init(ctx: jok.Context) !void { try as.addSimple( "player_circle_bg", &dcmds, - 8, - true, + 10, + .{ .loop = true }, ); } @@ -138,7 +139,7 @@ pub fn draw(ctx: jok.Context) !void { .scale = .{ .x = 4, .y = 4 }, }, ); - { + if (!try as.isStopped("player_circle_bg")) { try b.pushTransform(j2d.AffineTransform.init().translate(pos)); defer b.popTransform(); try b.pushDrawCommand(((try as.getCurrentFrame("player_circle_bg")).dcmd)); diff --git a/src/j2d/AnimationSystem.zig b/src/j2d/AnimationSystem.zig index fbe203be..59617bfb 100644 --- a/src/j2d/AnimationSystem.zig +++ b/src/j2d/AnimationSystem.zig @@ -39,12 +39,17 @@ pub fn destroy(self: *Self) void { self.allocator.destroy(self); } +pub const AnimOption = struct { + wait_time: f32 = 0, + loop: bool = false, +}; + /// Add animation, each frame has its own duration pub fn add( self: *Self, name: []const u8, frames: []const Frame, - loop: bool, + opt: AnimOption, ) !void { assert(name.len > 0); assert(frames.len > 0); @@ -56,7 +61,8 @@ pub fn add( const anim = Animation{ .name = dname, .frames = try self.allocator.alloc(Frame, frames.len), - .loop = loop, + .wait_time = opt.wait_time, + .loop = opt.loop, .play_index = 0, .passed_time = 0, .is_over = false, @@ -73,7 +79,7 @@ pub fn addSimple( name: []const u8, frames: []const Frame.Data, fps: f32, - loop: bool, + opt: AnimOption, ) !void { assert(name.len > 0); assert(frames.len > 0); @@ -86,7 +92,8 @@ pub fn addSimple( const anim = Animation{ .name = dname, .frames = try self.allocator.alloc(Frame, frames.len), - .loop = loop, + .wait_time = opt.wait_time, + .loop = opt.loop, .play_index = 0, .passed_time = 0, .is_over = false, @@ -152,10 +159,23 @@ pub fn isOver(self: Self, name: []const u8) !bool { return error.NameNotExist; } +// Get animation's stop state +pub fn isStopped(self: Self, name: []const u8) !bool { + if (self.animations.get(name)) |anim| { + return anim.is_stopped; + } + return error.NameNotExist; +} + /// Reset animation's status (clear over/stop state) pub fn reset(self: *Self, name: []const u8) !void { + try self.resetWait(name, 0); +} + +/// Reset animation's status (clear over/stop state), with wait time +pub fn resetWait(self: *Self, name: []const u8, wait_time: f32) !void { if (self.animations.getPtr(name)) |anim| { - return anim.reset(); + return anim.reset(wait_time); } return error.NameNotExist; } @@ -191,13 +211,15 @@ pub const Frame = struct { pub const Animation = struct { name: []u8, frames: []Frame, + wait_time: f32, loop: bool, play_index: u32, passed_time: f32, is_over: bool, is_stopped: bool, - pub fn reset(anim: *Animation) void { + pub fn reset(anim: *Animation, wait_time: f32) void { + anim.wait_time = wait_time; anim.play_index = 0; anim.passed_time = 0; anim.is_over = false; @@ -211,6 +233,11 @@ pub const Animation = struct { fn update(anim: *Animation, delta_tick: f32) void { if (anim.is_over or anim.is_stopped) return; anim.passed_time += delta_tick; + if (anim.passed_time < anim.wait_time) return; + if (anim.wait_time > 0) { + anim.passed_time -= anim.wait_time; + anim.wait_time = 0; // only take effect once + } while (anim.passed_time >= anim.frames[anim.play_index].duration) { anim.passed_time -= anim.frames[anim.play_index].duration; anim.play_index += 1;