• 2015/11/6用Python写游戏,pygame入门(6):控制大量的对象


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

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

    所以,我们要创建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()
        #刷新一下画面

  • 相关阅读:
    Java中只有按值传递,没有按引用传递!(两种参数情况下都是值传递)
    最简单的struts实例介绍
    Spring中bean的五个作用域简介(转载)
    Spring配置文件
    轻松搞定面试中的二叉树题目 (转)
    二叉树
    稳定排序与非稳定排序判别方法
    Yii的缓存机制之动态缓存
    Yii的缓存机制之数据缓存
    Yii的缓存机制之页面缓存
  • 原文地址:https://www.cnblogs.com/SRL-Southern/p/4942607.html
Copyright © 2020-2023  润新知