项目规划
开发项目时,做好规划后再动手编写项目其实很重要。固化可确保你不偏离轨道,从而提高项目成功的可能性。
在游戏《外星人入侵》中,玩家控制着一艘最初出现在屏幕底部中央的飞船。玩家可以使用箭头键左右移动飞船,还可使用空格键进行射击。游戏开始时,一群外星人出现在天空中,他们在屏幕中向下移动。玩家的任务是射杀这些外星人。玩家将所有外星人都消灭干净后,将出现一群新的外星人,他们移动的速度更快。只要有外星人撞到了玩家的飞船或到达了屏幕底部,玩家就损失一艘飞船。玩家损失三艘飞船后,游戏结束。
安装pygame
pygame是一组强大而又去的模块,可用于管理图形,动画乃至声音,让你能够更轻松地开发复杂的游戏。通过使用Pygame来处理再屏幕上绘制图像等任务,你不用考虑众多烦琐而艰难的编码工作,而是将重点放在程序的高级逻辑上。
###再windows系统中安装pip
python get-pip.py
###安装pygame
python -m pip install --user pygame-1.9.2a0-cp35-none-win32.whl
开始游戏项目
现在来开始开发游戏《外星人入侵》。
首先创建一个空的Pygame窗口,供后面用来绘制游戏元素。如飞船和外星人。
还要红色字游戏响应用户输入,设置背景色以及加载飞船图像
创建Pygame窗口以及响应用户输入
首先,要创建一个空的Pygame窗口。使用Pygame编写的游戏的基本结构
"""alien_dem"""
###sys调用系统的参数和功能
import sys
import pygame
def run_game():
"""初始化游戏并创建一个屏幕对象"""
##初始化背景设置
pygame.init()
##定义一个名为screen宽800高600的游戏窗口,screen是一个surface(表面),surface是屏幕的一部分,用于显示游戏对象,再这个游戏中外星人,飞船都是surface
screen = pygame.display.set_mode((800,600))
##显示窗口的解释说明
pygame.display.set_caption("Alien Invasion")
"""开始游戏的循环,这个游戏由一个循环语句来控制,死循环保证这个窗口一直再显示"""
while True:
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环
"""
for event in pygame.event.get():
##如果点击关闭窗口even.type的类型就为QUIT,则退出 pygaem.QUIT是退出事件,退出代码为256
if event.type == pygame.QUIT:
##退出
sys.exit()
"""让最近绘制的屏幕可见"""
##这里就是你每执行一个while循环这个就会刷新屏幕,把旧的屏幕擦去,然后显示新的
pygame.display.flip()
##调用这个函数
run_game()
###执行
##执行后就会有一个黑色的显示屏
设置背景色
pygame默认创建的是一个黑色的屏幕,这太乏味了。羡慕来讲背景设置为其他颜色
##alien_demo.py
.....
##设置显示背景颜色
bg_color = (230, 230, 230)
screen.fill(bg_color)
##设置显示背景颜色
"""再Pygame中颜色使用RGB来表现的,这种颜色由红色,蓝色,绿色来组成,取值范围都是0-255"""
bg_color = (230, 230, 230)
"""给屏幕填充色"""
screen.fill(bg_color)
##调用这个函数
run_game()
###执行
你会发现原来是黑色的背景变成白色的了
创建设置类
每次给游戏添加新功能是,通常也要引入一些新的设置
就比如你相改一些游戏中的某些设置--屏幕吧,你不需要直接打开本代码去修改,你将设置全部存储再一个地方,你要修改的时只需要修改那个设置的文件了,调用起来也比较方便。
这里我把显示屏幕的长宽高和背景颜色添加到了alien_setting_demo.py中并在ailen_demo.py中导入
###alien_setting_demo.py
"""定义一个设置类"""
class alien_settings():
"""外星人游戏中的设置参数"""
def __init__(self):
self.high = 600
self.width = 800
self.bg_color= (230,230,230)
##alien_demo.py
import sys
import pygame
from alien_setting_demo import alien_settings
def run_game():
"""初始化游戏并创建一个屏幕对象"""
##初始化背景设置
pygame.init()
"""创建类的实列,创建设置的实列"""
settings = alien_settings()
screen = pygame.display.set_mode((settings.width, settings.high))
##显示窗口的解释说明
pygame.display.set_caption("Alien Invasion")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
##退出
sys.exit()
##设置显示背景颜色
screen.fill(settings.bg_color)
"""让最近绘制的屏幕可见"""
pygame.display.flip()
##调用这个函数
run_game()
###执行
和上面一样的效果
添加飞船图标
首先我们先再文件中创建一个image目标以便于添加图片
再把飞船图添加到该文件夹中,以便后面调用
创建ship(飞船)类
创建一个ship类,它负责管理飞船的大部分1行为
##ship.py
import pygame
class ship():
def __init__(self,screen):
"""初始化飞船并设置位置"""
self.screen = screen
"""加载图像并获取其外接矩形 返回飞船的的surface并存储到self.image中"""
self.image = pygame.image.load('../alien/image/飞船.png')
"""调整图片大小"""
self.image = pygame.transform.scale(self.image, (30, 40))
"""get_rect()可以让Pygame读取到图像的矩形属性,Pygame之所以效率高是因为它可以像处理矩形那样处理图像,矩形是一个特别简单的形状"""
self.rect = self.image.get_rect()
"""获取到屏幕的矩形属性"""
self.screen_rect = screen.get_rect()
"""每搜飞船放在屏幕底部的中心,
要将游戏元素居中,可以设置相应rect对象的属性center(中央),centerx(x轴中央),centery(y轴中央)。要让游戏元素与屏幕边缘对齐,可是使用top、bottom、left、right;要调整游戏元素水平或垂直位置,可使用属性x和y。
"""
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
def print_ship(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
在屏幕上绘制飞船
###alien_demo.py
....
from ship import ship
def run_game():
....
screen = pygame.display.set_mode((settings.width, settings.high))
##显示窗口的解释说明
pygame.display.set_caption("Alien Invasion")
"""创建一个飞船"""
ship_demo = ship(screen)
"""开始游戏的循环,这个游戏由一个循环语句来控制,死循环保证这个窗口一直再显示"""
while True:
.....
screen.fill(settings.bg_color)
##打印出飞船到屏幕
ship_demo.print_ship()
pygame.display.flip()
##调用这个函数
run_game()
##执行
重构:模块game_functions
在大型项目中,经常需要在添加新代码前重构即现有代码。重构旨在简化既有代码的结果后,是其更容易扩展。
函数check_event
把检查事件放在这个函数模块里面
##game_functions.py
import pygame
import sys
def check_events():
for event in pygame.event.get():
##如果点击关闭窗口,则退出 pygaem.QUIT是退出事件
if event.type == pygame.QUIT:
##退出
sys.exit()
函数update_screen()
我们把更新屏幕函数放在这个模块里面
##game_functions.py
def update_screen(settings,screen,ship_demo):
##设置显示背景颜色
"""再Pygame中颜色使用RGB来表现的,这种颜色由红色,蓝色,绿色来组成,取值范围都是0-255"""
"""给屏幕填充色"""
screen.fill(settings.bg_color)
ship_demo.print_ship()
"""让最近绘制的屏幕可见"""
##这里就是你每执行一个while循环这个就会刷新屏幕,把新的屏幕擦去
pygame.display.flip()
##alien_demo.py
###sys调用系统的参数和功能
import sys
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
def run_game():
"""初始化游戏并创建一个屏幕对象"""
##初始化背景设置
pygame.init()
"""创建类的实列,创建设置的实列"""
settings = alien_settings()
##定义一个名为screen宽800高600的游戏窗口,screen是一个surface(表面),surface是屏幕的一部分,用于显示游戏对象,再这个游戏中外星人,飞船都是surface
screen = pygame.display.set_mode((settings.width, settings.high))
##显示窗口的解释说明
pygame.display.set_caption("Alien Invasion")
"""创建一个飞船"""
ship_demo = ship(screen)
"""开始游戏的循环,这个游戏由一个循环语句来控制,死循环保证这个窗口一直再显示"""
while True:
game_functions.check_events()
game_functions.update_screen(settings, screen, ship_demo)
##调用这个函数
run_game()
12-1蓝色天空:创建一个背景为蓝色的Pygame窗口
##bule_sky.py
import pygame
import sys
class settings():
def __init__(self):
self.high = 600
self.width = 1000
self.bg_color = (0,0,250)
def bule_sky():
##初始化
pygame.init()
setting = settings()
screen = pygame.display.set_mode((setting.width,setting.high))
pygame.display.set_caption("蓝色的背景")
while True:
for even in pygame.event.get():
if even.type == pygame.QUIT:
sys.exit()
screen.fill(setting.bg_color)
pygame.display.flip()
bule_sky()
12-2游戏角色:找一幅你喜欢的游戏角色位图图像或将一幅图像转换为位图。创建一个类,将该角色绘制到屏幕中央,并将该图像的背景色设置为屏幕背景色,或将屏幕背景色设置为该图像的背景色。
##tiger_doll_setting.py
"""基本设置,屏幕,背景色"""
class settings():
def __init__(self):
self.width = 800
self.high = 600
self.bg_color = (255, 255, 255)
##tiger_doll_image.py
import pygame
class tiger_doll_image():
def __init__(self,screen):
self.screen = screen
##获取图像
self.image = pygame.image.load('C:\\Users\\tanchang\Desktop\python\code\\alien\image\虎年娃娃-01.png')
##调整图像大小
self.image = pygame.transform.scale(self.image,(400,400))
##调整
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
def prin_image(self):
self.screen.blit(self.image,self.rect)
##tiger_doll.py
import pygame
import sys
from tiger_doll_setting import settings
from tiger_doll_image import tiger_doll_image
def tiger_doll():
pygame.init()
setting = settings()
screen = pygame.display.set_mode((setting.width, setting.high))
pygame.display.set_caption("虎娃娃")
image_demo = tiger_doll_image(screen)
while True:
for even in pygame.event.get():
if even.type == pygame.QUIT:
sys.exit()
screen.fill(setting.bg_color)
image_demo.prin_image()
pygame.display.flip()
tiger_doll()
驾驶飞船
只显示一个图片是不行的,必须要控制飞船前后左右移动
所以我们要编写代码控制飞船左右移动
按键响应
每当用户按键时,都将在pygame中注册一个事件。事件都是通过Pygame.event.get()获取的,因此在函数check_event()中,我们需要指定要检查哪些事件的类型。
每次按键都是被注册为一个KEYDOWN事件
检测到KEYDOWEN事件是,就要判断是否按下了特定的键
##game_functions.py
import pygame
import sys
def check_events(ship):
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环"""
for event in pygame.event.get():
##如果点击关闭窗口,则退出 pygaem.QUIT是退出事件
if event.type == pygame.QUIT:
##退出
sys.exit()
##判断是否按下键盘
elif event.type == pygame.KEYDOWN:
##判断按下的键是否是方向键右键
if event.key == pygame.K_RIGHT:
##向右移动飞船,横坐标+1
ship.rect.centerx += 1
##alien_demo.py
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
def run_game():
.....
while True:
.....
##调用
game_functions.check_events(ship_demo)
game_functions.update_screen(settings, screen, ship_demo)
run_game()
##执行后按下右键就会发现飞船可以动了
允许不断移动
玩家按住右箭头不放,飞船就可以不断移动,直到玩家松开为止
##ship.py
import pygame
class ship():
....
def __init__(self,screen):
##移动标志,,这只是一个变量
self.moving_right = False
def update(self):
##如果moving_right为True就向右移动
if self.moving_right:
self.rect.centerx += 1
def print_ship(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
###game_functions.py
import pygame
import sys
def check_events(ship):
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环"""
for event in pygame.event.get():
....
elif event.type == pygame.KEYDOWN:
##判断按下的键是否是方向键右键,如果是按下右键moving_right就为True就会向右移动
if event.key == pygame.K_RIGHT:
##向右移动飞船
ship.moving_right = True
##如果不是按下右键moving_right就为Flase就不会会向右移动
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
.....
##aline_demo.py
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
def run_game():
pygame.init()
settings = alien_settings()
screen = pygame.display.set_mode((settings.width, settings.high))
pygame.display.set_caption("Alien Invasion")
ship_demo = ship(screen)
while True:
game_functions.check_events(ship_demo)
ship_demo.update()
game_functions.update_screen(settings, screen, ship_demo)
左右移动
##ship.py
import pygame
class ship():
def __init__(self,screen):
....
##移动标志
self.moving_right = False
self.moving_left = False
def update(self):
##如果moving_right为True就向右移动
if self.moving_right:
self.rect.centerx += 1
##如果moving_left为True就向左移动
if self.moving_left:
self.rect.centerx -= 1
##game_functions.py
import pygame
import sys
def check_events(ship):
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环"""
for event in pygame.event.get():
##如果点击关闭窗口,则退出 pygaem.QUIT是退出事件
if event.type == pygame.QUIT:
##退出
sys.exit()
##判断是否按下键盘
elif event.type == pygame.KEYDOWN:
##判断按下的键是否是方向键右键,如果是按下右键moving_right就为True就会向右移动
if event.key == pygame.K_RIGHT:
##向右移动飞船
ship.moving_right = True
elif event.key == pygame.K_LEFT:
##向左移动飞船
ship.moving_left = True
##如果不是按下右键moving_right就为Flase就不会会向右移动
##如果不是按下左键moving_right就为Flase就不会会向左移动
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
##执行aline_demo.py
调整飞船的速度
当每次执行while循环时,飞船最多移动1像素,但是我们可以在设置类中添加移动属性,用于控制飞船的移动速度。
##alien_settings_demo.py
"""定义一个设置类"""
class alien_settings():
"""外星人游戏中的设置参数"""
def __init__(self):
....
##将速度设置为小数值,可以在游戏后期更好的控制飞船的移动,只要这个值大于一他就会移动速度比以前更快
self.ship_speed = 1.5
##ship.py
import pygame
class ship:
###这里多添加了一个形参settings
def __init__(self, screen, settings):
"""初始化飞船并设置位置"""
self.screen = screen
##导入设置
self.setting = settings
##存储小数值
self.center = float(self.rect.centerx)
def update(self):
##如果moving_right为True就向右移动
"""注意这里是self.center"""
if self.moving_right:
self.center += self.setting.ship_speed
##如果moving_left为True就向左移动
if self.moving_left:
self.center -= self.setting.ship_speed
##根据self.center更新rect对象 因为self.rect.centerx存储着飞船的x坐标的初始值,但是不能存储小数,只能存储整数
self.rect.centerx = self.center
##alien_demo.py
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
def run_game():
....
"""创建类的实列,创建设置的实列"""
settings = alien_settings()
....
##传入参数,这里要加有个设置
ship_demo = ship(screen,settings)
限制飞船移动范围
当玩家一直按住箭头左右移动就会使飞船在屏幕上消失的无影无踪,需要在update()中的if语句中在加个条件
##ship.py
def update(self):
##如果moving_right为True就向右移动
##self.screen_rect.right是800 这个屏幕最大宽度也就是800,向右移动时要小于这个宽度
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.setting.ship_speed
##如果moving_left为True就向左移动
##self.screen_rect.left是0
if self.moving_left and self.rect.left > 0:
self.center -= self.setting.ship_speed
#根据
self.rect.centerx = self.center
重构check_event()
##game_functions.py
import pygame
import sys
def check_events_keyup(event,ship):
##如果不是按下右键moving_right就为Flase就不会会向右移动
##如果不是按下左键moving_right就为Flase就不会会向左移动
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events_keydown(event,ship):
##判断按下的键是否是方向键右键,如果是按下右键moving_right就为True就会向右移动
if event.key == pygame.K_RIGHT:
##向右移动飞船
ship.moving_right = True
elif event.key == pygame.K_LEFT:
##向左移动飞船
ship.moving_left = True
def check_events(ship):
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环"""
for event in pygame.event.get():
##如果点击关闭窗口,则退出 pygaem.QUIT是退出事件
if event.type == pygame.QUIT:
##退出
sys.exit()
##判断是否按下键盘
elif event.type == pygame.KEYDOWN:
check_events_keydown(event,ship)
elif event.type == pygame.KEYUP:
check_events_keyup(event,ship)
射击
下面需要玩家按下空隔键飞船就发射子弹(小矩形)的代码,子弹将在屏幕中向上穿行,抵达屏幕上边缘后消失
添加子弹设置
首先,更新ailen_setting_demo.py,在初始化中存储子弹所需要的值
class alien_settings():
"""外星人游戏中的设置参数"""
def __init__(self):
##子弹设置
#速度
self.bullet_speed_factor = 1
#宽
self.bullet_width = 3
#高
self.bullet_high = 10
#颜色
self.bullet_color = (60, 60, 60)
创建Bullet类
import pygame
##导入pygame.sprite中的Sprite模块
from pygame.sprite import Sprite
class bullet(Sprite):
def __init__(self,settinge,screen,ship):
##把bullet子类和父类Sprite关联起来
super().__init__()
self.screen = screen
##子弹不是基于图形的,因此我们要使用pygame.Rect()类从空白处创建预估矩形,创建这个类的实列是需要提供x,y的坐标,表面在哪里创建,后面的就是表示这个矩形的宽和高
self.rect = pygame.Rect(0,0,settinge.bullet_width , settinge.bullet_high)
##子弹必须得从飞船中央的顶端发出
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
##子弹的y坐标设置为小数值,以便可以微调子弹的速度
self.y = float(self.rect.y)
print(self.y)
self.color = settinge.bullet_color
self.speed_factor = settinge.bullet_speed_factor
def update(self):
##移动子弹,向上移动
self.y -= self.speed_factor
##更新表示子弹的位置
self.rect.y = self.y
def prit_bullet(self):
##pygame.draw.rect()是绘制矩形的函数
pygame.draw.rect(self.screen,self.color,self.rect)
pygame.draw
pygame.draw.rect: 绘制矩形
pygame.draw.polygon: 绘制任意边数的多边形
pygame.draw.circle: 绘制圆
pygame.draw.ellipse: 在矩形内绘制椭圆
pygame.draw.arc: 绘制圆弧(或者椭圆的一部分)
pygame.draw.line: 绘制直线(线段)
pygame.draw.lines: 从一个点列表中连续绘制直线段
pygame.draw.aaline: 绘制一根平滑的线(反锯齿)
pygame.draw.aalines: 绘制一系列平滑的线
将子弹存储到编组中
现在编写让玩家没按一次空隔就发射一个子弹,我们将有效子弹存储到一个编组中,
pygame.sprite.Group类的一个实列,pygame.sprite.Group类似于列表,但提供了又助于开发游戏的额外功能
##alien_demo.py
...
from pygame.sprite import Group
def run_game():
"""定义一个编组 可以查看game_function.py 中的check_events_keydown,"""
bullets = Group()
"""开始游戏的循环,这个游戏由一个循环语句来控制,死循环保证这个窗口一直再显示"""
while True:
##game_fuctions,在这个里面需要设置按空格时来处理bullets
game_functions.check_events(ship_demo,settings, screen,bullets)
ship_demo.update()
##子弹向上移动,bullets.py,当你调用update时编组将自动对其中的每个精灵调用update()
bullets.update()
game_functions.update_screen(ship_demo,settings, screen,bullets)
开火
在game_function,我们需要对KEYDWON进行操作,当玩家按一次空格就会发送一颗子弹,还需要修改update_screen(),确保在调用filp()前在屏幕上重绘每颗子弹
##game_functions.py
import pygame
import sys
from bullet import bullet
def check_events_keydown(event,ship,settinge,screen,bullets):
##判断按下的键是否是方向键右键,如果是按下右键moving_right就为True就会向右移动
if event.key == pygame.K_RIGHT:
##向右移动飞船
ship.moving_right = True
elif event.key == pygame.K_LEFT:
##向左移动飞船
ship.moving_left = True
##如果按下空额就添加一个新的子弹
elif event.key == pygame.K_SPACE:
##创建新子弹bullet.py
new_bullet = bullet(settinge,screen,ship)
##存储到编组中我们在aline_demo.py中创建了一个编组
bullets.add(new_bullet)
def check_events(ship,settinge,screen,bullets):
"""监视键盘和鼠标事件,pygame.event是用来管理事件的,按键和移动键盘也是事件,也就是说一旦有事件发送就会执行这个for循环"""
for event in pygame.event.get():
......
elif event.type == pygame.KEYDOWN:
check_events_keydown(event,ship,settinge,screen,bullets)
def update_screen(ship,settings, screen,bullets):
....
###bullets.sprites()返回一个列表这个列表包含子弹,我们来遍历这个列表来获取子弹,然后一直不停的刷新子弹位置然后一直不停的打印
for bullet in bullets.sprites():
##打印子弹
bullet.prit_bullet()
"""让最近绘制的屏幕可见"""
##这里就是你每执行一个while循环这个就会刷新屏幕,把新的屏幕擦去
pygame.display.flip()
删除消失的子弹
现在屏幕上的子弹并不会消失,看不见了是因为pygame无法在屏幕外面绘制它,这些子弹依旧还在但y轴坐标会越来越小,当你发射子弹过多时就会占用过多的内存
##alien_demo.py
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
from pygame.sprite import Group
def run_game():
....
"""定义一个编组 可以查看game_function.py 中的check_events_keydown,"""
bullets = Group()
"""开始游戏的循环,这个游戏由一个循环语句来控制,死循环保证这个窗口一直再显示"""
while True:
##子弹向上移动,bullets.py
bullets.update()
###在for循环中不应该在列表或编组中直接删除条目内,如果直接删除本体而不用副本的画,python在每次删除本体第一个元素后面的元素都会向前移一位,相应的,索引值也会发生改变
for bullet in bullets.copy():
##子弹的最底部y轴位置小于0
if bullet.rect.bottom <= 0:
bullets.remove(bullet) ##用于测试,测试好了之后可以把这条删除,如果你留下这条语句,你的运行效率会大大降低,因为输出到终端打印的时间比绘制图像的时间还要久
print(len(bullets))
限制子弹数
可以设置子弹数量,以便玩家可以有效射击
##alien_settings_demo.py
class alien_settings():
"""外星人游戏中的设置参数"""
def __init__(self):
....
self.bullet_num = 3
##game_functions.py
import pygame
import sys
from bullet import bullet
def check_events_keydown(event,ship,settinge,screen,bullets):
##如果按下空额就添加一个新的子弹
elif event.key == pygame.K_SPACE:
##创建新子弹bullet.py
##先检查一下编组内的子弹数量,看看它是否小于默认设置的子弹数量,如果小于默认设置的子弹数量就可以继续添加子弹
if len(bullets) < settinge.bullet_num:
new_bullet = bullet(settinge,screen,ship)
##存储到编组中我们在aline_demo.py中创建了一个编组
bullets.add(new_bullet)
重构
##game_functions.py
我们可以把更新子弹和删除子弹,整合到一个模块函数中让主程序alien_demo.py尽量简单
def bullet_update(bullets):
##子弹向上移动,bullets.py
bullets.update()
##让超过屏幕的子弹消失
for bullet in bullets.copy():
if bullet.rect.bottom <= 0:
bullets.remove(bullet)
##alen_demo.py
import pygame
from alien_setting_demo import alien_settings
from ship import ship
import game_functions
from pygame.sprite import Group
def run_game():
....
"""定义一个编组 可以查看game_function.py 中的check_events_keydown,"""
bullets = Group()
while True:
....
game_functions.bullet_update(bullets)
....
##game_functions.py
def fire_bullet(ship, settinge, screen, bullets):
##创建新子弹bullet.py
##先检查一下编组内的子弹数量,看看它是否小于默认设置的子弹数量,如果小于默认设置的子弹数量就可以继续添加子弹
if len(bullets) < settinge.bullet_num:
new_bullet = bullet(settinge, screen, ship)
##存储到编组中我们在aline_demo.py中创建了一个编组
bullets.add(new_bullet)
....
def check_events_keydown(event, ship, settinge, screen, bullets):
elif event.key == pygame.K_SPACE:
fire_bullet(ship, settinge, screen, bullets)
12-5侧面射击:编写一个游戏,将一艘飞船放在屏幕左边,并允许玩家上下移动飞船。在玩家按空格键时,让飞船发射一颗在屏幕中向右穿行的子弹,并在子弹离开屏幕而消失后将其删除。
##game_man.py 游戏主程序
##game_setting.py 存储程序的一些设置
##game_fun12_5.py 存储程序while内部组成的函数
##ship_man.py 飞船
##game_bullets.py 子弹的程序
##game_man.py
import pygame
from game_setting import setting
import game_fun12_5
from ship_man import Ship
from pygame.sprite import Group
def run_game():
"""初始化游戏"""
pygame.init()
settings = setting()
screen = pygame.display.set_mode((settings.dispaly_width,settings.dispaly_high))
pygame.display.set_caption ("game")
##创建ship实列
ship = Ship(screen,settings)
bullet = Group()
while True:
##检测事件
game_fun12_5.check_even(ship,screen,bullet,settings)
# ##更新飞船位置
# ship.update_ship()
##更新飞船位置并检擦飞船的y轴坐标
game_fun12_5.bullet_udpate(bullet,settings)
##打印
game_fun12_5.update_screen(ship,screen,bullet,settings)
run_game()
##game_setting.py
class setting:
"""游戏设置"""
def __init__(self):
##屏幕设置
self.dispaly_width = 1200
self.dispaly_high = 600
self.bg_color= (70,100,80)
##飞船移动速度
self.sheep_ship = 1
##子弹设置
self.bullet_high = 3
self.bullet_width = 10
self.bullet_color = (60,60,60)
self.bullet_sheep = 0.5
self.bullet_num = 6
##game_fun12_5.py
import pygame
import sys
from game_bullets import bullet
def bullet_udpate(bullets, setting):
"""更新子弹位置并检擦子弹x轴坐标地点,大于屏幕就会被删"""
bullets.update()
for bullet in bullets.copy():
if bullet.rect.right >= setting.dispaly_width:
bullets.remove(bullet)
print(len(bullets))
def fire_bullet(ship, screen, bullets, setting):
"""添加子弹,如果子弹数大于设定的子弹数就不能添加子弹"""
if len(bullets) < setting.bullet_num:
new_bullet = bullet(ship, screen, setting)
bullets.add(new_bullet)
def check_even_keydown(even, ship, screen, bullets, setting):
"""检擦是否按下按键"""
if even.key == pygame.K_DOWN:
ship.moving_down = True
elif even.key == pygame.K_UP:
ship.moving_up = True
elif even.key == pygame.K_SPACE:
fire_bullet(ship, screen, bullets, setting)
def check_even_keyup(even, ship):
"""检查是否松开"""
if even.key == pygame.K_DOWN:
ship.moving_down = False
elif even.key == pygame.K_UP:
ship.moving_up = False
def check_even(ship, screen, bullets, setting):
"""汇总"""
for even in pygame.event.get():
if even.type == pygame.QUIT:
sys.exit()
elif even.type == pygame.KEYDOWN:
check_even_keydown(even, ship, screen, bullets, setting)
elif even.type == pygame.KEYUP:
check_even_keyup(even, ship)
def update_screen(ship, screen, bullets, setting):
##加上背景色
screen.fill(setting.bg_color)
##更新飞船位置
ship.update_ship()
##打印飞船
ship.prit_ship()
##打印子弹
for bulle in bullets.sprites():
bulle.prin_bullet()
##打印最新的屏幕
pygame.display.flip()
##ship_man.py
import pygame
class Ship:
def __init__(self,screen,setting):
##屏幕
self.screen = screen
self.settings = setting
self.image = pygame.image.load('C:\\Users\\tanchang\Desktop\python\code\\alien\image\飞船.png')
self.image = pygame.transform.scale(self.image,(30,40))
##旋转飞船
self.image = pygame.transform.rotate(self.image,270)
##设置飞船的矩形和位置
print(self)
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centery = self.screen_rect.centery
self.rect.left = self.screen_rect.left
self.center = float(self.rect.centery)
##移动标识,False为不移动,True为移动
self.moving_up = False
self.moving_down = False
def update_ship(self):
"""设置飞船的移动和移动范围"""
if self.moving_up and self.rect.top > self.screen_rect.top:
self.center -= self.settings.sheep_ship
elif self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.center += self.settings.sheep_ship
self.rect.centery = self.center
def prit_ship(self):
self.screen.blit(self.image,self.rect)
##game_bullets.py
import pygame
from pygame.sprite import Sprite
class bullet(Sprite):
def __init__(self, ship, screen, setting):
##子类和父类关联
super().__init__()
self.screen = screen
##画出矩形
self.rect = pygame.Rect(0, 0, setting.bullet_width, setting.bullet_high)
self.rect.right = ship.rect.right
self.rect.centery = ship.rect.centery
self.x = float(self.rect.x)
# print(self.x)
self.color = setting.bullet_color
self.sheep = setting.bullet_sheep
def update(self):
self.x += self.sheep
self.rect.x = self.x
# print(self.rect.x)
def prin_bullet(self):
pygame.draw.rect(self.screen,self.color,self.rect)