http://blog.sysuschool.com/u/mygod/index.html
请稍候,载入中。。。
 
请稍候,载入中。。。
2019-4-12 23:28:00
博文:python之pygame模块(一)

黑马大本营讲了一个飞机游戏的开发案例(面向对象),差不多看完了,里面用了一个pygame的模块,模块需要下载使用,教程是基于linux的,自己在win7下pycharm中的项目解释器里,鼓捣了半天终于装上了,在代码开始位置需要import pygame。黑马大本营这个老师讲解时就象个说书的,讲基础的时候还不觉得,讲到项目开发了,很晕!看完后,发现很多东西串不起来,从今天开始慢慢理理。

今天把有关绘制图像方面的方法理了下,大致明白了怎样在pygame中调用图像(背景和角色),整理如下:

一、游戏窗口的创建

pygame.Rect (x,y,width,height)  
——pygame的Rect() 方法,用来设置和保存一组数据(位置和宽高)
pygame.display.set_mode( (width,height) )
——pygame的display的set_mode()方法,创建窗口对象

如设置游戏窗口大小并赋值给常量SCREEN_RECT,再创建游戏窗口screen
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
screen = pygame.display.set_mode (SCREEN_RECT.size) # 创建游戏窗口

——可以用下列方式调用该数据
SCREEN_RECT.x
SCREEN_RECT.y
SCREEN_RECT.width
SCREEN_RECT.height
SCREEN_RECT.size # (480,700)
SCREEN_RECT.bottom\top\left\right #700 \0 \0 \480 
SCREEN_RECT.center\centerx\centery #(240,350) \240 \ 350

二、加载图像、获取和设置图像的位置、宽高
——游戏中的背景和角色需要通过图像显示出来

1、加载图像,返回图像对象,pygame.image.load(“./images/xx.png”) ,如
bg= pygame.image.load(“./images/bg.png”)
hero=pygame.image.load( "./images/me1.png" )

2、获取图像对象的位置和宽高,图像对象.get_rect() 方法,返回(x,y,width,height),默认x,y为0,0,如获取图像对象bg的位置和宽高
rect = bg.get_rect()
或rect=pygame.image.load("./images/bg.png").get_rect()
hero_rect=hero.get_rect()

三、游戏窗口中,背景和角色的绘制与显示

方法一: 用窗口对象的 blit() 方法绘制图像(须传入图像对象和位置)
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
screen = pygame.display.set_mode (SCREEN_RECT.size) # 创建游戏窗口对象 screen

bg = pygame.image.load("./images/background.png") # 加载背景图,创建图片对象bg
screen.blit(bg, (0, 0)) 或 screen.blit(bg, SCREEN_RECT) # 窗口绘制背景,注意用数字时须用元组格式

hero = pygame.image.load("./images/me1.png") # 加载角色图,创建图片对象hero
screen.blit(hero, (150, 300)) # 窗口绘制角色

pygame.display.update() # 绘制后需要调用pygame的display的update() 方法

方法二: 用精灵和精灵组
pygame.sprite.Sprite (pygame的sprite模块的Sprite类),如定义基于该类的GameSprite类,class GameSprite(pygame.sprite.Sprite):
——所谓精灵,即用基于pygame.sprite.Sprite的类(或子类)创建的对象

案例代码:

1、定义GameSprite类(基于pygame.sprite.Sprite类)

class GameSprite(pygame.sprite.Sprite):
    """飞机大战游戏精灵"""

    def __init__(self, image_name, speed=1):

        # 调用父类的初始化方法(以继承父类pygame.sprite.Sprite的方法和属性)
        super().__init__()

        # 定义对象的新属性(图像对象、图像位置宽高、运动速度)
        self.image = pygame.image.load(image_name)
        self.rect = self.image.get_rect()
        self.speed = speed

    def update(self): # 重写(不知父类是否有该方法)或定义update(),必须有!

        # 在屏幕的垂直方向上移动
        self.rect.y += self.speed

2、调用GameSprite类,创建多个精灵,如enemy1、enemy2(速度speed为2)
enemy1 = GameSprite("./images/enemy1.png")
enemy1 = GameSprite("./images/enemy1.png", 2)

3、创建精灵组(将上步创建的精灵组成精灵组)
enemy_group = pygame.sprite.Group(enemy1, enemy2)

4、在主程序中,循环调用 精灵组的update() 和 draw() 方法(一次性刷新和绘制)
while True:
    # 调用精灵组的update方法 - 让组中的所有精灵更新位置
    enemy_group.update()

    # 调用精灵组的draw方法 - 在screen上绘制所有的精灵
    enemy_group.draw(screen)

    # 调用pygame的display的update方法更新显示(同方法一)
    pygame.display.update()

总结:

关于游戏窗口角色和背景的绘制与显示,结合飞机游戏小结精灵与精灵组。

