14天学习训练营导师课程:
李宁《Python Pygame游戏开发入门与实战》
李宁《计算机视觉OpenCV Python项目实战》1
李宁《计算机视觉OpenCV Python项目实战》2
李宁《计算机视觉OpenCV Python项目实战》3
我第一次见到飞机大战是在我小学五年级下半学期的时候(2020年),这个游戏中可以说包含了几乎所有我目前可接触到的pygame知识。
下面用一个简单的飞机大战游戏,串一下pygame基础知识。
这里列举一些常用函数,详细内容请到pygame官网查看。
pygame场景里的动态物体都可视为精灵,如主角,敌人,子弹,可移动背景等等,换句话说,精灵就是一些动态图片,你要对这些图片进行一些交互操作,如移动,碰撞,爆炸等等。
Pygame提供了一个处理精灵的模块,也就是sprite(pygame.sprite)模块。我们使用该类Sprite来创建一个子类,真正达到处理精灵的目的,该子类提供了操作精灵的常用属性和方法,如下所示:
当游戏中有大量的精灵时,操作它们将变得复杂,此时通过构建精灵容器(group 类)也就是精灵组来统一管理这些精灵。构建方法如下:
# 创建精灵组
group = pygame.sprite.Group()
# 向组内添加一个精灵
group.add(sprite1)
键盘事件,这些会涉及到的日程安排操作,比如游戏批量的上下左右,或者人物中的前进、后继等操作,都需要键盘来配合执行。
一个事件的关键点,该事件可以进行连续的连续性控制。一个关键点、组合属性等以连续性的方式提供一系列事件,一系列常用的属性将通过一系列的连续性事件进行排序。
鼠标事件,Pygame 提供了三个鼠标事件:
flip函数将重新绘制整个屏幕对应的窗口。update函数仅仅重新绘制窗口中有变化的区域。如果仅仅是几个物体在移动,那么他只重绘其中移动的部分,没有变化的部分,并不进行重绘。
update比flip速度更快。因此在一般的游戏中,如果不是场景变化非常频繁的时候,建议使用update函数,而不是flip函数。
pygame可用函数有很多,但是真的不难,用文字讲述很麻烦,所以我只是列举了一些常用函数与方法,当你用到的时候记得去官网或者百度搜搜就可以了,把完整代码附在下面,仅供参考:
# 导入两个库
import pygame
import random
# 常量,屏幕宽高
WIDTH, HEIGHT = 800, 600
# 初始化操作
pygame.init()
pygame.mixer.init()
# 创建游戏窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 设置游戏标题
pygame.display.set_caption('飞机大战')
# 添加音乐
pygame.mixer.music.load('./sound/bgLoop.wav')
pygame.mixer.music.set_volume(0.5) # 音量
pygame.mixer.music.play(-1, 0)
# 添加系统时钟,用于设置帧的刷新
FPS = 40
clock = pygame.time.Clock()
# 创建用户自定义事件,每隔2000毫秒触发一次事件,随机创建敌人
CREATE_ENEMY = pygame.USEREVENT
# 每隔2000毫秒,会传递一个信号
pygame.time.set_timer(CREATE_ENEMY, 2000)
# 对于精灵定义了主角,子弹,敌人,爆炸,可移动背景四个。
#class Hero(pygame.sprite.Sprite)
#class Bullet(pygame.sprite.Sprite)
#class Enemy(pygame.sprite.Sprite)
#class Explode(pygame.sprite.Sprite)
#class BackGround(pygame.sprite.Sprite)
# 主角
class Hero(pygame.sprite.Sprite):
def __init__(self, speed):
super().__init__() # 调用父类的初始化方法
self.image = pygame.image.load('./image/plane.png')
self.rect = self.image.get_rect()
# 对图片进行一些尺寸处理
self.rect.width *= 0.5
self.rect.height *= 0.5
self.image = pygame.transform.scale(self.image, (self.rect.width, self.rect.height))
# 主角初始化位置
self.rect.x, self.rect.y = 0, 100
self.speed = speed
self.ready_to_fire = 0
def update(self, *args):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.rect.y -= self.speed
if keys[pygame.K_DOWN]:
self.rect.y += self.speed
if keys[pygame.K_LEFT]:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT]:
self.rect.x += self.speed
if keys[pygame.K_SPACE]:
if self.ready_to_fire == 0:
self.fire()
self.ready_to_fire += 1
if self.ready_to_fire > 5:
self.ready_to_fire = 0
else:
self.ready_to_fire = 0
if self.rect.x < 0:
self.rect.x = 0
if self.rect.y < 0:
self.rect.y = 0
if self.rect.y > HEIGHT - self.rect.height:
self.rect.y = HEIGHT - self.rect.height
# 子弹发射
def fire(self):
bullet = Bullet(10)
bullet.rect.x = self.rect.right
bullet.rect.centery = self.rect.centery
bullet_sprite.add(bullet)
# 音效
sound = pygame.mixer.Sound('./sound/laser.wav')
sound.play()
class Bullet(pygame.sprite.Sprite):
def __init__(self, speed):
super().__init__()
self.image = pygame.image.load('./image/bullet.png')
self.rect = self.image.get_rect()
self.speed = speed
def update(self, *args):
self.rect.x += self.speed
if self.rect.x > WIDTH:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self, speed):
super().__init__()
self.image = pygame.image.load('./image/enemy1.png')
self.rect = self.image.get_rect()
self.rect.x = 800
self.rect.y = random.randint(0, HEIGHT)
self.speed = speed
def update(self, *args):
self.rect.x -= self.speed
if self.rect.right < 0:
self.kill()
class Explode(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.images = [pygame.image.load('./image/explode' + str(i) + '.png') for i in range(1, 4)]
self.image_index = 0
self.image = self.images[self.image_index]
self.rect = self.image.get_rect()
self.readt_to_change = 0
sound = pygame.mixer.Sound('./sound/enemyExplode.wav')
sound.play()
def update(self, *args):
if self.image_index < 2:
self.readt_to_change += 1
if self.readt_to_change % 4 == 0:
self.image_index += 1
self.image = self.images[self.image_index]
else:
self.kill()
class BackGround(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load('./image/background.jpg')
self.rect = self.image.get_rect()
self.ready_to_move = 0
def update(self, *args):
self.rect.x -= 3
if self.rect.right <= 0:
self.rect.x = self.rect.width
# 初始化精灵组
bg_sprite = pygame.sprite.Group()
hero_sprite = pygame.sprite.Group()
enemy_sprite = pygame.sprite.Group()
bullet_sprite = pygame.sprite.Group()
explode_sprite = pygame.sprite.Group()
# 定义人物
hero1 = Hero(4)
hero_sprite.add(hero1)
enemy1 = Enemy(5)
enemy2 = Enemy(7)
bg1 = BackGround()
bg2 = BackGround()
bg2.rect.x = bg2.rect.width
bg_sprite.add(bg1, bg2)
# 保持游戏运行状态(游戏循环)
while True:
# ===========游戏帧的刷新===========
clock.tick(FPS)
# 检测事件
for event in pygame.event.get():
# 检测关闭按钮被点击的事件
if event.type == pygame.QUIT:
# 退出
pygame.quit()
exit()
if event.type == CREATE_ENEMY:
enemy_sprite.add(Enemy(random.randint(1, 7)))
# 碰撞检测,返回字典,得到二者信息
collision = pygame.sprite.groupcollide(enemy_sprite, bullet_sprite, True, True)
for enemy in collision.keys():
explode = Explode()
explode.rect = enemy.rect
explode_sprite.add(explode)
# screen.fill((0,0,0))
for group in [bg_sprite, hero_sprite, enemy_sprite, bullet_sprite, explode_sprite]:
group.update()
group.draw(screen)
pygame.display.update()
写了很多,但是很水,我自己都不想读下去,给自己找的理由是,它就像字典一样,用到的时候查查就行了。
重点不是这个,重点是理解其中面向对象的用法,如果看不懂源码,还请不要贪玩,打好基础再学习,因为这一个飞机大战源码算是最简单(也最粗糙)的源码了。
如果你已经看过一些pygame相关教程,需要一些源码练手,我将在下一篇整理几个常见的小游戏源码,供你学习参考。