昨天我们已经实现了这个游戏的三个基本类。

但是现在它还是没办法做成一个适合玩的游戏,毕竟只有一架敌机的游戏是很乏味的。所以,我们需要好多子弹,也需要好多敌机。

所以,我们要创建list,这个list存放Bullet或者Enemy的实例。

以Bullet为例:

bullet = [] #创建子弹
for i in range(6):
bullet.append(Bullet())
...
for b in bullet:#移动子弹
b.move(time_passed_second)
...
for b in bullet:#显示子弹
screen.blit(b.image, (b.x, b.y))

我们可以用这样的代码替换我们原来创建子弹,移动子弹和显示子弹的部分。但是实际运行结果却并没有变化。这是为什么?

因为一个list的子弹都按照了同样的方法创建和发射了,所有的子弹在同一时间发射了出去,同时到达了屏幕上方,然后又同时发射。这样的效果和发射一发子弹是没有区别的。所以我们要让它按照一定的时间间隔,一个个地发射。

另外,如果到了屏幕顶端就回头了,重新发射的子弹和按时发射的子弹混在了一起,打乱了发射节奏,所以子弹回收的方法也要更改。我们可以选择每发子弹只写它的发射,不写它的回收,但是这样每发射一发子弹就会创建一个空间,读取一次图片,这样会消耗内存资源,一般都应该避免。

那么我们必须解决两个问题,一个是定时发射,一个是回收子弹。


Python有专门的time模块,但是,在游戏中,我们本来就有帧率固定的循环,只要用一个计数器来计数,每隔多少个循环出发一次,就可以实现定时效果。

比如说,我们定义一个子弹发射的间隔interval_bullet,让它递增或者递减,到达某个数后,就重置间隔,并且运行特定的程序,就可以使子弹定时发射。

如果要重复利用子弹,我们可以让子弹本身多一个属性,来表明这个子弹是否应该被激活,只有它是激活状态,我们去处理它的运动和显示。

子弹本身是可以重复利用的,我们用一个循环队列的结构来处理子弹的利用。

依照这样的方法,我们可以修改Bullet类:

class Bullet(object):
def __init__(self):
self.x = 0
self.y = -100
self.speed = 600
self.image = pygame.image.load(bullet_image_filename).convert_alpha()
self.active = False def move(self, passed_time_second):
if self.y < 0:
self.active = False
else:
self.y -= self.speed*passed_time_second def restart(self):
self.active = True
mouseX, mouseY = pygame.mouse.get_pos()
self.x = mouseX - self.image.get_width()/2
self.y = mouseY - self.image.get_width()/2

添加了一个重新激活该子弹的方法restart(),还添加了一个数据属性active来标记子弹本身是否被激活。然后,我们把添加子弹,移动子弹,显示子弹部分的代码改成这样:

bullet = []
for i in range(6):#子弹总数量
bullet.append(Bullet())
interval_bullet = 25 #发射子弹的帧数间隔
index_bullet = 0 #初始化子弹坐标
...
interval_bullet -= 1
if interval_bullet <= 0:
interval_bullet = 25
bullet[index_bullet].restart()
index_bullet = (index_bullet + 1) % 6 for b in bullet:
if b.active:
b.move(time_passed_second)#移动子弹
screen.blit(b.image, (b.x, b.y))#显示子弹

结果就是这样了:

子弹完成了以后,飞机还会远么?


大家可以自己想一想敌机应该怎么去写,敌机不同的是,前后的间隔应该有更多的随机性。

我这里就不给出一步步的指南了,把自己实现的代码整个贴上来,也许大家有更好的控制方式,可以一起交流一下:

# -*- coding: utf8 -*-