绘制方法一种是用窗口对象的blit()方法绘制图像,须传入图像对象(pygame.load)和位置(须用元组)

第二种绘制方法是基于pygame的sprite模块里的Sprite类,

首先,定义类时须调用__init__方法以继承父类的方法和属性,本例飞机游戏中,设计传参图像(图像路径和名称)和速度speed(默认1),该方法内,还是用pygame.load加载图像,然后用图像方法get_rect()获取图像的(x,y,width,height),默认情况下x、y为0

其次,类中定义update方法(不知父类是否有该方法,如有就是重写),这个方法应该是必须的,因为后面精灵组使用精灵组的update方法时会一次性调用所有精灵对象的update方法,在这个update方法中,需要定义图像对象的位置改变,有个问题待测试——如果该对象不需要改变位置,是否不需要定义update方法,不知道不定义update方法是否报错(这个问题实际上就是不清楚pygame的精灵类是否已有update方法)。

本例飞机游戏,先基于pygame的sprite模块的Sprite类,定义一个GameSprite类,这个类中定义的属性有图像对象(以传入不同的图像)、图像对象的位置和宽高(通过图像对象的get_rect()方法去获取,不同图像对象宽高不一样)、速度(默认值1,可传入正负值);类中定义update方法,该方法改变对象的 y 坐标(即对象上下移动,self.rect.y += self.speed,speed为正时向下,为负向上,speed值越大速度越快),可理解为通用方法。

然后再基于GameSprite类定义子类,如英雄飞机类(Hero类)、敌机类(Enemy)、背景类(BackGround类,因为背景要动)、子弹类(Bullet类),所有的子类,初始化方法__init__都调用父类方法(用super().__init__(./images/xx.png)),传入具体的图像名称(即写死图像),有些接受默认speed值,有些需要传入speed值,如子弹类,由于子弹向上运动,传入的speed值为-2(默认1),这样,子类就具有了父类的属性和方法(image、rect、speed、update())。

各子类的update方法有不同需求,本例所有子类的update方法都重写了,
有些是继承性重写:
如Background类,因为背景也是向下运动,首先要调用父类update方法,代码super().update(),然后添加新的(背景运动的出界判断及处理);
再如子弹类Bullet类,子弹也是上下移动,只不过向上(默认向下),__init__方法中传入speed为-2,在初始化方法中没有再定义子弹位置(子弹比较特殊,需要跟随英雄飞机,后述);子弹类的update方法同样调用父类方法(super().update()),再添加子弹消失的代码。
再如敌机类Enemy类,敌机也是向下运动,其update方法也是一样,先调用父类方法(super().update()),再添加飞机出界判断和处理代码。倒是敌机的初始化方法,当然先调用父类的方法,并传入图像,super().__init__(./images/enemy.png),然后需要重写speed(让速度取1~3之间随机数),重写位置self.rect.bottom(上下方向的初始位置)和self.rect.x(左右位置),水平方向的敌机位置也需要随机出现,在最小值(0左边)和最大值(窗口宽-敌机图像宽)取随机数。
有些需要完全重写:
本例,其实就是英雄飞机类Hero类,因为英雄飞机不需要上下移动,只做左右移动,其update方法需要完全重写,不需要super().update(),重写代码如,self.rect.x += self.speed,再加上左右出界判断及处理。Hero类的初始化方法,除调用父类方法,写死图像外,同敌机类一样需要重写位置。

这里插入一段基于精灵类的类定义,继续关于窗口绘制的小结。

在第二种方法中,不需要使用窗口对象的blit()方法绘制图像,而是用精灵组的draw(screen)方法一次性绘制所有精灵对象,在draw之前,须调用精灵组的update方法,一次性刷新所有的精灵位置大小。

第一种方法可用于如游戏中不动的背景(现在只想到这个),因为游戏背景不动的话,没有必要用类创建,而且也不需要更新位置(因为不动)。

第二种方法应该是常用的,因为游戏的角色,比如飞机游戏中的英雄飞机(只有一架,可以左右移动)、敌机(很多,随机产生,向下运动),这些用精灵和精灵组比较好,在精灵(精灵的类)中的update方法中定义位置变化,用精灵组一次性更新和绘制。想想,感觉即使不动的背景对象也可以用这种方法处理,不过多定义一个基于精灵的类。

注意,两种方法的最后都需要用pygame.display.update(),才能显示,还有精灵组的update和draw是在循环中调用。

mygod | 阅读全文 | 回复(0) | 引用通告 | 编辑
发表评论:
请稍候,载入中。。。
公告
请稍候,载入中。。。
时间记忆
请稍候,载入中。。。
最新日志
请稍候,载入中。。。
最新评论
请稍候,载入中。。。
最新回复
请稍候,载入中。。。
我的好友
我的相册
站点信息
请稍候,载入中。。。
生活因感动而精彩,理想在创造中放飞
Powered by Oblog.