1

Тема: Допоможіть розібрати код

Знайшов в інтернеті іграшку на python (змійку).
Вирішив в ній розібратися, як вона працює...

Прихований текст
import pygame
import sys
import random
import time
class Game():
     def __init__(self):
         # задаємо розміри екрану
         self.screen_width = 720
         self.screen_height = 460
 
         # необхідні кольори
         self.green = pygame.Color(0, 255, 0)
         self.red = pygame.Color(255, 0, 0)
         self.black = pygame.Color(0, 0, 0)
         self.white = pygame.Color(255, 255, 255)
         self.brown = pygame.Color(165, 42, 42)
 
         # Frame per second controller
         # буде задавати кількість кадрів в секунду
         self.fps_controller = pygame.time.Clock()
 
         # змінна для відображення результату
         self.score = 0
 
     def init_and_check_for_errors(self):
         """початкова функція для ініціалізаці і
            перевірки як запуститься pygame"""
         check_errors = pygame.init()
         if check_errors[1] > 0:
             sys.exit()
         else:
             print('Ok')
 
     def set_surface_and_title(self):
         """задаєм surface(поверхність поверх якої буде все малюватися)
         і установлюємо заголовок вікна"""
         self.play_surface = pygame.display.set_mode((
             self.screen_width, self.screen_height))
         pygame.display.set_caption('Snake Game')
 
     def event_loop(self, change_to):
         """Функція для відслідкування натисків клавіш гравцем"""
 
         # запускаємо цикл по івентам
         for event in pygame.event.get():
             # якщо натиснули клавішу
             if event.type == pygame.KEYDOWN:
                 if event.key == pygame.K_RIGHT or event.key == ord('d'):
                     change_to = "RIGHT"
                 elif event.key == pygame.K_LEFT or event.key == ord('a'):
                     change_to = "LEFT"
                 elif event.key == pygame.K_UP or event.key == ord('w'):
                     change_to = "UP"
                 elif event.key == pygame.K_DOWN or event.key == ord('s'):
                     change_to = "DOWN"
                 # натиснули escape
                 elif event.key == pygame.K_ESCAPE:
                     pygame.quit()
                     sys.exit()
         return change_to
 
     def refresh_screen(self):
         """обновляємо екран і задаємо фпс"""
         pygame.display.flip()
         game.fps_controller.tick(20)
 
     def show_score(self, choice=1):
         """відображення результату"""
         s_font = pygame.font.SysFont('monaco', 24)
         s_surf = s_font.render(
             'Score: {0}'.format(self.score), True, self.black)
         s_rect = s_surf.get_rect()
         # дефолтний випадок відображаєм результат зліва зверху
         if choice == 1:
             s_rect.midtop = (80, 10)
         # при game_overe відображаєм результат по центру
         # під надписом game over
         else:
             s_rect.midtop = (360, 120)
         # малюєм прямокутник поверх surface
         self.play_surface.blit(s_surf, s_rect)
     def game_over(self):
         """Функція для виводу надпису Game Over і результатів
         в випадку завершення гри і вихід з гри"""
         go_font = pygame.font.SysFont('monaco', 72)
         go_surf = go_font.render('Game over', True, self.red)
         go_rect = go_surf.get_rect()
         go_rect.midtop = (360, 15)
         self.play_surface.blit(go_surf, go_rect)
         self.show_score(0)
         pygame.display.flip()
         time.sleep(3)
         pygame.quit()
         sys.exit()
class Snake():
     def __init__(self, snake_color):
         # важливі змінні - позиція голови змії і її тіла
         self.snake_head_pos = [100, 50]  # [x, y]
         # початкове тіло змії складається з трьох сегментів
         # голова змеії - перший елемент, хвіст - останній
         self.snake_body = [[100, 50], [90, 50], [80, 50]]
         self.snake_color = snake_color
         # напрям руху змії, спочатку
         # задамося вправо
         self.direction = "RIGHT"
         # куди буде мінятися напрям руху змії
         # при натисненні відповідних клавіш
         self.change_to = self.direction
 
     def validate_direction_and_change(self):
         """міняємо напрям руху змії тільки в тому випадку,
         якщо він не прямо протилежний даному"""
         if any((self.change_to == "RIGHT" and not self.direction == "LEFT",
                 self.change_to == "LEFT" and not self.direction == "RIGHT",
                 self.change_to == "UP" and not self.direction == "DOWN",
                 self.change_to == "DOWN" and not self.direction == "UP")):
             self.direction = self.change_to
 
     def change_head_position(self):
         """змінюєм положення голови змії"""
         if self.direction == "RIGHT":
             self.snake_head_pos[0] += 10
         elif self.direction == "LEFT":
             self.snake_head_pos[0] -= 10
         elif self.direction == "UP":
             self.snake_head_pos[1] -= 10
         elif self.direction == "DOWN":
             self.snake_head_pos[1] += 10
 
     def snake_body_mechanism(
             self, score, food_pos, screen_width, screen_height):
         # якщо вставляти просто snake_head_pos,
         # то на всіх трьох позиціях в snake_body
         # виявиться один и той же список з одинаковими координатами
         # і ми будемо управляти змією з одного квадрату
         self.snake_body.insert(0, list(self.snake_head_pos))
         # якщо з'їли їжу
         if (self.snake_head_pos[0] == food_pos[0] and
                 self.snake_head_pos[1] == food_pos[1]):
             # якщо з'їли їжу то задаємо нове положення їжі випадковим
             # чином і збільшуєм score на один
             food_pos = [random.randrange(1, screen_width/10)*10,
                         random.randrange(1, screen_height/10)*10]
             score += 1
         else:
             # якщо не знайшли їжу, то забираємо останній сегмент,
             # якщо цього не зробити, то змія буде постійно рости
             self.snake_body.pop()
         return score, food_pos
 
     def draw_snake(self, play_surface, surface_color):
         """відображаєм всі сегменти змії"""
         play_surface.fill(surface_color)
         for pos in self.snake_body:
             # pygame.Rect(x,y, sizex, sizey)
             pygame.draw.rect(
                 play_surface, self.snake_color, pygame.Rect(
                     pos[0], pos[1], 10, 10))
 
     def check_for_boundaries(self, game_over, screen_width, screen_height):
         """Перевірка, що зіткнулись з кінцями екрану або самі з собою
         (змія закільцювалася)"""
         if any((
             self.snake_head_pos[0] > screen_width-10
             or self.snake_head_pos[0] < 0,
             self.snake_head_pos[1] > screen_height-10
             or self.snake_head_pos[1] < 0
                 )):
             game_over()
         for block in self.snake_body[1:]:
             # перевірка на те, що перший елемент(голова) врізалася в
             # будь-який другий елемент змії (закільцювалася)
             if (block[0] == self.snake_head_pos[0] and
                     block[1] == self.snake_head_pos[1]):
                 game_over()
