一. 类与对象的概念
一个游戏里面的组成元素其实都是一个个的对象,而对象又是在类中的一个实例。
比如你是一个人,而你所属的类别叫做人类,你是人类中的一个实例。类中可以定义属性和方法,而对象是具有这些属性和方法的。方法可以就理解为函数。
比如人类有身高体重等属性,有走路和奔跑等方法。属性是静态特征,方法是动态行为
那么由此我们可以类比到游戏里面,我们可以定义一个飞机类。
飞机要呈现出来要有属性图像吧,你的飞机要移动得有属性速度吧,如果给飞机一个生命值,那是不是得有一个属性血量值,这是最基本得属性,还有别的属性我们后面讲。
上面的属性有感觉了吧,是不是就是用来描述飞机得静态特征的。
飞机要动起来是不是得有一个移动方法,比如键盘上得↑↓←→来控制飞机的移动;飞机要发射子弹是不是得有一个发射子弹的方法;上面我们给出了飞机的图像属性,那么飞机如何搬到游戏界面上 是不是得再来一个方法,把飞机得那张图像搬到游戏界面上。
方法是不是用来描述飞机的动态行为的
咱们对属性和方法有了初步的了解,现在我们对类再来深入了解一下。
我们是人类,但同时我们是不是也是动物,我们不是植物所以我们没有植物的那一套东西。但是我们是动物,动物会呼吸吧,动物会移动吧。所以我们人类会呼吸会移动。同时,鸟类是不是也是动物,他们也会呼吸会移动。所以人类是动物,鸟类也是动物。动物也是一个类,人类是动物的子类,动物称作父类,动物所具备的,我们人类也具备,鸟类也具备。所以子类可以继承父类。
动物会进食,人类和鸟类也会进食,但是人类和鸟类进食的方式是不一样的,人类进食需要先将食物搞熟,将食物搞美味,并且在用餐的时候会使用工具,而鸟类直接通过喙进食。进食是动物的方法,也是人类和鸟类的方法,但动物的进食方法很抽象,人类和鸟类的进食方法很具体,所以在写子类的时候可以将父类抽象的方法写得更具体。
所以子类在继承父类的时候可以将父类的方法覆盖重写。这被称为继承的多态性。
二. 模块与包 -- 我们站在巨人的肩膀上
我们在了解上面的内容之后,我在想一个问题,既然子类可以继承父类,那么我的飞机类是不是也可以继承它的父类,那样的话,我不就可以在他的父类上面修修补补不就行了。
对的,由于类的继承性,我们可以站在巨人的肩膀上,父类让别人给我写好,我直接继承,拿来吧你。
所以面向对象语言生态圈里就有这么一群人,他们专门写一些父类与模块,然后供别人使用。
pygame模块里就有一个精灵类,游戏里面的飞机类,子弹类,都可以继承这个精灵类。最下面有介绍精灵类里面的一些方法。
面向对象语言中,多个类和多个对象的关系是一个树形图的关系,大类就是树干,子类就是枝干,对象就是叶子。比如pygame.sprite.Sprite就是pygame.sprite的子类
pygame里面的各种类和方法,就是给出了树干,剩下的叶子根据我们的需求自己去完善
三. 思路大纲
我方飞机类 Class MyPlane(pygame.sprite.Sprite):
敌方飞机类 Class EnemyPlane(pygame.sprite.Sprite):
我方子弹类 Class MyBullet(pygame.sprite.Sprite):
敌方子弹类 Class EnemyBullet(pygame.sprite.Sprite):
游戏声音类 Class GameSound:
爆炸类 Class Bomb:
游戏背景类 Class GameBackgroud:
游戏管理类 Class Manager:
-------------------------------------------------------------------------
"由于我方飞机与敌方飞机共用的属性和方法非常少(本例中 他们的图片 速度 矩形区域等等属性都不一样)所以直接定义两个类(如果他们共用的属性和方法很多的话,我们可以定义一个他们的父类Plane)。"
细讲类里面的方法与属性(实例属性定义在初始化方法中,类属性的值在所有实例之间共享):
Class MyPlane(pygame.sprite.Sprite):
初始化方法 def __init__(self,screen): # 初始化就相当于一个具体对象的出生,定义各项属性
键盘控制方法 def key_control(self): # 飞机要移动需定义键盘控制方法
显示方法 def display(self): # 显示飞机图像,显示子弹图像,
更新方法 def update(self): # 更新飞机按键状态和显示状态
清除子弹方法 @classmethod
def clear_bullets(cls): # 类方法,清除子弹,避免子弹对象占用过多系统资源
Class EnemyPlane(pygame.sprite.Sprite):
有和上面类似的初始化方法,显示方法,更新方法。
自动移动方法 def auto_move(self): # 敌方飞机自动移动
自动开火方法 def auto_fire(self): # 敌方飞机自动开火
清除子弹方法
Class MyBullet(pygame.sprite.Sprite):
初始化方法
更新方法
Class EnemyBullet(pygame.sprite.Sprite):
初始化方法
更新方法
Class GameSound:
初始化方法 #加载下面的两种音乐
背景音乐方法
爆炸音效方法
Class Bomb:
初始化方法
爆炸触发方法 def action(self,rect): # 爆炸的位置与是否爆炸的开关
爆炸绘画方法 def draw(self): # 爆炸的动画绘制
# 爆炸与背景移动本质上是类似的 两张图片的切换形成爆炸图像效果 都有触发方法和绘制 只不过一个需要触发条件 一个是一直触发
Class GameBackgroud:
初始化方法
背景移动方法 def move(self):
背景绘制方法 def draw(self):
Class Manager:
类属性定义(给其他方法共享)
初始化方法
游戏退出方法 def exit(self):
显示游戏结束文字方法 def show_over_text(self):
游戏结束倒计时方法 def game_over_timer(self):
游戏重新开始方法 def start_game(self):
更新玩家飞机方法 def new_player(self):
更新敌方飞机方法 def new_enemy(self):
显示文本方法 def drawText(self,text,x,y, textHeight=30,
fontColor=(255,0,0), backgroundColor=None):
主方法 def main(self):
四. 代码实现细节
我方飞机类
class HeroPlane(pygame.sprite.Sprite):
# group to store all aircraft bullets
bullets = pygame.sprite.Group()
将子弹添加到pygame.sprite.Group()中,方便对子弹对象进行批量处理和管理
def __init__(self, screen):
# The initialization method of this sprite must be called:
pygame.sprite.Sprite.__init__(self)
# Create a picture as a player's plane
self.player = pygame.image.load("./photo/hero1.png")
# getting a rectangle object based on the image
self.rect = self.player.get_rect()
self.rect.topleft = [Manager.bg_size[0]/ 2 - 134 / 2 , 580]
# aircraft speed
self.speed = 4
self.screen = screen
# list of loaded bullets
self.bullets = pygame.sprite.Group()
初始化,将我方飞机像生小孩一样生下来。然后给飞机加载图像,“ . ”表示当前目录,“ .. ”表示上级目录。"./photo/hero1.png"表示在当前python脚本目录下的'photo'目录中查找'hero1.png'文件。
先定义一下 self.player ,加载玩家飞机图像 然后再self.rect=self.player.get_rect 相当于self.rect=pygame.image.load("./photo/hero1.png").get_rect
topleft是get_rect里面的,代表着图像坐上角的坐标,x定为背景图片的x/2-飞机x/2 y定为靠下方就行了(根据你背景图片的像素) 飞机速度自己定 self.screen = screen 以便后续飞机的display方法使用,将飞机显示到窗口上。
self.bullets = pygame.sprite.Group()将飞机子弹放入精灵组方便后续统一处理和管理
def key_control(self):
# Listen for keyboard events
key_pressed = pygame.key.get_pressed()
if key_pressed[K_w] or key_pressed[K_UP]:
self.rect.top -= self.speed
if key_pressed[K_s] or key_pressed[K_DOWN]:
self.rect.bottom += self.speed
if key_pressed[K_a] or key_pressed[K_LEFT]:
self.rect.left -= self.speed
if key_pressed[K_d] or key_pressed[K_RIGHT]:
self.rect.right += self.speed
if key_pressed[K_SPACE]:
# Create a new bullet
bullet = Bullet(self.screen, self.rect.left, self.rect.top)
self.bullets.add(bullet)
HeroPlane.bullets.add(bullet)
因为窗口坐标左上角为原点,所以飞机往上就是y值(top)减小,往左就是x值(left)减小
我们把飞机的左上角的坐标参数传给我方子弹类,
self.bullets.add(bullet)是将子弹添加到此飞机的列表里方便后续管理
HeroPlane.bullets.add(bullet)是将子弹添加到我方的所有飞机的列表里,如果我方只有一个飞机,此行代码可不要
def display(self):
# 3.Paste the player picture into the window
self.screen.blit(self.player, self.rect)
# updating the coordinates of the bullet
self.bullets.update()
# adding all bullets to the screen
self.bullets.draw(self.screen)
def update(self):
self.key_control()
self.display()
@classmethod
def clear_bullets(cls):
# clearing bullets
cls.bullets.empty()
blit是block t