The Snake class

Let's now create the Snake class. We have already passed a task to generate our food to the central queue. However, no additional thread was involved in the task. We could also generate our Snake class without using threads. However, because we are talking about ways to implement multithreaded applications, let's implement our Snake class to work from a separate thread (see 9.04_game_of_snake.py):

class Snake(threading.Thread):

is_game_over = False

def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
self.daemon = True
self.points_earned = 0
self.snake_points = [(495, 55), (485, 55), (475, 55), (465, 55),
(455, 55)]
self.food = Food(queue)
self.direction = 'Left'
self.start()

def run(self):
while not self.is_game_over:
self.queue.put({'move': self.snake_points})
time.sleep(0.1)
self.move()

def on_keypress(self, e):
self.direction = e.keysym

def move(self):
new_snake_point = self.calculate_new_coordinates()
if self.food.position == new_snake_point:
self.points_earned += 1
self.queue.put({'points_earned': self.points_earned})
self.food.generate_food()
else:
self.snake_points.pop(0)
self.check_game_over(new_snake_point)
self.snake_points.append(new_snake_point)

def calculate_new_coordinates(self):
last_x, last_y = self.snake_points[-1]
if self.direction == 'Up':
new_snake_point = (last_x, last_y - 10)
elif self.direction == 'Down':
new_snake_point = (last_x, last_y + 10)
elif self.direction == 'Left':
new_snake_point = (last_x - 10, last_y)
elif self.direction == 'Right':
new_snake_point = (last_x + 10, last_y)
return new_snake_point

def check_game_over(self, snake_point):
x, y = snake_point
if not -5 < x < 505 or not -5 < y < 315 or snake_point in self.snake_points:
self.is_game_over = True
self.queue.put({'game_over': True})

The description of the code is as follows:

  • We create a class named Snake to run from a separate thread. This class takes the queue as its input arguments.
  • We initialize the points earned by the player from zero and set the initial location of the snake using the attribute self.snake_points. Note that initially, the snake is 40 pixels long.
  • Finally, we start the thread and create an infinite loop to call the move() method at small intervals. During every run of the loop, the method populates the queue with a dictionary having the key as move and the value equal to the updated position of the snake, through the self.snake_points attribute.
  • First, the move method obtains the latest coordinates for the snake depending on the keyboard event. It uses a separate method called calculate_new_coordinates to get the latest coordinates.
  • It then checks whether the location of the new coordinates coincides with the location of the food. If they match, it increases the score of the player by one and calls the Food class' generate_food method to generate a new food at a new location.
  • If the current point does not coincide with the food coordinates, it deletes the first item from the snake coordinates using self.snake_points.pop(0).
  • Then, it calls another method named check_game_over to check whether the snake collides with the wall or itself. If the snake does collide, it appends a new dictionary item in the queue with the value 'game_over':True.
  • Finally, if the game is not over, it appends the new position of the snake to the list self.snake_points. This is automatically added to the queue, because we have defined self.queue.put({'move': self.snake_points } ) in the Snake class's run() method to update every 0.1 seconds as long as the game is not over.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.172.130