Python 玩出花儿了!一文教你用 Python 制作吃豆人游戏! | 附代码

    技术2022-07-12  66

    作者:李秋键

    来源:AI科技大本营

    一文教你用 Python 制作吃豆人游戏

    近几年来Python语言得到了快速发展,而Pygame作为Python开发应用和游戏必备的库更是展现了Python的优越性。

    而今天我们就将借助Pygame建立吃豆人游戏。

    吃豆人是电子游戏历史上的经典街机游戏,由Namco公司的岩谷彻设计并由Midway Games在1980年发行。Pac-Man被认为是80年代最经典的街机游戏之一,游戏的主角小精灵的形象甚至被作为一种大众文化符号,或是此产业的代表形象。

    而Pygame模块是跨平台Python模块,专为电子游戏设计,包含图像、声音。建立在SDL基础上,允许实时电子游戏研发而无需被低级语言(如机器语言和汇编语言)束缚。

    最终游戏效果如下可见:

     

    一、实验前的准备

    首先我们使用的python版本是3.6.5所用到的模块是pygame模块,用来创建游戏框架。Random模块用来随机生成方向。

    素材准备

    首先我们将图片放到images目录下,背景音乐放到sounds目录下。

    如下图可见:

    游戏搭建

    1、定义一些精灵:

    整体的类变量定义包括墙类,通过pygame的图片填充作为墙类的加载;同理还包括食物类和角色。而怪物的随机运动使用random产生随机运动方向。

    其对应的代码如下:

    import random import pygame '''墙类''' class Wall(pygame.sprite.Sprite):     def __init__(self, x, y, width, height, color, **kwargs):         pygame.sprite.Sprite.__init__(self)         self.image = pygame.Surface([width, height])         self.image.fill(color)         self.rect = self.image.get_rect()         self.rect.left = x         self.rect.top = y '''食物类''' class Food(pygame.sprite.Sprite):     def __init__(self, x, y, width, height, color, bg_color, **kwargs):         pygame.sprite.Sprite.__init__(self)         self.image = pygame.Surface([width, height])         self.image.fill(bg_color)         self.image.set_colorkey(bg_color)         pygame.draw.ellipse(self.image, color, [0, 0, width, height])         self.rect = self.image.get_rect()         self.rect.left = x         self.rect.top = y '''角色类''' class Player(pygame.sprite.Sprite):     def __init__(self, x, y, role_image_path):         pygame.sprite.Sprite.__init__(self)         self.role_name = role_image_path.split('/')[-1].split('.')[0]         self.base_image = pygame.image.load(role_image_path).convert()         self.image = self.base_image.copy()         self.rect = self.image.get_rect()         self.rect.left = x         self.rect.top = y         self.prev_x = x         self.prev_y = y         self.base_speed = [30, 30]         self.speed = [0, 0]         self.is_move = False         self.tracks = []         self.tracks_loc = [0, 0]     '''改变速度方向'''     def changeSpeed(self, direction):         if direction[0] < 0:             self.image = pygame.transform.flip(self.base_image, True, False)         elif direction[0] > 0:             self.image = self.base_image.copy()         elif direction[1] < 0:             self.image = pygame.transform.rotate(self.base_image, 90)         elif direction[1] > 0:             self.image = pygame.transform.rotate(self.base_image, -90)         self.speed = [direction[0] * self.base_speed[0], direction[1] * self.base_speed[1]]         return self.speed     '''更新角色位置'''     def update(self, wall_sprites, gate_sprites):         if not self.is_move:             return False         x_prev = self.rect.left         y_prev = self.rect.top         self.rect.left += self.speed[0]         self.rect.top += self.speed[1]         is_collide = pygame.sprite.spritecollide(self, wall_sprites, False)         if gate_sprites is not None:             if not is_collide:                 is_collide = pygame.sprite.spritecollide(self, gate_sprites, False)         if is_collide:             self.rect.left = x_prev             self.rect.top = y_prev             return False         return True     '''生成随机的方向'''     def randomDirection(self):         return random.choice([[-0.5, 0], [0.5, 0], [0, 0.5], [0, -0.5]])

    2、游戏关卡定义:

    在这里设置好了关卡一。关卡的定义必须包括墙的位置,不同关卡墙的位置和怪物的位置不同。更多关卡可以参照设置

    对应代码如下:

    import pygame from Sprites import * NUMLEVELS = 1 '''关卡一''' class Level1():     def __init__(self):         self.info = 'level1'     '''创建墙'''     def setupWalls(self, wall_color):         self.wall_sprites = pygame.sprite.Group()         wall_positions = [[0, 0, 6, 600],                           [0, 0, 600, 6],                           [0, 600, 606, 6],                           [600, 0, 6, 606],                           [300, 0, 6, 66],                           [60, 60, 186, 6],                           [360, 60, 186, 6],                           [60, 120, 66, 6],                           [60, 120, 6, 126],                           [180, 120, 246, 6],                           [300, 120, 6, 66],                           [480, 120, 66, 6],                           [540, 120, 6, 126],                           [120, 180, 126, 6],                           [120, 180, 6, 126],                           [360, 180, 126, 6],                           [480, 180, 6, 126],                           [180, 240, 6, 126],                           [180, 360, 246, 6],                           [420, 240, 6, 126],                           [240, 240, 42, 6],                           [324, 240, 42, 6],                           [240, 240, 6, 66],                           [240, 300, 126, 6],                           [360, 240, 6, 66],                           [0, 300, 66, 6],                           [540, 300, 66, 6],                           [60, 360, 66, 6],                           [60, 360, 6, 186],                           [480, 360, 66, 6],                           [540, 360, 6, 186],                           [120, 420, 366, 6],                           [120, 420, 6, 66],                           [480, 420, 6, 66],                           [180, 480, 246, 6],                           [300, 480, 6, 66],                           [120, 540, 126, 6],                           [360, 540, 126, 6]]         for wall_position in wall_positions:             wall = Wall(*wall_position, wall_color)             self.wall_sprites.add(wall)         return self.wall_sprites     '''创建门'''     def setupGate(self, gate_color):         self.gate_sprites = pygame.sprite.Group()         self.gate_sprites.add(Wall(282, 242, 42, 2, gate_color))         return self.gate_sprites     '''创建角色'''     def setupPlayers(self, hero_image_path, ghost_images_path):         self.hero_sprites = pygame.sprite.Group()         self.ghost_sprites = pygame.sprite.Group()         self.hero_sprites.add(Player(287, 439, hero_image_path))         for each in ghost_images_path:             role_name = each.split('/')[-1].split('.')[0]             if role_name == 'Blinky':                 player = Player(287, 199, each)                 player.is_move = True                 player.tracks = [[0, -0.5, 4], [0.5, 0, 9], [0, 0.5, 11], [0.5, 0, 3], [0, 0.5, 7], [-0.5, 0, 11], [0, 0.5, 3],                                  [0.5, 0, 15], [0, -0.5, 15], [0.5, 0, 3], [0, -0.5, 11], [-0.5, 0, 3], [0, -0.5, 11], [-0.5, 0, 3],                                  [0, -0.5, 3], [-0.5, 0, 7], [0, -0.5, 3], [0.5, 0, 15], [0, 0.5, 15], [-0.5, 0, 3], [0, 0.5, 3],                                  [-0.5, 0, 3], [0, -0.5, 7], [-0.5, 0, 3], [0, 0.5, 7], [-0.5, 0, 11], [0, -0.5, 7], [0.5, 0, 5]]                 self.ghost_sprites.add(player)             elif role_name == 'Clyde':                 player = Player(319, 259, each)                 player.is_move = True                 player.tracks = [[-1, 0, 2], [0, -0.5, 4], [0.5, 0, 5], [0, 0.5, 7], [-0.5, 0, 11], [0, -0.5, 7],                                  [-0.5, 0, 3], [0, 0.5, 7], [-0.5, 0, 7], [0, 0.5, 15], [0.5, 0, 15], [0, -0.5, 3],                                  [-0.5, 0, 11], [0, -0.5, 7], [0.5, 0, 3], [0, -0.5, 11], [0.5, 0, 9]]                 self.ghost_sprites.add(player)             elif role_name == 'Inky':                 player = Player(255, 259, each)                 player.is_move = True                 player.tracks = [[1, 0, 2], [0, -0.5, 4], [0.5, 0, 10], [0, 0.5, 7], [0.5, 0, 3], [0, -0.5, 3],                                  [0.5, 0, 3], [0, -0.5, 15], [-0.5, 0, 15], [0, 0.5, 3], [0.5, 0, 15], [0, 0.5, 11],                                  [-0.5, 0, 3], [0, -0.5, 7], [-0.5, 0, 11], [0, 0.5, 3], [-0.5, 0, 11], [0, 0.5, 7],                                  [-0.5, 0, 3], [0, -0.5, 3], [-0.5, 0, 3], [0, -0.5, 15], [0.5, 0, 15], [0, 0.5, 3],                                  [-0.5, 0, 15], [0, 0.5, 11], [0.5, 0, 3], [0, -0.5, 11], [0.5, 0, 11], [0, 0.5, 3], [0.5, 0, 1]]                 self.ghost_sprites.add(player)             elif role_name == 'Pinky':                 player = Player(287, 259, each)                 player.is_move = True                 player.tracks = [[0, -1, 4], [0.5, 0, 9], [0, 0.5, 11], [-0.5, 0, 23], [0, 0.5, 7], [0.5, 0, 3],                                  [0, -0.5, 3], [0.5, 0, 19], [0, 0.5, 3], [0.5, 0, 3], [0, 0.5, 3], [0.5, 0, 3],                                  [0, -0.5, 15], [-0.5, 0, 7], [0, 0.5, 3], [-0.5, 0, 19], [0, -0.5, 11], [0.5, 0, 9]]                 self.ghost_sprites.add(player)         return self.hero_sprites, self.ghost_sprites     '''创建食物'''     def setupFood(self, food_color, bg_color):         self.food_sprites = pygame.sprite.Group()         for row in range(19):             for col in range(19):                 if (row == 7 or row == 8) and (col == 8 or col == 9 or col == 10):                     continue                 else:                     food = Food(30*col+32, 30*row+32, 4, 4, food_color, bg_color)                     is_collide = pygame.sprite.spritecollide(food, self.wall_sprites, False)                     if is_collide:                         continue                     is_collide = pygame.sprite.spritecollide(food, self.hero_sprites, False)                     if is_collide:                         continue                     self.food_sprites.add(food)         return self.food_sprites

    3、游戏创建:

    在通过关卡定义墙等位置后以及精灵自身属性怪物运动、食物定义等后,通过调用已经创建好的类达到搭建游戏的目的。

    具体如下可见:

    import os import sys import pygame import Levels '''定义一些必要的参数''' BLACK = (0, 0, 0) WHITE = (255, 255, 255) BLUE = (0, 0, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) YELLOW = (255, 255, 0) PURPLE = (255, 0, 255) SKYBLUE = (0, 191, 255) BGMPATH = os.path.join(os.getcwd(), 'resources/sounds/bg.mp3') ICONPATH = os.path.join(os.getcwd(), 'resources/images/icon.png') FONTPATH = os.path.join(os.getcwd(), 'resources/font/ALGER.TTF') HEROPATH = os.path.join(os.getcwd(), 'resources/images/pacman.png') BlinkyPATH = os.path.join(os.getcwd(), 'resources/images/Blinky.png') ClydePATH = os.path.join(os.getcwd(), 'resources/images/Clyde.png') InkyPATH = os.path.join(os.getcwd(), 'resources/images/Inky.png') PinkyPATH = os.path.join(os.getcwd(), 'resources/images/Pinky.png') '''开始某一关游戏''' def startLevelGame(level, screen, font):     clock = pygame.time.Clock()     SCORE = 0     wall_sprites = level.setupWalls(SKYBLUE)     gate_sprites = level.setupGate(WHITE)     hero_sprites, ghost_sprites = level.setupPlayers(HEROPATH, [BlinkyPATH, ClydePATH, InkyPATH, PinkyPATH])     food_sprites = level.setupFood(YELLOW, WHITE)     is_clearance = False     while True:         for event in pygame.event.get():             if event.type == pygame.QUIT:                 sys.exit(-1)                 pygame.quit()             if event.type == pygame.KEYDOWN:                 if event.key == pygame.K_LEFT:                     for hero in hero_sprites:                         hero.changeSpeed([-1, 0])                         hero.is_move = True                 elif event.key == pygame.K_RIGHT:                     for hero in hero_sprites:                         hero.changeSpeed([1, 0])                         hero.is_move = True                 elif event.key == pygame.K_UP:                     for hero in hero_sprites:                         hero.changeSpeed([0, -1])                         hero.is_move = True                 elif event.key == pygame.K_DOWN:                     for hero in hero_sprites:                         hero.changeSpeed([0, 1])                         hero.is_move = True             if event.type == pygame.KEYUP:                 if (event.key == pygame.K_LEFT) or (event.key == pygame.K_RIGHT) or (event.key == pygame.K_UP) or (event.key == pygame.K_DOWN):                     hero.is_move = False         screen.fill(BLACK)         for hero in hero_sprites:             hero.update(wall_sprites, gate_sprites)         hero_sprites.draw(screen)         for hero in hero_sprites:             food_eaten = pygame.sprite.spritecollide(hero, food_sprites, True)         SCORE += len(food_eaten)         wall_sprites.draw(screen)         gate_sprites.draw(screen)         food_sprites.draw(screen)         for ghost in ghost_sprites:             # 幽灵随机运动(效果不好且有BUG)             '''             res = ghost.update(wall_sprites, None)             while not res:                 ghost.changeSpeed(ghost.randomDirection())                 res = ghost.update(wall_sprites, None)             '''             # 指定幽灵运动路径             if ghost.tracks_loc[1] < ghost.tracks[ghost.tracks_loc[0]][2]:                 ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2])                 ghost.tracks_loc[1] += 1             else:                 if ghost.tracks_loc[0] < len(ghost.tracks) - 1:                     ghost.tracks_loc[0] += 1                 elif ghost.role_name == 'Clyde':                     ghost.tracks_loc[0] = 2                 else:                     ghost.tracks_loc[0] = 0                 ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2])                 ghost.tracks_loc[1] = 0             if ghost.tracks_loc[1] < ghost.tracks[ghost.tracks_loc[0]][2]:                 ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[0]][0: 2])             else:                 if ghost.tracks_loc[0] < len(ghost.tracks) - 1:                     loc0 = ghost.tracks_loc[0] + 1                 elif ghost.role_name == 'Clyde':                     loc0 = 2                 else:                     loc0 = 0                 ghost.changeSpeed(ghost.tracks[loc0][0: 2])             ghost.update(wall_sprites, None)         ghost_sprites.draw(screen)         score_text = font.render("Score: %s" % SCORE, True, RED)         screen.blit(score_text, [10, 10])         if len(food_sprites) == 0:             is_clearance = True             break         if pygame.sprite.groupcollide(hero_sprites, ghost_sprites, False, False):             is_clearance = False             break         pygame.display.flip()         clock.tick(10)     return is_clearance '''显示文字''' def showText(screen, font, is_clearance, flag=False):     clock = pygame.time.Clock()     msg = 'Game Over!' if not is_clearance else 'Congratulations, you won!'     positions = [[235, 233], [65, 303], [170, 333]] if not is_clearance else [[145, 233], [65, 303], [170, 333]]     surface = pygame.Surface((400, 200))     surface.set_alpha(10)     surface.fill((128, 128, 128))     screen.blit(surface, (100, 200))     texts = [font.render(msg, True, WHITE),              font.render('Press ENTER to continue or play again.', True, WHITE),              font.render('Press ESCAPE to quit.', True, WHITE)]     while True:         for event in pygame.event.get():             if event.type == pygame.QUIT:                 sys.exit()                 pygame.quit()             if event.type == pygame.KEYDOWN:                 if event.key == pygame.K_RETURN:                     if is_clearance:                         if not flag:                             return                         else:                             main(initialize())                     else:                         main(initialize())                 elif event.key == pygame.K_ESCAPE:                     sys.exit()                     pygame.quit()         for idx, (text, position) in enumerate(zip(texts, positions)):             screen.blit(text, position)         pygame.display.flip()         clock.tick(10) '''初始化''' def initialize():     pygame.init()     icon_image = pygame.image.load(ICONPATH)     pygame.display.set_icon(icon_image)     screen = pygame.display.set_mode([606, 606])     pygame.display.set_caption('吃豆人')     return screen '''主函数''' def main(screen):     pygame.mixer.init()     pygame.mixer.music.load(BGMPATH)     pygame.mixer.music.play(-1, 0.0)     pygame.font.init()     font_small = pygame.font.Font(FONTPATH, 18)     font_big = pygame.font.Font(FONTPATH, 24)     for num_level in range(1, Levels.NUMLEVELS+1):         if num_level == 1:             level = Levels.Level1()             is_clearance = startLevelGame(level, screen, font_small)             if num_level == Levels.NUMLEVELS:                 showText(screen, font_big, is_clearance, True)             else:                 showText(screen, font_big, is_clearance)

    最终运行程序结果如下:

     

    源码地址:

    https://pan.baidu.com/s/128id8L-PDPgGOPuH-5uHDg

    提取码:rj9f

    作者简介:

    李秋键,博客专家,达人课作者。硕士在读于中国矿业大学,开发有taptap竞赛获奖等等。

    ---------End--------- 关注后回复“w”,加我私人微信 “分享”和“在看”是更好的支持!
    Processed: 0.012, SQL: 9