Python实现贪吃蛇一

贪吃蛇是一款经典的小游戏,最近尝试用Python实现它。先做一个基础版本实现以下目标:

1、做一个按钮,控制游戏开始

2、按Q键退出游戏

3、右上角显示一个记分牌

4、随机生成一个食物,蛇吃到食物后长度加一,得10分

5、蛇碰到边缘,游戏结束

6、蛇碰到自己,游戏结束

主流程代码(gluttonous_snake.py)如下:

python 复制代码
import sys

import pygame
import random

from settings import Settings
from snake import Snake
from game_stats import GameStats
from button import Button
from food import Food
from scoreboard import Scoreboard


class GluttonousSnake:
    """ 管理游戏资源和行为的类 """

    def __init__(self):
        """ 初始化游戏并创建游戏资源 """
        pygame.init()

        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 / 2
        snake.y = self.settings.screen_height / 2 + snake_number * self.settings.snake_height
        snake.rect.x = snake.x
        snake.rect.y = snake.y
        self.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

            # 隐藏鼠标光标
            pygame.mouse.set_visible(False)

            self.stats.score = 0
            self.sb.prep_score()
            self.settings.snake_direction = 'up'

            # 清空余下的蛇身
            self.snakes.clear()

            # 重新创建蛇身
            self._create_snakes()

    def _check_keydown_events(self, event):
        # 响应按键
        if event.key == pygame.K_RIGHT:
            if self.settings.snake_direction == 'up' or self.settings.snake_direction == 'down':
                self.settings.snake_direction = 'right'
        elif event.key == pygame.K_LEFT:
            if self.settings.snake_direction == 'up' or self.settings.snake_direction == 'down':
                self.settings.snake_direction = 'left'
        elif event.key == pygame.K_UP:
            if self.settings.snake_direction == 'right' or self.settings.snake_direction == 'left':
                self.settings.snake_direction = 'up'
        elif event.key == pygame.K_DOWN:
            if self.settings.snake_direction == 'right' or self.settings.snake_direction == 'left':
                self.settings.snake_direction = 'down'
        elif event.key == pygame.K_q:
            sys.exit()

    def _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.stats.game_active = False
            # 显示鼠标光标
            pygame.mouse.set_visible(True)

    def _check_eat_self(self, snake_head):
        """ 是否碰到自己 """
        for snake in self.snakes:
            if snake.rect.colliderect(snake_head.rect):
                self.stats.game_active = False
                # 显示鼠标光标
                pygame.mouse.set_visible(True)
                break

    def _check_eat_food(self):
        """ 检测蛇吃到食物 """
        snake_head = self.snakes[0]
        food = self.food
        if snake_head.rect.colliderect(food.rect):
            food.rect.x = round(random.randrange(20, self.settings.screen_width - self.settings.snake_width * 2) / 20.0) * 20.0
            food.rect.y = round(random.randrange(20, self.settings.screen_height - self.settings.snake_height * 2) / 20.0) * 20.0
            self.stats.score += self.settings.food_score
            self.sb.prep_score()
            return True
        else:
            return False

    def _create_snake_head(self, x, y):
        """ 创建蛇头 """
        snake = Snake(self)
        if self.settings.snake_direction == 'up':
            snake.x = x
            snake.y = y - self.settings.snake_height
        elif self.settings.snake_direction == 'down':
            snake.x = x
            snake.y = y + self.settings.snake_height
        elif self.settings.snake_direction == 'right':
            snake.x = x + self.settings.snake_width
            snake.y = y
        elif self.settings.snake_direction == 'left':
            snake.x = x - self.settings.snake_width
            snake.y = y
        snake.rect.x = snake.x
        snake.rect.y = snake.y
        self._check_eat_self(snake)
        self.snakes.insert(0, snake)

    def run_game(self):
        """ 开始游戏的主循环 """
        while True:
            self._check_events()
            if self.stats.game_active:
                if self.settings.update_count % 500 == 0: #控制游戏速度
                    self._update_snakes()
                    self._check_edges()
                    self.settings.update_count = 0
                self.settings.update_count += 1
            self._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()

按钮类(button.py) :

python 复制代码
import pygame.font


class Button:

    def __init__(self, ai_game, msg):
        """ 初始化按钮的属性 """
        self.screen = ai_game.screen
        self.screen_rect = self.screen.get_rect()

        # 设置按钮的尺寸和其他属性
        self.width, self.height = 100, 50
        self.button_color = (0, 255, 0)
        self.text_color = (255, 255, 255)
        self.font = pygame.font.SysFont(None, 48)

        # 创建按钮的rect对象,并使其居中
        self.rect = pygame.Rect(0, 0, self.width, self.height)
        self.rect.center = self.screen_rect.center
        self.rect.y = 100

        # 按钮的标签只需创建一次
        self._prep_msg(msg)

    def _prep_msg(self, msg):
        """ 将msg渲染为图像,并使其在按钮上居中 """
        self.msg_image = self.font.render(msg, True, self.text_color, self.button_color)
        self.msg_image_rect = self.msg_image.get_rect()
        self.msg_image_rect.center = self.rect.center

    def draw_button(self):
        # 绘制一个用颜色填充的按钮,再绘制文本
        self.screen.fill(self.button_color, self.rect)
        self.screen.blit(self.msg_image, self.msg_image_rect)

食物类(food.py):

python 复制代码
import pygame


