Animation

master
Louis Pearson 2022-01-15 00:04:26 -07:00
parent 0f56ac1f2c
commit 7a9626f839
1 changed files with 108 additions and 14 deletions

View File

@ -4,24 +4,105 @@ const ecs = @import("ecs.zig");
const assets = @import("assets"); const assets = @import("assets");
const Vec2f = std.meta.Vector(2, f32); const Vec2f = std.meta.Vector(2, f32);
const Anim = struct {
time: usize = 0,
currentOp: usize = 0,
delayUntil: usize = 0,
anim: []const Ops,
stopped: bool = false,
pub const Ops = union(enum) { Index: usize, Wait: usize, Stop };
pub fn play(this: *@This(), anim: []const Ops) void {
if (this.anim.ptr == anim.ptr) return;
this.anim = anim;
this.stopped = false;
this.currentOp = 0;
}
pub fn update(this: *@This(), out: *usize) void {
this.time += 1;
while (!this.stopped and this.anim.len > 0 and this.time >= this.delayUntil) {
switch (this.anim[this.currentOp]) {
.Index => |index| out.* = index,
.Wait => |wait| this.delayUntil = this.time + wait,
.Stop => this.stopped = true,
}
this.currentOp = (this.currentOp + 1) % this.anim.len;
}
}
pub fn simple(rate: usize, comptime arr: []const usize) [arr.len * 2]Ops {
var anim: [arr.len * 2]Ops = undefined;
inline for (arr) |item, i| {
anim[i * 2] = Ops{ .Index = item };
anim[i * 2 + 1] = Ops{ .Wait = rate };
}
return anim;
}
pub fn frame(comptime index: usize) [2]Ops {
return [_]Ops{ .{ .Index = index }, .Stop };
}
};
// Components
const Pos = Vec2f; const Pos = Vec2f;
const Control = enum { player }; const Control = struct { controller: enum { player }, state: enum { stand, walk, jump, fall } };
const Sprite = usize;
const StaticAnim = Anim;
const ControlAnim = struct { anims: []AnimData, state: Anim };
const Component = struct { const Component = struct {
pos: Pos, pos: Pos,
control: Control, control: Control,
sprite: Sprite,
staticAnim: StaticAnim,
controlAnim: ControlAnim,
}; };
const World = ecs.World(Component); const World = ecs.World(Component);
// Global vars
const KB = 1024; const KB = 1024;
var heap: [1 * KB]u8 = undefined; var heap: [1 * KB]u8 = undefined;
var fba = std.heap.FixedBufferAllocator.init(&heap); var fba = std.heap.FixedBufferAllocator.init(&heap);
var world: World = World.init(fba.allocator()); var world: World = World.init(fba.allocator());
const anim_store = struct {
const stand = Anim.frame(0);
const walk = Anim.simple(4, &[_]usize{ 1, 2, 3, 4 });
const jump = Anim.frame(5);
const fall = Anim.frame(6);
};
const AnimData = []const Anim.Ops;
const playerAnim = pac: {
var animArr = std.BoundedArray(AnimData, 100).init(0) catch unreachable;
animArr.append(&anim_store.stand) catch unreachable;
animArr.append(&anim_store.walk) catch unreachable;
animArr.append(&anim_store.jump) catch unreachable;
animArr.append(&anim_store.fall) catch unreachable;
break :pac animArr.slice();
};
export fn start() void { export fn start() void {
_ = world.create(.{ .pos = .{ 76, 76 }, .control = .player }); _ = world.create(.{
.pos = .{ 76, 76 },
.control = .{ .controller = .player, .state = .stand },
.sprite = 0,
.controlAnim = ControlAnim{
.anims = playerAnim,
.state = Anim{ .anim = &.{} },
},
});
} }
export fn update() void { export fn update() void {
world.process(1, &.{ .pos, .control }, controlProcess);
world.process(1, &.{ .sprite, .staticAnim }, staticAnimProcess);
world.process(1, &.{ .sprite, .controlAnim, .control }, controlAnimProcess);
world.process(1, &.{ .pos, .sprite }, drawProcess);
w4.DRAW_COLORS.* = 2; w4.DRAW_COLORS.* = 2;
w4.text("Hello from Zig!", .{ 10, 10 }); w4.text("Hello from Zig!", .{ 10, 10 });
@ -29,24 +110,37 @@ export fn update() void {
w4.DRAW_COLORS.* = 4; w4.DRAW_COLORS.* = 4;
} }
world.process(1, &.{ .pos, .control }, controlProcess);
world.process(1, &.{.pos}, drawProcess);
w4.DRAW_COLORS.* = 2;
// w4.blit(&smiley, .{ 76, 76 }, .{ 8, 8 }, .{ .bpp = .b1 }); // w4.blit(&smiley, .{ 76, 76 }, .{ 8, 8 }, .{ .bpp = .b1 });
w4.text("Press X to blink", .{ 16, 90 }); w4.text("Press X to blink", .{ 16, 90 });
} }
fn drawProcess(_: f32, pos: *Pos) void { fn drawProcess(_: f32, pos: *Pos, sprite: *Sprite) void {
w4.DRAW_COLORS.* = 0x0030; w4.DRAW_COLORS.* = 0x0030;
w4.externs.blitSub(&assets.sprites, @floatToInt(i32, pos.*[0]), @floatToInt(i32, pos.*[1]), 8, 8, 0, 0, 128, assets.sprites_flags); const tx = (sprite.* * 8) % 128;
const ty = (sprite.* * 8) / 128;
w4.externs.blitSub(&assets.sprites, @floatToInt(i32, pos.*[0]), @floatToInt(i32, pos.*[1]), 8, 8, tx, ty, 128, assets.sprites_flags);
}
fn staticAnimProcess(_: f32, sprite: *Sprite, anim: *StaticAnim) void {
anim.update(sprite);
}
fn controlAnimProcess(_: f32, sprite: *Sprite, anim: *ControlAnim, control: *Control) void {
const a: usize = if (control.state == .stand) 0 else 1;
anim.state.play(anim.anims[a]);
anim.state.update(sprite);
} }
fn controlProcess(_: f32, pos: *Pos, control: *Control) void { fn controlProcess(_: f32, pos: *Pos, control: *Control) void {
_ = control; var delta = Vec2f{ 0, 0 };
if (w4.GAMEPAD1.button_up) pos.*[1] -= 1; if (w4.GAMEPAD1.button_up) delta[1] -= 1;
if (w4.GAMEPAD1.button_down) pos.*[1] += 1; if (w4.GAMEPAD1.button_down) delta[1] += 1;
if (w4.GAMEPAD1.button_left) pos.*[0] -= 1; if (w4.GAMEPAD1.button_left) delta[0] -= 1;
if (w4.GAMEPAD1.button_right) pos.*[0] += 1; if (w4.GAMEPAD1.button_right) delta[0] += 1;
// w4.trace("here", .{}); if (delta[0] != 0 or delta[1] != 0) {
control.state = .walk;
pos.* += delta;
} else {
control.state = .stand;
}
} }