设为首页收藏本站

Crossin的编程教室

 找回密码
 立即加入
查看: 41730|回复: 15
打印 上一主题 下一主题

【Pygame 第8课】 火力全开

[复制链接]

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
楼主
发表于 2013-8-30 21:16:27 |显示全部楼层 |倒序浏览
游戏中的几个主要角色我们都有了,接下来就是去完善它们,用它们来组成一个完整的游戏。

首先我们要处理的是子弹。只有一发子弹显然是不够的,群众表示要火力全开!

所以,我们要有一个list,这里list里面存放着一些Bullet的对象。但一个list的Bullet都按之前的方法创建是不行的,那样所有的子弹都会在同一时间发射出去,同时到达屏幕上方,又同时再次发射,这样的视觉效果和一发子弹没什么区别。所以我们要让它们按照一定的时间间隔,一个一个地发射。

另外,之前到了屏幕顶端就回头的方法也会带来问题,重新发射的子弹会和按时发射的子弹混在一起,打乱发射的节奏。所以,子弹“回收”的方法也要改。有种最简单的方法,就是不回收,每次发射都是创建一个新的Bullet对象,飞出屏幕之后就抛弃它。这当然是可以的,但每次都要创建对象,读取图片,并在list上做添加和删除的操作。这样会比较消耗资源,在游戏开发中一般都尽量避免。即使现在这个小游戏中它还不至于影响到体验,也应该养成节约的良好习惯。

我们今天要解决的就是两个问题:定时和回收。

python中有定时运行的方法。但这里,我不打算用它。我们有现成的循环在这儿,只要设定好隔多少次循环运行,就简单地实现了定时的效果。尽管在游戏中,每次循环的时间并不相同,这么做会有潜在的问题:间隔的真实时间会受电脑运行速度的影响。但暂时你可以忽略这个细节(它是有解决办法的)。

我们设定一个变量interval_b,作为Bullet的发射间隔。在每次循环中,让interval_b递减,当减到0以下时,便运行,并重置interval_b的间隔。
  1. interval_b = 0
  2. while True:
  3.     interval_b -= 1
  4.     #当间隔小于0时,激活一发子弹
  5.     if interval_b < 0:
  6.         ###(发射子弹代码)
  7.         interval_b = 100
复制代码
关于子弹的重复利用,我们增加一个变量active,只有active为True的子弹,我们才去处理它的运动。另外,为了依次使用list中有限的子弹,还需要一个变量index_b来记录下一颗子弹是第几号。每激活发射一颗子弹,就把index_b指向它的下一号,最后一号之后再回头使用第0号。

修改一下Bullet类,增加active,并根据active的状态处理运动。增加一个restart方法,用来重新发射子弹。
  1. class Bullet:
  2.     def __init__(self):
  3.         self.x = 0
  4.         self.y = -1
  5.         self.image = pygame.image.load('bullet.png').convert_alpha()
  6.         #默认不激活
  7.         self.active = False

  8.     def move(self):
  9.         #激活状态下,向上移动
  10.         if self.active:
  11.             self.y -= 3
  12.         #当飞出屏幕,就设为不激活
  13.         if self.y < 0:
  14.             self.active = False

  15.     def restart(self):
  16.         #重置子弹位置
  17.         mouseX, mouseY = pygame.mouse.get_pos()
  18.         self.x = mouseX - self.image.get_width() / 2
  19.         self.y = mouseY - self.image.get_height() / 2
  20.         #激活子弹
  21.         self.active = True
复制代码
在游戏中创建5发子弹的list(5发足够了,只要保证你的子弹数足够在打完一轮之前到达屏幕顶端)。
  1. #创建子弹的list
  2. bullets = []
  3. #向list中添加5发子弹
  4. for i in range(5):
  5.     bullets.append(Bullet())
  6. #子弹总数
  7. count_b = len(bullets)
  8. #即将激活的子弹序号
  9. index_b = 0
  10. #发射子弹的间隔
  11. interval_b = 0
