????????上篇文章Python實現貪吃蛇一,實現了一個貪吃蛇的基礎版本。后面第二篇文章Python實現貪吃蛇二修改了一些不足,但最近發現還有兩點需要優化:
? ? ? ? 1、生成食物的時候有概率和記分牌重合
? ? ? ? 2、游戲缺少暫停功能
? ? ? ? 先看生成食物的時候有概率和記分牌重合的問題。在游戲過程中,有時吃掉一個食物后,發現“沒有”生成新的食物。實際上是食物生成的位置和記分牌重合了,被擋住了。這種情況很影響游戲體驗,并且嘗試去吃掉記分牌下面的食物時很容易撞墻。針對上面問題,在生成新的食物的時候,增加是否與記分牌重合的校驗,如果重合,重新生成食物,直到符合要求。修改后的代碼片段如下:
def _check_food(self):""" 檢查新生成的食物是否不與蛇身及記分牌重合 """food = self.foodfood.rect.x = round(random.randrange(20, self.settings.screen_width - self.settings.snake_width * 2) / 20.0) * 20.0food.rect.y = round(random.randrange(20, self.settings.screen_height - self.settings.snake_height * 2) / 20.0) * 20.0for snake in self.snakes:if snake.rect.colliderect(food.rect) or self.sb.score_rect.colliderect(food.rect):return Falsereturn True
? ? ? ? 再看游戲暫停功能。?有時正在游戲過程中,尤其是得分比較高的時候,有事需要離開,這時候沒有游戲暫停功能的話,只能結束游戲,體驗不太好。如何增加暫停功能,思路其實比較簡單:在游戲狀態類里增加一個游戲暫停狀態的屬性,當按下“空格”鍵的時候,將這個屬性值取反。同時游戲主循環里增加游戲暫停狀態的判斷,如果是暫停狀態游戲不再刷新,如果不是暫停狀態,游戲正常刷新。這樣,就實現了游戲暫停功能。相關代碼片段:
class GameStats:""" 跟蹤游戲的統計信息 """def __init__(self, ai_game):""" 初始化統計信息 """self.settings = ai_game.settingsself.reset_stats()# 游戲剛啟動時處于非活動狀態self.game_active = False# 游戲暫停狀態self.game_pause = Falsedef reset_stats(self):""" 初始化在游戲運行期間可能變化的統計信息 """self.score = 0def run_game(self):""" 開始游戲的主循環 """while True:self._check_events()if self.stats.game_active and not self.stats.game_pause:if self.settings.update_count > 500: #控制游戲速度self._update_snakes()self._check_edges()self.settings.update_count = 0self.settings.update_count += self.settings.game_speedself._update_screen()
? ? ? ? 修改后主程序類(gluttonous_snake.py)的完整代碼:
import sys
import timeimport pygame
import randomfrom settings import Settings
from snake import Snake
from game_stats import GameStats
from button import Button
from food import Food
from scoreboard import Scoreboard
from game_sound import GameSoundclass GluttonousSnake:""" 管理游戲資源和行為的類 """def __init__(self):""" 初始化游戲并創建游戲資源 """pygame.init()# 初始化音頻混合器pygame.mixer.init()# 初始化游戲聲音self.snake_eat_food_sound = GameSound('snake_eat_food.mp3')self.snake_game_over_sound = GameSound('snake_game_over.mp3')self.background_sound = GameSound('snake_background_sound.mp3')self.cheer_sound = GameSound('snake_cheer_sound.mp3')self.settings = Settings()self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height))pygame.display.set_caption("貪吃蛇")# 創建一個用于存儲游戲統計信息的實例self.stats = GameStats(self)# 創建記分牌self.sb = Scoreboard(self)self.food = Food(self)self.snakes = []self._create_snakes()# 創建Play按鈕self.play_button = Button(self, "Play")def _create_snakes(self):""" 初始化創建長度為3的蛇 """for snake_number in range(3):self._create_snake(snake_number)def _create_snake(self, snake_number):""" 創建一段蛇身 """snake = Snake(self)self.screen_rect = self.screen.get_rect()snake.x = self.settings.screen_width / 2snake.y = self.settings.screen_height / 2 + snake_number * self.settings.snake_heightsnake.rect.x = snake.xsnake.rect.y = snake.yself.snakes.append(snake)def _check_events(self):# 監視鍵盤和鼠標的事件for event in pygame.event.get():if event.type == pygame.QUIT:sys.exit()elif event.type == pygame.KEYDOWN:self._check_keydown_events(event)elif event.type == pygame.MOUSEBUTTONDOWN:mouse_pos = pygame.mouse.get_pos()self._check_play_button(mouse_pos)def _check_play_button(self, mouse_pos):""" 在玩家單擊Play按鈕時開始新游戲 """button_clicked = self.play_button.rect.collidepoint(mouse_pos)if button_clicked and not self.stats.game_active:# 重置游戲設置self.stats.game_active = True# 播放背景音樂self.background_sound.play(0)# 隱藏鼠標光標pygame.mouse.set_visible(False)self.stats.score = 0self.sb.prep_score()self.settings.snake_direction = 'up'self.settings.update_count = 0self.settings.game_speed = 1# 清空余下的蛇身self.snakes.clear()# 重新創建蛇身self._create_snakes()def _check_keydown_events(self, event):# 響應按鍵if event.key == pygame.K_RIGHT:if self.settings.snake_direction == 'right':self._change_speed(1)elif self.settings.snake_direction == 'left':self._change_speed(-1)else:self.settings.snake_direction = 'right'elif event.key == pygame.K_LEFT:if self.settings.snake_direction == 'left':self._change_speed(1)elif self.settings.snake_direction == 'right':self._change_speed(-1)else:self.settings.snake_direction = 'left'elif event.key == pygame.K_UP:if self.settings.snake_direction == 'up':self._change_speed(1)elif self.settings.snake_direction == 'down':self._change_speed(-1)else:self.settings.snake_direction = 'up'elif event.key == pygame.K_DOWN:if self.settings.snake_direction == 'down':self._change_speed(1)elif self.settings.snake_direction == 'up':self._change_speed(-1)else:self.settings.snake_direction = 'down'elif event.key == pygame.K_SPACE:self.stats.game_pause = not self.stats.game_pauseelif event.key == pygame.K_q:sys.exit()def _change_speed(self, add):# 改變蛇的移動速度if (self.settings.game_speed + add) > 0:self.settings.game_speed += adddef _update_snakes(self):""" 更新蛇 """snake_head = self.snakes[0]self._create_snake_head(snake_head.rect.x, snake_head.rect.y)""" 檢查是否吃到食物 """eat_food = self._check_eat_food()if not eat_food:self.snakes.pop()def _check_edges(self):""" 蛇碰到邊緣時采取相應的措施 """snake_head = self.snakes[0]if snake_head.check_edges():self._game_over()def _check_eat_self(self, snake_head):""" 是否碰到自己 """for snake in self.snakes:if snake.rect.colliderect(snake_head.rect):self._game_over()breakdef _game_over(self):# 播放音樂self.snake_game_over_sound.play(1)self.stats.game_active = False# 顯示鼠標光標pygame.mouse.set_visible(True)def _check_eat_food(self):""" 檢測蛇吃到食物 """snake_head = self.snakes[0]food = self.foodif snake_head.rect.colliderect(food.rect):self.stats.score += self.settings.food_score# 播放聲音if self.stats.score % 100 == 0:self.cheer_sound.play(1)else:self.snake_eat_food_sound.play(1)self.sb.prep_score()self._update_food()return Trueelse:return Falsedef _update_food(self):""" 更新食物 """while True:if self._check_food():returndef _check_food(self):""" 檢查新生成的食物是否不與蛇身及記分牌重合 """food = self.foodfood.rect.x = round(random.randrange(20, self.settings.screen_width - self.settings.snake_width * 2) / 20.0) * 20.0food.rect.y = round(random.randrange(20, self.settings.screen_height - self.settings.snake_height * 2) / 20.0) * 20.0for snake in self.snakes:if snake.rect.colliderect(food.rect) or self.sb.score_rect.colliderect(food.rect):return Falsereturn Truedef _create_snake_head(self, x, y):""" 創建蛇頭 """snake = Snake(self)if self.settings.snake_direction == 'up':snake.x = xsnake.y = y - self.settings.snake_heightelif self.settings.snake_direction == 'down':snake.x = xsnake.y = y + self.settings.snake_heightelif self.settings.snake_direction == 'right':snake.x = x + self.settings.snake_widthsnake.y = yelif self.settings.snake_direction == 'left':snake.x = x - self.settings.snake_widthsnake.y = ysnake.rect.x = snake.xsnake.rect.y = snake.yself._check_eat_self(snake)self.snakes.insert(0, snake)def run_game(self):""" 開始游戲的主循環 """while True:self._check_events()if self.stats.game_active and not self.stats.game_pause:if self.settings.update_count > 500: #控制游戲速度self._update_snakes()self._check_edges()self.settings.update_count = 0self.settings.update_count += self.settings.game_speedself._update_screen()def _update_screen(self):# 每次循環時都會重繪屏幕self.screen.fill(self.settings.bg_color)self.food.draw_food()for snake in self.snakes:snake.draw_snake()# 如果游戲處于非活動狀態,就繪制Play按鈕if not self.stats.game_active:self.play_button.draw_button()# 顯示得分self.sb.show_score()# 讓最近繪制的屏幕可見pygame.display.flip()if __name__ == '__main__':# 創建實例并運行游戲ai = GluttonousSnake()ai.run_game()