examples: add snek (a snake game) (#8257)
parent
6c24e9ba84
commit
d1286dbf18
|
@ -0,0 +1,191 @@
|
||||||
|
import gg
|
||||||
|
import gx
|
||||||
|
import sokol.sapp
|
||||||
|
import time
|
||||||
|
import rand
|
||||||
|
import os
|
||||||
|
|
||||||
|
// constants
|
||||||
|
const (
|
||||||
|
top_height = 100
|
||||||
|
canvas_size = 700
|
||||||
|
game_size = 17
|
||||||
|
tile_size = canvas_size / game_size
|
||||||
|
tick_rate_ms = 100
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
mut:
|
||||||
|
gg &gg.Context
|
||||||
|
score int
|
||||||
|
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 sapp.KeyCode, mod sapp.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++
|
||||||
|
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(canvas_size / 2, top_height / 2, app.score.str(), gx.TextCfg{
|
||||||
|
color: gx.white
|
||||||
|
align: .center
|
||||||
|
vertical_align: .middle
|
||||||
|
size: 75
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup
|
||||||
|
fn main() {
|
||||||
|
mut app := App{
|
||||||
|
gg: 0
|
||||||
|
}
|
||||||
|
app.reset_game()
|
||||||
|
|
||||||
|
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
|
||||||
|
use_ortho: true
|
||||||
|
create_window: true
|
||||||
|
resizable: false
|
||||||
|
window_title: 'snek'
|
||||||
|
font_path: os.resource_abs_path(os.join_path('../assets/fonts/', 'RobotoMono-Regular.ttf'))
|
||||||
|
)
|
||||||
|
|
||||||
|
app.gg.run()
|
||||||
|
}
|
Loading…
Reference in New Issue