background_image_filename = 'background.png'
mouse_image_filename = 'hero.png'
bullet_image_filename = 'bullet.png'
enemy_image_filename = 'enemy.png'
#指定图像文件名称 import pygame #导入pygame库
from sys import exit #向sys模块借一个exit函数用来退出程序
from random import randint #引入随机数 #定义一个Bullet类,封装子弹的数据和方法
class Bullet(object):
def __init__(self):
self.x = 0
self.y = -100
self.speed = 600
self.image = pygame.image.load(bullet_image_filename).convert_alpha()
self.active = False def move(self, passed_time_second):
if self.y < 0:
self.active = False
else:
self.y -= self.speed*passed_time_second def restart(self):
self.active = True
mouseX, mouseY = pygame.mouse.get_pos()
self.x = mouseX - self.image.get_width()/2
self.y = mouseY - self.image.get_width()/2 class Enemy(object):#定义一个Enemy类,封装敌机的数据和方法
def restart(self):
self.x = randint(-30,400)
self.y = randint(-100, -50)
self.speed = randint(100,400)
self.active = True
def __init__(self):
self.restart()
self.active = False
self.image = pygame.image.load(enemy_image_filename).convert_alpha() def move(self, passed_time_second):
if self.y < 650:
self.y += self.speed*passed_time_second
else:
self.active = False pygame.init() #初始化pygame,为使用硬件做准备
screen = pygame.display.set_mode((480, 650), 0, 32)
#创建了一个窗口
pygame.display.set_caption("PlaneFight!")
#设置窗口标题
pygame.mouse.set_visible(False) background = pygame.image.load(background_image_filename).convert()
mouse_cursor = pygame.image.load(mouse_image_filename).convert_alpha()
#加载并转换图像
bullet = []
for i in range(6):#子弹总数量
bullet.append(Bullet())
interval_bullet = 25 #发射子弹的帧数间隔
index_bullet = 0 #初始化子弹坐标
enemy = []
for i in range(10):#敌机总数量
enemy.append(Enemy())
interval_enemy = 100 #敌机出现的间隔
index_enemy = 0 #初始化敌机坐标
clock = pygame.time.Clock()
while True:
#游戏主循环 for event in pygame.event.get():
if event.type == pygame.QUIT:
#接收到退出事件后退出程序
pygame.quit()
exit()
time_passed = clock.tick(100)
time_passed_second = time_passed/1000.0
screen.blit(background, (0,0))
#将背景图画上去
x, y = pygame.mouse.get_pos()
#获得鼠标位置 interval_bullet -= 1
if interval_bullet <= 0:
interval_bullet = 25
bullet[index_bullet].restart()#重置子弹
index_bullet = (index_bullet + 1) % 6 #循环递增 for b in bullet:
if b.active:
b.move(time_passed_second)#移动子弹
screen.blit(b.image, (b.x, b.y))#显示子弹 interval_enemy -= 1
if interval_enemy <= 0:
interval_enemy = randint(30,100)
enemy[index_enemy].restart() #重置飞机
index_enemy = (index_enemy + 1) % 10 #循环递增
for e in enemy:
if e.active:
e.move(time_passed_second) #移动敌机
screen.blit(e.image, (e.x, e.y)) #显示敌机 x-= mouse_cursor.get_width() / 2
y-= mouse_cursor.get_height() / 2
#计算光标的左上角位置 #screen.blit(bullet.image, (bullet.x, bullet.y))
screen.blit(mouse_cursor, (x, y))
#把各个元素画上去 pygame.display.update()
#刷新一下画面

