IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Pygame学习笔记10:编程逻辑及Snake游戏 -> 正文阅读

[游戏开发]Pygame学习笔记10:编程逻辑及Snake游戏

贪吃蛇游戏想必大家都不陌生,这一次就来介绍开发一个简单的贪吃蛇游戏。

Snake游戏

创建精灵

首先需要在MySprite的基础上创建新的精灵类以满足我们的需求

代码如下:

# 蛇的身体部分
class SnakeSegment(MySprite):
    def __init__(self, color=(20, 200, 20)):
        MySprite.__init__(self)
        image = pygame.Surface((32, 32)).convert_alpha()
        image.fill((255, 255, 255, 0))
        pygame.draw.circle(image, color, (16, 16), 16, 0)
        self.set_image(image)
        MySprite.update(self, 0)


# 蛇的精灵类
class Snake():
    def __init__(self):
        self.velocity = Point(-1, 0)
        self.old_time = 0
        head = SnakeSegment((50, 250, 50))
        head.X = 12 * 32
        head.Y = 9 * 32
        self.segments = list()
        self.segments.append(head)
        self.add_segment()
        self.add_segment()

    def update(self, ticks):
        global step_time
        if ticks > self.old_time + step_time:
            self.old_time = ticks
            # 移动身体的每个部分
            for n in range(len(self.segments) - 1, 0, -1):
                self.segments[n].X = self.segments[n - 1].X
                self.segments[n].Y = self.segments[n - 1].Y
            self.segments[0].X += self.velocity.x * 32
            self.segments[0].Y += self.velocity.y * 32

    def draw(self, surface):
        for segment in self.segments:
            surface.blit(segment.image, (segment.X, segment.Y))

    def add_segment(self):
        last = len(self.segments) - 1
        segment = SnakeSegment()
        start = Point(0, 0)
        if self.velocity.x < 0:
            start.x = 32
        elif self.velocity.x > 0:
            start.x = -32
        if self.velocity.y < 0:
            start.y = 32
        elif self.velocity.y > 0:
            start.y = -32
        segment.X = self.segments[last].X + start.x
        segment.Y = self.segments[last].Y + start.y
        self.segments.append(segment)

我们构建了两个精灵类用于组成蛇,其中SnakeSegment类其实就是一个圆,用于表示蛇的长度以及表示蛇的身体的一部分,然后Snake类则是包含了多个SnakeSegment类构成一条蛇,其中的update()方法:

	def update(self, ticks):
        global step_time
        if ticks > self.old_time + step_time:
            self.old_time = ticks
            # 移动身体的每个部分
            for n in range(len(self.segments) - 1, 0, -1):
                self.segments[n].X = self.segments[n - 1].X
                self.segments[n].Y = self.segments[n - 1].Y
            self.segments[0].X += self.velocity.x * 32
            self.segments[0].Y += self.velocity.y * 32

由于是由多个SnakeSegment类组成的,因此我们这里蛇的移动的处理是依次移动SnakeSegment类的每一个对象。

食物

代码如下:

# 食物精灵类
class Food(MySprite):
    def __init__(self):
        MySprite.__init__(self)
        image = pygame.Surface((32, 32)).convert_alpha()
        image.fill((255, 255, 255, 0))
        pygame.draw.circle(image, (250, 250, 50), (16, 16), 16, 0)
        self.set_image(image)
        MySprite.update(self, 0)
        self.X = random.randint(0, 23) * 32
        self.Y = random.randint(0, 17) * 32

这其实也是一个圆,随机出现在图中某个位置上

游戏的一些初始化操作

代码如下:

