#!!! Создаём окно игры и подлодку
from tkinter import *
#Окно
HEIGHT = 500
WIDTH = 800
window = Tk( )
window.title ( 'Bubble Blaster' )
#Холст
c = Canvas( window, width= WIDTH, height= HEIGHT, bg= 'darkblue' )
c.pack ( )
#Подлодка-игрок
ship_id = c.create_polygon ( 5 , 5 , 5 , 25 , 30 , 15 , fill= 'red' ) #красный треугльник
ship_id2 = c.create_oval ( 0 , 0 , 30 , 30 , outline= 'red' ) #красный круг без заливки
SHIP_R = 15 #Радиус (размер) подлодки
MID_X = WIDTH / 2 #В этих двух переменных -
MID_Y = HEIGHT / 2 #координаты середины экрана
c.move ( ship_id, MID_X, MID_Y) #Перемещает обе части подлодки
c.move ( ship_id2, MID_X, MID_Y) #в середину экрана
#!!! Управление подлодкой
SHIP_SPD = 10 #Расстояние на которое сдвигается подлодка при нажатии клавиши
def move_ship( event) :
if event.keysym == 'Up' :
c.move ( ship_id, 0 , -SHIP_SPD) #Двигает обе части подлодки вверх
c.move ( ship_id2, 0 , -SHIP_SPD)
elif event.keysym == 'Down' :
c.move ( ship_id, 0 , SHIP_SPD)
c.move ( ship_id2, 0 , SHIP_SPD)
elif event.keysym == 'Left' :
c.move ( ship_id, -SHIP_SPD, 0 )
c.move ( ship_id2, -SHIP_SPD, 0 )
elif event.keysym == 'Right' :
c.move ( ship_id, SHIP_SPD, 0 )
c.move ( ship_id2, SHIP_SPD, 0 )
c.bind_all ( '<Key>' , move_ship) #Указывает, что надо вызывать функцию move_ship при нажатии любой клавиши.
#!!! Пузыри
from random import randint
bub_id = list ( ) # Создаёт пустые списки для хранения имени (bub_id),
bub_r = list ( ) # радиуса (bub_r) и
bub_speed = list ( ) # скорости (bub_speed) каждого пузыря.
MIN_BUB_R = 10 # Минимальный радиус пузыря: 10,
MAX_BUB_R = 30 # максимальный: 30.
MAX_BUB_SPD = 10 # Максимальная скорость пузыря.
GAP = 100
def create_bubble( ) :
x = WIDTH + GAP # Задаёт позицию пузыря (GAP нужен, чтобы пузырь точно был за
# видимым экраном)
y = randint( 0 , HEIGHT) # на холсте
r = randint( MIN_BUB_R, MAX_BUB_R) # Выбирает случайный радиус пузыря от
# минимального до максимального значения
id1 = c.create_oval ( x-r, y-r, x+r, y+r, outline= 'white' ) # Рисуем пузыри
bub_id.append ( id1) # Добавляет имя,
bub_r.append ( r) # радиус
bub_speed.append ( randint( 1 , MAX_BUB_SPD) ) # и скорость пузыря в списки.
#!!! Движение пузырей
def move_bubbles( ) :
for i in range ( len ( bub_id) ) : # По очереди берёт каждый пузырь из списка
c.move ( bub_id[ i] , -bub_speed[ i] , 0 ) # Двигает пузырь с его скоростью
def get_coords( id_num) :
pos = c.coords ( id_num)
x = ( pos[ 0 ] + pos[ 2 ] ) /2 # Вычисляет X-координату середины пузыря
y = ( pos[ 1 ] + pos[ 3 ] ) /2 # Вычисляет Y-координату середины пузыря
return x, y
from time import sleep, time # Загружает нужные функции из модуля Time
BUB_CHANGE = 10
#MAIN GAME LOOP ГЛАВНЫЙ ЦИКЛ ИГРЫ!!!
while True :
if randint( 1 , BUB_CHANGE) == 1 :# Выбирает случайное число от 1 до 10. Если случай-
# ное число = 1, создаёт новый пузырь (в среднем это 1 случай из 10, так что пузырей
# будет не слишком много)
create_bubble( ) # Вызывает функцию
move_bubbles( ) # Вызывает функцию Двигает пузыри
clean_up_bubs( ) # Удаляет пузыри, уплывшие за экран.
window.update ( ) # Обновляет окно, чтобы перерисовывать пузыри в новых позициях
sleep( 0.01 ) # Замедляет игру, чтобы играть было не слишком сложно
#!!! Пузыри лопаются
def del_bubble( i) : # Удаляет пузырь, имя которого в i
del bub_r[ i] # Удаляет пузырь из списка радиусов
del bub_speed[ i] # и скоростей
c.delete ( bub_id[ i] ) # Удаляет пузырь с холста
del bub_id[ i] # Удаляет пузырь из списка имён
def clean_up_bubs( ) : # Удаляет пузыри, уплывшие за пределы холста
for i in range ( len ( bub_id) -1 , -1 , -1 ) : # Обратный цикл по списку пузырей -
# чтобы избежать ошибки работы for при удалении пузырей
x, y = get_coords( bub_id[ i] ) # Находит координаты пузыря
if x < -GAP:
del_bubble( i) # Если пузырь уплыл за экран, его нужно удалить, иначе он будет
# замедлять игру (-GAP, чтобы пузырь уплыл за экран полностью, а потом там пропал)
IyEhISDQodC+0LfQtNCw0ZHQvCDQvtC60L3QviDQuNCz0YDRiyDQuCDQv9C+0LTQu9C+0LTQutGDCgpmcm9tIHRraW50ZXIgaW1wb3J0ICoKCiPQntC60L3QvgpIRUlHSFQgPSA1MDAKV0lEVEggPSA4MDAKd2luZG93ID0gVGsoKQp3aW5kb3cudGl0bGUoJ0J1YmJsZSBCbGFzdGVyJykKCiPQpdC+0LvRgdGCCmMgPSBDYW52YXMod2luZG93LCB3aWR0aD1XSURUSCwgaGVpZ2h0PUhFSUdIVCwgYmc9J2RhcmtibHVlJykKYy5wYWNrKCkKCgoj0J/QvtC00LvQvtC00LrQsC3QuNCz0YDQvtC6CnNoaXBfaWQgPSBjLmNyZWF0ZV9wb2x5Z29uKDUsIDUsIDUsIDI1LCAzMCwgMTUsIGZpbGw9J3JlZCcpICPQutGA0LDRgdC90YvQuSDRgtGA0LXRg9Cz0LvRjNC90LjQugpzaGlwX2lkMiA9IGMuY3JlYXRlX292YWwoMCwgMCwgMzAsIDMwLCBvdXRsaW5lPSdyZWQnKSAj0LrRgNCw0YHQvdGL0Lkg0LrRgNGD0LMg0LHQtdC3INC30LDQu9C40LLQutC4ClNISVBfUiA9IDE1ICPQoNCw0LTQuNGD0YEgKNGA0LDQt9C80LXRgCkg0L/QvtC00LvQvtC00LrQuApNSURfWCA9IFdJRFRIIC8gMiAj0JIg0Y3RgtC40YUg0LTQstGD0YUg0L/QtdGA0LXQvNC10L3QvdGL0YUgLQpNSURfWSA9IEhFSUdIVCAvIDIgI9C60L7QvtGA0LTQuNC90LDRgtGLINGB0LXRgNC10LTQuNC90Ysg0Y3QutGA0LDQvdCwCmMubW92ZShzaGlwX2lkLCBNSURfWCwgTUlEX1kpICPQn9C10YDQtdC80LXRidCw0LXRgiDQvtCx0LUg0YfQsNGB0YLQuCDQv9C+0LTQu9C+0LTQutC4CmMubW92ZShzaGlwX2lkMiwgTUlEX1gsIE1JRF9ZKSAj0LIg0YHQtdGA0LXQtNC40L3RgyDRjdC60YDQsNC90LAKCgojISEhINCj0L/RgNCw0LLQu9C10L3QuNC1INC/0L7QtNC70L7QtNC60L7QuQoKU0hJUF9TUEQgPSAxMCAj0KDQsNGB0YHRgtC+0Y/QvdC40LUg0L3QsCDQutC+0YLQvtGA0L7QtSDRgdC00LLQuNCz0LDQtdGC0YHRjyDQv9C+0LTQu9C+0LTQutCwINC/0YDQuCDQvdCw0LbQsNGC0LjQuCDQutC70LDQstC40YjQuApkZWYgbW92ZV9zaGlwKGV2ZW50KToKICAgIGlmIGV2ZW50LmtleXN5bSA9PSAnVXAnOgogICAgICAgIGMubW92ZShzaGlwX2lkLCAwLCAtU0hJUF9TUEQpICPQlNCy0LjQs9Cw0LXRgiDQvtCx0LUg0YfQsNGB0YLQuCDQv9C+0LTQu9C+0LTQutC4INCy0LLQtdGA0YUKICAgICAgICBjLm1vdmUoc2hpcF9pZDIsIDAsIC1TSElQX1NQRCkKICAgIGVsaWYgZXZlbnQua2V5c3ltID09ICdEb3duJzoKICAgICAgICBjLm1vdmUoc2hpcF9pZCwgMCwgU0hJUF9TUEQpCiAgICAgICAgYy5tb3ZlKHNoaXBfaWQyLCAwLCBTSElQX1NQRCkKICAgIGVsaWYgZXZlbnQua2V5c3ltID09ICdMZWZ0JzoKICAgICAgICBjLm1vdmUoc2hpcF9pZCwgLVNISVBfU1BELCAwKQogICAgICAgIGMubW92ZShzaGlwX2lkMiwgLVNISVBfU1BELCAwKQogICAgZWxpZiBldmVudC5rZXlzeW0gPT0gJ1JpZ2h0JzoKICAgICAgICBjLm1vdmUoc2hpcF9pZCwgU0hJUF9TUEQsIDApCiAgICAgICAgYy5tb3ZlKHNoaXBfaWQyLCBTSElQX1NQRCwgMCkKYy5iaW5kX2FsbCgnPEtleT4nLCBtb3ZlX3NoaXApICPQo9C60LDQt9GL0LLQsNC10YIsINGH0YLQviDQvdCw0LTQviDQstGL0LfRi9Cy0LDRgtGMINGE0YPQvdC60YbQuNGOIG1vdmVfc2hpcCDQv9GA0Lgg0L3QsNC20LDRgtC40Lgg0LvRjtCx0L7QuSDQutC70LDQstC40YjQuC4KCgojISEhINCf0YPQt9GL0YDQuAoKZnJvbSByYW5kb20gaW1wb3J0IHJhbmRpbnQKCmJ1Yl9pZCA9IGxpc3QoKSAjINCh0L7Qt9C00LDRkdGCINC/0YPRgdGC0YvQtSDRgdC/0LjRgdC60Lgg0LTQu9GPINGF0YDQsNC90LXQvdC40Y8g0LjQvNC10L3QuCAoYnViX2lkKSwKYnViX3IgPSBsaXN0KCkgIyDRgNCw0LTQuNGD0YHQsCAoYnViX3IpINC4CmJ1Yl9zcGVlZCA9IGxpc3QoKSAjINGB0LrQvtGA0L7RgdGC0LggKGJ1Yl9zcGVlZCkg0LrQsNC20LTQvtCz0L4g0L/Rg9C30YvRgNGPLgoKTUlOX0JVQl9SID0gMTAgIyDQnNC40L3QuNC80LDQu9GM0L3Ri9C5INGA0LDQtNC40YPRgSDQv9GD0LfRi9GA0Y86IDEwLApNQVhfQlVCX1IgPSAzMCAjINC80LDQutGB0LjQvNCw0LvRjNC90YvQuTogMzAuCk1BWF9CVUJfU1BEID0gMTAgIyDQnNCw0LrRgdC40LzQsNC70YzQvdCw0Y8g0YHQutC+0YDQvtGB0YLRjCDQv9GD0LfRi9GA0Y8uCkdBUCA9IDEwMAoKZGVmIGNyZWF0ZV9idWJibGUoKToKICAgIHggPSBXSURUSCArIEdBUCAjINCX0LDQtNCw0ZHRgiDQv9C+0LfQuNGG0LjRjiDQv9GD0LfRi9GA0Y8gKEdBUCDQvdGD0LbQtdC9LCDRh9GC0L7QsdGLINC/0YPQt9GL0YDRjCDRgtC+0YfQvdC+INCx0YvQuyDQt9CwCiMg0LLQuNC00LjQvNGL0Lwg0Y3QutGA0LDQvdC+0LwpCiAgICB5ID0gcmFuZGludCgwLCBIRUlHSFQpICMg0L3QsCDRhdC+0LvRgdGC0LUKICAgIAogICAgciA9IHJhbmRpbnQoTUlOX0JVQl9SLCBNQVhfQlVCX1IpICMg0JLRi9Cx0LjRgNCw0LXRgiDRgdC70YPRh9Cw0LnQvdGL0Lkg0YDQsNC00LjRg9GBINC/0YPQt9GL0YDRjyDQvtGCCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyDQvNC40L3QuNC80LDQu9GM0L3QvtCz0L4g0LTQviDQvNCw0LrRgdC40LzQsNC70YzQvdC+0LPQviDQt9C90LDRh9C10L3QuNGPICAKICAgIGlkMSA9IGMuY3JlYXRlX292YWwoeC1yLCB5LXIsIHgrciwgeStyLCBvdXRsaW5lPSd3aGl0ZScpICMg0KDQuNGB0YPQtdC8INC/0YPQt9GL0YDQuAogICAgCiAgICBidWJfaWQuYXBwZW5kKGlkMSkgIyDQlNC+0LHQsNCy0LvRj9C10YIg0LjQvNGPLAogICAgYnViX3IuYXBwZW5kKHIpICAgICMg0YDQsNC00LjRg9GBCiAgICBidWJfc3BlZWQuYXBwZW5kKHJhbmRpbnQoMSwgTUFYX0JVQl9TUEQpKSAjINC4INGB0LrQvtGA0L7RgdGC0Ywg0L/Rg9C30YvRgNGPINCyINGB0L/QuNGB0LrQuC4KCgojISEhINCU0LLQuNC20LXQvdC40LUg0L/Rg9C30YvRgNC10LkKCmRlZiBtb3ZlX2J1YmJsZXMoKToKICAgIGZvciBpIGluIHJhbmdlKGxlbihidWJfaWQpKTogIyDQn9C+INC+0YfQtdGA0LXQtNC4INCx0LXRgNGR0YIg0LrQsNC20LTRi9C5INC/0YPQt9GL0YDRjCDQuNC3INGB0L/QuNGB0LrQsAogICAgICAgIGMubW92ZShidWJfaWRbaV0sIC1idWJfc3BlZWRbaV0sIDApICMg0JTQstC40LPQsNC10YIg0L/Rg9C30YvRgNGMINGBINC10LPQviDRgdC60L7RgNC+0YHRgtGM0Y4KCmRlZiBnZXRfY29vcmRzKGlkX251bSk6CiAgICBwb3MgPSBjLmNvb3JkcyhpZF9udW0pCiAgICB4ID0gKHBvc1swXSArIHBvc1syXSkvMiAjINCS0YvRh9C40YHQu9GP0LXRgiBYLdC60L7QvtGA0LTQuNC90LDRgtGDINGB0LXRgNC10LTQuNC90Ysg0L/Rg9C30YvRgNGPCiAgICB5ID0gKHBvc1sxXSArIHBvc1szXSkvMiAjINCS0YvRh9C40YHQu9GP0LXRgiBZLdC60L7QvtGA0LTQuNC90LDRgtGDINGB0LXRgNC10LTQuNC90Ysg0L/Rg9C30YvRgNGPCiAgICByZXR1cm4geCwgeQoKZnJvbSB0aW1lIGltcG9ydCBzbGVlcCwgdGltZSAjINCX0LDQs9GA0YPQttCw0LXRgiDQvdGD0LbQvdGL0LUg0YTRg9C90LrRhtC40Lgg0LjQtyDQvNC+0LTRg9C70Y8gVGltZQpCVUJfQ0hBTkdFID0gMTAKI01BSU4gR0FNRSBMT09QINCT0JvQkNCS0J3Qq9CZINCm0JjQmtCbINCY0JPQoNCrISEhCndoaWxlIFRydWU6CiAgICBpZiByYW5kaW50KDEsIEJVQl9DSEFOR0UpID09IDE6IyDQktGL0LHQuNGA0LDQtdGCINGB0LvRg9GH0LDQudC90L7QtSDRh9C40YHQu9C+INC+0YIgMSDQtNC+IDEwLiDQldGB0LvQuCDRgdC70YPRh9Cw0LktCiMg0L3QvtC1INGH0LjRgdC70L4gPSAxLCDRgdC+0LfQtNCw0ZHRgiDQvdC+0LLRi9C5INC/0YPQt9GL0YDRjCAo0LIg0YHRgNC10LTQvdC10Lwg0Y3RgtC+IDEg0YHQu9GD0YfQsNC5INC40LcgMTAsINGC0LDQuiDRh9GC0L4g0L/Rg9C30YvRgNC10LkKIyDQsdGD0LTQtdGCINC90LUg0YHQu9C40YjQutC+0Lwg0LzQvdC+0LPQvikKICAgICAgICAKICAgICAgICBjcmVhdGVfYnViYmxlKCkgIyDQktGL0LfRi9Cy0LDQtdGCINGE0YPQvdC60YbQuNGOCiAgICBtb3ZlX2J1YmJsZXMoKSAjINCS0YvQt9GL0LLQsNC10YIg0YTRg9C90LrRhtC40Y4g0JTQstC40LPQsNC10YIg0L/Rg9C30YvRgNC4CiAgICBjbGVhbl91cF9idWJzKCkgIyDQo9C00LDQu9GP0LXRgiDQv9GD0LfRi9GA0LgsINGD0L/Qu9GL0LLRiNC40LUg0LfQsCDRjdC60YDQsNC9LgogICAgd2luZG93LnVwZGF0ZSgpICMg0J7QsdC90L7QstC70Y/QtdGCINC+0LrQvdC+LCDRh9GC0L7QsdGLINC/0LXRgNC10YDQuNGB0L7QstGL0LLQsNGC0Ywg0L/Rg9C30YvRgNC4INCyINC90L7QstGL0YUg0L/QvtC30LjRhtC40Y/RhQogICAgc2xlZXAoMC4wMSkgIyDQl9Cw0LzQtdC00LvRj9C10YIg0LjQs9GA0YMsINGH0YLQvtCx0Ysg0LjQs9GA0LDRgtGMINCx0YvQu9C+INC90LUg0YHQu9C40YjQutC+0Lwg0YHQu9C+0LbQvdC+CgoKIyEhISDQn9GD0LfRi9GA0Lgg0LvQvtC/0LDRjtGC0YHRjwoKZGVmIGRlbF9idWJibGUoaSk6ICMg0KPQtNCw0LvRj9C10YIg0L/Rg9C30YvRgNGMLCDQuNC80Y8g0LrQvtGC0L7RgNC+0LPQviDQsiBpCiAgICBkZWwgYnViX3JbaV0gIyDQo9C00LDQu9GP0LXRgiDQv9GD0LfRi9GA0Ywg0LjQtyDRgdC/0LjRgdC60LAg0YDQsNC00LjRg9GB0L7QsgogICAgZGVsIGJ1Yl9zcGVlZFtpXSAjINC4INGB0LrQvtGA0L7RgdGC0LXQuQogICAgYy5kZWxldGUoYnViX2lkW2ldKSAjINCj0LTQsNC70Y/QtdGCINC/0YPQt9GL0YDRjCDRgSDRhdC+0LvRgdGC0LAKICAgIGRlbCBidWJfaWRbaV0gIyDQo9C00LDQu9GP0LXRgiDQv9GD0LfRi9GA0Ywg0LjQtyDRgdC/0LjRgdC60LAg0LjQvNGR0L0KCmRlZiBjbGVhbl91cF9idWJzKCk6ICMg0KPQtNCw0LvRj9C10YIg0L/Rg9C30YvRgNC4LCDRg9C/0LvRi9Cy0YjQuNC1INC30LAg0L/RgNC10LTQtdC70Ysg0YXQvtC70YHRgtCwCiAgICBmb3IgaSBpbiByYW5nZShsZW4oYnViX2lkKS0xLCAtMSwgLTEpOiAjINCe0LHRgNCw0YLQvdGL0Lkg0YbQuNC60Lsg0L/QviDRgdC/0LjRgdC60YMg0L/Rg9C30YvRgNC10LkgLQojINGH0YLQvtCx0Ysg0LjQt9Cx0LXQttCw0YLRjCDQvtGI0LjQsdC60Lgg0YDQsNCx0L7RgtGLIGZvciDQv9GA0Lgg0YPQtNCw0LvQtdC90LjQuCDQv9GD0LfRi9GA0LXQuQogICAgICAgIHgsIHkgPSBnZXRfY29vcmRzKGJ1Yl9pZFtpXSkgIyDQndCw0YXQvtC00LjRgiDQutC+0L7RgNC00LjQvdCw0YLRiyDQv9GD0LfRi9GA0Y8KICAgICAgICBpZiB4IDwgLUdBUDoKICAgICAgICAgICAgZGVsX2J1YmJsZShpKSAjINCV0YHQu9C4INC/0YPQt9GL0YDRjCDRg9C/0LvRi9C7INC30LAg0Y3QutGA0LDQvSwg0LXQs9C+INC90YPQttC90L4g0YPQtNCw0LvQuNGC0YwsINC40L3QsNGH0LUg0L7QvSDQsdGD0LTQtdGCCiMg0LfQsNC80LXQtNC70Y/RgtGMINC40LPRgNGDICgtR0FQLCDRh9GC0L7QsdGLINC/0YPQt9GL0YDRjCDRg9C/0LvRi9C7INC30LAg0Y3QutGA0LDQvSDQv9C+0LvQvdC+0YHRgtGM0Y4sINCwINC/0L7RgtC+0Lwg0YLQsNC8INC/0YDQvtC/0LDQuykgICAgICAgICAgIAoKCgo=