aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/examples/snek/snek.v
diff options
context:
space:
mode:
authorIndrajith K L2022-12-03 17:00:20 +0530
committerIndrajith K L2022-12-03 17:00:20 +0530
commitf5c4671bfbad96bf346bd7e9a21fc4317b4959df (patch)
tree2764fc62da58f2ba8da7ed341643fc359873142f /v_windows/v/examples/snek/snek.v
downloadcli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.gz
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.tar.bz2
cli-tools-windows-f5c4671bfbad96bf346bd7e9a21fc4317b4959df.zip
Adds most of the toolsHEADmaster
Diffstat (limited to 'v_windows/v/examples/snek/snek.v')
-rw-r--r--v_windows/v/examples/snek/snek.v221
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()
+}