def game_init():
    global screen, backbuffer, font, timer, snake, food_group
    pygame.init()
    screen = pygame.display.set_mode((24 * 32, 18 * 32))
    pygame.display.set_caption("Snake Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()

    # 创建平面
    backbuffer = pygame.Surface((screen.get_rect().width, screen.get_rect().height))

    # 创建蛇
    snake = Snake()
    image = pygame.Surface((60, 60)).convert_alpha()
    image.fill((255, 255, 255, 0))
    pygame.draw.circle(image, (80, 80, 220, 70), (30, 30), 30, 0)
    pygame.draw.circle(image, (80, 80, 250, 255), (30, 30), 30, 4)

    # 创建食物
    food_group = pygame.sprite.Group()
    food = Food()
    food_group.add(food)

注意这里:

screen = pygame.display.set_mode((24 * 32, 18 * 32))

因为无论是蛇类,还是食物类,都是32*32的大小,因此将平面的长宽设置成32的倍数则刚刚好

实现蛇吃食物变长

# 判断是否吃到食物
hit_list = pygame.sprite.groupcollide(snake.segments, food_group, False, True)
if len(hit_list) > 0:
	food_group.add(Food())
    snake.add_segment()

这里使用到了pygame.sprite.groupcollide()冲突检测,因为考虑到食物随机出现,可能刚好出现在蛇身体的某一部分上(这也是一个小的问题,毕竟食物出现的位置理论上应该要避开蛇的身体,但这里没有考虑这个情况),因此是直接将蛇的身体与食物进行了冲突检测,若发生碰撞,则删除食物,同时蛇的长度增加。

检测蛇是否吃到自己

# 判断是否吃到自己
for n in range(1, len(snake.segments)):
	if pygame.sprite.collide_rect(snake.segments[0], snake.segments[n]):
		game_over = True

因为蛇的移动是第一个部分控制的,因此判断是否会知道自己,只需要用第一部分与剩余部分进行冲突检测即可。

实现蛇自动移动

其实到这里,就已经实现了Snake游戏的逻辑,直接运行即可。当然,这里还可以再添加一些代码以实现蛇的自动移动,这样就不需要我们手动控制方向了。

要实现该功能,首先要有几个辅助函数:

# 获取蛇的当前方向
def get_current_direction():
    global head_x, head_y
    first_segment_x = snake.segments[1].X // 32
    first_segment_y = snake.segments[1].Y // 32
    if head_x - 1 == first_segment_x:
        return "right"
    elif head_x + 1 == first_segment_x:
        return "left"
    elif head_y - 1 == first_segment_y:
        return "down"
    elif head_y + 1 == first_segment_y:
        return "up"


# 获取食物的方位
def get_food_direction():
    global head_x, head_y
    food = Point(0, 0)
    for obj in food_group:
        food = Point(obj.X // 32, obj.Y // 32)
    if head_x < food.x:
        return "right"
    elif head_x > food.x:
        return "left"
    elif head_x == food.x:
        if head_y < food.y:
            return "down"
        elif head_y > food.y:
            return "up"

这两个函数的功能就是用来确定当前蛇的移动方向和食物的相对位置(相对snake.segments[0]而言)。之后就可以实现自动移动了:

# 让蛇自动移动
def auto_move():
    direction = get_current_direction()
    food_dir = get_food_direction()
    if food_dir == "left":
        if direction != "right":
            direction = "left"
    elif food_dir == "right":
        if direction != "left":
            direction = "right"
    elif food_dir == "up":
        if direction != "down":
            direction = "up"
    elif food_dir == "down":
        if direction != "up":
            direction = "down"
    # 根据方向设置速度
    if direction == "up":
        snake.velocity = Point(0, -1)
    elif direction == "down":
        snake.velocity = Point(0, 1)
    elif direction == "right":
        snake.velocity = Point(1, 0)
    elif direction == "left":
        snake.velocity = Point(-1, 0)

实现自动移动需要用于按下空格键,只需要在检测键盘输入的时候,对空格键做相应的处理即可。

完整源代码

源代码如下:

import random
import sys
import pygame
from pygame.locals import *
from MyLibrary import *


# 蛇的身体部分
class SnakeSegment(MySprite):
    def __init__(self, color=(20, 200, 20)):
        MySprite.__init__(self)
        image = pygame.Surface((32, 32)).convert_alpha()
        image.fill((255, 255, 255, 0))
        pygame.draw.circle(image, color, (16, 16), 16, 0)
        self.set_image(image)
        MySprite.update(self, 0)


# 蛇的精灵类
class Snake():
    def __init__(self):
        self.velocity = Point(-1, 0)
        self.old_time = 0
        head = SnakeSegment((50, 250, 50))
        head.X = 12 * 32
        head.Y = 9 * 32
        self.segments = list()
        self.segments.append(head)
        self.add_segment()
        self.add_segment()

    def update(self, ticks):
        global step_time
        if ticks > self.old_time + step_time:
            self.old_time = ticks
            # 移动身体的每个部分
            for n in range(len(self.segments) - 1, 0, -1):
                self.segments[n].X = self.segments[n - 1].X
                self.segments[n].Y = self.segments[n - 1].Y
            self.segments[0].X += self.velocity.x * 32
            self.segments[0].Y += self.velocity.y * 32

    def draw(self, surface):
        for segment in self.segments:
            surface.blit(segment.image, (segment.X, segment.Y))

    def add_segment(self):
        last = len(self.segments) - 1
        segment = SnakeSegment()
        start = Point(0, 0)
        if self.velocity.x < 0:
            start.x = 32
        elif self.velocity.x > 0:
            start.x = -32
        if self.velocity.y < 0:
            start.y = 32
        elif self.velocity.y > 0:
            start.y = -32
        segment.X = self.segments[last].X + start.x
        segment.Y = self.segments[last].Y + start.y
        self.segments.append(segment)


# 食物精灵类
class Food(MySprite):
    def __init__(self):
        MySprite.__init__(self)
        image = pygame.Surface((32, 32)).convert_alpha()
        image.fill((255, 255, 255, 0))
        pygame.draw.circle(image, (250, 250, 50), (16, 16), 16, 0)
        self.set_image(image)
        MySprite.update(self, 0)
        self.X = random.randint(0, 23) * 32
        self.Y = random.randint(0, 17) * 32


def game_init():
    global screen, backbuffer, font, timer, snake, food_group
    pygame.init()
    screen = pygame.display.set_mode((24 * 32, 18 * 32))
    pygame.display.set_caption("Snake Game")
    font = pygame.font.Font(None, 30)
    timer = pygame.time.Clock()

    # 创建平面
    backbuffer = pygame.Surface((screen.get_rect().width, screen.get_rect().height))

    # 创建蛇
    snake = Snake()
    image = pygame.Surface((60, 60)).convert_alpha()
    image.fill((255, 255, 255, 0))
    pygame.draw.circle(image, (80, 80, 220, 70), (30, 30), 30, 0)
    pygame.draw.circle(image, (80, 80, 250, 255), (30, 30), 30, 4)

    # 创建食物
    food_group = pygame.sprite.Group()
    food = Food()
    food_group.add(food)


# 让蛇自动移动
def auto_move():
    direction = get_current_direction()
    food_dir = get_food_direction()
    if food_dir == "left":
        if direction != "right":
            direction = "left"
    elif food_dir == "right":
        if direction != "left":
            direction = "right"
    elif food_dir == "up":
        if direction != "down":
            direction = "up"
    elif food_dir == "down":
        if direction != "up":
            direction = "down"
    # 根据方向设置速度
    if direction == "up":
        snake.velocity = Point(0, -1)
    elif direction == "down":
        snake.velocity = Point(0, 1)
    elif direction == "right":
        snake.velocity = Point(1, 0)
    elif direction == "left":
        snake.velocity = Point(-1, 0)


# 获取蛇的当前方向
def get_current_direction():
    global head_x, head_y
    first_segment_x = snake.segments[1].X // 32
    first_segment_y = snake.segments[1].Y // 32
    if head_x - 1 == first_segment_x:
        return "right"
    elif head_x + 1 == first_segment_x:
        return "left"
    elif head_y - 1 == first_segment_y:
        return "down"
    elif head_y + 1 == first_segment_y:
        return "up"


# 获取食物的方位
def get_food_direction():
    global head_x, head_y
    food = Point(0, 0)
    for obj in food_group:
        food = Point(obj.X // 32, obj.Y // 32)
    if head_x < food.x:
        return "right"
    elif head_x > food.x:
        return "left"
    elif head_x == food.x:
        if head_y < food.y:
            return "down"
        elif head_y > food.y:
            return "up"


if __name__ == "__main__":
    game_init()
    game_over = False
    last_time = 0
    auto_play = False
    step_time = 400

    while True:
        timer.tick(50)
        ticks = pygame.time.get_ticks()

        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
        keys = pygame.key.get_pressed()
        if keys[K_ESCAPE]:
            sys.exit()
        elif keys[K_UP] or keys[K_w]:
            snake.velocity = Point(0, -1)
        elif keys[K_DOWN] or keys[K_s]:
            snake.velocity = Point(0, 1)
        elif keys[K_LEFT] or keys[K_a]:
            snake.velocity = Point(-1, 0)
        elif keys[K_RIGHT] or keys[K_d]:
            snake.velocity = Point(1, 0)
        elif keys[K_SPACE]:
            auto_play = True

        if not game_over:
            snake.update(ticks)
            food_group.update(ticks)
            # 判断是否吃到食物
            hit_list = pygame.sprite.groupcollide(snake.segments, food_group, False, True)
            if len(hit_list) > 0:
                food_group.add(Food())
                snake.add_segment()

        # 判断是否吃到自己
        for n in range(1, len(snake.segments)):
            if pygame.sprite.collide_rect(snake.segments[0], snake.segments[n]):
                game_over = True

        head_x = snake.segments[0].X // 32
        head_y = snake.segments[0].Y // 32
        if head_x < 0 or head_x > 24 or head_y < 0 or head_y > 17:
            game_over = True

        backbuffer.fill((20, 50, 20))
        snake.draw(backbuffer)
        food_group.draw(backbuffer)
        screen.blit(backbuffer, (0, 0))

        if not game_over:
            if auto_play:
                auto_move()
            print_text(font, 0, 0, "Length:" + str(len(snake.segments)))
            print_text(font, 0, 20, "Position:" + str(snake.segments[0].X // 32) +
                       ", " + str(snake.segments[0].Y // 32))
        else:
            print_text(font, 0, 0, "GAME OVER")

        pygame.display.update()


运行结果如下:
在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 02:19:50  更:2022-01-14 02:20:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 18:31:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码