zoukankan      html  css  js  c++  java
  • pygame 入门实例

    本文基于win7(64) + py3.5(64)环境。

    本文是这里的一篇学习笔记。加入了自己的理解。

    本文最终目的是实现一个飞机躲避导弹的游戏。

    1、核心概念

    pygame 的核心概念有:

    • Surface 对象(一个容器,一个载体,可以是空白的矩形区域,亦可是图片)
    • Surface 对象的矩形区域(用 Surface 实例的get_rect()方法获得)
    • 屏幕对象的blit()方法用于放置 Surface 对象
    • display 模块的flip()方法用于重绘游戏界面
    • 窗口主循环
    import pygame, sys
    from pygame.locals import * # 全局常量
    
    # 初始化
    pygame.init()
    
    # 屏幕对象
    screen = pygame.display.set_mode((400,270)) # 尺寸
    
    # Surface对象
    surf = pygame.Surface((50,50)) # 长、宽
    surf.fill((255,255,255)) # 颜色
    
    # Surface对象的矩形区域
    rect = surf.get_rect()
    
    
    # 窗口主循环
    while True:
        # 遍历事件队列    
        for event in pygame.event.get():
            if event.type == QUIT: # 点击右上角的'X',终止主循环
                pygame.quit()
                sys.exit()       
            elif event.type == KEYDOWN:           
                if event.key == K_ESCAPE: # 按下'ESC'键,终止主循环
                    pygame.quit()
                    sys.exit()                
        
        # 放置Surface对象
        screen.blit(surf, ((400-50)//2, (270-50)//2)) # 窗口正中
        #screen.blit(surf, rect)                      # surf的左上角
        
        # 重绘界面
        pygame.display.flip()
    

    效果图

    2、引入精灵

    上面的代码很能体现pygame的核心概念,但不利于规模比较大的游戏开发。

    为此,就需要继承 Sprite 类,并且设置属性surf为Surface对象。同时设置rect属性。

    调用屏幕对象的blit方法时,以精灵实例的surf属性和rect属性为参数。

    import pygame, sys
    from pygame.locals import *
    import random
    
    '''玩家随着方向键运动'''
    
    # 玩家
    class Player(pygame.sprite.Sprite):
        def __init__(self): 
            super().__init__()
            self.surf = pygame.Surface((75,25))
            self.surf.fill((255,255,255))
            self.rect = self.surf.get_rect()
            
        def update(self, key):
            # 随着方向键运动
            if key[K_UP]:
                self.rect.move_ip(0,-5)
            if key[K_DOWN]:
                self.rect.move_ip(0,5)
            if key[K_LEFT]:
                self.rect.move_ip(-5,0)
            if key[K_RIGHT]:
                self.rect.move_ip(5,0)
                
            # 限定player在屏幕中
            if self.rect.left < 0:
                self.rect.left = 0
            elif self.rect.right > 800:
                self.rect.right = 800
            if self.rect.top <= 0:
                self.rect.top = 0
            elif self.rect.bottom >= 600:
                self.rect.bottom = 600
        
    
    # 初始化
    pygame.init()
    
    # 屏幕对象
    screen = pygame.display.set_mode((800,600)) # 尺寸
    
    # 玩家精灵对象
    player = Player()
    
    
    
    # 窗口主循环
    while True:
        # 遍历事件队列    
        for event in pygame.event.get():
            if event.type == QUIT: # 点击右上角的'X',终止主循环
                pygame.quit()
                sys.exit()       
            elif event.type == KEYDOWN:           
                if event.key == K_ESCAPE: # 按下'ESC'键,终止主循环
                    pygame.quit()
                    sys.exit()                
        
        # 更新屏幕
        screen.fill((0,0,0))
        
        # 获得按键
        key = pygame.key.get_pressed() 
        
        # 更新玩家
        player.update(key)
        
        # 放置玩家
        screen.blit(player.surf, player.rect)
    
        # 更新界面
        pygame.display.flip()
        
    

    效果图

    3、引入敌人

    由于敌人很多,最好的方式是用Group来管理那么多的精灵。

    import pygame, sys
    from pygame.locals import *
    import random
    
    
    # 玩家
    class Player(pygame.sprite.Sprite):
        def __init__(self): 
            super().__init__()
            self.surf = pygame.Surface((75,25))
            self.surf.fill((255,255,255))
            self.rect = self.surf.get_rect()
            
        def update(self, key):
            if key[K_UP]:
                self.rect.move_ip(0,-5)
            if key[K_DOWN]:
                self.rect.move_ip(0,5)
            if key[K_LEFT]:
                self.rect.move_ip(-5,0)
            if key[K_RIGHT]:
                self.rect.move_ip(5,0)
                
            # 限定player在屏幕中
            if self.rect.left < 0:
                self.rect.left = 0
            elif self.rect.right > 800:
                self.rect.right = 800
            if self.rect.top <= 0:
                self.rect.top = 0
            elif self.rect.bottom >= 600:
                self.rect.bottom = 600
        
    # 敌人
    class Enemy(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.surf = pygame.Surface((20, 10))
            self.surf.fill((255, 255, 255))
            self.rect = self.surf.get_rect(center=(820, random.randint(0, 600)))
            self.speed = random.randint(5, 20)
    
        def update(self):
            self.rect.move_ip(-self.speed, 0) # 从右向左
            if self.rect.right < 0:
                self.kill() # Sprite 的内建方法
    
    # 初始化
    pygame.init()
    
    # 屏幕对象
    screen = pygame.display.set_mode((800,600)) # 尺寸
    
    # 自定义事件
    ADDENEMY = pygame.USEREVENT + 1      # 事件本质上就是整数常量。比 USEREVENT 小的数值已经对应内置事件,因此任何自定义事件都要比 USEREVENT 大
    pygame.time.set_timer(ADDENEMY, 250) # 每隔 250 毫秒(四分之一秒) 触发
    
    # 玩家
    player = Player()
    
    # 两个精灵组
    enemies = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player)
    
    
    # 窗口主循环
    while True:
        # 遍历事件队列    
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()       
            elif event.type == KEYDOWN:           
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit()                
            elif event.type == ADDENEMY: # 自定义事件
                new_enemy = Enemy()
                enemies.add(new_enemy)
                all_sprites.add(new_enemy)
        
        # 更新屏幕
        screen.fill((0,0,0))
        
        # 更新玩家
        key = pygame.key.get_pressed()
        player.update(key)
        screen.blit(player.surf, player.rect)
        
        # 更新敌人
        for enemy in enemies:
            enemy.update() 
            screen.blit(enemy.surf, enemy.rect)
            
        # 碰撞检测(灵魂所在)
        if pygame.sprite.spritecollideany(player, enemies):
            player.kill()
            print('发生碰撞!')
        
        # 重绘界面
        pygame.display.flip()
        
    

    效果图

    4、使用图片

    上面的例子是丑陋的黑白界面,需要进行美化。好的方式是使用图片来代替。可以去网上找素材,也可以自己画。

    为了让游戏更好看,增添了云朵精灵。

    注意:下面的surf属性用image来代替了。

    为方便朋友们测试,下面给出代码中用到的三张图片素材:


    import pygame, sys
    from pygame.locals import *
    import random
    
    '''飞机躲避导弹'''
    
    # 玩家
    class Player(pygame.sprite.Sprite):
        def __init__(self): 
            super().__init__()
            self.image = pygame.image.load('jet.png').convert() # load函数,返回一个 Surface 对象
            self.image.set_colorkey((255,255,255), RLEACCEL)
            self.rect = self.image.get_rect()
            
        def update(self, key):
            if key[K_UP]:
                self.rect.move_ip(0,-5)
            if key[K_DOWN]:
                self.rect.move_ip(0,5)
            if key[K_LEFT]:
                self.rect.move_ip(-5,0)
            if key[K_RIGHT]:
                self.rect.move_ip(5,0)
                
            # 限定player在屏幕中
            if self.rect.left < 0:
                self.rect.left = 0
            elif self.rect.right > 800:
                self.rect.right = 800
            if self.rect.top <= 0:
                self.rect.top = 0
            elif self.rect.bottom >= 600:
                self.rect.bottom = 600
        
    # 敌人
    class Enemy(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.image = pygame.image.load('missile.png').convert()
            self.image.set_colorkey((255, 255, 255), RLEACCEL)
            self.rect = self.image.get_rect(center=(820, random.randint(0, 600)))
            self.speed = random.randint(5, 20)
    
        def update(self):
            self.rect.move_ip(-self.speed, 0) # 从右向左
            if self.rect.right < 0:
                self.kill() # Sprite 的内建方法
    
    # 白云
    class Cloud(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.image = pygame.image.load('cloud.png').convert()
            self.image.set_colorkey((0,0,0),RLEACCEL)
            self.rect = self.image.get_rect(
                center = (random.randint(820,900),random.randint(0,600))
            )
    
        def update(self):
            self.rect.move_ip(-5,0)
            if self.rect.right < 0:
                self.kill()
                
    # 游戏初始化
    pygame.init()
    
    # 屏幕对象
    screen = pygame.display.set_mode((800,600)) # 尺寸
    
    # 背景Surface
    background = pygame.Surface(screen.get_size())
    background.fill((135, 206, 250)) # 浅蓝色
    
    # 两个自定义事件
    ADDENEMY = pygame.USEREVENT + 1      # 事件本质上就是整数常量。比 USEREVENT 小的数值已经对应内置事件,因此任何自定义事件都必须比 USEREVENT 大)
    pygame.time.set_timer(ADDENEMY, 250) # 每隔 250 毫秒(四分之一秒) 触发
    ADDCLOUD = pygame.USEREVENT + 2        
    pygame.time.set_timer(ADDCLOUD, 1000)
    
    # 玩家精灵对象
    player = Player()
    
    # 三个精灵组
    enemies = pygame.sprite.Group()
    clouds = pygame.sprite.Group()
    all_sprites = pygame.sprite.Group()
    all_sprites.add(player)
    
    
    # 窗口主循环
    while True:
        # 遍历事件队列    
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()       
            elif event.type == KEYDOWN:           
                if event.key == K_ESCAPE:
                    pygame.quit()
                    sys.exit()                
            elif event.type == ADDENEMY: # 自定义事件
                new_enemy = Enemy()
                enemies.add(new_enemy)
                all_sprites.add(new_enemy)
            elif event.type == ADDCLOUD: # 自定义事件
                new_cloud = Cloud()
                clouds.add(new_cloud)
                all_sprites.add(new_cloud)
                
        # 背景
        screen.blit(background, (0, 0))
        
        # 获取按键
        key = pygame.key.get_pressed()
        
        # 更新精灵(组)
        player.update(key)
        enemies.update()
        clouds.update()
        
        # 放置精灵
        for sprite in all_sprites:
            screen.blit(sprite.image, sprite.rect)
        
        # 碰撞检测(灵魂所在)
        if pygame.sprite.spritecollideany(player, enemies):
            player.kill()
            #print('发生碰撞!')
        
        # 重绘界面
        pygame.display.flip()
        
    

    效果图

    全都是类

    所有的东西都放到类里面!难道这就是传说中的面向对象编程???

    import pygame, sys
    from pygame.locals import *
    import random
    
    '''飞机躲避导弹'''
    
    # 根据概率随机选取
    def choice(seq, prob):
        p = random.random()
        for i in range(len(seq)):
            if sum(prob[:i]) < p < sum(prob[:i+1]):
                return seq[i]
    
    
    # 玩家
    class PlayerSprite(pygame.sprite.Sprite):
        speed = 5
        
        def __init__(self): 
            super().__init__()
            self.image = pygame.image.load('jet.png').convert() # load函数,返回一个 Surface 对象
            self.image.set_colorkey((255,255,255), RLEACCEL)
            self.rect = self.image.get_rect()
            
        def update(self, key):
            if key[K_UP]:
                self.rect.move_ip(0, -self.speed)
            if key[K_DOWN]:
                self.rect.move_ip(0, self.speed)
            if key[K_LEFT]:
                self.rect.move_ip(-self.speed, 0)
            if key[K_RIGHT]:
                self.rect.move_ip(self.speed, 0)
                
            # 限定player在屏幕中
            if self.rect.left < 0:
                self.rect.left = 0
            elif self.rect.right > 800:
                self.rect.right = 800
            if self.rect.top <= 0:
                self.rect.top = 0
            elif self.rect.bottom >= 600:
                self.rect.bottom = 600
        
    # 敌人
    class EnemySprite(pygame.sprite.Sprite):
        speed = choice([1,3,5], [0.5, 0.4, 0.1])
        
        def __init__(self):
            super().__init__()
            self.image = pygame.image.load('missile.png').convert()
            self.image.set_colorkey((255, 255, 255), RLEACCEL)
            self.rect = self.image.get_rect(center=(820, random.randint(0, 600)))
            #self.speed = random.randint(5, 20)
    
        def update(self):
            self.rect.move_ip(-self.speed, 0) # 从右向左
            if self.rect.right < 0:
                self.kill() # Sprite 的内建方法
    
    # 白云
    class CloudSprite(pygame.sprite.Sprite):
        speed = choice([1,2], [0.8, 0.2])
        
        def __init__(self):
            super().__init__()
            self.image = pygame.image.load('cloud.png').convert()
            self.image.set_colorkey((0,0,0),RLEACCEL)
            self.rect = self.image.get_rect(
                center = (random.randint(820,900),random.randint(0,600))
            )
    
        def update(self):
            self.rect.move_ip(-self.speed,0)
            if self.rect.right < 0:
                self.kill()
    
    
    # 背景
    class BackgroundSprite(pygame.sprite.Sprite):
    
        def __init__(self, size):
            super().__init__()
            self.image = pygame.Surface(size)  # 实际上是surf,为了统一写成image
            self.image.fill((135, 206, 250)) # 浅蓝色
            self.rect = pygame.Rect(0, 0, *size)
    
        def update(self):
            pass
            
    
    class Game():
    
        def __init__(self):
            # 游戏初始化
            pygame.init()
    
            # 屏幕大小及屏幕对象
            self.size = self.width, self.height = 800, 600
            self.screen = pygame.display.set_mode(self.size)
    
            pygame.display.set_caption("Pygame 2D RPG !")
            
            
            # 两个自定义事件
            self.ADDENEMY = pygame.USEREVENT + 1      # 事件本质上就是整数常量。比 USEREVENT 小的数值已经对应内置事件,因此任何自定义事件都必须比 USEREVENT 大)
            pygame.time.set_timer(self.ADDENEMY, 250) # 每隔 250 毫秒(四分之一秒) 触发
            self.ADDCLOUD = pygame.USEREVENT + 2        
            pygame.time.set_timer(self.ADDCLOUD, 1000)
    
            # 两个精灵对象
            self.background = BackgroundSprite(self.size)
            self.player = PlayerSprite()
    
            # 三个精灵组
            self.enemies = pygame.sprite.Group()
            self.clouds = pygame.sprite.Group()
            self.all_sprites = pygame.sprite.Group()
            
            self.all_sprites.add(self.player)
        
        
        def run(self):
            # 窗口主循环
            while True:
                # 遍历事件队列    
                for event in pygame.event.get():
                    if event.type == QUIT:
                        pygame.quit()
                        sys.exit()       
                    elif event.type == KEYDOWN:           
                        if event.key == K_ESCAPE:
                            pygame.quit()
                            sys.exit()                
                    elif event.type == self.ADDENEMY: # 自定义事件
                        new_enemy = EnemySprite()
                        self.enemies.add(new_enemy)
                        self.all_sprites.add(new_enemy)
                    elif event.type == self.ADDCLOUD: # 自定义事件
                        new_cloud = CloudSprite()
                        self.clouds.add(new_cloud)
                        self.all_sprites.add(new_cloud)
                
                # 背景
                self.screen.blit(self.background.image, self.background.rect)
                
                # 获取按键
                key = pygame.key.get_pressed()
                
                # 更新精灵(组)
                self.player.update(key)
                self.enemies.update()
                self.clouds.update()
                
                # 放置精灵
                for sprite in self.all_sprites:
                    self.screen.blit(sprite.image, sprite.rect)
                
                # 碰撞检测(灵魂所在)
                if pygame.sprite.spritecollideany(self.player, self.enemies):
                    self.player.kill()
                    print('发生碰撞!')
                
                # 重绘界面
                pygame.display.flip()
            
            
            
    if __name__ == '__main__':
        Game().run()
    
        
    
  • 相关阅读:
    4月24日 PHP基础
    4月22日 常用函数
    4月22日 练习题
    PHP正则数组
    PHP基础函数应用
    数据库SQL语句
    高级查询
    mysql
    CSS样式表
    词汇
  • 原文地址:https://www.cnblogs.com/hhh5460/p/7029217.html
Copyright © 2011-2022 走看看