步骤1 面向对象化改造
将原有的代码基础改造为面向对象编程的方法
原代码
import pygame
pygame.init()
screen=pygame.display.set_mode((400,600))
# 检查退出
while True
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 游戏更新
pygame.display.update()
if __name__ == '__main__':
# 创建游戏 并开始游戏
game=MainGame()
game.show()
更改后
SCREEN_W=400
SCREEN_H=600
class MainGame:
def __init__(self):
# 游戏初始化
pygame.init()
# 创建屏幕
self.screen = pygame.display.set_mode((SCREEN_W,SCREEN_H))
# 运行游戏
def show(self):
while True:
# 检查退出
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 游戏更新
pygame.display.update()
步骤2 增加战机类
2.1 游戏图操作
操作 | 代码 |
---|---|
加载图片 | img=pygame.image.load() |
裁剪 | img.subsurface(pygame.Rect(8,99,108,126)) |
透明化 | img.convert_alpha() |
2.2 游戏精灵类
精灵,简单来说是一个会动图片。
两个成员变量
1)self.image=要显示图片的Surface
2)self.rect = 显示Surface的区域,
import pygame
from pygame.locals import *
SCREEN_W=400
SCREEN_H=600
# 战机类(继承于游戏精灵类)
class Player(pygame.sprite.Sprite):
speed=1 # 移动速度
def __init__(self,plane_img,init_pos):
pygame.sprite.Sprite.__init__(self)
# 游戏精灵类 要点1:精灵的矩形区域
self.rect = pygame.Rect(5, 99, 98, 126) # (x,y,w,h)
# 游戏精灵类 要点2:精灵的显示图像
self.image = plane_img.subsurface(self.rect).convert_alpha() # 裁剪 之后透明化处理
# 初始化位置
self.rect.topleft=init_pos # 左上角等于初始坐标
# 继承游戏精灵类之后 移动只用修改rect的位置
def moveUp(self):
self.rect.top -= self.speed
def moveDown(self):
self.rect.top += self.speed
def moveLeft(self):
self.rect.left -= self.speed
def moveRight(self):
self.rect.left += self.speed
# 显示战机
def showPlane(self,scr):
scr.blit(self.image,self.rect)
# 主游戏
class MainGame:
def __init__(self):
# 游戏初始化
pygame.init()
# 创建屏幕
self.screen = pygame.display.set_mode((SCREEN_W,SCREEN_H))
# 设置标题
pygame.display.set_caption("飞机大战")
# 获得图片资源
plane_img = pygame.image.load('resources/image/shoot.png')
# 创建战机
self.player = Player(plane_img,(200,500))
# 运行游戏
def show(self):
while True:
# 检查退出
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 显示战机
self.player.showPlane(self.screen)
# 检查按键并操作战机
self.checkPress()
# 游戏更新
pygame.display.update()
# 检测按键并操作战机
def checkPress(self):
key_pressed = pygame.key.get_pressed()
if key_pressed[K_UP]:
self.player.moveUp()
if key_pressed[K_DOWN]:
self.player.moveDown()
if key_pressed[K_LEFT]:
self.player.moveLeft()
if key_pressed[K_RIGHT]:
self.player.moveRight()
if __name__ == '__main__':
# 创建游戏 并开始游戏
game=MainGame()
game.show()
2.3 战机状态变化(喷气效果)
可以改变战机的多种形态
# 战机类(继承于游戏精灵类) 增加喷气效果后的战机类
class Player(pygame.sprite.Sprite):
speed=1 # 移动速度
temp=0 # 控制显示图片的变量
def __init__(self,plane_img,init_pos):
pygame.sprite.Sprite.__init__(self)
# 游戏精灵类 要点1:精灵的矩形区域 区域集合
player_rects = []
player_rects.append(pygame.Rect(5, 99, 98, 126)) # 战机喷气
player_rects.append(pygame.Rect(170, 360, 98, 126))
# 游戏精灵类 要点2:精灵的显示图像列表
self.images = [] # 用来存储玩家对象精灵图片的列表
for i in range(len(player_rects)):
self.images.append(plane_img.subsurface(player_rects[i]).convert_alpha())
self.rect = player_rects[0]
# 初始化位置
self.rect.topleft=init_pos # 左上角等于初始坐标
def moveUp(self):
self.rect.top -= self.speed
def moveDown(self):
self.rect.top += self.speed
def moveLeft(self):
self.rect.left -= self.speed
def moveRight(self):
self.rect.left += self.speed
# 显示战机
def showPlane(self,scr):
self.temp += 1
if self.temp >= 2:
self.temp = 0
scr.blit(self.images[self.temp],self.rect)
2.4 战机运动范围限制
class Player(pygame.sprite.Sprite):
speed=1 # 移动速度
temp=0 # 控制显示图片的变量
def __init__(self,plane_img,init_pos):
# 游戏精灵类 要点1:精灵的矩形区域 区域集合
player_rects = []
player_rects.append(pygame.Rect(5, 99, 98, 126)) # 战机喷气
player_rects.append(pygame.Rect(170, 360, 98, 126))
# 游戏精灵类 要点2:精灵的显示图像列表
self.images = [] # 用来存储玩家对象精灵图片的列表
for i in range(len(player_rects)):
self.images.append(plane_img.subsurface(player_rects[i]).convert_alpha())
self.rect = player_rects[0]
# 初始化位置
self.rect.topleft=init_pos # 左上角等于初始坐标
# 继承游戏精灵类之后 移动只用修改rect的位置
def moveUp(self):
if self.rect.top <= 0:
self.rect.top = 0
else:
self.rect.top -= self.speed
def moveDown(self):
if self.rect.top >= SCREEN_H - self.rect.height:
self.rect.top = SCREEN_H - self.rect.height
else:
self.rect.top += self.speed
def moveLeft(self):
if self.rect.left <= 0:
self.rect.left = 0
else:
self.rect.left -= self.speed
def moveRight(self):
if self.rect.left >= SCREEN_W - self.rect.width:
self.rect.left = SCREEN_W - self.rect.width
else:
self.rect.left += self.speed
# 显示战机
def showPlane(self,scr):
self.temp += 1
if self.temp >= 2:
self.temp = 0
scr.blit(self.images[self.temp],self.rect)
步骤3 增加子弹类
import pygame
from pygame.locals import *
SCREEN_W = 400
SCREEN_H = 600
# 战机类(继承于游戏精灵类)
class Player(pygame.sprite.Sprite):
speed=1 # 移动速度
temp=0 # 控制显示图片的变量
def __init__(self,plane_img,init_pos):
pygame.sprite.Sprite.__init__(self)
# 游戏精灵类 要点1:精灵的矩形区域 区域集合
player_rects = []
player_rects.append(pygame.Rect(5, 99, 98, 126)) # 战机喷气
player_rects.append(pygame.Rect(170, 360, 98, 126))
# 游戏精灵类 要点2:精灵的显示图像列表
self.images = [] # 用来存储玩家对象精灵图片的列表
for i in range(len(player_rects)):
self.images.append(plane_img.subsurface(player_rects[i]).convert_alpha())
self.rect = player_rects[0]
# 创建子弹列表
self.bullets = pygame.sprite.Group()
bullet_rect = pygame.Rect(1004, 987, 9, 21)
self.bullet_image = plane_img.subsurface(bullet_rect)
# 初始化位置
self.rect.topleft=init_pos # 左上角等于初始坐标
# 继承游戏精灵类之后 移动只用修改rect的位置
def moveUp(self):
if self.rect.top <= 0:
self.rect.top = 0
else:
self.rect.top -= self.speed
def moveDown(self):
if self.rect.top >= SCREEN_H - self.rect.height:
self.rect.top = SCREEN_H - self.rect.height
else:
self.rect.top += self.speed
def moveLeft(self):
if self.rect.left <= 0:
self.rect.left = 0
else:
self.rect.left -= self.speed
def moveRight(self):
if self.rect.left >= SCREEN_W - self.rect.width:
self.rect.left = SCREEN_W - self.rect.width
else:
self.rect.left += self.speed
# 显示战机
def showPlane(self,scr):
self.temp += 1
if self.temp >= 2:
self.temp = 0
scr.blit(self.images[self.temp],self.rect)
# 发射炮弹
def shoot(self):
bullet = Bullet(self.bullet_image, self.rect.midtop)
self.bullets.add(bullet) #增加一颗子弹
# 炮弹移动
def moveBullet(self):
for bullet in self.bullets:
bullet.move()
# 子弹出界
if bullet.rect.bottom < 0:
self.bullets.remove(bullet)
# 绘制炮弹
def drawBullets(self, scr):
self.bullets.draw(scr)
# 子弹类
class Bullet(pygame.sprite.Sprite):
speed=2
def __init__(self, bullet_img, init_pos):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.rect = bullet_img.get_rect()
self.rect.midbottom = init_pos
def move(self):
self.rect.top -= self.speed
# 主游戏
class MainGame:
def __init__(self):
# 游戏初始化
pygame.init()
# 创建屏幕
self.screen = pygame.display.set_mode((SCREEN_W,SCREEN_H))
# 设置标题
pygame.display.set_caption("飞机大战")
# 获得图片资源
plane_img = pygame.image.load('resources/image/shoot.png')
# 创建战机
self.player = Player(plane_img,(200,500))
# 运行游戏
def show(self):
shoot_press,freq=0,30#射击计数 与频率控制值
while True:
# 检查退出
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 显示战机
self.player.showPlane(self.screen)
# 移动与绘画子弹
self.player.moveBullet()
self.player.drawBullets(self.screen)
# 检查按键并操作战机
shoot_press=self.checkPress(shoot_press,freq)
# 游戏更新
pygame.display.update()
# 检测按键并操作战机
def checkPress(self,shoot_press,freq=30):
key_pressed = pygame.key.get_pressed()
if key_pressed[K_UP]:
self.player.moveUp()
if key_pressed[K_DOWN]:
self.player.moveDown()
if key_pressed[K_LEFT]:
self.player.moveLeft()
if key_pressed[K_RIGHT]:
self.player.moveRight()
# 子弹操控 频率控制
if key_pressed[K_SPACE]:
if shoot_press % freq == 0:
self.player.shoot()
shoot_press += 1
if shoot_press >= 1000:
shoot_press = 0
return shoot_press
if __name__ == '__main__':
# 创建游戏 并开始游戏
game=MainGame()
game.show()
步骤4 添加敌机
import pygame
from pygame.locals import *
import random
SCREEN_W = 400
SCREEN_H = 600
# 战机类(继承于游戏精灵类)
class Player(pygame.sprite.Sprite):
...
# 子弹类
class Bullet(pygame.sprite.Sprite):
...
# 敌机类
class Enemy(pygame.sprite.Sprite):
speed = 1
def __init__(self, enemy_img, init_pos):
pygame.sprite.Sprite.__init__(self)
self.image = enemy_img # 图像
self.rect = enemy_img.get_rect()# 矩形区域
self.rect.topleft = init_pos # 初始位置
# 向下移动
def move(self):
self.rect.top += self.speed
# 主游戏
class MainGame:
def __init__(self):
# 游戏初始化
pygame.init()
# 创建屏幕
self.screen = pygame.display.set_mode((SCREEN_W,SCREEN_H))
# 设置标题
pygame.display.set_caption("飞机大战")
# 获得图片资源
plane_img = pygame.image.load('resources/image/shoot.png')
# 创建战机
self.player = Player(plane_img,(200,500))
# 获得敌机图片和创建敌机群
self.enemies = pygame.sprite.Group()
self.enemy_rect = pygame.Rect(534, 612, 57, 43)
self.enemy_img = plane_img.subsurface(self.enemy_rect)
# 运行游戏
def show(self):
shoot_press,shoot_freq=0,30#射击计数 与频率控制值
enemy_count,enemy_creat_freq,enemy_move_freq=0,100,20#敌机循环计数 与频率控制
while True:
# 检查退出
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 显示战机
self.player.showPlane(self.screen)
# 移动与绘画子弹
self.player.moveBullet()
self.player.drawBullets(self.screen)
# 创建、移动与显示敌机
enemy_count+=1
if enemy_count>=1000:
enemy_count=0
if enemy_count%enemy_creat_freq==0:
self.createEnemy()
if enemy_count%enemy_move_freq ==0:
self.moveEnemy()
self.enemies.draw(self.screen)
# 检查按键并操作战机
shoot_press=self.checkPress(shoot_press,shoot_freq)
# 游戏更新
pygame.display.update()
# 检测按键并操作战机
def checkPress(self,shoot_press,freq=30):
key_pressed = pygame.key.get_pressed()
if key_pressed[K_UP]:
self.player.moveUp()
if key_pressed[K_DOWN]:
self.player.moveDown()
if key_pressed[K_LEFT]:
self.player.moveLeft()
if key_pressed[K_RIGHT]:
self.player.moveRight()
# 子弹操控 频率控制
if key_pressed[K_SPACE]:
if shoot_press % freq == 0:
self.player.shoot()
shoot_press += 1
if shoot_press >= 1000:
shoot_press = 0
return shoot_press
# 随机地创建敌机
def createEnemy(self):
self.enemy_pos = [random.randint(0, SCREEN_W - self.enemy_rect.width), 0] # 随机位置
self.enemy = Enemy(self.enemy_img,self.enemy_pos) # 创建敌机
self.enemies.add(self.enemy) # 添加到敌机群
# 统一地移动敌机
def moveEnemy(self):
for enemy in self.enemies:
enemy.move()
if enemy.rect.top > SCREEN_H: # 超过边界移除
self.enemies.remove(enemy)
if __name__ == '__main__':
# 创建游戏 并开始游戏
game=MainGame()
game.show()
步骤5 击毁判断
5.1 碰撞检测
pygame 提供了 两个非常方便 的方法可以实现碰撞检测:
pygame.sprite.groupcollide()
两个精灵组 中 所有的精灵 的碰撞检测
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
dokill 设置为 True,则发生碰撞的精灵将被自动移除
collided 参数是用于 计算碰撞的回调函数
如果没有指定,则每个精灵必须有一个 rect 属性
返回发生碰撞的 精灵列表
pygame.sprite.spritecollide()
判断 某个精灵 和 指定精灵组 中的精灵的碰撞
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
如果将 dokill 设置为 True,则 指定精灵组 中 发生碰撞的精灵将被自动移除
collided 参数是用于 计算碰撞的回调函数
如果没有指定,则每个精灵必须有一个 rect 属性
返回 精灵组 中跟 精灵 发生碰撞的 精灵列表
import pygame
from pygame.locals import *
import random
SCREEN_W = 400
SCREEN_H = 600
# 战机类(继承于游戏精灵类)
class Player(pygame.sprite.Sprite):
...
# 子弹类
class Bullet(pygame.sprite.Sprite):
...
# 敌机类
class Enemy(pygame.sprite.Sprite):
speed = 1
def __init__(self, enemy_img, init_pos,enemy_down_imgs):
pygame.sprite.Sprite.__init__(self)
self.image = enemy_img # 图像
self.rect = enemy_img.get_rect()# 矩形区域
self.rect.topleft = init_pos # 初始位置
# 接收爆炸图像
self.down_imgs = enemy_down_imgs
self.down_index = 0
# 向下移动
def move(self):
self.rect.top += self.speed
# 绘画爆炸图
def drawImg(self, scr):
for i in range(len(self.down_imgs)):
scr.blit(self.down_imgs[self.down_index ], self.rect)
self.down_index += 1
# 主游戏
class MainGame:
def __init__(self):
....
# 敌机击落图像集合
self.enemy_down_imgs = []
self.enemy_down_imgs.append(
plane_img.subsurface(pygame.Rect(267, 347, 57, 43)))
self.enemy_down_imgs.append(
plane_img.subsurface(pygame.Rect(873, 697, 57, 43)))
self.enemy_down_imgs.append(
plane_img.subsurface(pygame.Rect(267, 296, 57, 43)))
self.enemy_down_imgs.append(
plane_img.subsurface(pygame.Rect(930, 697, 57, 43)))
# 运行游戏
def show(self):
shoot_press,shoot_freq=0,30#射击计数 与频率控制值
enemy_count,enemy_creat_freq,enemy_move_freq=0,100,20#敌机循环计数 与频率控制
while True:
# 检查退出
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# 设置背景
self.screen.fill((255,255,255))
# 显示战机
self.player.showPlane(self.screen)
# 移动与绘画子弹
self.player.moveBullet()
self.player.drawBullets(self.screen)
# 创建、移动与显示敌机
enemy_count+=1
if enemy_count>=1000:
enemy_count=0
if enemy_count%enemy_creat_freq==0:
self.createEnemy()
if enemy_count%enemy_move_freq ==0:
self.moveEnemy()
# 判断敌机击落
self.judgeEnemy()
self.enemies.draw(self.screen)
# 检查按键并操作战机
shoot_press=self.checkPress(shoot_press,shoot_freq)
# 游戏更新
pygame.display.update()
# 检测按键并操作战机
def checkPress(self,shoot_press,freq=30):
...
# 判断敌机击落
def judgeEnemy(self):
# 调用 groupcollide函数 判断两个群组的重合集合
enemy_dic = pygame.sprite.groupcollide(self.enemies, self.player.bullets, True, True)
for enemy in enemy_dic:
enemy.drawImg(self.screen)
# 随机地创建敌机
def createEnemy(self):
self.enemy_pos = [random.randint(0, SCREEN_W - self.enemy_rect.width), 0] # 随机位置
self.enemy = Enemy(self.enemy_img,self.enemy_pos,self.enemy_down_imgs) # 创建敌机
self.enemies.add(self.enemy) # 添加到敌机群
# 统一地移动敌机
def moveEnemy(self):
...
if __name__ == '__main__':
# 创建游戏 并开始游戏
game=MainGame()
game.show()