diff options
Diffstat (limited to 'v_windows/v/examples/snek/snek.v')
-rw-r--r-- | v_windows/v/examples/snek/snek.v | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/v_windows/v/examples/snek/snek.v b/v_windows/v/examples/snek/snek.v new file mode 100644 index 0000000..1d66fb1 --- /dev/null +++ b/v_windows/v/examples/snek/snek.v @@ -0,0 +1,221 @@ +import os +import gg +import gx +// import sokol.sapp +import time +import rand + +// constants +const ( + top_height = 100 + canvas_size = 700 + game_size = 17 + tile_size = canvas_size / game_size + tick_rate_ms = 100 +) + +const high_score_file_path = os.join_path(os.cache_dir(), 'v', 'examples', 'snek') + +// types +struct Pos { + x int + y int +} + +fn (a Pos) + (b Pos) Pos { + return Pos{a.x + b.x, a.y + b.y} +} + +fn (a Pos) - (b Pos) Pos { + return Pos{a.x - b.x, a.y - b.y} +} + +enum Direction { + up + down + left + right +} + +type HighScore = int + +fn (mut h HighScore) save() { + os.mkdir_all(os.dir(high_score_file_path)) or { return } + os.write_file(high_score_file_path, (*h).str()) or { return } +} + +fn (mut h HighScore) load() { + h = (os.read_file(high_score_file_path) or { '' }).int() +} + +struct App { +mut: + gg &gg.Context + score int + best HighScore + snake []Pos + dir Direction + food Pos + start_time i64 + last_tick i64 +} + +// utility +fn (mut app App) reset_game() { + app.score = 0 + app.snake = [ + Pos{3, 8}, + Pos{2, 8}, + Pos{1, 8}, + Pos{0, 8}, + ] + app.dir = .right + app.food = Pos{10, 8} + app.start_time = time.ticks() + app.last_tick = time.ticks() +} + +fn (mut app App) move_food() { + for { + x := rand.int_in_range(0, game_size) + y := rand.int_in_range(0, game_size) + app.food = Pos{x, y} + + if app.food !in app.snake { + return + } + } +} + +// events +fn on_keydown(key gg.KeyCode, mod gg.Modifier, mut app App) { + match key { + .w, .up { + if app.dir != .down { + app.dir = .up + } + } + .s, .down { + if app.dir != .up { + app.dir = .down + } + } + .a, .left { + if app.dir != .right { + app.dir = .left + } + } + .d, .right { + if app.dir != .left { + app.dir = .right + } + } + else {} + } +} + +fn on_frame(mut app App) { + app.gg.begin() + + now := time.ticks() + + if now - app.last_tick >= tick_rate_ms { + app.last_tick = now + + // finding delta direction + delta_dir := match app.dir { + .up { Pos{0, -1} } + .down { Pos{0, 1} } + .left { Pos{-1, 0} } + .right { Pos{1, 0} } + } + + // "snaking" along + mut prev := app.snake[0] + app.snake[0] = app.snake[0] + delta_dir + + for i in 1 .. app.snake.len { + tmp := app.snake[i] + app.snake[i] = prev + prev = tmp + } + + // adding last segment + if app.snake[0] == app.food { + app.move_food() + app.score++ + if app.score > app.best { + app.best = app.score + app.best.save() + } + app.snake << app.snake.last() + app.snake.last() - app.snake[app.snake.len - 2] + } + } + // drawing snake + for pos in app.snake { + app.gg.draw_rect(tile_size * pos.x, tile_size * pos.y + top_height, tile_size, + tile_size, gx.blue) + } + + // drawing food + app.gg.draw_rect(tile_size * app.food.x, tile_size * app.food.y + top_height, tile_size, + tile_size, gx.red) + + // drawing top + app.gg.draw_rect(0, 0, canvas_size, top_height, gx.black) + app.gg.draw_text(150, top_height / 2, 'Score: $app.score', gx.TextCfg{ + color: gx.white + align: .center + vertical_align: .middle + size: 65 + }) + app.gg.draw_text(canvas_size - 150, top_height / 2, 'Best: $app.best', gx.TextCfg{ + color: gx.white + align: .center + vertical_align: .middle + size: 65 + }) + + // checking if snake bit itself + if app.snake[0] in app.snake[1..] { + app.reset_game() + } + // checking if snake hit a wall + if app.snake[0].x < 0 || app.snake[0].x >= game_size || app.snake[0].y < 0 + || app.snake[0].y >= game_size { + app.reset_game() + } + + app.gg.end() +} + +const font = $embed_file('../assets/fonts/RobotoMono-Regular.ttf') + +// setup +fn main() { + mut app := App{ + gg: 0 + } + app.reset_game() + app.best.load() + + mut font_copy := font + font_bytes := unsafe { + font_copy.data().vbytes(font_copy.len) + } + + app.gg = gg.new_context( + bg_color: gx.white + frame_fn: on_frame + keydown_fn: on_keydown + user_data: &app + width: canvas_size + height: top_height + canvas_size + create_window: true + resizable: false + window_title: 'snek' + font_bytes_normal: font_bytes + ) + + app.gg.run() +} |