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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
| import pygame as pg
import random
import sqlite3
# import sys
# from button import ImageButton
# Задаём название игры, размеры окна, фиксированные кадры в секунду
TITLE = "MudPong"
WIDTH = 880
HEIGHT = 600
FPS = 60
size = (WIDTH, HEIGHT)
# звуки
pg.mixer.pre_init(44100, -16, 1, 512)
# Создание игры и окна
pg.init()
pg.font.init() # для шрифта
pg.mixer.init() # для звуков
screen = pg.display.set_mode(size)
pg.display.set_caption(TITLE)
clock = pg.time.Clock()
bong = pg.mixer.Sound("sound/bong.ogg")
# Задаём используемые цвета
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# Создание шрифта
ARIAL_FONT_PATH = pg.font.match_font('arial') # путь шрифта
ARIAL_FONT_48 = pg.font.Font(ARIAL_FONT_PATH, 48)
ARIAL_FONT_36 = pg.font.Font(ARIAL_FONT_PATH, 36)
# Функция отрисовки текста
def draw_text(text, x, y):
text_surface = ARIAL_FONT_48.render(text, True, WHITE)
text_rect = text_surface.get_rect(center=(x, y))
screen.blit(text_surface, text_rect)
# Размеры платформы и её реакция на действия
PLATFORM_WIDTH = 150 # длина платформы
PLATFORM_HEIGHT = 15 # высота платформы
PLATFORM_SPEED = 15 # скорость платформы
platform_rect = pg.rect.Rect(WIDTH / 2 - PLATFORM_WIDTH / 2, # проверка столкновения платформы с шаром, контроль позиции
HEIGHT - PLATFORM_HEIGHT * 2, # расположение платформы снизу (По y)
PLATFORM_WIDTH, # ширина
PLATFORM_HEIGHT) # высота
# Размеры Шарика + его движение
CIRCLE_RADIUS = 15
CIRCLE_SPEED = 10
circle_first_collide = False
circle_x_speed = 0 # скорость по x (0, потому что при спавне он просто падает вниз)
circle_y_speed = CIRCLE_SPEED # скорость по y
circle_rect = pg.rect.Rect(WIDTH / 2 - CIRCLE_RADIUS, # расположение мячика (по x (центр))
HEIGHT / 2 - CIRCLE_RADIUS, # по y (центр)
CIRCLE_RADIUS * 2, # размеры (диаметр)
CIRCLE_RADIUS * 2)
# Объявление счёта
score = 0
def reset_score():
global score, circle_x_speed, circle_y_speed, circle_first_collide
score = 0
circle_rect.center = [WIDTH / 2, HEIGHT / 2]
circle_x_speed = 0
circle_y_speed = CIRCLE_SPEED
circle_first_collide = False
platform_rect.centerx = WIDTH / 2
platform_rect.bottom = HEIGHT - PLATFORM_HEIGHT
def play_game():
global running, game_over, circle_first_collide, score, circle_x_speed, circle_y_speed
running = True
game_over = False
circle_first_collide = False
pg.mixer.music.pause()
while running:
# ввод события (процесса)
for event in pg.event.get():
# проверка закрытия окна
if event.type == pg.QUIT: # выход
running = False
continue
elif event.type == pg.KEYDOWN: # нажатие клавиши (проверка какая клавиша нажата)
if event.key == pg.K_ESCAPE: # выход на Esc
running = False
continue
elif event.key == pg.K_r: # Перезагрузка игры на R
game_over = False
reset_score()
screen.fill('#000000') # рендеринг, чтобы платформа перемещалась, при помощи заливки экрана цветом (чёрным)
if not game_over:
keys = pg.key.get_pressed() # создание списка всех нажатых клавишей
if keys[pg.K_a]: # нажатие A
platform_rect.x -= PLATFORM_SPEED
elif keys[pg.K_LEFT]:
platform_rect.x -= PLATFORM_SPEED # движение платформы влево
elif keys[pg.K_d]: # нажатие D
platform_rect.x += PLATFORM_SPEED
elif keys[pg.K_RIGHT]:
platform_rect.x += PLATFORM_SPEED # движение платформы вправо
# столкновение шарика с платформой
if platform_rect.colliderect(circle_rect):
bong.play()
if not circle_first_collide:
if random.randint(0, 1) == 0:
circle_x_speed = -CIRCLE_SPEED
else:
circle_x_speed = CIRCLE_SPEED
circle_first_collide = True
circle_y_speed = -CIRCLE_SPEED
score += 1
pg.draw.rect(screen, '#FF0000', platform_rect) # отрисовка платформы (поверхность, цвет, позиция фигуры)
circle_rect.x += circle_x_speed # отскакивание шарика по x
circle_rect.y += circle_y_speed # отскакивание шарика по y
# проверка на столкновение шарика с нижней границей
if circle_rect.bottom >= HEIGHT:
bong.play()
game_over = True
circle_y_speed = -CIRCLE_SPEED
# проверка на столкновение с верхней границей (верхняя граница = 0)
elif circle_rect.top <= 0:
bong.play()
circle_y_speed = CIRCLE_SPEED
# Проверка на столкновение с правой и левой границей
elif circle_rect.right >= WIDTH:
bong.play()
circle_x_speed = -CIRCLE_SPEED
elif circle_rect.left <= 0:
bong.play()
circle_x_speed = CIRCLE_SPEED
# отрисовка шарика (поверхность, цвет, расположение (центр, радиус круга))
pg.draw.circle(screen, '#000FFF', circle_rect.center, CIRCLE_RADIUS)
# количество очков
score_surface = ARIAL_FONT_48.render(str(score), True, WHITE)
if not game_over:
screen.blit(score_surface, [WIDTH / 2 - score_surface.get_width() / 2, 10])
else: # вывод очков после конца игры
over_score = ARIAL_FONT_48.render('Счёт: ', True, WHITE)
screen.blit(over_score, [WIDTH / 2 - over_score.get_width() / 2, HEIGHT / 4])
screen.blit(score_surface, [WIDTH / 2 - score_surface.get_width() / 2, HEIGHT / 3])
# подсказка
retry_surface = ARIAL_FONT_36.render('Нажмите R, чтобы начать заново', True, WHITE)
screen.blit(retry_surface,
[WIDTH / 2 - retry_surface.get_width() / 2, HEIGHT / 2 + score_surface.get_height()])
clock.tick(FPS) # контроль цикла на правильной скорости (искусственное замедление цикла)
pg.display.update() # обновление всего экрана (переворот экрана после конца отрисовки 1 FPS)
if game_over:
game_over_menu()
game_over = True
# код для сброса начальных значений перед перезапуском игры
def game_over_menu():
running = True
reset_score()
while running:
screen.fill('#000000')
draw_text("Игра окончена", WIDTH // 2, HEIGHT // 5)
draw_text("Нажмите R, чтобы перезапустить игру", WIDTH // 2, HEIGHT // 2.5)
draw_text("Нажмите M, чтобы вернуться в главное меню", WIDTH // 2, HEIGHT // 2)
pg.display.update()
for event in pg.event.get():
if event.type == pg.KEYDOWN:
if event.key == pg.K_r:
play_game()
if event.key == pg.K_m:
main_menu()
# Главное меню игры
def main_menu():
running = True
pg.mixer.music.unpause()
while running:
screen.fill(BLACK)
draw_text("MudPong", WIDTH // 2, HEIGHT // 5)
draw_text("Нажмите SPACE, чтобы начать игру", WIDTH // 2, HEIGHT // 2)
draw_text("Нажмите H, чтобы открыть таблицу рекордов", WIDTH // 2, HEIGHT * 2.5 // 4)
draw_text("Нажмите Q чтобы выйти", WIDTH // 2, HEIGHT * 3.5 // 4)
pg.display.update()
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_SPACE:
running = True
play_game()
if event.key == pg.K_h:
high_scores_menu()
if event.key == pg.K_q:
pg.quit()
quit()
# Меню таблицы рекордов
def high_scores_menu():
running = True
while running:
screen.fill(BLACK)
draw_text("Таблица рекордов", WIDTH // 2, HEIGHT // 4)
# Отобразите таблицу рекордов здесь
draw_text("Нажмите ESC, чтобы вернуться назад", WIDTH // 2, HEIGHT * 3 // 4)
pg.display.update()
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
main_menu()
if __name__ == "__main__":
main_menu()
pg.quit()
# https://habr.com/ru/articles/588605/
# https://habr.com/ru/articles/754400/
# Возможные идеи реализации игры:
# За каждые 50 очков новая музыка в меню.
# Выбор сложности в настройках, изменение музыки при игре |