复制代码
时间间隔到达时,restart一颗子弹,并将序号递增。
  1. while True:
  2.     #发射间隔递减
  3.     interval_b -= 1
  4.     #当间隔小于0时,激活一发子弹
  5.     if interval_b < 0:
  6.         bullets[index_b].restart()
  7.         #重置间隔时间
  8.         interval_b = 100
  9.         #子弹序号周期性递增
  10.         index_b = (index_b + 1) % count_b
  11.     #判断每个子弹的状态
  12.     for b in bullets:
  13.         #处于激活状态的子弹,移动位置并绘制
  14.         if b.active:
  15.             b.move()
  16.             screen.blit(b.image, (b.x, b.y))
复制代码
只处理active的子弹,绘制它们。

如此一来,你可以不停地向敌机开火了。根据你电脑的运行状况,适当调整一下子弹的移动速度和发射间隔,让它看起来更自然。

至于敌机的行为,比子弹要简单一些,因为不需要定时出现,所以之前用的回收方法可以继续使用,我们下次再说。

8-1.png

8-2.png

#==== Crossin的编程教室 ====#
微信ID:crossincode
论坛:http://crossin.me
QQ群:312723402(接近满员) 156630350

面向零基础初学者的编程课
每天5分钟,轻松学编程

#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

沙发
发表于 2013-8-30 21:18:00 |显示全部楼层
PS:我们的QQ群眼看要接近满员了,所以我又新建了一个2号群,群号:156630350。继续欢迎大家来讨论。
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

板凳
发表于 2013-9-1 22:48:11 |显示全部楼层
匠逍之岿 发表于 2013-9-1 16:09
for i in range(5):
    bullets.append(Bullet())
这一句向bullets中添加Bullet()是什么意思啊?我print ...

Bullet()是创建了一个子弹的实例,把它append到bullets中,就有了一个Bullet实例组成的list,里面每一项都是一个Bullet的对象
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

地板
发表于 2013-9-1 22:48:53 |显示全部楼层
匠逍之岿 发表于 2013-9-1 16:12
还有这一句
bullets.restart()
这里的restart()是调用类Bullet中的restart方法吗?但是又没有设定对象, ...

因为bullets里面存放的都是Bullet对象,所以取出其中一项,直接调用这个对象的方法就可以了
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

5#
发表于 2013-9-8 12:45:36 |显示全部楼层
waller516435165 发表于 2013-9-8 04:12
为什么我的代码run了以后,python没有响应?跟第8课的代码一模一样啊。求教先生

...

有报错吗?
图片文件都有吗?
之前几课代码有没有运行成功过?
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

6#
发表于 2013-9-8 16:03:25 |显示全部楼层
waller516435165 发表于 2013-9-8 04:16
发现问题了...我的变量命名错了,bullets,我的是bullet....粗心要不得啊

一般都会遇到这种问题。所以一个好的ide会帮上大忙
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

7#
发表于 2013-9-10 23:23:46 |显示全部楼层
aresli 发表于 2013-9-10 22:20
python 貌似没什么好的ide吧!

呵呵。。。
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

8#
发表于 2013-9-13 01:43:48 |显示全部楼层
test777 发表于 2013-9-11 13:17
感觉让Bullet类自己管理实例的状态的也不错

是的,这样似乎更符合面向对象
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

9#
发表于 2014-7-18 14:15:16 |显示全部楼层
toddlerya 发表于 2014-7-17 22:49
Traceback (most recent call last):
  File "E:\feijidazhan\hello.py", line 106, in
    if b.active() ...

你的这个b是个bool变量吧
#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

174

主题

45

好友

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

10#
发表于 2017-6-11 21:46:00 |显示全部楼层
aibuzhe 发表于 2017-6-11 14:23
很喜欢Crossin的文章,对萌新很友好。

#==== Crossin的编程教室 ====#
微信ID:crossincode
网站:http://crossincode.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即加入

QQ|手机版|Archiver|Crossin的编程教室 ( 苏ICP备15063769号  

GMT+8, 2024-5-4 01:46 , Processed in 0.030503 second(s), 25 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

回顶部