why are the tiles still 24bytes...
This commit is contained in:
parent
22f9af5417
commit
f7a409f565
BIN
game/data/worlds/test_world/chunks/0_0.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/0_0.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/0_1.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/0_1.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/0_2.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/0_2.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/0_3.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/0_3.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/0_4.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/0_4.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/1_0.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/1_0.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/1_1.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/1_1.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/1_2.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/1_2.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/1_3.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/1_3.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/1_4.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/1_4.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/2_0.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/2_0.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/2_1.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/2_1.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/2_2.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/2_2.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/2_3.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/2_3.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/2_4.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/2_4.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/3_0.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/3_0.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/3_1.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/3_1.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/3_2.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/3_2.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/3_3.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/3_3.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/3_4.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/3_4.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/4_0.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/4_0.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/4_1.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/4_1.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/4_2.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/4_2.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/4_3.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/4_3.chunk
Normal file
Binary file not shown.
BIN
game/data/worlds/test_world/chunks/4_4.chunk
Normal file
BIN
game/data/worlds/test_world/chunks/4_4.chunk
Normal file
Binary file not shown.
@ -11,30 +11,32 @@ import "core:strings"
|
|||||||
player : Player
|
player : Player
|
||||||
world : World
|
world : World
|
||||||
|
|
||||||
camera : rl.Camera2D
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
|
|
||||||
rl.InitWindow(1280, 720, "Odin game")
|
rl.InitWindow(1280, 720, "Odin game")
|
||||||
|
|
||||||
flags : rl.ConfigFlags = {.VSYNC_HINT}
|
flags : rl.ConfigFlags = {.VSYNC_HINT}
|
||||||
rl.SetConfigFlags(flags)
|
rl.SetConfigFlags(flags)
|
||||||
|
|
||||||
rl.SetTargetFPS(60)
|
rl.SetTargetFPS(60)
|
||||||
|
|
||||||
player.position.x = CELL_SIZE * 5
|
player = {
|
||||||
player.position.y = CELL_SIZE * 5
|
position = {CELL_SIZE * 5, CELL_SIZE * 5},
|
||||||
player.mode = .INTERACT
|
camera = {
|
||||||
|
zoom = 2,
|
||||||
camera.target = {player.position.x + (CELL_SIZE / 2), player.position.y + (CELL_SIZE / 2)}
|
target = {player.position.x + (CELL_SIZE / 2), player.position.y + (CELL_SIZE / 2)},
|
||||||
camera.zoom = 2
|
offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2},
|
||||||
camera.offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2}
|
},
|
||||||
|
mode = .INTERACT,
|
||||||
|
}
|
||||||
|
|
||||||
load_tilemap()
|
load_tilemap()
|
||||||
defer unload_tilemap()
|
defer unload_tilemap()
|
||||||
|
|
||||||
fill_world_grid_with_nothing(&world)
|
world = create_world("test_world")
|
||||||
|
load_nearby_chunks(&world, player.position)
|
||||||
|
save_world(&world)
|
||||||
|
|
||||||
place_random_trees(&world)
|
|
||||||
|
|
||||||
game_loop()
|
game_loop()
|
||||||
}
|
}
|
||||||
@ -50,7 +52,7 @@ game_loop :: proc() {
|
|||||||
|
|
||||||
rl.BeginDrawing()
|
rl.BeginDrawing()
|
||||||
rl.ClearBackground(rl.BLACK)
|
rl.ClearBackground(rl.BLACK)
|
||||||
rl.BeginMode2D(camera)
|
rl.BeginMode2D(player.camera)
|
||||||
|
|
||||||
draw()
|
draw()
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ game_loop :: proc() {
|
|||||||
rl.DrawFPS(5,5)
|
rl.DrawFPS(5,5)
|
||||||
|
|
||||||
player_grid_pos := get_player_grid_position(&player)
|
player_grid_pos := get_player_grid_position(&player)
|
||||||
player_grid_pos_tile := get_grid_tile(&world, vec2_to_vec2i(player_grid_pos))
|
player_grid_pos_tile := get_world_tile(&world, vec2_to_vec2i(player_grid_pos))
|
||||||
status_string := rl.TextFormat("POS: %v : %v | MODE: %v", player_grid_pos, player_grid_pos_tile.type, player.mode)
|
status_string := rl.TextFormat("POS: %v : %v | MODE: %v", player_grid_pos, player_grid_pos_tile.type, player.mode)
|
||||||
|
|
||||||
rl.DrawText(status_string, 5, 25, 20, rl.RED)
|
rl.DrawText(status_string, 5, 25, 20, rl.RED)
|
||||||
@ -73,11 +75,7 @@ game_loop :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update :: proc() {
|
update :: proc() {
|
||||||
|
player_update(&player, &world)
|
||||||
handle_player_input(&player, &world)
|
|
||||||
handle_window_resize()
|
|
||||||
camera.target = {player.position.x + (CELL_SIZE / 2), player.position.y + (CELL_SIZE / 2)}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
draw :: proc() {
|
draw :: proc() {
|
||||||
@ -85,16 +83,3 @@ draw :: proc() {
|
|||||||
draw_player(&player)
|
draw_player(&player)
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_window_resize :: proc() {
|
|
||||||
if rl.IsWindowResized() {
|
|
||||||
camera.offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print_grid :: proc() {
|
|
||||||
for x in 0..< len(world.grid) {
|
|
||||||
for y in 0..< len(world.grid) {
|
|
||||||
fmt.printfln("[%d, %d] %v", x, y, world.grid[x][y].type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package game
|
package game
|
||||||
|
|
||||||
Vec2i :: struct {
|
Vec2i :: struct {
|
||||||
x: u32,
|
x: int,
|
||||||
y:u32,
|
y: int,
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2i_to_vec2 :: proc(v2i:Vec2i) -> [2]f32 {
|
vec2i_to_vec2 :: proc(v2i:Vec2i) -> [2]f32 {
|
||||||
@ -10,5 +10,43 @@ vec2i_to_vec2 :: proc(v2i:Vec2i) -> [2]f32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec2_to_vec2i :: proc(v2:[2]f32) -> Vec2i {
|
vec2_to_vec2i :: proc(v2:[2]f32) -> Vec2i {
|
||||||
return {u32(v2.x), u32(v2.y)}
|
return {int(v2.x), int(v2.y)}
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize_vec2i :: proc(v:Vec2i) -> [8]byte {
|
||||||
|
data: [8]byte
|
||||||
|
|
||||||
|
x := serialize_int(v.x)
|
||||||
|
y := serialize_int(v.y)
|
||||||
|
|
||||||
|
for i in 0..<4 {
|
||||||
|
data[i] = x[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<4 {
|
||||||
|
data[4 + i] = y[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
deserialize_vec2i :: proc(data:[]byte) -> Vec2i {
|
||||||
|
x := deserialize_int(data[0:4])
|
||||||
|
y := deserialize_int(data[4:8])
|
||||||
|
return Vec2i{x,y}
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize_int :: proc(v:int) -> [4]byte {
|
||||||
|
data : [4]byte
|
||||||
|
|
||||||
|
data[0] = byte(v)
|
||||||
|
data[1] = byte(v >> 8)
|
||||||
|
data[2] = byte(v >> 16)
|
||||||
|
data[3] = byte(v >> 24)
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
deserialize_int :: proc(data:[]byte) -> int {
|
||||||
|
return int(data[0]) | int(data[1]) << 8 | int(data[2]) << 16 | int(data[3]) << 24
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,13 @@ package game
|
|||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
|
CHUNK_UNLOAD_DISTANCE :: 3
|
||||||
|
|
||||||
Player :: struct {
|
Player :: struct {
|
||||||
position : rl.Vector2,
|
position : rl.Vector2,
|
||||||
move_timer: f32,
|
move_timer: f32,
|
||||||
mode: InteractMode
|
mode: InteractMode,
|
||||||
|
camera: rl.Camera2D
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractMode :: enum {
|
InteractMode :: enum {
|
||||||
@ -14,8 +17,46 @@ InteractMode :: enum {
|
|||||||
ATTACK,
|
ATTACK,
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_player_input :: proc(p : ^Player, w: ^World) {
|
handle_player_camera :: proc(p:^Player) {
|
||||||
|
p.camera.target = {p.position.x + (CELL_SIZE / 2), p.position.y + (CELL_SIZE / 2)}
|
||||||
|
|
||||||
|
if rl.IsWindowResized() {
|
||||||
|
p.camera.offset = {f32(rl.GetScreenWidth()) / 2, f32(rl.GetScreenHeight()) / 2}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player_update :: proc(p : ^Player, w: ^World) {
|
||||||
|
handle_player_input(p,w)
|
||||||
|
handle_player_camera(p)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
load_nearby_chunks :: proc(w:^World, player_pos:rl.Vector2) {
|
||||||
|
player_chunk_pos := world_pos_to_chunk_pos(player_pos)
|
||||||
|
|
||||||
|
chunk_radius := 2 // Adjust based on the camera size
|
||||||
|
|
||||||
|
for x := -chunk_radius; x <= chunk_radius; x += 1 {
|
||||||
|
for y := -chunk_radius; y <= chunk_radius; y += 1 {
|
||||||
|
chunk_pos := Vec2i{player_chunk_pos.x + x, player_chunk_pos.y + y}
|
||||||
|
get_chunk(w, chunk_pos) // Ensures chunk is loaded or generated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unload_far_chunks :: proc(w: ^World, player_pos: Vec2i) {
|
||||||
|
for chunk_pos in w.chunks {
|
||||||
|
dist_x := abs(chunk_pos.x - player_pos.x)
|
||||||
|
dist_y := abs(chunk_pos.y - player_pos.y)
|
||||||
|
|
||||||
|
if dist_x > CHUNK_UNLOAD_DISTANCE || dist_y > CHUNK_UNLOAD_DISTANCE {
|
||||||
|
unload_chunk(chunk_pos, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_player_input :: proc(p:^Player, w:^World) {
|
||||||
target_pos := get_player_grid_position(p)
|
target_pos := get_player_grid_position(p)
|
||||||
|
|
||||||
dt := rl.GetFrameTime()
|
dt := rl.GetFrameTime()
|
||||||
@ -31,33 +72,41 @@ handle_player_input :: proc(p : ^Player, w: ^World) {
|
|||||||
if p.move_timer <= 0 {
|
if p.move_timer <= 0 {
|
||||||
if rl.IsKeyDown(.D) {
|
if rl.IsKeyDown(.D) {
|
||||||
target_pos.x += 1
|
target_pos.x += 1
|
||||||
if !will_collide(target_pos, w) {
|
if !will_collide(w, target_pos) {
|
||||||
player.position.x += CELL_SIZE
|
player.position.x += CELL_SIZE
|
||||||
p.move_timer = move_delay
|
p.move_timer = move_delay
|
||||||
|
load_nearby_chunks(w, p.position)
|
||||||
|
unload_far_chunks(w, vec2_to_vec2i(p.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyDown(.A) {
|
if rl.IsKeyDown(.A) {
|
||||||
target_pos.x -= 1
|
target_pos.x -= 1
|
||||||
if !will_collide(target_pos, w) {
|
if !will_collide(w, target_pos) {
|
||||||
player.position.x -= CELL_SIZE
|
player.position.x -= CELL_SIZE
|
||||||
p.move_timer = move_delay
|
p.move_timer = move_delay
|
||||||
|
load_nearby_chunks(w, p.position)
|
||||||
|
unload_far_chunks(w, vec2_to_vec2i(p.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyDown(.W) {
|
if rl.IsKeyDown(.W) {
|
||||||
target_pos.y -= 1
|
target_pos.y -= 1
|
||||||
if !will_collide(target_pos, w) {
|
if !will_collide(w, target_pos) {
|
||||||
player.position.y -= CELL_SIZE
|
player.position.y -= CELL_SIZE
|
||||||
p.move_timer = move_delay
|
p.move_timer = move_delay
|
||||||
|
load_nearby_chunks(w, p.position)
|
||||||
|
unload_far_chunks(w, vec2_to_vec2i(p.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyDown(.S) {
|
if rl.IsKeyDown(.S) {
|
||||||
target_pos.y += 1
|
target_pos.y += 1
|
||||||
if !will_collide(target_pos, w) {
|
if !will_collide(w, target_pos) {
|
||||||
p.move_timer = move_delay
|
p.move_timer = move_delay
|
||||||
player.position.y += CELL_SIZE
|
player.position.y += CELL_SIZE
|
||||||
|
load_nearby_chunks(w, p.position)
|
||||||
|
unload_far_chunks(w, vec2_to_vec2i(p.position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,12 +123,13 @@ draw_player :: proc(player:^Player) {
|
|||||||
draw_tile({27,0}, player.position, rl.DARKBLUE)
|
draw_tile({27,0}, player.position, rl.DARKBLUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
will_collide :: proc(pos:rl.Vector2, w:^World) -> bool {
|
will_collide :: proc(w:^World, pos:rl.Vector2) -> bool {
|
||||||
if pos.y > WORLD_SIZE * CELL_SIZE || pos.x > WORLD_SIZE * CELL_SIZE {
|
world_grid_pos := vec2_to_vec2i(pos)
|
||||||
return false
|
chunk_pos := world_pos_to_chunk_pos(pos)
|
||||||
}
|
local_pos := get_local_chunk_pos(world_grid_pos)
|
||||||
|
|
||||||
tile := get_grid_tile(w, vec2_to_vec2i(pos))
|
chunk := get_chunk(w, chunk_pos)
|
||||||
|
tile := get_chunk_tile(chunk, local_pos)
|
||||||
|
|
||||||
#partial switch tile.type {
|
#partial switch tile.type {
|
||||||
case .WALL:
|
case .WALL:
|
||||||
|
139
game/tiles.odin
139
game/tiles.odin
@ -3,21 +3,132 @@ package game
|
|||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import "core:math/rand"
|
import "core:math/rand"
|
||||||
|
|
||||||
|
Tile :: struct #packed {
|
||||||
|
tilemap_pos: Vec2i,
|
||||||
|
color: rl.Color,
|
||||||
|
type: TileType,
|
||||||
|
interaction: InteractionType,
|
||||||
|
resource: ResourceType,
|
||||||
|
}
|
||||||
|
|
||||||
|
TileType :: enum {
|
||||||
|
NOTHING,
|
||||||
|
WALL,
|
||||||
|
FOLIAGE,
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceType :: enum {
|
||||||
|
NOTHING,
|
||||||
|
TREE,
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractionType :: enum {
|
||||||
|
NOTHING,
|
||||||
|
RESOURCE,
|
||||||
|
ENEMY,
|
||||||
|
}
|
||||||
|
serialize_tile :: proc(t: Tile) -> []byte {
|
||||||
|
data: [dynamic]byte
|
||||||
|
|
||||||
|
// Tilemap Pos (16 bytes)
|
||||||
|
tilemap_pos_bytes := serialize_vec2i(t.tilemap_pos)
|
||||||
|
append(&data, ..tilemap_pos_bytes[:])
|
||||||
|
|
||||||
|
// Color (4 bytes)
|
||||||
|
append(&data, byte(t.color.r), byte(t.color.g), byte(t.color.b), byte(t.color.a))
|
||||||
|
|
||||||
|
// TileType (8 bytes)
|
||||||
|
tile_type_bytes := serialize_int(int(t.type))
|
||||||
|
append(&data, ..tile_type_bytes[:])
|
||||||
|
|
||||||
|
// Interaction Type (8 bytes)
|
||||||
|
interaction_bytes := serialize_int(int(t.interaction))
|
||||||
|
append(&data, ..interaction_bytes[:])
|
||||||
|
|
||||||
|
// Resource Type (8 bytes)
|
||||||
|
resource_bytes := serialize_int(int(t.resource))
|
||||||
|
append(&data, ..resource_bytes[:])
|
||||||
|
|
||||||
|
return data[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
deserialize_tile :: proc(data: []byte) -> Tile {
|
||||||
|
t: Tile
|
||||||
|
|
||||||
|
// Tilemap Pos (16 bytes)
|
||||||
|
t.tilemap_pos = deserialize_vec2i(data[0:16])
|
||||||
|
|
||||||
|
// Color (4 bytes)
|
||||||
|
t.color.r = u8(data[16])
|
||||||
|
t.color.g = u8(data[17])
|
||||||
|
t.color.b = u8(data[18])
|
||||||
|
t.color.a = u8(data[19])
|
||||||
|
|
||||||
|
// TileType (8 bytes)
|
||||||
|
t.type = TileType(deserialize_int(data[20:28]))
|
||||||
|
|
||||||
|
// Interaction Type (8 bytes)
|
||||||
|
t.interaction = InteractionType(deserialize_int(data[28:36]))
|
||||||
|
|
||||||
|
// Resource Type (8 bytes)
|
||||||
|
t.resource = ResourceType(deserialize_int(data[36:44]))
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize_tile :: proc(t: Tile) -> []byte {
|
||||||
|
// data: [dynamic]byte
|
||||||
|
|
||||||
|
// // TileType
|
||||||
|
// tile_type_bytes := serialize_int(int(t.type))
|
||||||
|
// append(&data, ..tile_type_bytes[:])
|
||||||
|
|
||||||
|
// // Tilemap Pos
|
||||||
|
// tilemap_pos_bytes := serialize_vec2i(t.tilemap_pos)
|
||||||
|
// append(&data, ..tilemap_pos_bytes[:])
|
||||||
|
|
||||||
|
// // Color
|
||||||
|
// append(&data, byte(t.color.r), byte(t.color.g), byte(t.color.b), byte(t.color.a))
|
||||||
|
|
||||||
|
// // Interaction Type
|
||||||
|
// interaction_bytes := serialize_int(int(t.interaction))
|
||||||
|
// append(&data, ..interaction_bytes[:])
|
||||||
|
|
||||||
|
// // Resource Type
|
||||||
|
// resource_bytes := serialize_int(int(t.resource))
|
||||||
|
// append(&data, ..resource_bytes[:])
|
||||||
|
|
||||||
|
// return data[:]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// deserialize_tile :: proc(data:[]byte) -> Tile {
|
||||||
|
// t: Tile
|
||||||
|
|
||||||
|
// // TileType
|
||||||
|
// t.type = TileType(deserialize_int(data[0:4]))
|
||||||
|
|
||||||
|
// // TilemapPos
|
||||||
|
// t.tilemap_pos = deserialize_vec2i(data[4:12])
|
||||||
|
|
||||||
|
// // Color
|
||||||
|
// t.color.r = u8(data[12])
|
||||||
|
// t.color.g = u8(data[13])
|
||||||
|
// t.color.b = u8(data[14])
|
||||||
|
// t.color.a = u8(data[15])
|
||||||
|
|
||||||
|
// // ResourceType
|
||||||
|
// t.resource = ResourceType(deserialize_int(data[16:20]))
|
||||||
|
|
||||||
|
// // InteractionType
|
||||||
|
// t.interaction = InteractionType(deserialize_int(data[20:24]))
|
||||||
|
|
||||||
|
// return t
|
||||||
|
// }
|
||||||
|
|
||||||
tree_tile := Tile {
|
tree_tile := Tile {
|
||||||
type = .WALL,
|
type = .WALL,
|
||||||
tilemap_pos = {0,1},
|
tilemap_pos = {0,1},
|
||||||
color = rl.DARKGREEN
|
color = rl.DARKGREEN,
|
||||||
}
|
resource = .TREE,
|
||||||
|
interaction = .RESOURCE,
|
||||||
place_random_trees :: proc(w:^World) {
|
|
||||||
for x in 0..< len(w.grid) {
|
|
||||||
for y in 0..< len(w.grid) {
|
|
||||||
|
|
||||||
chance := rand.int_max(100)
|
|
||||||
|
|
||||||
if chance <= 5 {
|
|
||||||
w.grid[x][y] = tree_tile
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
275
game/world.odin
275
game/world.odin
@ -2,61 +2,266 @@ package game
|
|||||||
|
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
import "core:os"
|
||||||
|
import "core:path/filepath"
|
||||||
|
|
||||||
CELL_SIZE :: 16
|
CELL_SIZE :: 16
|
||||||
WORLD_SIZE :: 100
|
CHUNK_SIZE :: 32
|
||||||
|
WORLD_DATA_PATH :: "data/worlds"
|
||||||
|
|
||||||
World :: struct {
|
World :: struct {
|
||||||
grid: [WORLD_SIZE][WORLD_SIZE]Tile
|
data_dir: string,
|
||||||
|
chunks: map[Vec2i]Chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile :: struct {
|
Chunk :: struct #packed {
|
||||||
type: TileType,
|
position: Vec2i,
|
||||||
tilemap_pos:rl.Vector2,
|
tiles: [CHUNK_SIZE][CHUNK_SIZE]Tile,
|
||||||
color:rl.Color,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TileType :: enum {
|
create_world :: proc(name:string) -> World {
|
||||||
NOTHING,
|
data_dir := fmt.tprintf("%v/%v", WORLD_DATA_PATH, name)
|
||||||
WALL,
|
if !os.is_dir(data_dir) {
|
||||||
DOOR,
|
fmt.printfln("Data dir: %v does not exist", data_dir)
|
||||||
FLOOR,
|
os.make_directory(data_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
set_grid_tile :: proc(w:^World, pos:Vec2i, t:Tile) {
|
chunk_dir := fmt.tprintf("%v/%v", data_dir, "chunks")
|
||||||
w.grid[pos.x][pos.y] = t
|
if !os.is_dir(chunk_dir) {
|
||||||
}
|
os.make_directory(chunk_dir)
|
||||||
|
}
|
||||||
get_grid_tile :: proc(w: ^World, pos: Vec2i) -> Tile {
|
|
||||||
if pos.x < 0 || pos.x >= len(w.grid) || pos.y < 0 || pos.y >= len(w.grid[0]) {
|
return World {
|
||||||
// fmt.printfln("Target [%v] outside of world bounds", pos)
|
data_dir = data_dir,
|
||||||
return w.grid[0][0] // Default or error tile
|
chunks = make(map[Vec2i]Chunk),
|
||||||
}
|
}
|
||||||
return w.grid[pos.x][pos.y]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fill_world_grid_with_nothing :: proc(w:^World) {
|
load_world :: proc(name:string) -> World {
|
||||||
for x in 0..< len(w.grid) {
|
dir := fmt.tprintf("%v/%v", WORLD_DATA_PATH, name)
|
||||||
for y in 0..<len(w.grid) {
|
if !os.is_dir(dir) {
|
||||||
w.grid[x][y] = Tile {
|
panic("Couldnt load world")
|
||||||
type = .NOTHING,
|
}
|
||||||
tilemap_pos = {0,0}
|
|
||||||
|
return World {
|
||||||
|
data_dir = dir,
|
||||||
|
chunks = make(map[Vec2i]Chunk),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save_world :: proc(w:^World) {
|
||||||
|
if !os.is_dir(w.data_dir) {
|
||||||
|
panic("World has invalid data_path")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.printfln("Saving world %v", w.data_dir)
|
||||||
|
|
||||||
|
for chunk in w.chunks {
|
||||||
|
save_chunk(get_chunk(w, chunk), w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize_chunk :: proc(c:^Chunk) -> []byte {
|
||||||
|
data : [dynamic]byte
|
||||||
|
|
||||||
|
// Position
|
||||||
|
pos_bytes := serialize_vec2i(c.position)
|
||||||
|
append(&data, ..pos_bytes[:])
|
||||||
|
|
||||||
|
// Tiles
|
||||||
|
for y in 0..<CHUNK_SIZE {
|
||||||
|
for x in 0..<CHUNK_SIZE {
|
||||||
|
tile_bytes := serialize_tile(c.tiles[x][y])
|
||||||
|
fmt.printfln("Serialized tile size: %v", len(tile_bytes))
|
||||||
|
append(&data, ..tile_bytes[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.printfln("Serialized chunk size: %v", len(data)) // Print final serialized size
|
||||||
|
fmt.printfln("Before serialization, Chunk position: %v", c.position)
|
||||||
|
return data[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
deserialize_chunk :: proc(data: []byte) -> Chunk {
|
||||||
|
chunk: Chunk
|
||||||
|
|
||||||
|
// Position
|
||||||
|
chunk.position = deserialize_vec2i(data[0:8])
|
||||||
|
|
||||||
|
// Tiles
|
||||||
|
offset := 8
|
||||||
|
tile_size := size_of(Tile)
|
||||||
|
|
||||||
|
// Check total expected size of data
|
||||||
|
expected_size := offset + (CHUNK_SIZE * CHUNK_SIZE * tile_size)
|
||||||
|
if len(data) != expected_size {
|
||||||
|
fmt.printfln("Error: Data size mismatch. Expected size: %v, Actual size: %v", expected_size, len(data))
|
||||||
|
fmt.printfln("Chunk position: %v", chunk.position)
|
||||||
|
|
||||||
|
return chunk // Return empty or invalid chunk to handle the error.
|
||||||
|
}
|
||||||
|
|
||||||
|
for y in 0..<CHUNK_SIZE {
|
||||||
|
for x in 0..<CHUNK_SIZE {
|
||||||
|
start := offset + (y * CHUNK_SIZE + x) * tile_size
|
||||||
|
end := start + tile_size
|
||||||
|
|
||||||
|
fmt.printfln("Start:%v, End:%v", start, end)
|
||||||
|
|
||||||
|
if end > len(data) {
|
||||||
|
fmt.printfln("Out of bounds access. Start:%v, End:%v | Data Length: %v", start, end, len(data))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.tiles[x][y] = deserialize_tile(data[start:end])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.printfln("Expected chunk size: %v | Serialized chunk data size: %v", size_of(Chunk), len(data))
|
||||||
|
|
||||||
|
return chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
save_chunk :: proc(c:^Chunk, w:^World) {
|
||||||
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
||||||
|
if !os.is_dir(chunk_dir) {
|
||||||
|
os.make_directory(chunk_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := fmt.tprintf("%v/%v_%v.chunk", chunk_dir, c.position.x, c.position.y)
|
||||||
|
|
||||||
|
data := serialize_chunk(c)
|
||||||
|
|
||||||
|
fmt.printfln("Writing chunk data: %v bytes", len(data))
|
||||||
|
|
||||||
|
|
||||||
|
err := os.write_entire_file_or_err(filename, data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.printfln("Failed to save chunk: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load_chunk :: proc(pos:Vec2i, w:^World) -> Chunk {
|
||||||
|
chunk_dir := fmt.tprintf("%v/%v", w.data_dir, "chunks")
|
||||||
|
if !os.is_dir(chunk_dir) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := fmt.tprintf("%v/%v_%v.chunk", chunk_dir, pos.x, pos.y)
|
||||||
|
|
||||||
|
data, err := os.read_entire_file_from_filename_or_err(filename)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.printfln("Chunk %v file does not exist, creating new chunk", pos)
|
||||||
|
return generate_chunk(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserialize_chunk(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
unload_chunk :: proc(pos:Vec2i, w:^World) {
|
||||||
|
_, exists := w.chunks[pos]
|
||||||
|
if exists {
|
||||||
|
save_chunk(get_chunk(w, pos), w)
|
||||||
|
delete_key(&w.chunks, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
generate_chunk :: proc(pos:Vec2i) -> Chunk {
|
||||||
|
chunk := Chunk {position = pos}
|
||||||
|
|
||||||
|
for x in 0..<CHUNK_SIZE {
|
||||||
|
for y in 0..<CHUNK_SIZE {
|
||||||
|
chunk.tiles[x][y] = Tile {
|
||||||
|
type = .FOLIAGE,
|
||||||
|
tilemap_pos = {0,2},
|
||||||
|
interaction = .NOTHING,
|
||||||
|
resource = .NOTHING,
|
||||||
|
color = rl.GREEN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
center_pos := Vec2i{CHUNK_SIZE/2, CHUNK_SIZE/2}
|
||||||
|
// set_chunk_tile(&chunk, tree_tile, center_pos)
|
||||||
|
|
||||||
|
return chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
get_chunk :: proc(w:^World, chunk_pos:Vec2i) -> ^Chunk {
|
||||||
|
chunk, exists := w.chunks[chunk_pos]
|
||||||
|
if !exists {
|
||||||
|
w.chunks[chunk_pos] = load_chunk(chunk_pos, w)
|
||||||
|
}
|
||||||
|
return &w.chunks[chunk_pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
get_chunk_from_world_pos :: proc(w:^World, pos:rl.Vector2) -> ^Chunk {
|
||||||
|
chunk_pos := world_pos_to_chunk_pos(pos)
|
||||||
|
return get_chunk(w, chunk_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
world_pos_to_chunk_pos :: proc(pos:rl.Vector2) -> Vec2i {
|
||||||
|
chunk_pos := vec2_to_vec2i({pos.x / CHUNK_SIZE, pos.y / CHUNK_SIZE})
|
||||||
|
return chunk_pos
|
||||||
|
}
|
||||||
|
|
||||||
|
get_local_chunk_pos :: proc(pos:Vec2i) -> Vec2i {
|
||||||
|
return Vec2i {
|
||||||
|
(pos.x % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE,
|
||||||
|
(pos.y % CHUNK_SIZE + CHUNK_SIZE) % CHUNK_SIZE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get_world_tile :: proc(w:^World, pos:Vec2i) -> ^Tile {
|
||||||
|
chunk_pos := world_pos_to_chunk_pos(vec2i_to_vec2(pos))
|
||||||
|
local_pos := get_local_chunk_pos(pos)
|
||||||
|
|
||||||
|
chunk := get_chunk(w, chunk_pos)
|
||||||
|
|
||||||
|
return get_chunk_tile(chunk, local_pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
get_chunk_tile :: proc(c:^Chunk, pos:Vec2i) -> ^Tile {
|
||||||
|
return &c.tiles[pos.x][pos.y]
|
||||||
|
}
|
||||||
|
|
||||||
|
set_chunk_tile :: proc(c:^Chunk, t:Tile, pos:Vec2i) {
|
||||||
|
c.tiles[pos.x][pos.y] = t
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_world :: proc(w:^World) {
|
draw_world :: proc(w:^World) {
|
||||||
for x in 0..< len(w.grid) {
|
for chunk_pos, chunk in w.chunks {
|
||||||
for y in 0..< len(w.grid) {
|
for x in 0..<CHUNK_SIZE {
|
||||||
tile := w.grid[x][y]
|
for y in 0..<CHUNK_SIZE {
|
||||||
posX := x * TILE_SIZE
|
tile := chunk.tiles[x][y]
|
||||||
posY := y * TILE_SIZE
|
world_x := chunk_pos.x * CHUNK_SIZE + x
|
||||||
|
world_y := chunk_pos.y * CHUNK_SIZE + y
|
||||||
|
pos := rl.Vector2{f32(world_x * CELL_SIZE), f32(world_y * CELL_SIZE)}
|
||||||
|
|
||||||
if tile.type != .NOTHING {
|
if tile.type != .NOTHING {
|
||||||
draw_tile(tile.tilemap_pos, {f32(posX), f32(posY)}, tile.color)
|
draw_tile(vec2i_to_vec2(tile.tilemap_pos), pos, tile.color)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// draw_world :: proc(w:^World) {
|
||||||
|
// for x in 0..< len(w.grid) {
|
||||||
|
// for y in 0..< len(w.grid) {
|
||||||
|
// tile := w.grid[x][y]
|
||||||
|
// posX := x * TILE_SIZE
|
||||||
|
// posY := y * TILE_SIZE
|
||||||
|
|
||||||
|
// if tile.type != .NOTHING {
|
||||||
|
// draw_tile(tile.tilemap_pos, {f32(posX), f32(posY)}, tile.color)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user