Last active
May 12, 2022 03:58
-
-
Save maximvl/f3205407d6eeea4a370c9e4cd20d4167 to your computer and use it in GitHub Desktop.
python game
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Red [ | |
author: {Maxim Velesyuk} | |
description: { | |
A Snake Game / basic version | |
specification by Edward de Jong, version 1 | |
The game runs at 6 frames per second, and the snake moves one cell per frame. If the snake moves into the apple the length is increased by one, a crunch sound is emitted, and the apple is moved to a new cell. If the snake crosses over itself, then a beep is emitted and the part of the snake from that cell onward is erased. The snake wraps around the board in all four directions. | |
The playing board, drawn solid black, is subdivided into square cells of 42 points at the screen resolution. Since the window size will not be an even number of cells, the cells are stretched slightly so that all screen space is used by the grid. At the start, the snake is set to length 1 and positioned at cell (4,4). The apple, which is the goal of the snake to eat, is one cell drawn as a circle in HTML color crimson, and is placed at a random location on the board. | |
At the start of the game the snake is paused. As soon as an arrow key is pressed, the snake begins to move in that direction, and leaves a trail behind. Initially the trail is limited to 5 cells total. If the snake moves into the Apple, the snake's length grows by 1. Once the apple is eaten, it is immediately respawned into a random new cell. The apple may end up on occasion placed inside the body of the snake, however, the snake only is considered to have eaten the apple if the head moves onto the apple. The snake cells are drawn as 40 point squares with 2pts on the right and bottom to create a separation. The snake cells are drawn in alternating colors lime green and lawn green. The head of the snake is drawn as a rounded rectangle with a corner radius of 8 pt and a border of 2 pt dark green. The remaining cells of the snake are drawn as a rounded rectangle with 2 pt corner radius. If the snake cells had to be reduced from 42 pt due to window size limitations, then the radii and border thickness are reduced accordingly. | |
The only input to the game is the keyboard. The arrow keys change the direction of the snake, however, to prevent frustration the player is not allowed to move the snake head back into itself. So if the snake is traveling east, any attempted movement west is ignored. A command to move in the direction already in motion is ignored. To permit fast maneuvers the direction inputs are queued, so that the player can do WEST - SOUTH - EAST to perform a 180 degree turn in 3 consecutive frames. Pressing the space bar pauses or resumes the game. | |
As the snake grows and shrinks, the current size and high score is reported at the top of the screen as a topmost layer at 30% opacity, centered in 28 pt black text, for example: "8 high:22". | |
The default starting window size is 700 x 700 interior pixels. If the user resizes the window, the game is reset back to the starting state. | |
Note: since the window size will not usually be an even multiple of 42 points, the cells are slightly stretched to not have any dead space leftover. If the given window size is too small to accommodate at least 10 cells in both directions, the cellsize is reduced. So the program must first figure out how many the proper cell size such that at least 10 cells can fit in the X and Y directions, but no larger than 42 pts in size, then divide the width and height by the number of cells in each direction, and then pad the cells by the leftover amount so that the cell grid fills the space perfectly. | |
External resources: | |
crunch.mp3 sound | |
beep.mp3 sound | |
you are given a window size in pixels, and the resolution of the device. | |
o device resolution might vary from 86 dpi (desktop), to 500+ dpi (mobile) | |
} | |
] | |
nope: no | |
yup: yes | |
window-size: 400x400 | |
grid-size: 40x40 | |
tile-size: window-size / grid-size | |
frame-rate: 6 | |
game: object [ | |
init: does [ | |
snake: copy [4x4 4x3 4x2 4x1 4x0] | |
snake-tail: last snake | |
apple-pos: random grid-size - 1x1 | |
direction: random/only [north south east west] | |
speed: 1 | |
score: 0 | |
window/rate: frame-rate | |
finished: paused: nope | |
] | |
snake: none | |
snake-tail: none | |
apple-pos: none | |
direction: none | |
speed: none | |
score: none | |
paused: yup | |
finished: yup | |
step: func [] [ | |
insert snake (switch direction [ | |
north [ 0x-1 ] | |
east [ 1x0 ] | |
south [ 0x1 ] | |
west [ -1x0 ] | |
]) + snake/1 | |
case [ | |
snake/1/x >= grid-size/x [ snake/1/x: 0 ] | |
snake/1/x < 0 [ snake/1/x: grid-size/x - 1 ] | |
snake/1/y >= grid-size/y [ snake/1/y: 0 ] | |
snake/1/y < 0 [ snake/1/y: grid-size/y - 1 ] | |
] | |
either apple-pos = snake/1 [ | |
apple-pos: random grid-size - 1x1 | |
if zero? ((length? snake) % 3) [ | |
window/rate: window/rate + 3 | |
speed: speed + 1 | |
] | |
score: score + speed | |
] [ | |
snake-tail: take/last snake | |
] | |
if find next snake snake/1 [ finished: paused: yup ] | |
] | |
opposites: #(south north north south east west west east) | |
set-direction: func [new] [ | |
if direction <> (opposites/(new)) [ direction: new ] | |
] | |
color-switch: yup | |
snake-color: does [ | |
color-switch: not color-switch | |
either color-switch [ 50.205.50 ] [ 124.252.0 ] | |
] | |
background: black | |
apple-color: crimson | |
] | |
window: make face! [ | |
type: 'window | |
title: "Python" | |
size: window-size | |
rate: frame-rate | |
pane: reduce [ | |
make face! [ | |
type: 'base | |
size: window-size | |
image: make image! window-size | |
] | |
] | |
actors: object [ | |
on-time: func [face /local image center tail-top-left apple-pos ws] [ | |
if not game/paused [ | |
image: face/pane/1/image | |
game/step | |
apple-pos: (game/apple-pos * tile-size) + (tile-size / 2) | |
ws: window-size | |
ws/y: 0 | |
system/words/draw image compose [ | |
fill-pen (game/background) | |
pen off | |
box (ws - 100x0) (ws + 50) | |
pen white | |
text (ws - 100x0) "score: " text (ws - 50x0) (to-string game/score) | |
text (ws - 100x-20) "speed: " text (ws - 50x-20) (to-string game/speed) | |
pen off | |
fill-pen (game/apple-color) | |
circle (apple-pos) (tile-size/x / 2) | |
] | |
snake: game/snake | |
forall snake [ | |
center: (snake/1 * tile-size) + (tile-size / 2) | |
tail-top-left: game/snake-tail * tile-size | |
system/words/draw image compose [ | |
pen off fill-pen (game/background) box (tail-top-left) (tail-top-left + tile-size) | |
fill-pen (game/snake-color) circle (center) (tile-size/x / 2) | |
] | |
] | |
show face | |
] | |
] | |
on-key: func [face event /local snake] [ | |
if game/finished [ | |
window/pane/1/image/rgb: game/background | |
game/init | |
exit | |
] | |
switch event/key [ | |
up [ game/set-direction 'north ] | |
right [ game/set-direction 'east ] | |
down [ game/set-direction 'south ] | |
left [ game/set-direction 'west ] | |
#" " [ game/paused: not game/paused ] | |
] | |
] | |
on-resize: func [face event] [ | |
window/pane/1/size: window/size | |
] | |
] | |
] | |
draw-grid: func [/local tmp pos] [ | |
tmp: 0x0 | |
while [tmp/x < grid-size/x] [ | |
while [tmp/y < grid-size/y] [ | |
pos: tmp * tile-size | |
draw window/pane/1/image compose [fill-pen (game/background) box (pos) (pos + tile-size) ] | |
tmp/y: tmp/y + 1 | |
] | |
tmp/x: tmp/x + 1 | |
tmp/y: 0 | |
] | |
] | |
draw-grid | |
system/view/auto-sync?: no | |
view/flags/no-wait window [resize] | |
do-events |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment