上一篇(Python游戏之Pygame——太空飞机大战(二))完成了敌机类以及敌机坠毁时释放包裹类,这一篇将给出英雄战机类和处理。由于英雄战机是由游戏者操控的,所以要处理操控事件,比如往那个方向飞,发射子弹或者导弹,或者都发射,遇到敌机太多时还可以发射大boss——核弹,遇到很多子弹时通过变形躲子弹等。看起来很炫酷,下面开始打码。
class HeroPlane(Sprite):
def __init__(self, heroType, position, layerGroup, hPlaneGroup):
self.groups = layerGroup, hPlaneGroup
self.type = heroType
self._layer = HERO_PLANES[self.type]['LAYER']
super().__init__(self.groups)
self.image = pygame.image.load(IMAGE_PATH + HERO_PLANES[self.type]['IMAGE']).convert_alpha()
self.rect = Rect(position, self.image.get_size())
self.xSpeed = HERO_PLANES[self.type]['X_SPD']
self.ySpeed = HERO_PLANES[self.type]['Y_SPD']
self.speedupFactor = HERO_PLANES[self.type]['SP_FACTOR']
self.bulletType = random.choice(list(HERO_BULLETS_TYPE.values()))
self.missileType = random.choice(list(HERO_MISSILES_TYPE.values()))
self.bShootCount = HERO_PLANES[self.type]['B_COUNT']
self.mShootCount = HERO_PLANES[self.type]['M_COUNT']
self.nuclearQty = HERO_PLANES[self.type]['QUANTITY']
self.defence = HERO_PLANES[self.type]['DEFENCE']
# 捡到power子弹包计算数量
self.power_bullet_qty = 0
def move_left(self):
if self.rect.left >= self.xSpeed * self.speedupFactor:
self.rect.left -= self.xSpeed * self.speedupFactor
else:
self.rect.left = 0
def move_right(self):
if self.rect.right <= SCREEN_SIZE[0] - self.xSpeed * self.speedupFactor:
self.rect.right += self.xSpeed * self.speedupFactor
else:
self.rect.right = SCREEN_SIZE[0]
def move_up(self):
if self.rect.top >= GAME_AREA_START_HEIGHT + self.ySpeed * self.speedupFactor:
self.rect.top -= self.ySpeed * self.speedupFactor
else:
self.rect.top = GAME_AREA_START_HEIGHT
def move_down(self):
if self.rect.bottom <= SCREEN_SIZE[1] - self.ySpeed * self.speedupFactor:
self.rect.bottom += self.ySpeed * self.speedupFactor
else:
self.rect.bottom = SCREEN_SIZE[1]
# 处理键盘事件,分别用 awsd 来控制方向,你懂得,如果你喜欢 方向键自己修改。当然你可以扩展为游戏手柄。
def move(self, keyPressed):
if keyPressed[K_a]:
self.move_left()
if keyPressed[K_w]:
self.move_up()
if keyPressed[K_s]:
self.move_down()
if keyPressed[K_d]:
self.move_right()
# 发射子弹,根据配制文件修改数量,请考虑对称性,子弹也不要太多,不然满屏子弹飞
def shoot_bullets(self):
if self.bShootCount == 2:
Bullet(self.bulletType, (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
Bullet(self.bulletType, (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
if self.bShootCount == 4:
Bullet(self.bulletType, (self.rect.left + 20, self.rect.top), self.groups[0], heroBulletGroup)
Bullet(self.bulletType, (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
Bullet(self.bulletType, (self.rect.right - 20, self.rect.top), self.groups[0], heroBulletGroup)
Bullet(self.bulletType, (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
# 如果有强力子弹,也可以发射
def shoot_power_bullets(self):
if self.power_bullet_qty > 0:
if self.bShootCount == 2:
Bullet('P_BULLET', (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
Bullet('P_BULLET', (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
self.power_bullet_qty -= 2
if self.bShootCount == 4:
Bullet('P_BULLET', (self.rect.left + 20, self.rect.top), self.groups[0], heroBulletGroup)
Bullet('P_BULLET', (self.rect.left + 40, self.rect.top), self.groups[0], heroBulletGroup)
Bullet('P_BULLET', (self.rect.right - 20, self.rect.top), self.groups[0], heroBulletGroup)
Bullet('P_BULLET', (self.rect.right - 40, self.rect.top), self.groups[0], heroBulletGroup)
self.power_bullet_qty -= 4
return True
return False
# 发射导弹
def shoot_missiles(self):
if self.mShootCount == 1:
Bullet(self.missileType, (self.rect.centerx, self.rect.top), self.groups[0], heroBulletGroup)
if self.bShootCount == 2:
Bullet(self.missileType, (self.rect.centerx - 15, self.rect.top), self.groups[0], heroBulletGroup)
Bullet(self.missileType, (self.rect.centerx + 15, self.rect.top), self.groups[0], heroBulletGroup)
# 发射核弹
def shoot_nuclear(self):
if self.nuclearQty >= 1:
Bullet('NUCLEAR', (self.rect.centerx, self.rect.top + 10), self.groups[0], nuclearGroup)
self.nuclearQty -= 1
return True
return False
# 捡到敌机丢下的包裹
def pickup_package(self, pType):
if pType == 'P_BULLET':
self.power_bullet_qty += PACKAGES['P_BULLET']['QUANTITY']
if pType == 'NUCLEAR':
self.nuclearQty += 1
if pType == 'DEFENCE':
self.defence += PACKAGES['DEFENCE']['QUANTITY']
# 躲子弹变形和恢复
def transform(self, event):
if event.type == KEYDOWN and event.key == K_SPACE:
currentCenter = self.rect.center
self.image = pygame.transform.smoothscale(self.image, (40, 80))
self.rect.center = currentCenter
elif event.type == KEYUP and event.key == K_SPACE:
currentCenter = self.rect.center
self.image = pygame.image.load(IMAGE_PATH + HERO_PLANES[self.type]['IMAGE']).convert_alpha()
self.rect.center = currentCenter
# sounds 为声音数组, 0 用于普通子弹、导弹, 1 用于核弹
def shoot(self, keyPressed, sounds):
if keyPressed[K_j]:
self.shoot_bullets()
sounds[0].play()
if keyPressed[K_k]:
self.shoot_missiles()
sounds[0].play()
if keyPressed[K_l]:
if self.shoot_power_bullets():
sounds[0].play()
if keyPressed[K_i]:
if self.shoot_nuclear():
sounds[1].play()
# 处理 heroPlane 被子弹击中 或者 被敌机撞击
def was_collided(self, group):
for sp in group:
if pygame.sprite.collide_rect(self, sp):
self.defence -= sp.destroyValue
sp.kill()
if self.defence <= 0:
return True
return False
好了,英雄战机类和方法、以及处理相关键盘事件( 一共处理了 aswd, ijkl,space 九个键)。如果你想扩展别的功能,堆积木就好了。
仔细的朋友注意到了, HeroPlane类没有update方法,因为位置更新由用户来操作,这里是不需要的。当然你也可以添加update()方法,把特殊需要处理的事情放在这里,将会由战机所在的群的update()自动调用。
到这里,已经完整给出了 子弹类、敌机类、包裹类、英雄战机类的完整处理,有兴趣的朋友已经可以自己动手了,先准备好相关素材,然后编写个play() 来玩了。
哦,忘了,还有星空背景。
由于星空背景不是本人原创,是在原创的基础上进行了改写,以便能融入游戏。这里要感谢原创人。
星空背景使用了两个类: Star 类 和 Space,Space里有很多Star,对吧。
class Star(object):
def __init__(self, x, y, speed):
self.x = x
self.y = y
self.speed = speed
class Space:
def __init__(self, targetSurf):
self.targetSurf = targetSurf
self.stars = self.get_stars()
def get_stars(self):
stars = []
for n in range(10):
x = randint(0, SCREEN_SIZE[0] - 1)
y = randint(0, SCREEN_SIZE[1] - 1) + GAME_AREA_START_HEIGHT
speed = randint(100, 300)
stars.append(Star(x, y, speed))
return stars
def showspace(self, spaceClock):
x = randint(0, SCREEN_SIZE[0])
speed = randint(3, 15)
star = Star(x, GAME_AREA_START_HEIGHT, speed)
self.stars.append(star)
time_passed_in_seconds = spaceClock.tick() / 1000.
# 新产生的星星由于时间长(time_passed_in_seconds),因此移动速度快很多
# 导致产生了很多不同速度的星星,当都朝一个方向运动时,看起来就像星空了。
white = (255, 255, 255)
for star in self.stars:
new_y = star.y + time_passed_in_seconds * star.speed * 30
pygame.draw.aaline(self.targetSurf, white, (star.x, new_y), (star.x, new_y + 2)) # 2 星星长度
star.y = new_y
def on_targetSurf(star):
return star.y < SCREEN_SIZE[1]
self.stars = list(filter(on_targetSurf, self.stars))
这里Star是一个点,有兴趣的朋友可以改为Sprite和Group来实现,将Star修改为一个小圆或者不同亮度的星星图片等。但也需要考虑Star太多后占用内存太多。
好了,本文就到这里,下一篇将会给出主函数,将这些东西组合起来玩游戏了。