class Food():
     def __init__(self, food_color, screen_width, screen_height):
         """ініт їжі"""
         self.food_color = food_color
         self.food_size_x = 10
         self.food_size_y = 10
         self.food_pos = [random.randrange(1, screen_width/10)*10,
                          random.randrange(1, screen_height/10)*10]
 
     def draw_food(self, play_surface):
         """відображення їжі"""
         pygame.draw.rect(
             play_surface, self.food_color, pygame.Rect(
                 self.food_pos[0], self.food_pos[1],
                 self.food_size_x, self.food_size_y))
game = Game()
snake = Snake(game.green)
food = Food(game.brown, game.screen_width, game.screen_height)

game.init_and_check_for_errors()
game.set_surface_and_title()
while True:
     snake.change_to = game.event_loop(snake.change_to)
 
     snake.validate_direction_and_change()
     snake.change_head_position()
     game.score, food.food_pos = snake.snake_body_mechanism(
         game.score, food.food_pos, game.screen_width, game.screen_height)
     snake.draw_snake(game.play_surface, game.white)
 
     food.draw_food(game.play_surface)
 
     snake.check_for_boundaries(
         game.game_over, game.screen_width, game.screen_height)
 
     game.show_score()
     game.refresh_screen()

Ніяк не можу зрозуміти що робить "self". Гуглив, але так нічого і не зрозумів. Там пише, що це ніби посилання на себе. Тобто?
Ще не можу зрозуміти як програма визначає який колір для змійки, їжі, надписів. Там просто задається

self.food_color = food_color

Але ж до того ніде не вказується який колір для чого.

2 Востаннє редагувалося koala (27.10.2018 00:07:31)

Re: Допоможіть розібрати код

Про self, якщо коротко: коли ви викликаєте метод якогось об'єкту, наприклад

'abc'.replace('c','d')

то в метод передається на один параметр більше, ніж є в дужках - бо також передається (за посиланням) те, що перед крапкою, і воно і зветься self. Можете переконатися, що

str.replace('abc','c','d')

працює так само, як і приклад зверху - бо це є той самий виклик, інакше оформлений.
Що ж до того, що self означає "посилання на сам об`єкт" чи навіть "на себе", то це питання філософії програми (чи парадигми, як вам приємніше). В другому випадку ми ніби кажемо: "викликаємо функцію, яка робить нову стрічку - копію "abc", та замінює в ній всі входження "c" на "d" і повертає." В першому - "abc" повертає свою копію із заміненими "c" на "d". Другий спосіб зазвичай зручніший для розуміння.
Де вказуються кольори:

snake = Snake(game.green)
food = Food(game.brown, game.screen_width, game.screen_height)
Подякували: Eff1c, leofun01, vulyan3

3 Востаннє редагувалося Eff1c (27.10.2018 21:05:03)

Re: Допоможіть розібрати код

koala написав:

Де вказуються кольори:

snake = Snake(game.green)
food = Food(game.brown, game.screen_width, game.screen_height)

Дякую) Якось пропустив цю частину коду. Чомусь думав, що кольори мають задаватися на початку.

koala написав:

Про self, якщо коротко: коли ви викликаєте метод якогось об'єкту...

Ну на даному прикладі зрозумів, але можете пояснити:

self.food_color = food_color

І для чого "self" задається в функіях? с
P's. Ще нарив тут в інеті щось таке:

class Human:
    def __init__(self):
        self.blood = 7000

    def add_blood(self, volume):
        self.blood += volume

"Це ссилка на сам об'єкт цього класу."
Тобто я так зрозумів, що в випадку

def __init__(self, food_color, screen_width, screen_height):

За допомогою "self" змінюють "food_color, screen_width, screen_height"?

4

Re: Допоможіть розібрати код

Походу я вже зрозумів)) нарешті *YAHOO*

Подякували: FakiNyan1