设为首页 收藏本站
查看: 1348|回复: 0

[经验分享] Pygame

[复制链接]

尚未签到

发表于 2015-12-1 12:22:27 | 显示全部楼层 |阅读模式
前言
    在上一篇中,我们初步熟悉了pygame的控制流程,但这对于一个游戏而言是远远不够的。所以在这一篇中,我们的任务是添加一架飞机(玩家),并且能够控制它进行移动,这样我们就又离目标进了一步了~ε=ε=(ノ≧∇≦)ノ
  

正片开始!

1. 把我们的战斗机搬上屏幕
    在正式上代码以前,有一点需要说明的,我们可以看到,所有屏幕上出现的元素都在资源文件(resources/image/shoot.png)中,那我们要怎么做才能把一只飞机给裁剪出来呢?在pygame中,所有在屏幕上显示的元素都可以视为一个surface,利用这个特点,我们可以把资源文件导入(load()函数),然后用surface.subsurface()函数把shoot.png中我们想要的元素裁剪出来,这样问题就解决了~(tips:怎样才知道shoot.png中飞机的准确坐标呢?在resources/image/shoot.pack文件中已经详细记录了每个屏幕元素的左上角坐标以及它的宽和高了)
    先上代码:(在注释# == new add ==之间的代码为新加入代码)



1 import pygame                   # 导入pygame库
2 from pygame.locals import *     # 导入pygame库中的一些常量
3 from sys import exit            # 导入sys库中的exit函数
4
5 # 定义窗口的分辨率
6 SCREEN_WIDTH = 480
7 SCREEN_HEIGHT = 640
8
9 # 计数ticks == new add ==
10 ticks = 0
11 # 计数ticks == new add ==
12   
13 # 初始化游戏
14 pygame.init()                   # 初始化pygame
15 screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])     # 初始化窗口
16 pygame.display.set_caption('This is my first pygame-program')       # 设置窗口标题
17
18 # 载入背景图
19 background = pygame.image.load('resources/image/background.png')
20
21 # 载入资源图片 == new add ==
22 shoot_img = pygame.image.load('resources/image/shoot.png')
23 # 用subsurface剪切读入的图片
24 hero1_rect = pygame.Rect(0, 99, 102, 126)
25 hero2_rect = pygame.Rect(165, 360, 102, 126)
26 hero1 = shoot_img.subsurface(hero1_rect)
27 hero2 = shoot_img.subsurface(hero2_rect)
28 hero_pos = [200, 500]
29 # 载入资源图片 == new add ==
30
31 # 事件循环(main loop)
32 while True:
33
34     # 绘制背景
35     screen.blit(background, (0, 0))
36     
37     # 绘制飞机 == new add ==
38     if ticks % 50 < 25:
39         screen.blit(hero1, hero_pos)
40     else:
41         screen.blit(hero2, hero_pos)
42     ticks += 1
43     # 绘制飞机  == new add ==
44     
45     # 更新屏幕
46     pygame.display.update()                                         
47     
48     # 处理游戏退出
49     # 从消息队列中循环取
50     for event in pygame.event.get():
51         if event.type == pygame.QUIT:
52             pygame.quit()
53             exit()
  不妨运行一下:
