diff --git a/src/main.odin b/src/main.odin index 723cba6..20a5dff 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,6 +1,7 @@ package main import "core:fmt" +import "core:strings" import "vendor:raylib" player: Player @@ -42,6 +43,7 @@ main :: proc() { raylib.EndMode2D() raylib.DrawFPS(20, 20) + draw_player_grid_debug() raylib.EndDrawing() update(delta) @@ -62,3 +64,16 @@ draw :: proc() { draw_player(&player) } +draw_player_grid_debug :: proc() { + gx, gy := player_pos_to_grid_pos() + + tile := get_tile(&interactables_layer_grid, gx, gy) + type := tile.type + + s := fmt.tprintf("Player Grid Pos: (%d, %d) | Tile: %v", gx, gy, type) + cs := strings.clone_to_cstring(s, context.temp_allocator) + + + raylib.DrawText(cs, 20, 40, 20, raylib.GREEN) +} + diff --git a/src/player.odin b/src/player.odin index 78fd23c..a5940a2 100644 --- a/src/player.odin +++ b/src/player.odin @@ -1,7 +1,6 @@ package main -import "core:fmt" -import "core:strings" +import "core:math" import "vendor:raylib" PLAYER_SPRINT_SPEED :: 2.5 @@ -58,44 +57,40 @@ handle_player_input :: proc(p: ^Player, delta: f32) { is_moving := dir.x != 0 || dir.y != 0 - if (is_moving) { - is_sprinting := false - - if raylib.IsKeyDown(.LEFT_SHIFT) { - is_sprinting = true - } else { - is_sprinting = false - } - + if is_moving { + is_sprinting := raylib.IsKeyDown(.LEFT_SHIFT) dir = raylib.Vector2Normalize(dir) - if is_sprinting { - dir = dir * PLAYER_SPRINT_SPEED - p.animator.anim.fps = 11 - } else { - dir = dir * PLAYER_SPEED - p.animator.anim.fps = 6 + speed: f32 = is_sprinting ? PLAYER_SPRINT_SPEED : PLAYER_SPEED + p.animator.anim.fps = is_sprinting ? 11 : 6 + + velocity := dir * speed + + new_pos_x := p.position + new_pos_x.x += velocity.x + + foot_offset_y := f32(p.sprite.height) + foot_offset_x := f32(p.sprite.width) * 0.5 + + if !is_wall_at({new_pos_x.x + foot_offset_x, new_pos_x.y + foot_offset_y}) { + p.position.x = new_pos_x.x } - p.position = p.position + dir - - if dir.x < 0 { - p.facing_left = true + new_pos_y := p.position + new_pos_y.y += velocity.y + if !is_wall_at({p.position.x + foot_offset_x, new_pos_y.y + foot_offset_y}) { + p.position.y = new_pos_y.y } - if dir.x > 0 { - p.facing_left = false - } + if dir.x < 0 do p.facing_left = true + if dir.x > 0 do p.facing_left = false p.state = .WALKING } else { p.state = .IDLE } - - } - idle_animation: SpriteAnimation = { start_frame = 0, end_frame = 5, @@ -111,10 +106,6 @@ player_walk_anim: SpriteAnimation = { } draw_player :: proc(p: ^Player) { - // raylib.DrawRectangle(i32(p.position.x), i32(p.position.y), 32, 32, raylib.BLACK) - - // draw_sprite_frame(&p.sprite, {0, 0}, p.position, raylib.WHITE) - draw_sprite_animated(&p.sprite, &p.animator, p.position, p.facing_left, false, raylib.WHITE) } @@ -133,3 +124,26 @@ update_player :: proc(p: ^Player, delta: f32) { update_animator(&p.animator, delta) } +player_pos_to_grid_pos :: proc() -> (gx: int, gy: int) { + tile_size := f32(TILEMAP_TILE_SIZE) + + foot_x := player.position.x + (f32(player.sprite.width) * 0.5) + foot_y := player.position.y + f32(player.sprite.height) + + gx = int(math.floor(foot_x / tile_size)) + gy = int(math.floor(foot_y / tile_size)) + + return +} + +is_wall_at :: proc(world_pos: raylib.Vector2) -> bool { + tile_size := f32(TILEMAP_TILE_SIZE) + + gx := int(math.floor(world_pos.x / tile_size)) + gy := int(math.floor(world_pos.y / tile_size)) + + tile := get_tile(&ground_layer_grid, gx, gy) + + return tile != nil && tile.type == .WALL +} + diff --git a/src/tile.odin b/src/tile.odin index c3ad0ce..5cfcbb6 100644 --- a/src/tile.odin +++ b/src/tile.odin @@ -53,6 +53,15 @@ ground_tile := Tile { animator = nil, } +test_wall_tile := Tile { + type = .WALL, + frame_index = 1, + color = raylib.WHITE, + interaction = .NONE, + resource = .NONE, + animator = nil, +} + plant_tile := Tile { type = .FLORA, frame_index = 0, @@ -116,7 +125,3 @@ update_tile_anim :: proc(tile: ^Tile, delta: f32) { tile.frame_index = tile.animator.current_frame } -set_tile :: proc(grid: [][]Tile, x: int, y: int, tile: Tile) { - grid[y][x] = tile -} - diff --git a/src/tilemap.odin b/src/tilemap.odin index 4f52721..04c31a4 100644 --- a/src/tilemap.odin +++ b/src/tilemap.odin @@ -1,6 +1,5 @@ package main -import "core:fmt" import "vendor:raylib" TilemapSpritesheet :: struct { @@ -16,6 +15,12 @@ VisibleTileRange :: struct { end_x, end_y: int, } +Grid :: struct { + width: int, + height: int, + tiles: []Tile, +} + load_tilemap_sheet :: proc(path: cstring, tile_width, tile_height: i32) -> TilemapSpritesheet { tex := raylib.LoadTexture(path) @@ -28,60 +33,52 @@ load_tilemap_sheet :: proc(path: cstring, tile_width, tile_height: i32) -> Tilem } } -create_tile_grid :: proc(width, height: i32, fill_tile: Tile) -> [][]Tile { - grid: [][]Tile = make([][]Tile, height) - for y := 0; y < int(height); y += 1 { - grid[y] = make([]Tile, width) - for x := 0; x < int(width); x += 1 { - grid[y][x] = fill_tile - } +create_tile_grid :: proc(width, height: i32, fill_tile: Tile) -> Grid { + w, h := int(width), int(height) + grid_slice := make([]Tile, w * h) + + for i := 0; i < len(grid_slice); i += 1 { + grid_slice[i] = fill_tile } - return grid + + return Grid{width = w, height = h, tiles = grid_slice} } -update_tile_grid :: proc( - grid: [][]Tile, - camera: ^raylib.Camera2D, - tile_w, tile_h: f32, - delta: f32, -) { +update_tile_grid :: proc(grid: ^Grid, camera: ^raylib.Camera2D, tile_w, tile_h: f32, delta: f32) { range := get_visible_tile_range(grid, tile_w, tile_h, camera) for y := range.start_y; y <= range.end_y; y += 1 { - row := grid[y] for x := range.start_x; x <= range.end_x; x += 1 { - update_tile_anim(&row[x], delta) + tile := &grid.tiles[y * grid.width + x] + update_tile_anim(tile, delta) } } } - -draw_tile_grid :: proc(sheet: ^TilemapSpritesheet, grid: [][]Tile, camera: ^raylib.Camera2D) { +draw_tile_grid :: proc(sheet: ^TilemapSpritesheet, grid: ^Grid, camera: ^raylib.Camera2D) { tile_w := f32(sheet.tile_width) tile_h := f32(sheet.tile_height) range := get_visible_tile_range(grid, tile_w, tile_h, camera) for y := range.start_y; y <= range.end_y; y += 1 { - row := grid[y] for x := range.start_x; x <= range.end_x; x += 1 { - tile := &row[x] - if tile.type == TileType.NOTHING do continue + tile := &grid.tiles[y * grid.width + x] + + if tile.type == .NOTHING do continue pos := raylib.Vector2{f32(x) * tile_w, f32(y) * tile_h} - draw_tile(sheet, tile, pos, raylib.WHITE) } } } get_visible_tile_range :: proc( - grid: [][]Tile, + grid: ^Grid, tile_w, tile_h: f32, camera: ^raylib.Camera2D, padding: int = 1, ) -> VisibleTileRange { - screen_w := f32(raylib.GetScreenWidth()) screen_h := f32(raylib.GetScreenHeight()) @@ -98,12 +95,27 @@ get_visible_tile_range :: proc( end_x := int(max_x / tile_w) + padding end_y := int(max_y / tile_h) + padding - start_x = max(start_x, 0) - start_y = max(start_y, 0) - - end_x = min(end_x, len(grid[0]) - 1) - end_y = min(end_y, len(grid) - 1) - - return VisibleTileRange{start_x = start_x, start_y = start_y, end_x = end_x, end_y = end_y} + return VisibleTileRange { + start_x = clamp(start_x, 0, grid.width - 1), + start_y = clamp(start_y, 0, grid.height - 1), + end_x = clamp(end_x, 0, grid.width - 1), + end_y = clamp(end_y, 0, grid.height - 1), + } +} + +get_tile :: proc(grid: ^Grid, x, y: int) -> ^Tile { + if x < 0 || x >= grid.width || y < 0 || y >= grid.height do return nil + return &grid.tiles[y * grid.width + x] +} + +set_tile :: proc(grid: ^Grid, x: int, y: int, tile: Tile) { + if x < 0 || x >= grid.width || y < 0 || y >= grid.height do return + grid.tiles[y * grid.width + x] = tile +} + +delete_tile_grid :: proc(grid: ^Grid) { + delete(grid.tiles) + grid.width = 0 + grid.height = 0 } diff --git a/src/world.odin b/src/world.odin index 245d12b..2401434 100644 --- a/src/world.odin +++ b/src/world.odin @@ -3,10 +3,10 @@ package main WORLD_SIZE_X :: 1000 WORLD_SIZE_Y :: 1000 -ground_layer_grid: [][]Tile +ground_layer_grid: Grid ground_tilemap_sheet: TilemapSpritesheet -interactables_layer_grid: [][]Tile +interactables_layer_grid: Grid interactables_tilemap_sheet: TilemapSpritesheet init_world :: proc() { @@ -25,31 +25,41 @@ init_world :: proc() { ground_layer_grid = create_tile_grid(WORLD_SIZE_X, WORLD_SIZE_Y, ground_tile) interactables_layer_grid = create_tile_grid(WORLD_SIZE_X, WORLD_SIZE_Y, nothing_tile) - set_tile(interactables_layer_grid, 2, 2, plant_tile) - set_tile(interactables_layer_grid, 4, 2, plant_2_tile) - set_tile(interactables_layer_grid, 6, 2, plant_3_tile) + set_tile(&interactables_layer_grid, 2, 2, plant_tile) + set_tile(&interactables_layer_grid, 4, 2, plant_2_tile) + set_tile(&interactables_layer_grid, 6, 2, plant_3_tile) + + set_tile(&ground_layer_grid, 5, 5, test_wall_tile) + set_tile(&ground_layer_grid, 6, 5, test_wall_tile) + set_tile(&ground_layer_grid, 7, 5, test_wall_tile) + set_tile(&ground_layer_grid, 8, 5, test_wall_tile) +} + +deinit_world :: proc() { + delete_tile_grid(&ground_layer_grid) + delete_tile_grid(&interactables_layer_grid) } update_world :: proc(delta: f32) { update_tile_grid( - ground_layer_grid, + &ground_layer_grid, &player.camera, - f32(ground_tilemap_sheet.tile_width), - f32(ground_tilemap_sheet.tile_height), + f32(TILEMAP_TILE_SIZE), + f32(TILEMAP_TILE_SIZE), delta, ) update_tile_grid( - interactables_layer_grid, + &interactables_layer_grid, &player.camera, - f32(interactables_tilemap_sheet.tile_width), - f32(interactables_tilemap_sheet.tile_height), + f32(TILEMAP_TILE_SIZE), + f32(TILEMAP_TILE_SIZE), delta, ) } draw_world :: proc() { - draw_tile_grid(&ground_tilemap_sheet, ground_layer_grid, &player.camera) - draw_tile_grid(&interactables_tilemap_sheet, interactables_layer_grid, &player.camera) + draw_tile_grid(&ground_tilemap_sheet, &ground_layer_grid, &player.camera) + draw_tile_grid(&interactables_tilemap_sheet, &interactables_layer_grid, &player.camera) }