Python学习笔记(1)—B站黑马程序员
Python学习笔记(2)—B站黑马程序员
Python学习笔记(3)—B站黑马程序员
(1)点击pycharm下方的Terminal:
(2)输入命令:pip install pygame
(3)输入命令验证pygame是否安装:python -m pygame.examples.aliens
游戏素材评论区有,这里给出链接:
飞机大战游戏素材
移动静止的图像产生动画效果
游戏中的所有元素(物体)都是以 矩形区域 来描述位置的
通过四个要素(x, y)物体在游戏窗口中的位置(物体所在矩形区域的左上角),
(width, height)物体所在矩形区域的宽度和高度,来描述这个矩形区域。
python提供pygame.Rect类来描述矩形区域,这个类中很多属性,如上图。
pygame.Rect(x, y, width, height) ---> 创建对象
size属性返回一个元组(width, height)
不执行 pygame.init()方法,同样可以使用 pygame.Rect
上面图像的小格子是透明区域
每次调用update方法会将之前所有绘制的结果,一次性更新到游戏屏幕上。
每次调用update方法得到的结果是帧,一般要达到每秒调用60次update方法。
游戏中的动画效果,大部分是通过静态图像移动显示的。
英雄(飞机)每移动一次,背景图片就要被重新绘制一次,否则英雄会有残影。
当飞机“完全”从上方飞出屏幕之后,再将飞机移动到屏幕底部:
两种方法:
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 700
或者
hero_rect.bottom = hero_rect.y + hero_rect.height
if hero_rect.bottom <= 0:
hero_rect.y = 700
pygame.event.get()可以获得用户所有的操作:
鼠标移动,按键盘,关闭窗口等等
上面的代码,点击叉号 是无法关闭游戏窗口的,下面演示如何关闭游戏窗口:
在一个游戏中,有很多游戏对象。
对于每一个游戏对象,都要设置它的图像image,位置rect等属性和更新位置update等方法,
如果一个一个创建游戏对象很麻烦,所以pygame提供里两个类:sprite是精灵的意思。
pygame.sprite.Sprite ---> 专门设置游戏对象的图像,位置等属性和更新位置等方法
pygame.sprite.Group ---> 游戏对象组,放置多个游戏对象,可以同时设置多个游戏对象
注意:pygame.sprite.Sprite类中本身是没有image和rect两个属性的,要在它的派生子类中设置
并且默认的update方法中也没有写任何代码,要在子类中重写。
如果一个类的父类不是object,在重写初始化方法__init__时,要先super()调用一个父类的__init__方法,因为父类的__init__也写有代码,需要执行,而子类重写__init__方法会覆盖父类的init方法,导致父类的init方法无法执行。
import pygame
from plane_sprites import *
pygame.init()
# 创建游戏窗口 宽480像素 高700像素,返回游戏屏幕
screen = pygame.display.set_mode((480, 700))
# 绘制背景图像
# 1>加载图像数据
background = pygame.image.load("./images/background.png")
# 2> blit 设置图像位置:(0, 0) 图像的左上角放在游戏窗口左上角
screen.blit(background, (0, 0))
# 3> update 更新屏幕显示
# pygame.display.update()
# 绘制英雄的飞机图像
hero = pygame.image.load("./images/me1.png")
screen.blit(hero, (200, 500))
# 最后调用一次update方法即可
pygame.display.update()
# 创建游戏时钟对象
clock = pygame.time.Clock()
# 1.定义英雄的初始位置
hero_rect = pygame.Rect(150, 500, 102, 126)
# 创建敌机精灵
enemy1 = GameSprite("./images/enemy1.png")
enemy2 = GameSprite("./images/enemy1.png", 2)
enemy2.rect.x = 200
# 创建敌机精灵组
enemy_group = pygame.sprite.Group(enemy1, enemy2)
# 游戏循环,让游戏窗口一直保持(游戏循环,意味着游戏开始)
while True:
# 设置游戏刷新帧率
clock.tick(60)
# 监听事件(同一时刻可能会发生多个事件,所以用for)
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("游戏结束。。。")
# 卸载所有游戏模块
pygame.quit()
# 终止程序执行(因为有for和while,所以不能使用break)
exit()
# 2.更新英雄位置
hero_rect.y -= 1
# 3.如果移出屏幕,则将英雄从顶部移动到屏幕底部
if hero_rect.y + hero_rect.height <= 0:
hero_rect.y = 700
# 4.绘制背景图片(英雄每移动一次,背景图片就要被重新绘制一次,否则会出现英雄的残影)
screen.blit(background, (0, 0))
# 5.绘制英雄图像
screen.blit(hero, hero_rect)
# 让精灵组调用两个方法
# update--->调用精灵组的update方法可以让每一个精灵分别调用自己的update方法(让组中的所有精灵更新位置)
enemy_group.update()
# draw(self,surface屏幕对象)--->将所有的精灵图像显示到屏幕上(在screen上绘制所有的精灵)
enemy_group.draw(screen)
# 6.更新显示
pygame.display.update()
pygame.quit()
一个游戏主程序的职责有两个:
游戏初始化:init
设置游戏窗口
创建游戏时钟
创建精灵/精灵组 --->创建一个私有方法__create_sprites专门处理
游戏循环(即游戏开始):start_game
设置刷新帧率
事件监听--->__event_handler
碰撞检测--->__check_collide
更新/绘制精灵组--->__update_sprites
更新屏幕显示
游戏结束--->__game_over 在事件监听到鼠标点击×时调用
一个循环里写了太多东西,所以创建相应的私有方法解决部分操作。
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战游戏主程序"""
def __init__(self):
print("游戏初始化")
# 1.创建游戏的窗口(set_mode(元组) SCREEN_RECT.size--->元组(屏幕宽度,屏幕高度))
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2.创建游戏的时钟
self.clock = pygame.time.Clock()
# 3.调用私有方法,创建精灵和精灵组
self.__create_sprites()
def __create_sprites(self):
pass
def start_game(self):
print("开始游戏。。。")
while True:
pass
# 测试当前程序:创建游戏对象,开始游戏
# __name__代表当前模块名,如果__name__=__main__则导入当前模块
if __name__ == "__main__":
# 创建游戏对象
game = PlaneGame()
# 开始游戏
game.start_game()
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飞机大战游戏主程序"""
def __init__(self):
print("游戏初始化")
# 1.创建游戏的窗口(set_mode(元组) SCREEN_RECT.size--->元组(屏幕宽度,屏幕高度))
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 2.创建游戏的时钟
self.clock = pygame.time.Clock()
# 3.调用私有方法,创建精灵和精灵组
self.__create_sprites()
def __create_sprites(self):
pass
def start_game(self):
print("开始游戏。。。")
# 游戏循环(代表游戏开始)
while True:
# 1.设置刷新帧率(将刷新帧率设置为常量,在为主程序提供工具的plane_sprites文件中设置)
self.clock.tick(FRAME_PER_SCREEN)
# 2.事件监听
self.__event_handler()
# 3.碰撞检测
self.__check_collide()
# 4.更新精灵组
self.__update_sprites()
# 5.更新屏幕显示
pygame.display.update()
def __event_handler(self):
"""事件监听"""
for event in pygame.event.get():
# 游戏结束
if event.type == pygame.QUIT:
PlaneGame.__game_over()
def __check_collide(self):
"""碰撞检测"""
pass
def __update_sprites(self):
"""更新精灵组"""
pass
@staticmethod
# 没有调用任何属性,应设置位静态方法
def __game_over():
"""游戏结束"""
print("游戏结束")
pygame.quit()
exit()
# 测试当前程序:创建游戏对象,开始游戏
# __name__代表当前模块名,如果__name__=__main__则导入当前模块
if __name__ == "__main__":
# 创建游戏对象
game = PlaneGame()
# 开始游戏
game.start_game()
父类GameSprite的update方法无法实现背景图片滚动,所以再写一个子类Background重写父类的update方法。
在plane_main.py的__create_sprites,添加敌机精灵组:
敌机是定时被创建的,因此在这里不需要创建敌机精灵。
在plane_main.py的__event_handler,定时创建敌机,并添加到敌机精灵组:
在plane_main.py的__update_sprites,更新精灵组并绘制到屏幕上:
import random 写在 import pygame 上方
敌机y方向的初始位置:bottom=0或者y=bottom-height
使用自带的kill()方法可以将精灵从精灵组中移出(即删除这个精灵)
因为__del__内置方法会在对象被销毁前调用,所以可以用来判断对象是否被销毁。
在 plane_sprites.py 中写如下代码:
首先将plane_sprites中的print()注释掉,太多了。然后给__del__中添加pass。
groupcollide()方法--->两个精灵组中所有的精灵的碰撞检测:
group1--->精灵组1
group2--->精灵组2
dokill1--->布尔类型,若设为True,则发生碰撞时销毁group1中发生碰撞的精灵
dokill2--->布尔类型,若设为True,则发生碰撞时销毁group2中发生碰撞的精灵
spritecollide()方法--->判断某个精灵和指定精灵组中的精灵是否发生碰撞:
sprite--->某个精灵
group--->指定精灵组
dokill--->布尔类型,如为True,则指定精灵组中发生碰撞的精灵会被自动移除
该方法返回 指定精灵组中被移除的精灵列表
在评论区找到的讲义:
B站的Python课程讲义