DSC0000.gif
  可以看到,我们的飞机动了,究竟是怎样实现动画效果的呢?在代码中,新加入的代码一共有三处,显示玩家飞机的那一段已经解释过了,现在我们来解释其余的两段新加入的代码。首先增加了一个计数变量ticks,在消息循环中,每循环一次就累加一次,可以理解为每一个周期就是1 tick,我们可以利用周期数来分隔不同的显示效果;我们读入了两张不同的玩家飞机图片,利用周期数实现每50个周期,前25个周期显示hero1,后25个周期显示hero2,这样就有了缓慢变化的动态效果。不过值得注意的是,这样每一次循环就计算并判断一次ticks的做法明显不是好方法。还有!(╯°口°)╯(┴—┴,Python是木有自增表达式的,我试图++ticks结果报错了。
    战斗机已经准备就绪,该教会飞行员怎样操作了~(`・&omega;・&acute;)
  

2. 用键盘控制飞机移动
    我们知道,每敲一下键盘都会产生一个事件,而这个事件能被Python检测到,既然知道了这个大前提,那控制飞机就很容易了。
    come on code~ ( °&forall;°)ノ



1 import pygame                   # 导入pygame库
2 from pygame.locals import *     # 导入pygame库中的一些常量
3 from sys import exit            # 导入sys库中的exit函数
4
5 # 定义窗口的分辨率
6 SCREEN_WIDTH = 480
7 SCREEN_HEIGHT = 640
8
9 ticks = 0
10 # dict == new add ==
11 offset = {pygame.K_LEFT:0, pygame.K_RIGHT:0, pygame.K_UP:0, pygame.K_DOWN:0}
12 # dict == new add ==
13   
14 # 初始化游戏
15 pygame.init()                   # 初始化pygame
16 screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])     # 初始化窗口
17 pygame.display.set_caption('This is my first pygame-program')       # 设置窗口标题
18
19 # 载入背景图
20 background = pygame.image.load('resources/image/background.png')
21
22 # 载入飞机图片
23 shoot_img = pygame.image.load('resources/image/shoot.png')
24 # 用subsurface剪切读入的图片
25 hero1_rect = pygame.Rect(0, 99, 102, 126)
26 hero2_rect = pygame.Rect(165, 360, 102, 126)
27 hero1 = shoot_img.subsurface(hero1_rect)
28 hero2 = shoot_img.subsurface(hero2_rect)
29 hero_pos = [200, 500]
30
31 # 事件循环(main loop)
32 while True:
33
34     # 绘制背景
35     screen.blit(background, (0, 0))
36
37     # 绘制飞机
38     if ticks % 50 < 25:
39         screen.blit(hero1, hero_pos)
40     else:
41         screen.blit(hero2, hero_pos)
42     ticks += 1 # python已略去自增运算符
43
44     # 更新屏幕
45     pygame.display.update()                                         
46     
47     # 处理游戏退出
48     # 从消息队列中循环取
49     for event in pygame.event.get():
50         if event.type == pygame.QUIT:
51             pygame.quit()
52             exit()
53
54         # Python中没有switch-case 多用字典类型替代
55         # 控制方向 == new add ==         
56         if event.type == pygame.KEYDOWN:
57             if event.key in offset:
58                 offset[event.key] = 3
59         elif event.type == pygame.KEYUP:
60             if event.key in offset:
61                 offset[event.key] = 0
62
63         # part 1
64         #offset_x = offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
65         #offset_y = offset[pygame.K_DOWN] - offset[pygame.K_UP]
66         #hero_pos = [hero_pos[0] + offset_x, hero_pos[1] + offset_y]
67     # part 2
68     offset_x = offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
69     offset_y = offset[pygame.K_DOWN] - offset[pygame.K_UP]
70     hero_pos = [hero_pos[0] + offset_x, hero_pos[1] + offset_y]
71     # 控制方向 == new add ==         
  新加入了两处,一个是字典类型的变量,一个是控制方向的代码。跟之前控制程序退出的代码一样,依然是从事件队列中取事件;当event.type为按键事件时,再判断event.key是否属于上下左右四个键位中的其中一个;最后在其相应方向上给一个偏移量,即完成判断的过程;松键的话该方向上的偏移量赋值为0,这样该键方向上就没有位移了;最后将偏移量加到飞机的pos上,下一轮刷新时自然就到移动到新地方了。(这里插播一个事,我以前写过c++和java,所以写到判断键盘键位时,很自然就想用switch-case语句,没想到竟然出错了(╯°口°)╯(┴—┴,后来才发现原来Python是没有switch-case语句的,switch-case语句多用字典数据结构代替,感觉这样的写法就更灵活了)
  上面讲得都比较简单,现在我们要思考一个问题,上面的代码中,line 63-66和line 67-70的代码是一样的,但两部分代码的效果却是很不一样。part1代码使得我们要按一次键飞机才会动一次,而在part2代码中我们可以长按方向键来控制飞机,不禁感慨一下Python的缩进。part1是在for循环的影响下的,也就是说,事件队列中有事件才会执行part1的代码,假设我们长按方向左键(注意,击键一次只会产生一个pygame.KEYDOWN事件,所以长按也只触发一次),飞机也只会往左移3个像素点;而part2代码由于不在for循环内,所以每一tick就向左移3个像素点直到松开方向左键。
  演示一下效果:
DSC0001.gif
  好的,控制飞机已经不成问题了,不过大家发现飞机有一个小问题了吗?它会穿到窗口的“外面”去!不过我们只要添加一个小小的限制就可以解决问题了,只要把line68-70换成以下边界判断代码就可以了。



1     hero_x = hero_pos[0] + offset[pygame.K_RIGHT] - offset[pygame.K_LEFT]
2     hero_y = hero_pos[1] + offset[pygame.K_DOWN] - offset[pygame.K_UP]
3     if hero_x < 0:
4         hero_pos[0] = 0
5     elif hero_x > SCREEN_WIDTH - hero1_rect.width:
6         hero_pos[0] = SCREEN_WIDTH - hero1_rect.width
7     else:
8         hero_pos[0] = hero_x
9         
10     if hero_y < 0:
11         hero_pos[1] = 0
12     elif hero_y > SCREEN_HEIGHT - hero1_rect.height:
13         hero_pos[1] = SCREEN_HEIGHT - hero1_rect.height
14     else:
15         hero_pos[1] = hero_y
  今天功能就完成到这里吧~(`・&omega;・&acute;)
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-145855-1-1.html 上篇帖子: Python Tutorial 学习(五)--Data Structures 下篇帖子: Python 基础学习 总结篇
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表