Pygame游戏开发
文章目录
pygame简介
模块库请参考:pygame官方文档
pygame可以用作游戏开发,但在商业游戏中真正的开发工具却不是pygame。使用pygame开发游戏周期长。
安装pygame
在pycharm中安装第三方库pygame:
在计算机中安装pygame:
需要用到pip:
查看pip:pip --version
pip也可以查看自己已经安装的扩展包: pip list
安装方法可以直接在命令行输入pip install -扩展包名字。
加快安装速度可以使用国内镜像源。
清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:http://mirrors.aliyun.com/pypi/simple/
游戏最小系统
所谓游戏最小系统指的是如果要写一个游戏最少要写哪些代码。
# 游戏最小系统 import pygame # 1.初始化操作 pygame.init() # 这是对所有操作进行初始化,包括声音、图像等 # 2.创建游戏窗口 # set_mode(大小) window = pygame.display.set_mode((800, 600)) # 设置游戏标题 pygame.display.set_caption("酷电编程") # 3.让游戏保持一直运行的状态 # game loop(游戏循环) while True: # 4.检测事件 for event in pygame.event.get(): # 检测关闭按钮被点击的事件 if event.type == pygame.QUIT: # 退出 exit()
显示图片
import pygame pygame.init() window = pygame.display.set_mode((800, 600)) pygame.display.set_caption("酷电编程") # 设置背景颜色 window.fill((255, 255, 255)) # RGB值,(255,255,255)为白色 # 游戏开始页面静态效果 # 1、加载图片 image1 = pygame.image.load('D:\\上课内容lxl\\2024_4_20\\酷电仔.png') # 2、渲染图片 # blit(渲染对象,坐标) window.blit(image1, (0, 0)) # 4、操作图片 # 1)获取图片大小 width, high = image1.get_size() # 获取图片的长、宽 print(width, high) window.blit(image1, (800 - width, 600 - high)) # 让图片在右下角显示 # 2)旋转和缩放 # scale(缩放对象,目标大小) --> 可能会发生形变 new_image1 = pygame.transform.scale(image1, (200, 200)) window.blit(new_image1, (300, 100)) # rotozoom(缩放/旋转对象,旋转角度,缩放比例) 逆时针旋转 new_image2 = pygame.transform.rotozoom(image1, 90, 0.5) window.blit(new_image2, (300, 400)) # 3、刷新显示页面 # pygame.display.flip() 第一次刷新 # pygame.display.update() 第二次及以后刷新。两者耗费的资源是不一样的 pygame.display.update() while True: # 游戏帧刷新 for event in pygame.event.get(): if event.type == pygame.QUIT: exit()
显示文字
import pygame pygame.init() window = pygame.display.set_mode((800, 600)) pygame.display.set_caption("酷电编程") # 设置背景颜色 window.fill((255, 255, 255)) # RGB值,(255,255,255)为白色 # 显示文字 # 1、创建字体对象(选笔) # font = pygame.font.Font() # Font(字体文件路径,字号)是自定义字体 # font = pygame.font.SysFont() # SysFont(字体名,字体大小, 是否加粗=False, 是否倾斜=False)用的是系统字体 # lst = pygame.font.get_fonts() # 获取所有可使用的字体,返回值是所有可用的字体列表 # print(lst) font = pygame.font.SysFont('arial', 30) # 2、通过字体创建文字对象(用笔写字) # 字体对象.render(文字内容,True,文字颜色,背景颜色=None) text = font.render('hello pygame', True, (0, 0, 255), (0, 255, 0)) # 3、渲染到窗口上 window.blit(text, (0, 0)) # 4、操作文字对象 # (1).获取文字内容的宽度和高度 text_w, text_h = text.get_size() window.blit(text, (800 - text_w, 600 - text_h)) # (2)文字缩放和旋转 new_text1 = pygame.transform.scale(text, (400, 200)) window.blit(new_text1, (400, 0)) new_text2 = pygame.transform.rotozoom(text, 90, 2) window.blit(new_text2, (100, 200)) # 刷新 pygame.display.update() while True: # 游戏帧刷新 for event in pygame.event.get(): if event.type == pygame.QUIT: exit()
画线
import pygame pygame.init() window = pygame.display.set_mode((800, 600)) pygame.display.set_caption("酷电编程") # 设置背景颜色 window.fill((255, 255, 255)) # RGB值,(255,255,255)为白色 # 显示图形 # 1、画直线(原理:两点确定一条直线) # line(画在哪儿,线的颜色,线的起点,线的终点,线宽(默认为1)) pygame.draw.line(window, (255, 0, 0), (10, 20), (200, 20)) # 这里画在游戏窗口上(一般也是画在游戏窗口上) # 2、画折线(原理:多个点按顺序连接起来) # lines(画在哪儿,线的颜色,是否闭合,多个点(列表),线宽(默认为1)) points = [(10, 300), (100, 160), (180, 260), (300, 100)] pygame.draw.lines(window, (0, 255, 0), False, points, 3) # True:闭合;False:不闭合 # 刷新显示页面 # pygame.display.flip() 第一次刷新 # pygame.display.update() 第二次及以后刷新。两者耗费的资源是不一样的 pygame.display.update() while True: # 游戏帧刷新 for event in pygame.event.get(): if event.type == pygame.QUIT: exit()
其他图像
其他图像:圆、矩形、椭圆、弧线。
import pygame from math import pi pygame.init() window = pygame.display.set_mode((800, 600)) pygame.display.set_caption("酷电编程") # 设置背景颜色 window.fill((255, 255, 255)) # RGB值,(255,255,255)为白色 # 显示图形 # 1、画直线(原理:两点确定一条直线) # line(画在哪儿,线的颜色,线的起点,线的终点,线宽(默认为1)) pygame.draw.line(window, (255, 0, 0), (10, 20), (200, 20)) # 这里画在游戏窗口上(一般也是画在游戏窗口上) # 2、画折线(原理:多个点按顺序连接起来) # lines(画在哪儿,线的颜色,是否闭合,多个点(列表),线宽(默认为1)) points = [(10, 300), (100, 160), (180, 260), (300, 100)] pygame.draw.lines(window, (0, 255, 0), True, points, 3) # True:闭合;False:不闭合 # 3、画圆(原理:圆心+半径) # circle(画在哪儿,线的颜色,圆心坐标,半径,线宽(默认为0,线宽=0时为实心圆,非0时为空心圆)) pygame.draw.circle(window, (0, 0, 255), (200, 250), 100, 2) # 这里线宽=2,画的是空心圆 # 4、画矩形(原理:根据左上角顶点坐标和长、宽即可确定一个矩形) # rect(画在哪儿,线的颜色,矩形范围(x,y,length,width),线宽(默认为0,线宽=0时为实心矩形,非0时为空心矩形)) pygame.draw.rect(window, (120, 20, 60), (400, 100, 200, 100)) # 线宽默认为0,画的是实心矩形 # 5、画椭圆(原理:在矩形里画内切圆,因此画椭圆的参数与画矩形参数一模一样) # ellipse(画在哪儿,线的颜色,矩形范围(x,y,length,width),线宽(默认为0,线宽=0时为实心椭圆,非0时为空心椭圆)) pygame.draw.ellipse(window, (255, 0, 0), (400, 400, 200, 100), 3) # 这里线宽=3,画的是空心椭圆 # 6、画弧线(原理:弧线是椭圆的一段长度,因此也需要借助矩形参数) # arc(画在哪儿,线的颜色,矩形范围(x,y,length,width),起始弧度,终止弧度,线宽(默认为1)) # 弧度:0-2π;角度:0-360 pygame.draw.arc(window, (255, 0, 0), (400, 250, 200, 100), 0, pi, 3) # 这里的弧度与数学中的坐标是完全一样的 # 这里引入了math模块中的pi # 刷新显示页面 # pygame.display.flip() 第一次刷新 # pygame.display.update() 第二次及以后刷新。两者耗费的资源是不一样的 pygame.display.update() while True: # 游戏帧刷新 for event in pygame.event.get(): if event.type == pygame.QUIT: exit()
在上面画弧线时用到的弧度与数学中的坐标是一模一样的:
动画原理
所有动画的原理都是一样的,都是多张照片快速的播放形成动画效果。
移动、缩放和旋转动画
移动动画
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 1、显示静态球(实心圆,用画圆的方法) # circle(画在哪儿,线的颜色,圆心坐标,半径,线宽(默认为0。线宽为0即实心圆,非0为空心圆)) y = 100 pygame.draw.circle(window, (255, 0, 0), (100, y), 50) # 这里线宽为0画实心圆 # 刷新 pygame.display.update() # 在循环上面写的都是静态效果,要实现动态效果必须写在循环内 # 游戏循环 while True: # 2、移动动画(动态球,实心) pygame.draw.circle(window, (255, 255, 255), (100, y), 50) # 在画下一幅图之前需要将前面一副图覆盖掉(使用背景颜色覆盖,这里背景颜色为白色) y += 1 # 数字越大,动画移动的速度越快 pygame.draw.circle(window, (255, 0, 0), (100, y), 50) pygame.display.update() # 刷新 # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出
运行上述代码发现即便在循环中写 y += 1 ,动画的移动速度还是太快,如何再减慢速度?
答:可以规定每循环 100 次(数字越大,速度越慢)移动一次。
num = 1 while True: num += 1 if num % 100 == 0: y += 1 # 画图代码...
具体实现:
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 1、显示静态球(实心圆,用画圆的方法) # circle(画在哪儿,线的颜色,圆心坐标,半径,线宽(默认为0。线宽为0即实心圆,非0为空心圆)) y = 100 pygame.draw.circle(window, (255, 0, 0), (100, y), 50) # 这里线宽为0画实心圆 # 刷新 pygame.display.update() # 在循环上面写的都是静态效果,要实现动态效果必须写在循环内 num = 1 # 游戏循环 while True: num += 1 # 1)移动动画(动态球,实心) if num % 1000 == 0: pygame.draw.circle(window, (255, 255, 255), (100, y), 50) # 在画下一幅图之前需要将前面一副图覆盖掉(使用背景颜色覆盖,这里背景颜色为白色) y += 1 # 数字越大,动画移动的速度越快 pygame.draw.circle(window, (255, 0, 0), (100, y), 50) pygame.display.update() # 刷新 # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出
pygame学习-移动动画章节-动画演示
缩放动画
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 1、显示静态球(实心圆,用画圆的方法) # circle(画在哪儿,线的颜色,圆心坐标,半径,线宽(默认为0。线宽为0即实心圆,非0为空心圆)) y = 100 # 圆心初始纵坐标 r = 50 # 圆的初始半径 pygame.draw.circle(window, (255, 0, 0), (100, y), r) # 这里线宽为0画实心圆 # 刷新 pygame.display.update() # 在循环上面写的都是静态效果,要实现动态效果必须写在循环内 num = 1 # 游戏循环 while True: num += 1 # 2)缩放动画(动态球,实心) if num % 1000 == 0: pygame.draw.circle(window, (255, 255, 255), (100, y), r) # 在画下一幅图之前需要将前面一副图覆盖掉(使用背景颜色覆盖,这里背景颜色为白色) r += 1 # r += 1 --->半径增大,动画放大;r -= 1 --->半径减小,动画缩小 pygame.draw.circle(window, (255, 0, 0), (100, y), r) pygame.display.update() # 刷新 # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出
pygame学习-缩放动画章节-动画演示
旋转动画
# 3)旋转动画 if num % 1000 == 0: window.fill((255, 255, 255)) pygame.draw.circle(window, (255, 0, 0), (100, y), r) pygame.draw.rect(window, (255, 255, 255), (ix, iy, iw, ih)) d += 1 new_image = pygame.transform.scale(image, d, 1) # 旋转 window.blit(new_image, (ix, iy)) pygame.display.update()
移动和缩放同时进行
# 2)移动和缩放同时进行动画(动态球,实心) if num % 1000 == 0: pygame.draw.circle(window, (255, 255, 255), (100, y), r) # 在画下一幅图之前需要将前面一副图覆盖掉(使用背景颜色覆盖,这里背景颜色为白色) y += 2 # 移动 r += 1 # r += 1 --->半径增大,动画放大;r -= 1 --->半径减小,动画缩小 pygame.draw.circle(window, (255, 0, 0), (100, y), r) pygame.display.update() # 刷新
动画的灵活控制
下面检测边界和修改坐标值得学习:
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 静态球(实心圆,用画圆的方法) # circle(画在哪儿,线的颜色,圆心坐标,半径,线宽(默认为0。线宽为0即实心圆,非0为空心圆)) x, y = 200, 30 # 圆心初始坐标 r = 30 # 圆的初始半径 y_speed = 1 # 圆上下移动的速度 pygame.draw.circle(window, (255, 0, 0), (x, y), r) # 这里线宽为0画实心圆 # 刷新 pygame.display.update() # 在循环上面写的都是静态效果,要实现动态效果必须写在循环内 num = 1 # 游戏循环 while True: num += 1 # 小球上下反弹的效果 if num % 1000 == 0: ''' 前面在学习移动、缩放动画时用的都是:在画下一幅图之前需要将前面一副图覆盖掉 pygame.draw.circle(window, (255, 255, 255), (x, y), r) # (使用背景颜色覆盖,这里背景颜色为白色) 也可以用其他方法处理,就是直接再填充一次背景颜色:window.fill((255, 255, 255)) # 原来背景颜色为白色 当再次填充完背景颜色后其余之前在窗口中显示的内容需要再重新画出来。【这条不要忘了】 ''' window.fill((255, 255, 255)) # 再填充一次背景颜色,需要注意其余之前在窗口中显示的内容需要再重新画出来 # 修改y坐标 y += y_speed # 检测边界 # 下边界 if y >= WIN_HEIGHT - r: y_speed = y_speed * -1 # 上边界 if y <= r: y_speed = y_speed * -1 pygame.draw.circle(window, (255, 0, 0), (x, y), r) pygame.display.update() # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出
pygame学习-动画的灵活控制章节-动画演示
鼠标事件
import pygame from random import randint WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 刷新 pygame.display.update() count = 0 # 统计事件发生的次数 # 游戏循环 while True: # 检测事件 for event in pygame.event.get(): # for循环中的代码只有事件发生后才会执行 # 发生什么事件执行对应的代码一定要写在for循环中 count += 1 print(count) # event的type属性是用来区分不同类型的事件 ''' QUIT ---> 点击关闭按钮对应的事件 1、鼠标事件 MOUSEBUTTONDOWN ---> 鼠标按下 MOUSEBUTTONUP ---> 鼠标弹起 MOUSEMOTION ---> 鼠标移动 pos ---> 鼠标位置属性(点的哪儿) ''' if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出 # ---------鼠标事件--------- if event.type == pygame.MOUSEBUTTONDOWN: print('鼠标按下', '鼠标按下的位置', event.pos) # x,y = event.pos 。 event.pos会返回(x,y)元组类型 mx, my = event.pos # 取出鼠标的x,y坐标 pygame.draw.circle(window, (255, 255, 0), (mx, my), 50) # 画圆 pygame.display.update() # 刷新 if event.type == pygame.MOUSEBUTTONUP: print('鼠标弹起') if event.type == pygame.MOUSEMOTION: print('鼠标移动') r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) mx, my = event.pos # 取出鼠标的x,y坐标 pygame.draw.circle(window, (r, g, b), (mx, my), 30) # 画圆 pygame.display.update() # 刷新
pygame学习-鼠标事件章节-动画演示
键盘事件
说明:
如果按下键盘没反应一般就是输入法的问题,切换成英文输入法即可。
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 刷新 pygame.display.update() # 字体 font = pygame.font.SysFont('arial', 30) tx = 0 count = 0 # 统计事件发生的次数 # 游戏循环 while True: # 检测事件 for event in pygame.event.get(): # for循环中的代码只有事件发生后才会执行 # 发生什么事件执行对应的代码一定要写在for循环中 count += 1 print(count) # event的type属性是用来区分不同类型的事件 ''' QUIT ---> 点击关闭按钮对应的事件 2、键盘事件 KEYDOWN ---> 键盘按键按下 KEYUP ---> 键盘按键弹起 key ---> 按键值属性(哪个键被按了) ''' if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出 # ---------键盘事件--------- if event.type == pygame.KEYDOWN: print('键盘按键按下', event.key, chr(event.key)) # event.key返回的是ASCII码值,需要转换成对应的字符 # 注意这里如果按下键盘没反应一般就是输入法的问题,切换成英文输入法即可 if chr(event.key) == 'f': print('闪现') text = font.render(chr(event.key), True, (250, 0, 0)) # window.fill((255, 255, 255)) # 再填充一次背景将原来的内容覆盖掉 tx += 20 window.blit(text, (tx, 300)) pygame.display.update() if event.type == pygame.KEYUP: print('键盘按键弹起')
pygame学习-键盘事件章节-动画演示
音乐
在Pygame中播放背景音乐和音效主要涉及到pygame.mixer模块:
方法名称 | 功能描述 |
---|---|
bgmusic = pygame.mixer.Sound(音乐文件路径) | 加载音乐 |
bgmusic.play() | 播放音乐 |
bgmusic.set_volume(0.1) | 控制音量。参数范围是0.0到1.0 |
bgmusic.stop() | 停止音乐 |
bgmusic.pause() | 暂停音乐 |
bgmusic.unpause() | 恢复音乐播放 |
按钮点击效果
按钮被点击就是要判断鼠标点击事件发生时鼠标点击的坐标是否在按钮的范围内,点击效果实现就是将按钮再重新画一遍。
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 按钮上的文字 font = pygame.font.SysFont('隶书', 30) # 按钮:需要先画矩形,再在上面写字 # 1、“确定”按钮 bx1, by1, bw, bh = 30, 100, 100, 50 # x,y,width,height pygame.draw.rect(window, (255, 0, 0), (bx1, by1, bw, bh)) text1 = font.render('确定', True, (255, 255, 255)) tw1, th1 = text1.get_size() # 获取文字对象的长、宽 tx1 = bx1 + bw / 2 - tw1 / 2 # 文字对象x坐标 ty1 = by1 + bh / 2 - th1 / 2 # 文字对象y坐标 window.blit(text1, (tx1, ty1)) # 2、“取消”按钮 bx2, by2 = 30, 200 pygame.draw.rect(window, (0, 255, 0), (bx2, by2, bw, bh)) text2 = font.render('取消', True, (255, 255, 255)) tw2, th2 = text2.get_size() # 获取文字对象的长、宽 tx2 = bx2 + bw / 2 - tw2 / 2 # 文字对象x坐标 ty2 = by2 + bh / 2 - th2 / 2 # 文字对象y坐标 window.blit(text2, (tx2, ty2)) # 刷新 pygame.display.update() # 游戏循环 while True: # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出 # 鼠标点击按钮要做的事 if event.type == pygame.MOUSEBUTTONDOWN: mx, my = event.pos # 获取鼠标点击的坐标 # 是否点击了“确定”按钮 if bx1 <= mx <= bx1 + bw and by1 <= my <= by1 + bh: # 运算符优先级:算术运算符>比较运算符>逻辑运算符。因此这里并不需要加小括号 # 按钮点击的反应:按钮被点击后背景颜色改变,松开后背景颜色恢复 pygame.draw.rect(window, (200, 200, 200), (bx1, by1, bw, bh)) # 这里按钮被点击时变为灰色 window.blit(text1, (tx1, ty1)) # 文字也要重新渲染 pygame.display.update() # 刷新 print('确定按钮被点击') # 是否点击了“取消”按钮 if bx2 <= mx <= bx2 + bw and by2 <= my <= by2 + bh: # 运算符优先级:算术运算符>比较运算符>逻辑运算符。因此这里并不需要加小括号 # 按钮点击的反应:按钮被点击后背景颜色改变,松开后背景颜色恢复 pygame.draw.rect(window, (200, 200, 200), (bx2, by2, bw, bh)) # 这里按钮被点击时变为灰色 window.blit(text2, (tx2, ty2)) # 文字也要重新渲染 pygame.display.update() # 刷新 print('取消按钮被点击') # exit() # 鼠标松开按钮要做的事 if event.type == pygame.MOUSEBUTTONUP: # 鼠标松开后背景颜色恢复 # 这里并没有获取鼠标松开的坐标,意思是不管在哪松开都要执行 # “确定”按钮被松开 pygame.draw.rect(window, (255, 0, 0), (bx1, by1, bw, bh)) # 鼠标松开时恢复为红色 window.blit(text1, (tx1, ty1)) # 文字也要重新渲染 pygame.display.update() # 刷新 # “取消”按钮被松开 pygame.draw.rect(window, (0, 255, 0), (bx2, by2, bw, bh)) # 鼠标松开时恢复为绿色 window.blit(text2, (tx2, ty2)) # 文字也要重新渲染 pygame.display.update() # 刷新
其中确定文字对象坐标的方法:
pygame学习-按钮点击效果章节-动画演示
封装好的按钮
在上面“按钮点击效果”中发现要实现一个按钮点击效果的代码很多,如果按钮很多,写起来会很繁琐。这时可以用面向对象编程思想,将按钮封装起来,使用时直接调用。
坦克控制
坦克控制主要在于键盘按住不放,坦克移动;键盘松开,坦克停止。
学会了键盘按住不放,移动;键盘松开,停止。鼠标按住不放,鼠标松开实现的方法是一样的。关键在于用到了一个bool值。
说明:
如果按下键盘没反应一般就是输入法的问题,切换成英文输入法即可。
import pygame WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('动画原理') # 设置标题 window.fill((255, 255, 255)) # 背景 # 放坦克 tank_up = pygame.image.load('坦克up.png') # 向上的坦克 tank_down = pygame.image.load('坦克down.png') # 向下的坦克 tank_left = pygame.image.load('坦克left.png') # 向左的坦克 tank_right = pygame.image.load('坦克right.png') # 向右的坦克 tank_up_width, tank_up_height = tank_up.get_size() tank_x, tank_y = WIN_WIDTH / 2 - tank_up_width / 2, WIN_HEIGHT - tank_up_height # 坦克的坐标。涉及坦克的移动(动画的移动),坐标不能写死 tank = tank_up # 默认画的是向上的坦克 window.blit(tank, (tank_x, tank_y)) # 刷新 pygame.display.update() is_move = False # 是否移动。默认不动 x_speed = 0 # x坐标移动速度 y_speed = 0 # y坐标移动速度 # 游戏循环 while True: # 要实现“键盘按住不放,移动;键盘松开,停止”的效果需要将移动的效果写在for循环外面 if is_move == True: window.fill((255, 255, 255)) # 以背景色覆盖掉原来的 tank_x += x_speed tank_y += y_speed window.blit(tank, (tank_x, tank_y)) pygame.display.update() # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出 # 坦克移动 if event.type == pygame.KEYDOWN: char = chr(event.key) # 往上移动 if char == 'w': is_move = True # 移动 x_speed = 0 y_speed = -1 tank = tank_up elif char == 's': is_move = True # 向下移动 x_speed = 0 y_speed = 1 tank = tank_down elif char == 'a': is_move = True # 向左移动 x_speed = -1 y_speed = 0 tank = tank_left elif char == 'd': is_move = True # 向右移动 x_speed = 1 y_speed = 0 tank = tank_right else: is_move = False # 停止 if event.type == pygame.KEYUP: is_move = False # 停止
pygame学习-坦克控制章节-动画演示
补充
前面提到使用如下代码减慢动画速度:
num = 1 while True: num += 1 if num % 100 == 0: y += 1 # 画图代码...
但事实上有更好的方法。pygame中有time类,可以设置游戏帧数,以此来减慢动画速度。
clock = pygame.time.Clock() # (放到while循环外) clock.tick(60) # 设置帧频。(放到while循环内)
另外,上面控制坦克移动时使用的是 w、s、a、d 控制 上、下、左、右;但也可以使用 ↑、↓、←、→ 控制 上、下、左、右。只需要将控制移动方向的代码修改为如下代码即可(同样下面贪吃蛇控制移动方向的按键也可以修改):
# 坦克移动 if event.type == pygame.KEYDOWN: # 往上移动 if event.key == pygame.K_UP: is_move = True # 移动 x_speed = 0 y_speed = -1 tank = tank_up elif event.key == pygame.K_DOWN: is_move = True # 向下移动 x_speed = 0 y_speed = 1 tank = tank_down elif event.key == pygame.K_LEFT: is_move = True # 向左移动 x_speed = -1 y_speed = 0 tank = tank_left elif event.key == pygame.K_RIGHT: is_move = True # 向右移动 x_speed = 1 y_speed = 0 tank = tank_right else: is_move = False # 停止
K_UP、K_DOWN、K_LEFT、K_RIGHT分别表示 ↑、↓、←、→。
贪吃蛇(简易版)
实现了简易版的贪吃蛇,没有实现更详细的控制(比如此时蛇正向上走,如果向让蛇向下走,不能直接按 ‘s’ 键,而应该先向右或向左,然后向下)。
代码目录:
import pygame import random import time from pygame import Rect WIN_WIDTH = 800 # 窗口宽度 WIN_HEIGHT = 600 # 窗口高度 # 初始化游戏 pygame.init() # 创建窗口 window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # 实际开发中窗口宽和高都是设置为全局变量,这样以后修改很方便(类似于封装的好处) pygame.display.set_caption('贪吃蛇') # 设置标题 window.fill((255, 255, 255)) # 背景 # 覆盖背景 snakebg = pygame.image.load("snakebg.png") applebg = pygame.image.load("applebg.png") # 加载音乐 bgm = pygame.mixer.Sound('backgroundmusic.mp3') # 背景音乐 eatbgm = pygame.mixer.Sound('eat.mp3') # 吃掉食物音效 diebgm = pygame.mixer.Sound('die.mp3') # 死亡音效 # 播放背景音乐 bgm.play() # 食物(apple) apple = pygame.image.load("apple.png") apple_width, apple_height = apple.get_size() apple_x, apple_y = WIN_WIDTH // 4, WIN_HEIGHT // 4 window.blit(apple, (apple_x, apple_y)) # 蛇 snake_up = pygame.image.load("snakeup.png") # 向上 snake_down = pygame.image.load("snakedown.png") # 向下 snake_left = pygame.image.load("snakeleft.png") # 向左 snake_right = pygame.image.load("snakeright.png") # 向右 snake_width, snake_height = snake_up.get_size() snake_x, snake_y = WIN_WIDTH / 2 - snake_width / 2, WIN_HEIGHT - snake_height snake = snake_up # 默认向上 window.blit(snake, (snake_x, snake_y)) # 刷新 pygame.display.update() clock = pygame.time.Clock() x_speed = 0 # x坐标移动速度 y_speed = -1 # y坐标移动速度 # 游戏循环 while True: # 创建矩形对象用于碰撞检测 snake_rect = Rect(snake_x, snake_y, snake_width, snake_height) # 蛇的矩形对象 apple_rect = Rect(apple_x, apple_y, apple.get_width(), apple.get_height()) # 苹果的矩形对象 # 碰撞检测 if snake_rect.colliderect(apple_rect): # 碰撞函数 window.blit(applebg, (apple_x, apple_y)) apple_x, apple_y = random.randint(0, WIN_WIDTH - apple_width), random.randint(0, WIN_HEIGHT - apple_height) window.blit(snake, (snake_x, snake_y)) window.blit(apple, (apple_x, apple_y)) eatbgm.play() # 播放吃掉食物音效 print("吃掉苹果") pygame.draw.circle(window, (255, 255, 255), (snake_x + snake_width / 2, snake_y + snake_height / 2), 52) # window.blit(snakebg, (snake_x, snake_y)) snake_x += x_speed snake_y += y_speed if snake_x <= 0 or snake_x >= WIN_WIDTH - snake_width: diebgm.play() # 播放死亡音效 print('碰到墙壁,游戏结束') time.sleep(1) exit() if snake_y <= 0 or snake_y >= WIN_HEIGHT - snake_height: diebgm.play() # 播放死亡音效 print('碰到墙壁,游戏结束') time.sleep(1) exit() window.blit(snake, (snake_x, snake_y)) pygame.display.update() # 设置帧频 clock.tick(60) # 检测事件 for event in pygame.event.get(): if event.type == pygame.QUIT: # 退出 exit() # 如果是多线程,这里只会退出该线程,进程并不会退出 # 使用 w、s、a、d 控制移动方向上、下、左、右 if event.type == pygame.KEYDOWN: char = chr(event.key) if chr(event.key) == 'w': # 向上 x_speed = 0 y_speed = -1 snake = snake_up elif chr(event.key) == 's': # 向下 x_speed = 0 y_speed = 1 snake = snake_down elif chr(event.key) == 'a': # 向左 x_speed = -1 y_speed = 0 snake = snake_left elif chr(event.key) == 'd': # 向右 x_speed = 1 y_speed = 0 snake = snake_right else: pass # 使用 ↑、↓、←、→ 控制移动方向上、下、左、右 # if event.type == pygame.KEYDOWN: # if event.key == pygame.K_UP: # 向上 # x_speed = 0 # y_speed = -1 # snake = snake_up # elif event.key == pygame.K_DOWN: # 向下 # x_speed = 0 # y_speed = 1 # snake = snake_down # elif event.key == pygame.K_LEFT: # 向左 # x_speed = -1 # y_speed = 0 # snake = snake_left # elif event.key == pygame.K_RIGHT: # 向右 # x_speed = 1 # y_speed = 0 # snake = snake_right # else: # pass
pygame学习-贪吃蛇章节-动画演示