pygame 入门实例

简介: 本文基于win7(64) + py3.5(64)环境。本文是这里的一篇学习笔记。加入了自己的理解。本文最终目的是实现一个飞机躲避导弹的游戏。1、核心概念pygame 的核心概念有:Surface 对象(一个容器,一个载体,可以是空白的矩形区域,亦可是图片)Surface 对象的矩形区域...

本文基于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()

效果图

img_9b42334c8675c797edb28668092c38b5.jpg

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()
    

效果图

img_22f2cfcdefd1e7676fac6cf8e6ffdeb4.jpg

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()
    

效果图

img_4ca344906f12113dc291b487d1e78b10.jpg

4、使用图片

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

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

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

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

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()
    

效果图

img_e098e44411828f9e57f37fb3eb428da7.jpg

全都是类

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

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()

    
目录
相关文章
|
5月前
|
Python
Pygame入门 2022 (2)
Pygame入门 2022 (2)
Pygame入门 2022 (2)
|
5月前
|
开发者 Python
Pygame提供了一套全面的工具和接口
【6月更文挑战第11天】,Pygame提供了一套全面的工具和接口
35 4
|
5月前
|
开发工具 图形学 Python
Pygame入门 2022 (1)
Pygame入门 2022 (1)
|
5月前
|
Python
Pygame入门 2022 (3)
Pygame入门 2022 (3)
|
5月前
|
数据可视化 Python
Pygame基础10-物理模拟
Pygame基础10-物理模拟
|
5月前
|
Python
Pygame基础8-碰撞
Pygame基础8-碰撞
Turtle入门(实例)
Turtle入门(实例)
172 0
Turtle入门(实例)