From 3b59929a343c7e209a093ce595b0ddd43888d30b Mon Sep 17 00:00:00 2001 From: Brandon Skewes Date: Sun, 7 Dec 2025 15:52:04 +1100 Subject: [PATCH] added player --- src/entities/player.zig | 207 ++++++++++++++++++++++++++++++++++++++++ src/main.zig | 54 ++++++----- 2 files changed, 237 insertions(+), 24 deletions(-) create mode 100644 src/entities/player.zig diff --git a/src/entities/player.zig b/src/entities/player.zig new file mode 100644 index 0000000..445c172 --- /dev/null +++ b/src/entities/player.zig @@ -0,0 +1,207 @@ +const rl = @import("raylib"); + +pub const premium_character_path = "/Users/ratludu/Downloads/Sprout Lands - Sprites - premium pack/Characters/Premium Charakter Spritesheet.png"; + +const state = enum { idle, hoeForward, walkLeft, walkRight, walkUp, walkDown }; +const direction = enum { left, right, up, down }; +const animations = enum { repeating, oneshot }; + +pub const Animation = struct { + type: animations, + first: u32, + last: u32, + current: u32, + + speed: f32, + durationLeft: f32, + + pub fn init(animation_type: animations, first: u32, last: u32, current: u32) Animation { + return Animation{ + .type = animation_type, + .first = first, + .last = last, + .current = current, + .speed = 0.1, + .durationLeft = 0.1, + }; + } + + pub fn animation_frame(self: *Animation, num_frames_per_row: u32, tile_size: f32) rl.Rectangle { + const x: f32 = @as(f32, @floatFromInt(self.current % num_frames_per_row)) * tile_size; + const y: f32 = @as(f32, @floatFromInt(self.current / num_frames_per_row)) * tile_size; + + return rl.Rectangle{ + .x = x, + .y = y, + .width = tile_size, + .height = tile_size, + }; + } + + pub fn animationUpdate(self: *Animation) void { + const dt: f32 = rl.getFrameTime(); + self.durationLeft -= dt; + + if (self.durationLeft <= 0.0) { + self.durationLeft = self.speed; + self.current += 1; + + if (self.current > self.last) { + switch (self.type) { + .repeating => blk: { + self.current = self.first; + break :blk; + }, + .oneshot => blk: { + self.current = self.last; + break :blk; + }, + } + } + } + } +}; + +pub const Player = struct { + sourceRect: rl.Rectangle, + playerSprite: rl.Texture2D, + playerState: state, + playerDirection: direction, + anim: Animation, + + pub fn init() rl.RaylibError!Player { + const player_sprite = try rl.loadTexture(premium_character_path); + var source_rect = rl.Rectangle.init(0, 0, 48, 48); + _ = &source_rect; + + var anim = Animation.init(.repeating, 0, 7, 0); + _ = &anim; + + return Player{ + .sourceRect = source_rect, + .playerSprite = player_sprite, + .playerState = state.idle, + .playerDirection = direction.down, + .anim = anim, + }; + } + + pub fn update(self: *Player, new_state: state) void { + if (new_state == self.playerState) { + return; + } + + self.playerState = new_state; + + switch (self.playerState) { + .idle => blk: { + idleAnimation(self); + break :blk; + }, + .hoeForward => blk: { + hoeForward(self); + break :blk; + }, + .walkLeft => blk: { + walkLeft(self); + break :blk; + }, + .walkRight => blk: { + walkRight(self); + break :blk; + }, + .walkUp => blk: { + walkUp(self); + break :blk; + }, + .walkDown => blk: { + walkDown(self); + break :blk; + }, + } + } + + pub fn animate(self: *Player, screenWidth: i32, screenHeight: i32) void { + rl.drawTexturePro(self.playerSprite, self.anim.animation_frame(8, 48), .{ .x = @floatFromInt(@divFloor(screenWidth, 2) - 100 / 2), .y = @floatFromInt(@divFloor(screenHeight, 2) - 100 / 2), .width = 100, .height = 100 }, .{ .x = 0.0, .y = 0.0 }, 0.0, .white); + } + + pub fn idleAnimation(self: *Player) void { + var anim = Animation.init(.repeating, 0, 7, 0); + _ = &anim; + self.anim = anim; + } + + pub fn hoeForward(self: *Player) void { + const first = 12 * 8; + var anim = Animation.init(.oneshot, first, first + 7, first); + _ = &anim; + self.anim = anim; + } + + pub fn walkLeft(self: *Player) void { + const first = 8 * 7; + var anim = Animation.init(.oneshot, first, first + 7, first); + _ = &anim; + self.anim = anim; + } + + pub fn walkRight(self: *Player) void { + const first = 8 * 6; + var anim = Animation.init(.oneshot, first, first + 7, first); + _ = &anim; + self.anim = anim; + } + + pub fn walkUp(self: *Player) void { + const first = 8 * 9; + var anim = Animation.init(.oneshot, first, first + 7, first); + _ = &anim; + self.anim = anim; + } + + pub fn walkDown(self: *Player) void { + const first = 8 * 8; + var anim = Animation.init(.oneshot, first, first + 7, first); + _ = &anim; + self.anim = anim; + } + + pub fn walkingUpdate(self: *Player) void { + if (rl.isKeyDown(rl.KeyboardKey.a)) { + self.update(.walkLeft); + } + + if (rl.isKeyDown(rl.KeyboardKey.d)) { + self.update(.walkRight); + } + + if (rl.isKeyDown(rl.KeyboardKey.w)) { + self.update(.walkUp); + } + if (rl.isKeyDown(rl.KeyboardKey.s)) { + self.update(.walkDown); + } + } + + pub fn resetToIdle(self: *Player) void { + if (self.anim.current == self.anim.last and self.anim.type == .oneshot) { + self.update(.idle); + } + + if (!rl.isKeyDown(rl.KeyboardKey.a) and self.playerState == .walkLeft) { + self.update(.idle); + } + + if (!rl.isKeyDown(rl.KeyboardKey.d) and self.playerState == .walkRight) { + self.update(.idle); + } + + if (!rl.isKeyDown(rl.KeyboardKey.s) and self.playerState == .walkDown) { + self.update(.idle); + } + + if (!rl.isKeyDown(rl.KeyboardKey.w) and self.playerState == .walkUp) { + self.update(.idle); + } + } +}; diff --git a/src/main.zig b/src/main.zig index 2a2bc6c..c52b41a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,18 @@ const std = @import("std"); const Hidden_Leaf_Island = @import("Hidden_Leaf_Island"); const rl = @import("raylib"); +const Entities = @import("entities/player.zig"); + +fn toggleFullScreen(windowWidth: i32, windowHeight: i32) void { + if (!rl.isWindowFullscreen()) { + const monitor = rl.getCurrentMonitor(); + rl.setWindowSize(rl.getMonitorWidth(monitor), rl.getMonitorHeight(monitor)); + rl.toggleFullscreen(); + } else { + rl.toggleFullscreen(); + rl.setWindowSize(windowWidth, windowHeight); + } +} pub fn main() anyerror!void { // Initialization @@ -13,31 +25,25 @@ pub fn main() anyerror!void { rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- - const sprite = try rl.loadTexture("/home/ratludu/assets/Sprout Lands - Sprites - premium pack/Characters/Basic Charakter Actions.png"); - defer rl.unloadTexture(sprite); - - const sourceRect = rl.Rectangle{ - .x = 0.0, - .y = 0.0, - .width = 32.0, - .height = 32.0, - }; - - const destRect = rl.Rectangle{ - .x = screenWidth / 2 - 32, - .y = screenHeight / 2 - 32, - .width = 64.0, - .height = 64.0, - }; - - const positiion = rl.Vector2{ - .x = destRect.width + destRect.width / 2, - .y = destRect.height + destRect.width / 2, - }; + var player = try Entities.Player.init(); + defer rl.unloadTexture(player.playerSprite); // Main game loop while (!rl.windowShouldClose()) { // Detect window close button or ESC key + // Full screen toggle + if (rl.isKeyDown(rl.KeyboardKey.left_super) and rl.isKeyPressed(rl.KeyboardKey.f)) { + toggleFullScreen(screenWidth, screenHeight); + } // Update + + player.resetToIdle(); + + if (rl.isKeyDown(rl.KeyboardKey.e)) { + player.update(.hoeForward); + } + player.walkingUpdate(); + + player.anim.animationUpdate(); //---------------------------------------------------------------------------------- // TODO: Update your variables here //---------------------------------------------------------------------------------- @@ -46,11 +52,11 @@ pub fn main() anyerror!void { //---------------------------------------------------------------------------------- rl.beginDrawing(); defer rl.endDrawing(); - rl.drawTexturePro(sprite, sourceRect, destRect, positiion, 0.0, .white); - rl.clearBackground(.white); + player.animate(screenWidth, screenHeight); + + rl.clearBackground(.sky_blue); - rl.drawText("Congrats! You created your first window!", 190, 200, 20, .light_gray); //---------------------------------------------------------------------------------- } }