|
|
@@ -26,6 +26,15 @@ move_direction: Vec2i
|
|
|
game_over: bool
|
|
|
food_pos: Vec2i
|
|
|
|
|
|
+food_sprite: k2.Texture
|
|
|
+head_sprite: k2.Texture
|
|
|
+body_sprite: k2.Texture
|
|
|
+tail_sprite: k2.Texture
|
|
|
+
|
|
|
+food_eaten_at: time.Time
|
|
|
+started_at: time.Time
|
|
|
+prev_time: time.Time
|
|
|
+
|
|
|
place_food :: proc() {
|
|
|
occupied: [GRID_WIDTH][GRID_WIDTH]bool
|
|
|
|
|
|
@@ -65,7 +74,7 @@ main :: proc() {
|
|
|
context.logger = log.create_console_logger()
|
|
|
|
|
|
when ODIN_DEBUG {
|
|
|
- track: mem.Tracking_Allocatorx
|
|
|
+ track: mem.Tracking_Allocator
|
|
|
mem.tracking_allocator_init(&track, context.allocator)
|
|
|
context.allocator = mem.tracking_allocator(&track)
|
|
|
|
|
|
@@ -79,157 +88,148 @@ main :: proc() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ for !k2.shutdown_wanted() {
|
|
|
+ time_now := time.now()
|
|
|
+ dt := f32(time.duration_seconds(time.diff(prev_time, time_now)))
|
|
|
+ prev_time = time_now
|
|
|
+ step(dt)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+init :: proc() {
|
|
|
k2.init(WINDOW_SIZE, WINDOW_SIZE, "Snake")
|
|
|
k2.set_window_position(300, 300)
|
|
|
|
|
|
- SHADER_SOURCE :: #load("shader.hlsl")
|
|
|
+ prev_time = time.now()
|
|
|
|
|
|
- shader := k2.load_shader_from_memory(SHADER_SOURCE, SHADER_SOURCE, {
|
|
|
- .RG_32_Float,
|
|
|
- .RG_32_Float,
|
|
|
- .RGBA_8_Norm,
|
|
|
- .RG_32_Float,
|
|
|
- })
|
|
|
+ restart()
|
|
|
|
|
|
- prev_time := time.now()
|
|
|
+ food_sprite = k2.load_texture_from_bytes(#load("food.png"))
|
|
|
+ head_sprite = k2.load_texture_from_bytes(#load("head.png"))
|
|
|
+ body_sprite = k2.load_texture_from_bytes(#load("body.png"))
|
|
|
+ tail_sprite = k2.load_texture_from_bytes(#load("tail.png"))
|
|
|
|
|
|
- restart()
|
|
|
+ food_eaten_at = time.now()
|
|
|
+ started_at = time.now()
|
|
|
+}
|
|
|
|
|
|
- food_sprite := k2.load_texture_from_file("food.png")
|
|
|
- head_sprite := k2.load_texture_from_file("head.png")
|
|
|
- body_sprite := k2.load_texture_from_file("body.png")
|
|
|
- tail_sprite := k2.load_texture_from_file("tail.png")
|
|
|
+step :: proc(dt: f32) -> bool {
|
|
|
+ k2.process_events()
|
|
|
|
|
|
- food_eaten_at := time.now()
|
|
|
- started_at := time.now()
|
|
|
+ if k2.key_is_held(.Up) || k2.gamepad_button_is_held(0, .Left_Face_Up) {
|
|
|
+ move_direction = {0, -1}
|
|
|
+ }
|
|
|
|
|
|
- for !k2.shutdown_wanted() {
|
|
|
- time_now := time.now()
|
|
|
- dt := f32(time.duration_seconds(time.diff(prev_time, time_now)))
|
|
|
- prev_time = time_now
|
|
|
- total_time := time.duration_seconds(time.diff(started_at, time_now))
|
|
|
- k2.process_events()
|
|
|
+ if k2.key_is_held(.Down) || k2.gamepad_button_is_held(0, .Left_Face_Down) {
|
|
|
+ move_direction = {0, 1}
|
|
|
+ }
|
|
|
|
|
|
- if k2.key_is_held(.Up) || k2.gamepad_button_is_held(0, .Left_Face_Up) {
|
|
|
- move_direction = {0, -1}
|
|
|
- }
|
|
|
+ if k2.key_is_held(.Left) || k2.gamepad_button_is_held(0, .Left_Face_Left) {
|
|
|
+ move_direction = {-1, 0}
|
|
|
+ }
|
|
|
|
|
|
- if k2.key_is_held(.Down) || k2.gamepad_button_is_held(0, .Left_Face_Down) {
|
|
|
- move_direction = {0, 1}
|
|
|
- }
|
|
|
+ if k2.key_is_held(.Right) || k2.gamepad_button_is_held(0, .Left_Face_Right) {
|
|
|
+ move_direction = {1, 0}
|
|
|
+ }
|
|
|
|
|
|
- if k2.key_is_held(.Left) || k2.gamepad_button_is_held(0, .Left_Face_Left) {
|
|
|
- move_direction = {-1, 0}
|
|
|
+ if game_over {
|
|
|
+ if k2.key_went_down(.Enter) {
|
|
|
+ restart()
|
|
|
}
|
|
|
+ } else {
|
|
|
+ tick_timer -= dt
|
|
|
+ }
|
|
|
|
|
|
- if k2.key_is_held(.Right) || k2.gamepad_button_is_held(0, .Left_Face_Right) {
|
|
|
- move_direction = {1, 0}
|
|
|
- }
|
|
|
+ if tick_timer <= 0 {
|
|
|
+ next_part_pos := snake[0]
|
|
|
+ snake[0] += move_direction
|
|
|
+ head_pos := snake[0]
|
|
|
|
|
|
- if game_over {
|
|
|
- if k2.key_went_down(.Enter) {
|
|
|
- restart()
|
|
|
- }
|
|
|
- } else {
|
|
|
- tick_timer -= dt
|
|
|
+ if head_pos.x < 0 || head_pos.y < 0 || head_pos.x >= GRID_WIDTH || head_pos.y >= GRID_WIDTH {
|
|
|
+ game_over = true
|
|
|
}
|
|
|
|
|
|
- if tick_timer <= 0 {
|
|
|
- next_part_pos := snake[0]
|
|
|
- snake[0] += move_direction
|
|
|
- head_pos := snake[0]
|
|
|
+ for i in 1..<snake_length {
|
|
|
+ cur_pos := snake[i]
|
|
|
|
|
|
- if head_pos.x < 0 || head_pos.y < 0 || head_pos.x >= GRID_WIDTH || head_pos.y >= GRID_WIDTH {
|
|
|
+ if cur_pos == head_pos {
|
|
|
game_over = true
|
|
|
}
|
|
|
|
|
|
- for i in 1..<snake_length {
|
|
|
- cur_pos := snake[i]
|
|
|
-
|
|
|
- if cur_pos == head_pos {
|
|
|
- game_over = true
|
|
|
- }
|
|
|
-
|
|
|
- snake[i] = next_part_pos
|
|
|
- next_part_pos = cur_pos
|
|
|
- }
|
|
|
-
|
|
|
- if head_pos == food_pos {
|
|
|
- snake_length += 1
|
|
|
- snake[snake_length - 1] = next_part_pos
|
|
|
- place_food()
|
|
|
- food_eaten_at = time.now()
|
|
|
- }
|
|
|
-
|
|
|
- tick_timer = TICK_RATE + tick_timer
|
|
|
- }
|
|
|
-
|
|
|
- k2.clear({76, 53, 83, 255})
|
|
|
- k2.set_shader(shader)
|
|
|
-
|
|
|
- camera := k2.Camera {
|
|
|
- zoom = f32(WINDOW_SIZE) / CANVAS_SIZE,
|
|
|
+ snake[i] = next_part_pos
|
|
|
+ next_part_pos = cur_pos
|
|
|
}
|
|
|
-
|
|
|
- k2.set_camera(camera)
|
|
|
- food_sprite.width = CELL_SIZE
|
|
|
- food_sprite.height = CELL_SIZE
|
|
|
-
|
|
|
- time_since_food := time.duration_seconds(time.diff(food_eaten_at, time_now))
|
|
|
|
|
|
- if time_since_food < 0.5 && total_time > 1 {
|
|
|
- k2.override_shader_input(shader, 3, k2.Vec2{f32(math.cos(total_time*100)*4), f32(math.sin(total_time*120 + 3)*4)})
|
|
|
+ if head_pos == food_pos {
|
|
|
+ snake_length += 1
|
|
|
+ snake[snake_length - 1] = next_part_pos
|
|
|
+ place_food()
|
|
|
+ food_eaten_at = time.now()
|
|
|
}
|
|
|
|
|
|
- k2.draw_texture(food_sprite, {f32(food_pos.x), f32(food_pos.y)}*CELL_SIZE)
|
|
|
+ tick_timer = TICK_RATE + tick_timer
|
|
|
+ }
|
|
|
|
|
|
- k2.override_shader_input(shader, 3, nil)
|
|
|
+ k2.clear({76, 53, 83, 255})
|
|
|
|
|
|
- for i in 0..<snake_length {
|
|
|
- part_sprite := body_sprite
|
|
|
- dir: Vec2i
|
|
|
+ camera := k2.Camera {
|
|
|
+ zoom = f32(WINDOW_SIZE) / CANVAS_SIZE,
|
|
|
+ }
|
|
|
+
|
|
|
+ k2.set_camera(camera)
|
|
|
+ food_sprite.width = CELL_SIZE
|
|
|
+ food_sprite.height = CELL_SIZE
|
|
|
|
|
|
- if i == 0 {
|
|
|
- part_sprite = head_sprite
|
|
|
- dir = snake[i] - snake[i + 1]
|
|
|
- } else if i == snake_length - 1 {
|
|
|
- part_sprite = tail_sprite
|
|
|
- dir = snake[i - 1] - snake[i]
|
|
|
- } else {
|
|
|
- dir = snake[i - 1] - snake[i]
|
|
|
- }
|
|
|
+ k2.draw_texture(food_sprite, {f32(food_pos.x), f32(food_pos.y)}*CELL_SIZE)
|
|
|
|
|
|
- rot := math.atan2(f32(dir.y), f32(dir.x)) * math.DEG_PER_RAD
|
|
|
|
|
|
- source := k2.Rect {
|
|
|
- 0, 0,
|
|
|
- f32(part_sprite.width), f32(part_sprite.height),
|
|
|
- }
|
|
|
+ for i in 0..<snake_length {
|
|
|
+ part_sprite := body_sprite
|
|
|
+ dir: Vec2i
|
|
|
+
|
|
|
+ if i == 0 {
|
|
|
+ part_sprite = head_sprite
|
|
|
+ dir = snake[i] - snake[i + 1]
|
|
|
+ } else if i == snake_length - 1 {
|
|
|
+ part_sprite = tail_sprite
|
|
|
+ dir = snake[i - 1] - snake[i]
|
|
|
+ } else {
|
|
|
+ dir = snake[i - 1] - snake[i]
|
|
|
+ }
|
|
|
|
|
|
- dest := k2.Rect {
|
|
|
- f32(snake[i].x)*CELL_SIZE + 0.5*CELL_SIZE,
|
|
|
- f32(snake[i].y)*CELL_SIZE + 0.5*CELL_SIZE,
|
|
|
- CELL_SIZE,
|
|
|
- CELL_SIZE,
|
|
|
- }
|
|
|
+ rot := math.atan2(f32(dir.y), f32(dir.x)) * math.DEG_PER_RAD
|
|
|
|
|
|
- k2.draw_texture_ex(part_sprite, source, dest, {CELL_SIZE, CELL_SIZE}*0.5, rot)
|
|
|
+ source := k2.Rect {
|
|
|
+ 0, 0,
|
|
|
+ f32(part_sprite.width), f32(part_sprite.height),
|
|
|
}
|
|
|
|
|
|
- if game_over {
|
|
|
- k2.draw_text("Game Over!", {4, 4}, 25, k2.RL_RED)
|
|
|
- k2.draw_text("Press Enter to play again", {4, 30}, 15, k2.BLACK)
|
|
|
+ dest := k2.Rect {
|
|
|
+ f32(snake[i].x)*CELL_SIZE + 0.5*CELL_SIZE,
|
|
|
+ f32(snake[i].y)*CELL_SIZE + 0.5*CELL_SIZE,
|
|
|
+ CELL_SIZE,
|
|
|
+ CELL_SIZE,
|
|
|
}
|
|
|
|
|
|
- score := snake_length - 3
|
|
|
- score_str := fmt.tprintf("Score: %v", score)
|
|
|
- k2.draw_text(score_str, {4, CANVAS_SIZE - 14}, 10, k2.RL_GRAY)
|
|
|
- k2.present()
|
|
|
+ k2.draw_texture_ex(part_sprite, source, dest, {CELL_SIZE, CELL_SIZE}*0.5, rot)
|
|
|
+ }
|
|
|
|
|
|
- free_all(context.temp_allocator)
|
|
|
+ if game_over {
|
|
|
+ k2.draw_text("Game Over!", {4, 4}, 25, k2.RL_RED)
|
|
|
+ k2.draw_text("Press Enter to play again", {4, 30}, 15, k2.BLACK)
|
|
|
}
|
|
|
|
|
|
- k2.destroy_shader(shader)
|
|
|
+ score := snake_length - 3
|
|
|
+ score_str := fmt.tprintf("Score: %v", score)
|
|
|
+ k2.draw_text(score_str, {4, CANVAS_SIZE - 14}, 10, k2.RL_GRAY)
|
|
|
+ k2.present()
|
|
|
+
|
|
|
+ free_all(context.temp_allocator)
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+shutdown :: proc() {
|
|
|
k2.destroy_texture(head_sprite)
|
|
|
k2.destroy_texture(food_sprite)
|
|
|
k2.destroy_texture(body_sprite)
|