class Food:

    def __init__(self, ai_game):
        """ 创建一个蛇身对象 """
        super().__init__()
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        self.settings = ai_game.settings
        self.color = self.settings.food_color

        # 在(0,0)处创建一个表示食物的矩形,再设置正确的位置
        self.rect = pygame.Rect(0, 0, self.settings.food_width,
                                self.settings.food_height)
        # 对于每个食物,都将其放在屏幕底部的中央
        self.rect.x = self.settings.screen_width / 2
        self.rect.y = self.settings.screen_height - 100

        # 在食物的属性x中存储小数值
        self.x = float(self.rect.x)
        # 存储用小数点表示的食物位置
        self.y = float(self.rect.y)

    def draw_food(self):
        """ 在屏幕上绘制食物 """
        pygame.draw.rect(self.screen, self.color, self.rect)

游戏状态(game_stats.py):

python 复制代码
class GameStats:
    """ 跟踪游戏的统计信息 """

    def __init__(self, ai_game):
        """ 初始化统计信息 """
        self.settings = ai_game.settings
        self.reset_stats()

        # 游戏刚启动时处于非活动状态
        self.game_active = False

    def reset_stats(self):
        """ 初始化在游戏运行期间可能变化的统计信息 """
        self.score = 0

游戏设置(settings.py):

python 复制代码
class Settings:

    def __init__(self):
        """ 初始化游戏的静态设置 """
        # 屏幕设置
        self.screen_width = 800
        self.screen_height = 600
        self.bg_color = (230, 230, 230)

        # 游戏设置
        self.update_count = 1

        # 蛇身设置
        self.snake_width = 20
        self.snake_height = 20
        self.snake_color = (0, 230, 0)
        self.snake_direction = 'up'

        # 食物设置
        self.food_width = 20
        self.food_height = 20
        self.food_color = (230, 0, 0)
        self.food_score = 10

记分牌(scoreboard.py):

python 复制代码
import pygame.font
from pygame.sprite import Group


class Scoreboard:
    """ 显示得分信息的类 """

    def __init__(self, ai_game):
        """ 初始化显示得分涉及的属性 """
        self.ai_game = ai_game
        self.screen = ai_game.screen
        self.screen_rect = self.screen.get_rect()
        self.settings = ai_game.settings
        self.stats = ai_game.stats

        # 显示得分信息时使用的字体设置
        self.text_color = (30, 30, 30)
        self.font = pygame.font.SysFont(None, 48)
        # 准备初始得分的图像
        self.prep_score()

    def prep_score(self):
        """ 将得分转换为一副渲染的图像 """
        round_score = round(self.stats.score, -1)
        score_str = "{:,}".format(round_score)
        self.score_image = self.font.render(score_str, True,
                                            self.text_color, self.settings.bg_color)

        # 在屏幕右上角显示得分
        self.score_rect = self.score_image.get_rect()
        self.score_rect.right = self.screen_rect.right - 20
        self.score_rect.top = 20

    def show_score(self):
        """ 在屏幕上显示得分 """
        self.screen.blit(self.score_image, self.score_rect)

蛇对象(snake.py):

python 复制代码
import pygame
from pygame.sprite import Sprite


class Snake(Sprite):

    def __init__(self, ai_game):
        """ 创建一个蛇身对象 """
        super().__init__()
        self.screen = ai_game.screen
        self.screen_rect = ai_game.screen.get_rect()
        self.settings = ai_game.settings
        self.color = self.settings.snake_color

        # 在(0,0)处创建一个表示一段蛇身的矩形,再设置正确的位置
        self.rect = pygame.Rect(0, 0, self.settings.snake_width,
                                self.settings.snake_height)
        # 对于每段蛇身,都将其放在屏幕底部的中央
        self.rect.x = self.screen_rect.width + (self.settings.screen_width / 2)
        self.rect.y = self.screen_rect.height + (self.settings.screen_height / 2)

        # 在蛇身的属性x中存储小数值
        self.x = float(self.rect.x)

        # 存储用小数点表示的子弹位置
        self.y = float(self.rect.y)

    def draw_snake(self):
        """ 在屏幕上绘制蛇身 """
        pygame.draw.rect(self.screen, self.color, self.rect)

    def check_edges(self):
        """ 如果蛇位于屏幕边缘,就返回True """
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right or self.rect.left <= 0 or self.rect.top <= 0 or self.rect.bottom >= screen_rect.bottom:
            return True

运行游戏,下面是初始界面:

蛇碰到边缘,游戏结束界面:

蛇碰到自己,游戏结束界面:

以上是一个基础版本的代码实现,后续将对代码进行优化并丰富游戏的功能。

相关推荐
向哆哆7 分钟前
Java 企业级应用:SOA 与微服务的对比与选择
java·开发语言·微服务
帮帮志9 分钟前
PyCharm 开发工具 修改字体大小及使用滚轮没有反应
ide·python·pycharm
流云一号25 分钟前
Python实现贪吃蛇二
开发语言·python
ππ记录36 分钟前
java面试题带答案2025最新整理
java·开发语言
PHASELESS41137 分钟前
Java栈与队列深度解析:结构、实现与应用指南
java·开发语言·算法
听风吹等浪起1 小时前
NLP实战(3):RNN英文名国家分类
人工智能·python·rnn·深度学习
SeasonedDriverDG1 小时前
C语言编写的线程池
linux·c语言·开发语言·算法
啊阿狸不会拉杆1 小时前
数据结构-限定性线性表 - 栈与队列
java·c语言·数据结构·c++·python·算法
杂学者1 小时前
python办公自动化------word文件的操作
python·word