2015/11/6用Python写游戏,pygame入门(6):控制大量的对象的更多相关文章

  1. 2015/11/1用Python写游戏,pygame入门(1):pygame的安装

    这两天学习数据结构和算法,有时感觉并不如直接做项目来的有趣.刚刚学完python的基本使用,现在刚好趁热打铁做个小项目. 由于本人一直很想制作一款游戏,就想使用Python制作一个基础的游戏.搜了一下 ...

  2. 2015/11/9用Python写游戏,pygame入门(8):按钮和游戏结束

    昨天没有更新内容,今天相对多写一些. 因为我们已经基本完成游戏框架,但是游戏结束后,并不知道怎样比较好开始.我本来本着懒的原则,想结束后显示一个黑屏,然后你重新点一下鼠标就重新开始.但是那样实在太不像 ...

  3. 2015/11/3用Python写游戏,pygame入门(3):字体模块、事件显示和错误处理

    游戏里面一般是肯定会出现文字显示的,即使是俄罗斯方块也应该显示分数.那么我们应该怎样来显示文字呢,今天一起学习一下pygame的font模块. 使用字体模块 pygame可以直接调用系统字体,也可以调 ...

  4. 2015/11/7用Python写游戏,pygame入门(7):碰撞检测

    我们已经完成了飞机大战的大部分东西,但是游戏还是没有办法正式开玩,因为子弹并不能打掉飞机.只有完成了这一个工作,游戏才算基本成型. 今天的内容就非常简单了,就是做到这个碰撞检测,以及控制好子弹和飞机的 ...

  5. 2015/11/5用Python写游戏,pygame入门(5):面向对象的游戏设计

    昨天的内容里有了运动的子弹,虽然我们只添加了一个子弹,但你可以看到我们需要记录子弹的x,y坐标,每次要更新它的坐标.如果我们想要有多颗子弹,就需要存储多个坐标.那时候处理起来就不显得那么简单,也许我们 ...

  6. 2015/11/4用Python写游戏,pygame入门(4):获取鼠标的位置及运动

    按昨天的说法,今天将开始做一个简单的游戏了. 目标是拷贝微信的飞机大战,当然拷贝完以后大家就具备自己添加不同内容的能力了. 首先是要拿到一些图片素材,熟悉使用图像处理软件和绘画的人可以自己制作,并没有 ...

  7. 2015/11/2用Python写游戏,pygame入门(2):游戏中的事件和显示

    pygame是一个比较大的库,以我这点弱小的实力是没办法详解的.所以我只讲我懂得那些部分,其他部分由大家慢慢查找了解. ------------------------------- 我用pygame ...

  8. 用Python和Pygame写游戏-从入门到精通(py2exe篇)

    这次不是直接讲解下去,而是谈一下如何把我们写的游戏做成一个exe文件,这样一来,用户不需要安装python就可以玩了.扫清了游戏发布一大障碍啊! perl,python,java等编程语言,非常好用, ...

  9. python小游戏-pygame模块

    一.tkinter模块的GUI 基本上使用tkinter来开发GUI应用需要以下5个步骤: 导入tkinter模块中我们需要的东西. 创建一个顶层窗口对象并用它来承载整个GUI应用. 在顶层窗口对象上 ...

随机推荐

  1. 使用Axure RP设计Android界面原型

    转至@徐州瑞步科技(http://www.cnblogs.com/brooks-dotnet/archive/2013/06/05/3119923.html) 资源地址:http://pan.baid ...

  2. python字符串操作、文件操作,英文词频统计预处理

    1.字符串操作: 解析身份证号:生日.性别.出生地等. 凯撒密码编码与解码 网址观察与批量生成 解析身份证号:生日.性别.出生地等 def function3(): print('请输入身份证号') ...

  3. 标头 header()函数的用法

    头 (header) 是服务器以 HTTP 协议传 HTML 资料到浏览器前所送出的字串,在标头与 HTML 文件之间尚需空一行分隔. 范例一: 本例使浏览器重定向到 PHP 的官方网站. <? ...

  4. linux创建账户并自动生成主目录和主目录下的文件

    # useradd -d /home/test -m test; 然后给test设置密码. # passwd test; 1. useradd 添加用户或更新新创建用户的默认信息 语法:useradd ...

  5. SpringBoot(十)_springboot集成Redis

    Redis 介绍 Redis是一款开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存也可持久化的日志型.Key-Value高性能数据库. 数据模型 Redis 数据模型不仅与关系数据 ...

  6. IE 低版本 透明度

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 调用webservice超时问题的解决[转]

    1.web.config配置,<system.web></system.web>里面增加:<httpRuntime maxRequestLength="1024 ...

  8. Digits of Factorial LightOJ - 1045(数学题?)

    原文地址: https://blog.csdn.net/fenghoumilin/article/details/52293910 题意:求 n 的阶乘在 base 进制下的位数,这里有一个简单的方法 ...

  9. Paint Chain HDU - 3980(sg)

    因为题中是个环, 所以我们可以首先拿出一组m 如果n<m 先手必输 否则的话跑sg函数 n = n-m #include <iostream> #include <cstdio ...

  10. aliyun阿里云alibabaMaven仓库地址——加速你的maven构建

    在maven的settings.xml 文件里 搜索  mirrors   ,把下面内容添加在其子节点内 <mirror> <id>nexus-aliyun</id> ...