Animatable generic
This commit is contained in:
parent
0eb71cc4e6
commit
707fbd98bd
1 changed files with 122 additions and 36 deletions
158
src/main.zig
158
src/main.zig
|
@ -22,26 +22,26 @@ pub fn main() !void {
|
|||
);
|
||||
defer column.deinit();
|
||||
|
||||
var item1 = Item.init(
|
||||
var item1 = AnimatableItem{ .a = .{ .v = .init(
|
||||
raylib.LoadTexture("menu/game/CometCrash/ICON0.PNG"),
|
||||
"Comet Crash",
|
||||
"3/1/2025 23:11",
|
||||
);
|
||||
var item2 = Item.init(
|
||||
) } };
|
||||
var item2 = AnimatableItem{ .a = .{ .v = .init(
|
||||
raylib.LoadTexture("menu/game/LBP1/ICON0.PNG"),
|
||||
"LittleBigPlanet",
|
||||
"3/1/2025 23:15",
|
||||
);
|
||||
var item3 = Item.init(
|
||||
) } };
|
||||
var item3 = AnimatableItem{ .a = .{ .v = .init(
|
||||
raylib.LoadTexture("menu/game/LBP2/ICON0.PNG"),
|
||||
"LittleBigPlanet 2",
|
||||
"3/1/2025 23:26",
|
||||
);
|
||||
var item4 = Item.init(
|
||||
) } };
|
||||
var item4 = AnimatableItem{ .a = .{ .v = .init(
|
||||
raylib.LoadTexture("menu/game/LBP3/ICON0.PNG"),
|
||||
"LittleBigPlanet 3",
|
||||
"3/1/2025 23:48",
|
||||
);
|
||||
) } };
|
||||
try column.appendItem(&item1);
|
||||
try column.appendItem(&item2);
|
||||
try column.appendItem(&item3);
|
||||
|
@ -55,7 +55,7 @@ pub fn main() !void {
|
|||
scales.recalculate();
|
||||
}
|
||||
if (raylib.IsKeyPressed('D')) debug_draw = !debug_draw;
|
||||
if (raylib.IsKeyPressed('Z')) item1.setLarge(!item1.large);
|
||||
// if (raylib.IsKeyPressed('Z')) item1.setLarge(!item1.large);
|
||||
if (raylib.IsKeyPressed('S')) raylib.TakeScreenshot("screenshot.png");
|
||||
|
||||
column.updatePositions();
|
||||
|
@ -131,9 +131,8 @@ pub const Column = struct {
|
|||
icon: raylib.Texture2D,
|
||||
title: []const u8,
|
||||
|
||||
items: std.ArrayList(*Item),
|
||||
items: std.ArrayList(*AnimatableItem),
|
||||
selected: usize = 0,
|
||||
start_y: f32 = undefined,
|
||||
|
||||
pub fn init(allocator: Allocator, icon: raylib.Texture2D, title: []const u8) Column {
|
||||
raylib.SetTextureFilter(icon, raylib.TEXTURE_FILTER_BILINEAR);
|
||||
|
@ -173,18 +172,19 @@ pub const Column = struct {
|
|||
};
|
||||
|
||||
// self.start_y = scales.column_position_center.y + icon.box.h + title.box.h + scales.column_item_spacing;
|
||||
for (self.items.items) |item| item.draw();
|
||||
for (self.items.items) |item| item.update();
|
||||
for (self.items.items) |item| item.a.v.draw();
|
||||
|
||||
icon.draw();
|
||||
title.draw();
|
||||
}
|
||||
|
||||
pub fn appendItem(self: *Column, item: *Item) !void {
|
||||
pub fn appendItem(self: *Column, item: *AnimatableItem) !void {
|
||||
try self.items.append(item);
|
||||
self.refresh();
|
||||
}
|
||||
|
||||
pub fn insertItem(self: *Column, idx: usize, item: *Item) !void {
|
||||
pub fn insertItem(self: *Column, idx: usize, item: *AnimatableItem) !void {
|
||||
try self.items.insert(idx, item);
|
||||
self.refresh();
|
||||
}
|
||||
|
@ -206,18 +206,106 @@ pub const Column = struct {
|
|||
fn refresh(self: *Column) void {
|
||||
var y = scales.column_item_start;
|
||||
for (self.items.items[self.selected..]) |item| {
|
||||
item.setPosition(.{ .x = scales.column_position_center.x, .y = y });
|
||||
item.set("position", raylib.Vector2{ .x = scales.column_position_center.x, .y = y });
|
||||
y += scales.item_icon_small_height + scales.column_item_spacing;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn Animatable(comptime T: type, comptime props: anytype) type {
|
||||
const Type = @typeInfo(T);
|
||||
|
||||
var fields: [props.len * 2 + 2]std.builtin.Type.StructField = undefined;
|
||||
inline for (props, 0..) |prop, i| {
|
||||
const field = blk: inline for (Type.@"struct".fields) |f| {
|
||||
if (std.mem.eql(u8, f.name, prop)) break :blk f;
|
||||
};
|
||||
// const default_value = switch (field.type) {
|
||||
// f32 => 0,
|
||||
// raylib.Vector2 => .{ .x = 0, .y = 0 },
|
||||
// else => @compileError("no default value for type " ++ @typeName(field.type)),
|
||||
// };
|
||||
fields[i * 2] = .{
|
||||
.name = "start_" ++ prop,
|
||||
.type = field.type,
|
||||
.default_value_ptr = field.default_value_ptr,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
fields[i * 2 + 1] = .{
|
||||
.name = "target_" ++ prop,
|
||||
.type = field.type,
|
||||
.default_value_ptr = field.default_value_ptr,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
}
|
||||
fields[props.len * 2] = .{
|
||||
.name = "time",
|
||||
.type = f32,
|
||||
.default_value_ptr = &@as(f32, 0.0),
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
fields[props.len * 2 + 1] = .{
|
||||
.name = "v",
|
||||
.type = T,
|
||||
.default_value_ptr = null,
|
||||
.is_comptime = false,
|
||||
.alignment = 0,
|
||||
};
|
||||
|
||||
const Self = @Type(.{ .@"struct" = .{
|
||||
.layout = .auto,
|
||||
.fields = &fields,
|
||||
.decls = &[_]std.builtin.Type.Declaration{},
|
||||
.is_tuple = false,
|
||||
} });
|
||||
return struct {
|
||||
a: Self,
|
||||
|
||||
pub fn set(self: *@This(), comptime field_name: []const u8, value: anytype) void {
|
||||
self.a.time = 0;
|
||||
@field(self.a, "start_" ++ field_name) = @field(self.a.v, field_name);
|
||||
@field(self.a, "target_" ++ field_name) = value;
|
||||
}
|
||||
|
||||
pub fn update(self: *@This()) void {
|
||||
self.a.time += raylib.GetFrameTime();
|
||||
inline for (props) |prop| {
|
||||
const field = comptime blk: for (@typeInfo(T).@"struct".fields) |f| {
|
||||
if (std.mem.eql(u8, f.name, prop)) break :blk f;
|
||||
};
|
||||
@field(self.a.v, field.name) = switch (field.type) {
|
||||
f32 => std.math.lerp(
|
||||
@field(self.a, "start_" ++ field.name),
|
||||
@field(self.a, "target_" ++ field.name),
|
||||
easeOutExpo(self.a.time / 0.333),
|
||||
),
|
||||
raylib.Vector2 => raylib.Vector2Lerp(
|
||||
@field(self.a, "start_" ++ field.name),
|
||||
@field(self.a, "target_" ++ field.name),
|
||||
easeOutExpo(self.a.time / 0.333),
|
||||
),
|
||||
else => @compileError("cannot animate type " ++ @typeName(field.type)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn easeOutExpo(x: f32) f32 {
|
||||
return 1.0 - std.math.pow(f32, 2, -10 * std.math.clamp(x, 0.0, 1.0));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const AnimatableItem = Animatable(Item, .{"position"});
|
||||
|
||||
pub const Item = struct {
|
||||
position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
||||
// icon_scale: f32,
|
||||
// start_scale: f32,
|
||||
time: f32 = 0.0,
|
||||
start_position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
||||
// time: f32 = 0.0,
|
||||
// start_position: raylib.Vector2 = .{ .x = 0, .y = 0 },
|
||||
|
||||
icon: raylib.Texture2D,
|
||||
title: []const u8,
|
||||
|
@ -236,17 +324,18 @@ pub const Item = struct {
|
|||
}
|
||||
|
||||
pub fn draw(self: *Item) void {
|
||||
self.time += raylib.GetFrameTime();
|
||||
// self.time += raylib.GetFrameTime();
|
||||
// self.icon_scale = std.math.lerp(
|
||||
// self.start_scale,
|
||||
// if (self.large) scales.item_icon_large_scale else scales.item_icon_small_scale,
|
||||
// easeOutExpo(self.time / 0.333),
|
||||
// );
|
||||
const position = raylib.Vector2Lerp(
|
||||
self.start_position,
|
||||
self.position,
|
||||
easeOutExpo(self.time / 0.333),
|
||||
);
|
||||
// const position = raylib.Vector2Lerp(
|
||||
// self.start_position,
|
||||
// self.position,
|
||||
// easeOutExpo(self.time / 0.333),
|
||||
// );
|
||||
const position = self.position;
|
||||
|
||||
var icon = Image{
|
||||
.texture = self.icon,
|
||||
|
@ -289,21 +378,18 @@ pub const Item = struct {
|
|||
subtitle.draw();
|
||||
}
|
||||
|
||||
pub fn setLarge(self: *Item, large: bool) void {
|
||||
self.large = large;
|
||||
// self.time = 0;
|
||||
// self.start_scale = self.icon_scale;
|
||||
}
|
||||
// pub fn setLarge(self: *Item, large: bool) void {
|
||||
// self.large = large;
|
||||
// // self.time = 0;
|
||||
// // self.start_scale = self.icon_scale;
|
||||
// }
|
||||
|
||||
pub fn setPosition(self: *Item, position: raylib.Vector2) void {
|
||||
self.start_position = self.position;
|
||||
self.position = position;
|
||||
self.time = 0;
|
||||
}
|
||||
// pub fn setPosition(self: *Item, position: raylib.Vector2) void {
|
||||
// self.start_position = self.position;
|
||||
// self.position = position;
|
||||
// self.time = 0;
|
||||
// }
|
||||
|
||||
fn easeOutExpo(x: f32) f32 {
|
||||
return 1.0 - std.math.pow(f32, 2, -10 * std.math.clamp(x, 0.0, 1.0));
|
||||
}
|
||||
};
|
||||
|
||||
/// Draws the dynamic gradient background.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue