WASM4 Snake
Bhathiya Perera
Hint: Snake game in Yaksha for WASM4 (ported)
import w4
import libs.random
class Point:
# Point (x, y)
x: i16
y: i16
class Snake:
# Snake's body and direction
body: Array[Point]
direction: Point
class State:
# Game state
snake: Snake
fruit_sprite: Ptr[Const[u8]]
fruit: Point
frame_count: u32
gamepad_prev: u8
def point(x: i16, y: i16) -> Point:
my_point: Point = Point()
my_point.x = x
my_point.y = y
return my_point
def set_random_point(p: Point) -> Point:
x: i16 = cast("i16", random.random_u64() % 20u64)
y: i16 = cast("i16", random.random_u64() % 20u64)
p.x = x
p.y = y
def random_point() -> Point:
p: Point = Point()
return set_random_point(p)
def draw_snake(snake: Snake) -> None:
# Body
w4.set_draw_colors(0x0043u16)
i: int = 0
while i < len(snake.body):
body_part: Point = snake.body[i]
x: int = cast("int", body_part.x * 8i16)
y: int = cast("int", body_part.y * 8i16)
w4.rect(x, y, 8u32, 8u32)
i += 1
# Head
w4.set_draw_colors(0x0004u16)
body_part: Point = snake.body[0]
x: int = cast("int", body_part.x * 8i16)
y: int = cast("int", body_part.y * 8i16)
w4.rect(x, y, 8u32, 8u32)
def snake_push(snake: Snake, p: Point) -> None:
arrput(snake.body, p)
def snake_update(snake: Snake) -> None:
# Move snake a level up
position: int = len(snake.body) - 1
while position > 0:
snake.body[position].x = snake.body[position - 1].x
snake.body[position].y = snake.body[position - 1].y
position -= 1
snake.body[0].x = (snake.body[0].x + snake.direction.x) % 20i16
snake.body[0].y = (snake.body[0].y + snake.direction.y) % 20i16
if snake.body[0].x < 0i16:
snake.body[0].x = 19i16
if snake.body[0].y < 0i16:
snake.body[0].y = 19i16
def snake_up(snake: Snake) -> None:
if snake.direction.y == 0i16:
snake.direction.x = 0i16
snake.direction.y = -1i16
def snake_down(snake: Snake) -> None:
if snake.direction.y == 0i16:
snake.direction.x = 0i16
snake.direction.y = 1i16
def snake_left(snake: Snake) -> None:
if snake.direction.x == 0i16:
snake.direction.x = -1i16
snake.direction.y = 0i16
def snake_right(snake: Snake) -> None:
if snake.direction.x == 0i16:
snake.direction.x = 1i16
snake.direction.y = 0i16
def snake_isdead(snake: Snake) -> bool:
part: int = 1
while part < len(snake.body):
if snake.body[part].x == snake.body[0].x and snake.body[part].y == snake.body[0].y:
return True
part += 1
return False
def del_point(p: Point, ignored: int) -> bool:
del p
return True
def snake_reset(snake: Snake) -> None:
foreach(snake.body, del_point, 0)
del snake.body
body: Array[Point]
arrput(body, point(2i16, 0i16))
arrput(body, point(1i16, 0i16))
arrput(body, point(0i16, 0i16))
snake.body = body
snake.direction.x = 1i16
snake.direction.y = 0i16
def handle_input(state: State) -> None:
just_pressed: u8 = w4.gamepad1() & (w4.gamepad1() ^ state.gamepad_prev)
if just_pressed & w4.BUTTON_UP != 0u8:
snake_up(state.snake)
if just_pressed & w4.BUTTON_DOWN != 0u8:
snake_down(state.snake)
if just_pressed & w4.BUTTON_LEFT != 0u8:
snake_left(state.snake)
if just_pressed & w4.BUTTON_RIGHT != 0u8:
snake_right(state.snake)
state.gamepad_prev = w4.gamepad1()
def game_step(data: AnyPtr) -> None:
state: State = cast("State", data)
state.frame_count += 1u32
random.set_seed(cast("u64", state.frame_count))
x: int = 8 * cast("int", state.fruit.x)
y: int = 8 * cast("int", state.fruit.y)
handle_input(state)
if state.frame_count % 15u32 == 0u32:
snake_update(state.snake)
if snake_isdead(state.snake):
snake_reset(state.snake)
state.fruit = set_random_point(state.fruit)
# Ate fruit
if state.snake.body[0].x == state.fruit.x and state.snake.body[0].y == state.fruit.y:
penultimate: int = len(state.snake.body) - 1
snake_push(state.snake, point(state.snake.body[penultimate].x, state.snake.body[penultimate].y))
state.fruit = set_random_point(state.fruit)
draw_snake(state.snake)
# Draw sprite
w4.set_draw_colors(0x4320u16)
w4.blit(state.fruit_sprite, x, y, 8u32, 8u32, w4.BLIT_2BPP)
def main() -> int:
random.set_seed(0x20u64)
w4.set_palette(0xfbf7f3u32, 0xe5b083u32, 0x426e5du32, 0x20283du32)
state: State = State()
state.snake = Snake()
state.fruit = point(10i16, 8i16)
state.snake.direction = point(1i16, 0i16)
state.frame_count = 0u32
state.gamepad_prev = 0u8
body: Array[Point]
arrput(body, point(2i16, 0i16))
arrput(body, point(1i16, 0i16))
arrput(body, point(0i16, 0i16))
state.snake.body = body
state.fruit_sprite = binarydata("\x00\xa0\x02\x00\x0e\xf0\x36\x5c\xd6\x57\xd5\x57\x35\x5c\x0f\xf0")
w4.set_game_state(cast("AnyPtr", state))
return 0