/
Snake.py
169 lines (133 loc) · 5.67 KB
/
Snake.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import sys
from time import sleep
from random import randint
import pyglet
from pyglet import gl
from pyglet.window import key
from draw import draw_rectangle, draw_text
### sys.argv makes a list of all arguments we call with Python, second one is scaling unit size, e.g. python Snake.py 20
if len(sys.argv) == 2:
PIECE = int(sys.argv[1])
else:
PIECE = 10
### Snake consists of N units, unit = PIECE
WIDTH=100
HEIGHT=50
SNAKE_LENGTH=20
N=20
WALL_THICKNESS=1
FONT_SIZE=4
SCORE_POSITION=[WIDTH//2-FONT_SIZE//2,HEIGHT-FONT_SIZE-WALL_THICKNESS]
QUIT_SIGNAL=0
speed = 0.1 # s
elapsed_time = 0
snake_position = []
food_position=(WIDTH//2, HEIGHT//2)
last_key='right'
DIRECTIONS = {
'up': (0, 1),
'down': (0, -1),
'left': (-1, 0),
'right': (1, 0)
}
def reset():
global N, last_key, snake_position, food_position
N=20
snake_position = []
### We start with the snake placed in the middle, heading right
for i in range(0, N):
snake_position.append((WIDTH//2+i, HEIGHT//2))
last_key = 'right' # Default movement of snake is right direction
food_position = (randint(WALL_THICKNESS + 1, WIDTH - WALL_THICKNESS-1),
randint(WALL_THICKNESS + 1, HEIGHT-WALL_THICKNESS-1))
def refresh():
global snake_position, last_key, N, QUIT_SIGNAL, food_position
if QUIT_SIGNAL==1:
return
### We move almost all snake elements one unit forward, except the last one
snake_position[:-1]=snake_position[1:]
dx, dy = DIRECTIONS[last_key]
### The last element is moved according to last pressed key
snake_position[-1] = (snake_position[-1][0] + dx, snake_position[-1][1] + dy)
### Snake hits the boundary. QUIT_SIGNAL is activated
if (snake_position[-1][0] + 1 > WIDTH-WALL_THICKNESS or
snake_position[-1][0] < WALL_THICKNESS or
snake_position[-1][1] + 1 > HEIGHT-WALL_THICKNESS or
snake_position[-1][1] < WALL_THICKNESS):
QUIT_SIGNAL = 1
### Eating food, head position = food position
if snake_position[-1] == food_position:
snake_position.append((food_position[0] + dx, food_position[1] + dy))
### New food appears
food_position = (randint(WALL_THICKNESS + 1, WIDTH - WALL_THICKNESS-1),
randint(WALL_THICKNESS + 1, HEIGHT-WALL_THICKNESS-1))
N+=1
### Checks if snake doesn't cross itself
if snake_position[-1] in snake_position[:-1]:
QUIT_SIGNAL = 1
def drawing():
gl.glClear(gl.GL_COLOR_BUFFER_BIT) # smaz obsah okna (vybarvi na cerno)
gl.glColor3f(0, 1, 0) # nastav barvu kresleni na zelenu
### Plots the snake body
for i in range(0,len(snake_position)-1):
draw_rectangle(PIECE*snake_position[i][0],PIECE*snake_position[i][1],PIECE*(snake_position[i][0]+1),PIECE*(snake_position[i][1]+1))
### Snake head in blue
gl.glColor3f(0, 0, 1)
draw_rectangle(PIECE*snake_position[-1][0],PIECE*snake_position[-1][1],PIECE*(snake_position[-1][0]+1),PIECE*(snake_position[-1][1]+1))
### Food
draw_rectangle(PIECE*food_position[0],PIECE*food_position[1],PIECE*(food_position[0]+1),PIECE*(food_position[1]+1))
### Score
draw_text(str(N-20),PIECE*SCORE_POSITION[0],PIECE*SCORE_POSITION[1],'left', PIECE*FONT_SIZE)
### Walls
gl.glColor3f(0, 1, 0) # nastav barvu kresleni na zelenu
draw_rectangle(0, 0, PIECE*WALL_THICKNESS, PIECE*HEIGHT)
draw_rectangle(0, 0, PIECE*WIDTH, PIECE*WALL_THICKNESS)
draw_rectangle(PIECE*WIDTH-PIECE*WALL_THICKNESS,0,PIECE*WIDTH,PIECE*HEIGHT)
draw_rectangle(0,PIECE*HEIGHT-PIECE*WALL_THICKNESS,PIECE*WIDTH,PIECE*HEIGHT)
if QUIT_SIGNAL==1:
draw_text('GAME OVER',PIECE*WIDTH//2-PIECE*FONT_SIZE*4,PIECE*HEIGHT//2-PIECE*FONT_SIZE//2,'left', PIECE*FONT_SIZE)
def key_press(symbol, modificators):
"""Osetri stisknuti klavesy
Kdyz hrac stiskne spravnou klavesu, do mnoziny ``stisknute_klavesy`` se
prida dvojice (n-tice) tvaru (smer, cislo palky).
Program pak muze pohybovat palkou podle toho, co je v mnozine.
"""
global last_key
if symbol == key.LEFT and last_key != 'right':
last_key = 'left'
if symbol == key.RIGHT and last_key != 'left':
last_key = 'right'
if symbol == key.UP and last_key != 'down':
last_key = 'up'
if symbol == key.DOWN and last_key != 'up':
last_key = 'down'
# N.B. klavesu ESC Pyglet osetri sam: zavre okno a ukonci funkci run()
def update(dt):
global elapsed_time, speed
elapsed_time += dt
while elapsed_time > speed:
#speed-=0.00002
elapsed_time-=speed
refresh()
# Nastavime prvotni stav
reset()
# Vytvorime okno, do ktereho budeme kreslit
window = pyglet.window.Window(width=int(WIDTH*PIECE), height=int(HEIGHT*PIECE))
# Oknu priradime par funkci, ktere budou reagovat na udalosti.
# Kdyz napr. uzivatel zmackne klavesu na klavesnici,
# Pyglet zavola funkci, kterou tady zaregistrujeme pod `on_key_press`,
# a preda ji prislusne argumenty.
# Jake vsechny udalosti muzou nastat, a jake argumenty se predaji prislusne
# funkci, se doctete v dokumentaci Pygletu,
# nebo pomoci `help(pyglet.window.event)`.
window.push_handlers(
on_draw=drawing, # na vykresleni okna pouzij funkci `vykresli`
on_key_press=key_press, # po stisknuti klavesy zavolej `stisk_klavesy`
)
# Jeste mame jednu podobnou funkci, kterou ale neprirazujeme primo
# oknu. Misto toho chceme aby ji Pyglet zavolal vzdycky kdyz "tiknou hodiny"
pyglet.clock.schedule(update)
pyglet.app.run() # vse je nastaveno, at zacne hra
# (funkce run() bude porad dokola volat obnov_stav, vykresli, a kdyz se mezitim
# neco stane, zavola navic funkci kterou jsme nastavili jako reakci na
# danou udalost)