• 基于Python实现制作的接金币小游戏


    Python 版本:3.6.4

    相关模块:

    pygame 模块;

    以及一些 python 自带的模块。

    环境搭建

    安装 Python 并添加到环境变量,pip 安装需要的相关模块即可。

    原理简介

    首先先声明一下,这个小游戏主要是依赖 pygame 写的,不会 pygame 的小伙伴请先阅读相关的开发文档了解一下这是啥

    首先,我们来进行一下游戏的初始化操作(比如初始化游戏窗口,加载一些必要的游戏素材等等),代码实现如下:

    
    '''游戏初始化'''
    def initGame():
        # 初始化pygame, 设置展示窗口
        pygame.init()
        screen = pygame.display.set_mode(cfg.SCREENSIZE)
        pygame.display.set_caption('catch coins —— 微信公众号: Charles的皮卡丘')
        # 加载必要的游戏素材
        game_images = {}
        for key, value in cfg.IMAGE_PATHS.items():
            if isinstance(value, list):
                images = []
                for item in value: images.append(pygame.image.load(item))
                game_images[key] = images
            else:
                game_images[key] = pygame.image.load(value)
        game_sounds = {}
        for key, value in cfg.AUDIO_PATHS.items():
            if key == 'bgm': continue
            game_sounds[key] = pygame.mixer.Sound(value)
        # 返回初始化数据
        return screen, game_images, game_sounds
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    接着,为了让我们在写小游戏的过程中保持一个良好的心情,就先让自己喜欢的游戏背景音乐响起来吧

    然后选一张好看的背景图片,这样才可以在它的基础上逐渐加入接金币这个小游戏涉及到的游戏元素嘛:

    源代码如下:

    
    # 游戏主循环
    clock = pygame.time.Clock()
    while True:
        # --填充背景
        screen.fill(0)
        screen.blit(game_images['background'], (0, 0))
        # --按键检测
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
        # --更新屏幕
        pygame.display.flip()
        clock.tick(cfg.FPS)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    小人的移动主要是通过我们自己定义的 Hero 类里的 move 函数实现的,具体而言代码实现如下:

    
    '''定义hero类'''
    class Hero(pygame.sprite.Sprite):
        def __init__(self, images, position=(375, 520), **kwargs):
            pygame.sprite.Sprite.__init__(self)
            self.images_right = images[:5]
            self.images_left = images[5:]
            self.images = self.images_right.copy()
            self.image = self.images[0]
            self.mask = pygame.mask.from_surface(self.image)
            self.rect = self.image.get_rect()
            self.rect.left, self.rect.top = position
            self.diretion = 'right'
            self.speed = 8
            self.switch_frame_count = 0
            self.switch_frame_freq = 1
            self.frame_index = 0
        '''左右移动hero'''
        def move(self, screensize, direction):
            assert direction in ['left', 'right']
            if direction != self.diretion:
                self.images = self.images_left.copy() if direction == 'left' else self.images_right.copy()
                self.image = self.images[0]
                self.diretion = direction
                self.switch_frame_count = 0
            self.switch_frame_count += 1
            if self.switch_frame_count % self.switch_frame_freq == 0:
                self.switch_frame_count = 0
                self.frame_index = (self.frame_index + 1) % len(self.images)
                self.image = self.images[self.frame_index]
            if direction == 'left':
                self.rect.left = max(self.rect.left-self.speed, 0)
            else:
                self.rect.left = min(self.rect.left+self.speed, screensize[0])
        '''画到屏幕上'''
        def draw(self, screen):
            screen.blit(self.image, self.rect)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    实现小人左右走动这个效果的核心思路其实就是根据函数输入的方向来改变小人可以使用的图片组合(images_right/images_left)。然后对于正在往某个方向行动中的小人,每隔 switch_frame_freq 帧游戏画面就切换一次小人的图片,游戏中的小人图片一共十张:

    前 5 张是向右走的图片组,后 5 张是向左走的图片组。

    现在,我们开始实现掉金币的效果啦,就像这样:

    核心代码实现如下:

    # 定义食物组
    food_sprites_group = pygame.sprite.Group()
    generate_food_freq = random.randint(10, 20)
    generate_food_count = 0
    while True:
        ...
        # --随机生成食物
        generate_food_count += 1
        if generate_food_count > generate_food_freq:
            generate_food_freq = random.randint(10, 20)
            generate_food_count = 0
            food = Food(game_images, random.choice(['gold',] * 10 + ['apple']), cfg.SCREENSIZE)
            food_sprites_group.add(food)
        # --更新食物
        for food in food_sprites_group:
            if food.update(): food_sprites_group.remove(food)
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    其中食物类的定义如下:

    
    '''定义食物类'''
    class Food(pygame.sprite.Sprite):
        def __init__(self, images_dict, selected_key, screensize, **kwargs):
            pygame.sprite.Sprite.__init__(self)
            self.screensize = screensize
            self.image = images_dict[selected_key]
            self.mask = pygame.mask.from_surface(self.image)
            self.rect = self.image.get_rect()
            self.rect.left, self.rect.bottom = random.randint(20, screensize[0]-20), -10
            self.speed = random.randrange(5, 10)
            self.score = 1 if selected_key == 'gold' else 5
        '''更新食物位置'''
        def update(self):
            self.rect.bottom += self.speed
            if self.rect.top > self.screensize[1]:
                return True
            return False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    整个定义其实很简单,苹果 5 分,金币 1 分,update 函数用于实时更新食物的位置以实现食物下降的效果。

    问题来了,我们该怎么实现接金币的效果呢,这金币一直往下掉接不住可咋办啊。别担心,只需要调用到 pygame 库里的碰撞检测功能就可以啦,具体而言代码实现如下:

    while True:
        ...
        # --碰撞检测
        for food in food_sprites_group:
            if pygame.sprite.collide_mask(food, hero):
                game_sounds['get'].play()
                food_sprites_group.remove(food)
                score += food.score
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码原理其实很简单,就是实时地检测小人有没有接触到金币,接触到的话就发出接到金币的声音,并移除对应的金币和获得一定的奖励得分。效果是这样子的:

    最后,我们来完善一下我们的小游戏,让它看起来更加"规范"一些:

    (1) 加入倒计时(在规定的时间内获得尽量高的得分)

    while True:
        ...
        # --倒计时信息
        countdown_text = 'Count down: ' + str((90000 - pygame.time.get_ticks()) // 60000) + ":" + str((90000 - pygame.time.get_ticks()) // 1000 % 60).zfill(2)
        countdown_text = font.render(countdown_text, True, (0, 0, 0))
        countdown_rect = countdown_text.get_rect()
        countdown_rect.topright = [cfg.SCREENSIZE[0]-30, 5]
        screen.blit(countdown_text, countdown_rect)
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    (2) 显示得分(显示当前的得分和历史最高分)

    
    while True:
        ...
        # --显示得分
        score_text = f'Score: {score}, Highest: {highest_score}'
        score_text = font.render(score_text, True, (0, 0, 0))
        score_rect = score_text.get_rect()
        score_rect.topleft = [5, 5]
        screen.blit(score_text, score_rect)
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (3) 添加游戏结束界面(玩家想结束游戏还是想重新开始游戏呢?)

    
    '''游戏结束画面'''
    def showEndGameInterface(screen, cfg, score, highest_score):
        # 显示的文本信息设置
        font_big = pygame.font.Font(cfg.FONT_PATH, 60)
        font_small = pygame.font.Font(cfg.FONT_PATH, 40)
        text_title = font_big.render(f"Time is up!", True, (255, 0, 0))
        text_title_rect = text_title.get_rect()
        text_title_rect.centerx = screen.get_rect().centerx
        text_title_rect.centery = screen.get_rect().centery - 100
        text_score = font_small.render(f"Score: {score}, Highest Score: {highest_score}", True, (255, 0, 0))
        text_score_rect = text_score.get_rect()
        text_score_rect.centerx = screen.get_rect().centerx
        text_score_rect.centery = screen.get_rect().centery - 10
        text_tip = font_small.render(f"Enter Q to quit game or Enter R to restart game", True, (255, 0, 0))
        text_tip_rect = text_tip.get_rect()
        text_tip_rect.centerx = screen.get_rect().centerx
        text_tip_rect.centery = screen.get_rect().centery + 60
        text_tip_count = 0
        text_tip_freq = 10
        text_tip_show_flag = True
        # 界面主循环
        clock = pygame.time.Clock()
        while True:
            screen.fill(0)
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        return False
                    elif event.key == pygame.K_r:
                        return True
            screen.blit(text_title, text_title_rect)
            screen.blit(text_score, text_score_rect)
            if text_tip_show_flag:
                screen.blit(text_tip, text_tip_rect)
            text_tip_count += 1
            if text_tip_count % text_tip_freq == 0:
                text_tip_count = 0
                text_tip_show_flag = not text_tip_show_flag
            pygame.display.flip()
            clock.tick(cfg.FPS)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    大功告成啦,完整源代码详见相关文件~

    在终端运行如下命令即可:

    python Game9.py
    
    • 1

    效果如下:

  • 相关阅读:
    【路径规划-TSP问题】基于遗传算法求解多起点多TSP问题附matlab代码
    Docker的镜像管理
    11 - Debian如何限制sudo权限
    Redis面试(二)
    捷报频传!苏州箱讯荣获2023年江苏省物流产业服务贡献奖
    Neural Collaborative Graph Machines for Table Structure Recognition ----论文阅读
    “==”和equals的区别
    代码覆盖率统计神器-jacoco工具实战
    ChatGPT:使用fastjson读取JSON数据问题——如何使用com.alibaba.fastjson库读取JSON数据的特定字段
    python如何判断字符串中的所有字符都是字母——isalpha函数的用法及实例
  • 原文地址:https://blog.csdn.net/newlw/article/details/124817997