1. Підготовка ігрового поля # замовлення бібліотек: from tkinter import * # tkinter import random # random w = 740 # ширина ігрового поля h = 540 # висота ігрового поля a = 20 # сторона квадрата - сегмента змійки чи плоду # - бажано, щоб була дільником w i h IN_GAME = True # стан гри: при справдженні гра триває root = Tk() # створення вікна root.title("Гра «Змійка»") # встановлення назви вікна # створення полотна темнозеленого кольору c = Canvas(root, width=w, height=h, bg="#005500") c.grid() # розташування полотна у вікні c.focus_set() # надання фокуса полотну # 2. Створення зображення червоного "плоду" def create_block(): # створення червоного круга global BLOCK x = a * random.randint(1,(w-a)/a) # випадкова абсциса ЛВК, кратна a y = a * random.randint(1,(h-a)/a) # випадкова ордината ЛВК, кратна a BLOCK = c.create_oval(x, y, x+a, y+a, fill="red") create_block() # створити зображення червоного "плоду" # 3. Створення початкового зображення "змійки" class Segment(object): # Cегмент - квадрат білого кольору def __init__(self, x, y): # з ЛВК у точці (x,y) і стороною а self.instance = c.create_rectangle(x,y,x+a,y+a,fill="white") class Snake(object): # змійка як набір сегментів з методами руху, # зміни напрямку і додавання сегмента. def __init__(self, segments): self.segments = segments # перелік напрямків руху змійки self.mapping = {"Down":(0,1), "Right":(1,0), "Up":(0,-1), "Left":(-1,0)} # початковий вектор руху змійки - праворуч self.vector = self.mapping["Right"] def move(self): # метод руху в поточному напрямку # перебір усіх сегментів крім "голови" # - того, що має найбільший номер for index in range(len(self.segments)-1): segment = self.segments[index].instance # поточний сегмент # координати наступного сегмента - ближчого до "голови" x1, y1, x2, y2 = c.coords(self.segments[index+1].instance) # переміщення поточного сегмента у позицію наступного c.coords(segment, x1, y1, x2, y2) # координати того сегмента, що зайняв місце "голови" x1, y1, x2, y2 = c.coords(self.segments[-2].instance) # переміщення "голови" у напрямку, вказаному вектором руху c.coords(self.segments[-1].instance, x1+self.vector[0]*a, y1+self.vector[1]*a, x2+self.vector[0]*a, y2+self.vector[1]*a) def add_segment(self): # додавання сегмента # найдальший від "голови сегмент" last = c.coords(self.segments[0].instance) # координати ЛВК сегмента, який буде вставлено x = last[2] - a y = last[3] - a # додавання сегмента змійки self.segments.insert(0, Segment(x, y)) # Зміна напрямку руху змійки def change_direction(self, event): # якщо натиснуто клавішу зі стрілкою... if event.keysym in self.mapping: self.vector = self.mapping[event.keysym] # створення змійки з 3 сегментів # у верхньому лівому куті ігрового поля s = Snake([Segment(a,a), Segment(a*2,a), Segment(a*3,a)]) # 4. Пов'язування полотна с, події натискання клавіші # KeyPress і обробника події s.change_direction c.bind("", s.change_direction) # 5. Опис перебігу гри def main(): # основну функція керування перебігом гри global IN_GAME if IN_GAME: s.move() # рух "змійки" head_coords = c.coords(s.segments[-1].instance) # координати голови x1, y1, x2, y2 = head_coords if x2 > w or x1 < 0 or y1 < 0 or y2 > h: # якщо є спроба вийти за межі поля IN_GAME = False # вихід з гри elif head_coords == c.coords(BLOCK): # якщо "з'їли" червоний "плід": s.add_segment() # збільшити довжину; c.delete(BLOCK) # знищити старий "плід"; create_block() # створити новий "плід"; else: for index in range(len(s.segments)-1): # перебір сегментів - крім "голови" if head_coords == c.coords(s.segments[index].instance): # при перетині з головою... IN_GAME = False # вихід з гри root.after(100, main) # запуск через 100 мілісекунд програми main (таймер) else: # виведення повідомлення про завершення гри c.create_text(w/2, h/2, text="Гру завершено з довжиною змійки "+str(len(s.segments)), font="Ubuntu 28", fill="yellow") main() root.mainloop() # запуск циклу опрацювання подій