cha12 武装飞船
基本概念:
Pygame中rect 初探
何为精灵
surface:是pygame的画图对象,可以理解为画板
习题答案
12-1
import pygame
bg_color = (0,0,255) #蓝色
bg_field = (900,600) #背景大小
screen = pygame.display.set_mode(bg_field)
#必须有while True: 否则背景只是闪现
while True:
screen.fill(bg_color)
pygame.display.flip()
12-2
import sys
import pygame
class rocket():
def __init__(self, screen):
self.screen = screen
self.image = pygame.image.load('ship.bmp')
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 blitme(self):
self.screen.blit(self.image, self.rect)
def run_game():
pygame.init()
bg_color = (230,230,230) #蓝色
bg_field = (400,300) #背景大小
screen = pygame.display.set_mode(bg_field)
#必须有while True: 否则背景只是闪现
while True:
Rocket = rocket(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(bg_color)
Rocket.blitme()
pygame.display.flip() #在最后
run_game()
12-3
注意方向左上为原点,向右下方移动市坐标值增大
alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建一艘飞船
ship = Ship(ai_settings, screen)
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
gf.check_events(ship)
ship.update()
"""更新屏幕上的图像,并切换屏幕"""
gf.update_screen(ai_settings, screen, ship)
run_game()
settings.py
class Settings():
"""储存 外星人入侵 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =1200
self.screen_height = 600
#设置背景色
self.bg_color = (230,230,230)
#飞船的设置
self.ship_speed_factor = 1.5
ship.py
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""初始化飞船并设置其初始位置"""
self.screen = screen
self.ai_settings =ai_settings
#加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp')
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
#在飞船的属性center中存储小数值
self.center = float(self.rect.centerx)
#在飞船的属性bottom中存储小数值
self.bottom = float(self.rect.bottom)
#移动标志
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
def update(self):
"""根据移动标志调整飞船的位置"""
#更新飞船的center值,而不是rect
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0 :
self.center -= self.ai_settings.ship_speed_factor
#根据self.center更新rect对象
self.rect.centerx = self.center
#更新飞船的bottom值,而不是rect
if self.moving_up and self.rect.top > self.screen_rect.top:
self.bottom -= self.ai_settings.ship_speed_factor
if self.moving_down and self.rect.bottom < self.screen_rect.bottom :
self.bottom += self.ai_settings.ship_speed_factor
#根据self.bottom更新rect对象
self.rect.bottom = self.bottom
def blitme(self):
"""在指定为止绘制飞船"""
self.screen.blit(self.image, self.rect)
game_functions.py
import sys
import pygame
def check_keydown_events(event, ship):
"""响应按键"""
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_UP:
ship.moving_up = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
def check_keyup_events(event, ship):
if event.key == pygame.K_RIGHT :
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
elif event.key == pygame.K_UP:
ship.moving_up = False
elif event.key == pygame.K_DOWN:
ship.moving_down = False
def check_events(ship) :
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ship)
#松开箭头
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship) :
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
12-4
game_functions.py
def check_keydown_events(event, ship):
"""响应按键"""
print(event.key)#添加这行
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_UP:
ship.moving_up = True
elif event.key == pygame.K_DOWN:
ship.moving_down = True
cha13 外星人
13-2 修改game_functions.py
def create_fleet(ai_settings, screen, ship, aliens):
"""创建外星人群"""
#创建一个外星人,并计算一行可容纳多少个外星人
#外星人间距为外星人宽度
alien = Alien(ai_settings, screen)
number_aliens_x = get_number_aliens_x(ai_settings, alien.rect.width)
number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)
#创建外星人群
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
#创建一行外星人
if randint(-10,10)>0:
create_alien(ai_settings, screen, aliens, alien_number, row_number)
13-3
这里加了个按空格暂停,再按空格继续下落的功能
所有函数都写在一个.py了
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
from time import sleep
class Settings():
"""储存 雨滴下落 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =600
self.screen_height = 800
#设置背景色
self.bg_color = (230,230,230)
#雨滴的设置
self.drop_speed_factor = 1.1
#是否暂停,1为不暂停
self.pause = 1
class Drop(Sprite):
"""一个对雨滴进行管理的类"""
def __init__(self, ai_settings, screen) :
super(Drop, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载雨滴图像,并设置其rect属性
self.image = pygame.image.load('drop.bmp')
self.rect = self.image.get_rect()
#每个雨滴最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
#存储雨滴的准确位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置绘制雨滴"""
self.screen.blit(self.image, self.rect)
def update(self) :
if self.ai_settings.pause == 1 :
"""向下移动雨滴"""
#更新表示子弹位置的小数值
self.rect.y += float(self.ai_settings.drop_speed_factor)
def check_edges(self):
"""如果雨滴位于屏幕底部,就返回True"""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom:
return True
def get_number_drops_x(ai_settings, drop_width):
"""计算每行可容纳多少雨滴"""
available_space_x = ai_settings.screen_width - 2 * drop_width
number_drops_x = int(available_space_x / (2 * drop_width) )
return number_drops_x
def get_number_rows(ai_settings, drop_height):
"""计算屏幕可容纳多少行雨滴"""
available_space_y = ai_settings.screen_height - 3 * drop_height
number_rows = int(available_space_y / (2 * drop_height) )
return number_rows
def create_drop(ai_settings, screen, drops, drop_number, row_number):
"""创建一个雨滴并将其放在当前行"""
drop = Drop(ai_settings, screen)
drop_width = drop.rect.width
drop.rect.x = drop_width + 2 * drop_width * drop_number
drop.rect.y = drop.rect.height + 2 * drop.rect.height * row_number
drops.add(drop)
def create_drops(ai_settings, screen, drops):
"""创建雨滴群"""
#创建一个雨滴,并计算一行可容纳多少个雨滴
#雨滴间距为外雨滴宽度
drop = Drop(ai_settings, screen)
number_drops_x = get_number_drops_x(ai_settings, drop.rect.width)
number_rows = get_number_rows(ai_settings, drop.rect.height)
#创建雨滴群
for row_number in range(number_rows):
for drop_number in range(number_drops_x):
#创建雨滴
create_drop(ai_settings, screen, drops, drop_number, row_number)
def check_keydown_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
ai_settings.pause *= -1
def check_events(ai_settings, screen) :
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings)
def update_drops(ai_settings, drops):
"""检查是否有雨滴位于屏幕边缘,并更新雨滴的位置"""
check_drop_edges(ai_settings, drops)
drops.update()
def check_drop_edges(ai_settings, drops):
"""有雨滴到达边缘时采取相应的措施"""
for drop in drops.sprites():
if drop.check_edges():
drops.remove(drop)
break
def update_screen(ai_settings, screen, drops) :
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
#绘制所有雨滴
for drop in drops.sprites():
drop.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Rain Drop")
#创建一个用于存储雨滴的编组
drops = Group()
#创建外星人群
create_drops(ai_settings, screen, drops)
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
check_events(ai_settings, screen)
update_drops(ai_settings, drops)
"""更新屏幕上的图像,并切换屏幕"""
update_screen(ai_settings, screen, drops)
run_game()
实现效果
13-4
和13-3相比在update_drops中判断是否需要新生成一行雨滴,check_drop_edges中返回是否有雨滴到达底部的标志给update_drops
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
from time import sleep
class Settings():
"""储存 雨滴下落 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =700
self.screen_height = 700
#设置背景色
self.bg_color = (230,230,230)
#雨滴的设置
self.drop_speed_factor = 1.8
#是否暂停,1为不暂停
self.pause = 1
class Drop(Sprite):
"""一个对雨滴进行管理的类"""
def __init__(self, ai_settings, screen) :
super(Drop, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载雨滴图像,并设置其rect属性
self.image = pygame.image.load('drop.bmp')
self.rect = self.image.get_rect()
#每个雨滴最初都在屏幕左上角附近
self.rect.x = self.rect.width
self.rect.y = self.rect.height
#存储雨滴的准确位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置绘制雨滴"""
self.screen.blit(self.image, self.rect)
def update(self) :
if self.ai_settings.pause == 1 :
"""向下移动雨滴"""
#更新表示子弹位置的小数值
self.rect.y += float(self.ai_settings.drop_speed_factor)
def check_edges(self):
"""如果雨滴位于屏幕底部,就返回True"""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom:
return True
def get_number_drops_x(ai_settings, drop_width):
"""计算每行可容纳多少雨滴"""
available_space_x = ai_settings.screen_width - 2 * drop_width
number_drops_x = int(available_space_x / (2 * drop_width) )
return number_drops_x
def get_number_rows(ai_settings, drop_height):
"""计算屏幕可容纳多少行雨滴"""
available_space_y = ai_settings.screen_height - 6 * drop_height
number_rows = int(available_space_y / (2 * drop_height) )
return number_rows
def create_drop(ai_settings, screen, drops, drop_number, row_number):
"""创建一个雨滴并将其放在当前行"""
drop = Drop(ai_settings, screen)
drop_width = drop.rect.width
drop.rect.x = drop_width + 2 * drop_width * drop_number
drop.rect.y = drop.rect.height + 2 * drop.rect.height * row_number
drops.add(drop)
def create_drops(ai_settings, screen, drops):
"""创建雨滴群"""
#创建一个雨滴,并计算一行可容纳多少个雨滴
#雨滴间距为外雨滴宽度
drop = Drop(ai_settings, screen)
number_drops_x = get_number_drops_x(ai_settings, drop.rect.width)
number_rows = get_number_rows(ai_settings, drop.rect.height)
#创建雨滴群
for row_number in range(number_rows):
for drop_number in range(number_drops_x):
#创建雨滴
create_drop(ai_settings, screen, drops, drop_number, row_number)
def check_keydown_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
ai_settings.pause *= -1
def check_events(ai_settings, screen) :
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings)
def update_drops(ai_settings, drops, screen):
"""检查是否有雨滴位于屏幕边缘,并更新雨滴的位置"""
drops_number_after_reach = check_drop_edges(ai_settings, drops, screen)
if drops_number_after_reach:
#创建一行雨滴
drop = Drop(ai_settings, screen)
number_drops_x = get_number_drops_x(ai_settings, drop.rect.width)
for drop_number in range(number_drops_x):
#创建雨滴
create_drop(ai_settings, screen, drops, drop_number,0)
drops.update()
def check_drop_edges(ai_settings, drops, screen):
have_reach = False
"""有雨滴到达底端时,"""
for drop in drops.sprites():
if drop.check_edges():
drops.remove(drop)
have_reach = True
if have_reach:
return True
else:
return False
def update_screen(ai_settings, screen, drops) :
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
#绘制所有雨滴
for drop in drops.sprites():
drop.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Rain Drop")
#创建一个用于存储雨滴的编组
drops = Group()
#创建外星人群
create_drops(ai_settings, screen, drops)
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
check_events(ai_settings, screen)
update_drops(ai_settings, drops, screen)
"""更新屏幕上的图像,并切换屏幕"""
update_screen(ai_settings, screen, drops)
run_game()
实验结果
13-5
collide_circle检测两个精灵的碰撞
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
from random import randint
class Settings():
"""储存 雨滴下落 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =900
self.screen_height = 600
#设置背景色
self.bg_color = (230,230,230)
#球的设置
self.drop_speed_factor = 1
#是否暂停,1为不暂停
self.pause = 1
#人物的左右移动
self.moving_left = False
self.moving_right = False
self.moving_speed = 1 #要比较小的数值
class Character():
def __init__(self, ai_settings, screen) :
self.screen = screen
self.ai_settings = ai_settings
#加载人物图像,并设置其rect属性
self.image = pygame.image.load('role.bmp')
self.rect = self.image.get_rect()
#人物在屏幕底端中间
self.screen_rect = self.screen.get_rect()
self.rect.bottom = self.screen_rect.bottom
self.rect.centerx = self.screen_rect.centerx
def update(self, ai_settings):
if ai_settings.moving_left and self.rect.x >=0 :
self.rect.x -= self.ai_settings.moving_speed
if ai_settings.moving_right and self.rect.right <= self.screen_rect.right:
self.rect.x += self.ai_settings.moving_speed
def blitme(self):
"""在指定位置绘制人物"""
self.screen.blit(self.image, self.rect)
class Ball(Sprite):
"""一个对球进行管理的类"""
def __init__(self, ai_settings, screen) :
super(Ball, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载球的图像,并设置其rect属性
self.image = pygame.image.load('ball.bmp')
self.rect = self.image.get_rect()
#每个球最初都在屏幕上方 横坐标随机
self.screen_rect = self.screen.get_rect()
self.rect.x = randint(0, self.screen_rect.right)
self.rect.y = self.rect.height
#存储雨滴的准确位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置绘制球"""
self.screen.blit(self.image, self.rect)
def update(self) :
if self.ai_settings.pause == 1 :
"""向下移动球"""
#更新表示子弹位置的小数值
self.rect.y += float(self.ai_settings.drop_speed_factor)
def check_edges(self):
"""如果球位于屏幕底端,就返回True"""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom:
return True
def check_keyup_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_LEFT:
ai_settings.moving_left = False
elif event.key == pygame.K_RIGHT:
ai_settings.moving_right = False
def check_keydown_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
ai_settings.pause *= -1
elif event.key == pygame.K_LEFT:
ai_settings.moving_left = True
elif event.key == pygame.K_RIGHT:
ai_settings.moving_right = True
def check_events(ai_settings, screen) :
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ai_settings)
def check_catching_ball(fighter, ball):
if pygame.sprite.collide_circle(fighter, ball):
return True
def update_ball(ai_settings,fighter, ball, screen):
"""检查球是否有位于屏幕边缘,并更新球的位置"""
if ball.check_edges() or check_catching_ball(fighter, ball):
#将球的位置重新从屏幕上部的某处开始
ball.rect.y = ball.rect.height
ball.rect.x = randint(0, ball.screen_rect.right)
else:
ball.update()
def update_screen(ai_settings, screen, fighter, ball) :
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
#绘制球
ball.blitme()
#绘制人物
fighter.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Catch Ball")
#创建一个球
ball = Ball(ai_settings, screen)
#创建人物
people = Character(ai_settings, screen)
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
check_events(ai_settings, screen)
update_ball(ai_settings, people, ball, screen)
people.update(ai_settings)
"""更新屏幕上的图像,并切换屏幕"""
update_screen(ai_settings, screen, people, ball)
run_game()
运行结果
13-5
引入统计游戏信息的类,以及是否还能进行游戏的标志
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
from random import randint
from time import sleep
class Settings():
"""储存 雨滴下落 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =900
self.screen_height = 600
#设置背景色
self.bg_color = (230,230,230)
#球的设置
self.drop_speed_factor = 1
self.permit_missing_times = 3
#是否暂停,1为不暂停
self.pause = 1
#人物的左右移动
self.moving_left = False
self.moving_right = False
self.moving_speed = 1 #要比较小的数值
class Character():
def __init__(self, ai_settings, screen) :
self.screen = screen
self.ai_settings = ai_settings
#加载人物图像,并设置其rect属性
self.image = pygame.image.load('role.bmp')
self.rect = self.image.get_rect()
#人物在屏幕底端中间
self.screen_rect = self.screen.get_rect()
self.rect.bottom = self.screen_rect.bottom
self.rect.centerx = self.screen_rect.centerx
def update(self, ai_settings):
if ai_settings.moving_left and self.rect.x >=0 :
self.rect.x -= self.ai_settings.moving_speed
if ai_settings.moving_right and self.rect.right <= self.screen_rect.right:
self.rect.x += self.ai_settings.moving_speed
def blitme(self):
"""在指定位置绘制人物"""
self.screen.blit(self.image, self.rect)
class Ball(Sprite):
"""一个对球进行管理的类"""
def __init__(self, ai_settings, screen) :
super(Ball, self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载球的图像,并设置其rect属性
self.image = pygame.image.load('ball.bmp')
self.rect = self.image.get_rect()
#每个球最初都在屏幕上方 横坐标随机
self.screen_rect = self.screen.get_rect()
self.rect.x = randint(0, self.screen_rect.right)
self.rect.y = self.rect.height
#存储雨滴的准确位置
self.x = float(self.rect.x)
def blitme(self):
"""在指定位置绘制球"""
self.screen.blit(self.image, self.rect)
def update(self) :
if self.ai_settings.pause == 1 :
"""向下移动球"""
#更新表示子弹位置的小数值
self.rect.y += float(self.ai_settings.drop_speed_factor)
def check_edges(self):
"""如果球位于屏幕底端,就返回True"""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom:
return True
class GameStats():
"""跟踪游戏的统计信息"""
def __init__(self, ai_settings):
"""初始化统计信息"""
self.ai_settings = ai_settings
self.game_active = True
self.reset_stats()
def reset_stats(self):
"""初始化在游戏运行期间可能变化的统计信息"""
self.missing_balls = 0
def check_keyup_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_LEFT:
ai_settings.moving_left = False
elif event.key == pygame.K_RIGHT:
ai_settings.moving_right = False
def check_keydown_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
ai_settings.pause *= -1
elif event.key == pygame.K_LEFT:
ai_settings.moving_left = True
elif event.key == pygame.K_RIGHT:
ai_settings.moving_right = True
def check_events(ai_settings, screen) :
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ai_settings)
def check_catching_ball(fighter, ball):
if pygame.sprite.collide_circle(fighter, ball):
return True
def update_ball(ai_settings,fighter, ball, screen, stats):
"""检查球是否有位于屏幕边缘,并更新球的位置"""
if ball.check_edges():
stats.missing_balls += 1
sleep(0.5)
if stats.missing_balls >= ai_settings.permit_missing_times:
stats.game_active = False
else:
if ball.check_edges() or check_catching_ball(fighter, ball):
#将球的位置重新从屏幕上部的某处开始
ball.rect.y = ball.rect.height
ball.rect.x = randint(0, ball.screen_rect.right)
else:
ball.update()
def update_screen(ai_settings, screen, fighter, ball) :
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
#绘制球
ball.blitme()
#绘制人物
fighter.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Catch Ball")
#创建一个储存游戏统计信息的实例
stats = GameStats(ai_settings)
#创建一个球
ball = Ball(ai_settings, screen)
#创建人物
people = Character(ai_settings, screen)
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
check_events(ai_settings, screen)
if stats.game_active:
update_ball(ai_settings, people, ball, screen, stats)
people.update(ai_settings)
"""更新屏幕上的图像,并切换屏幕"""
update_screen(ai_settings, screen, people, ball)
run_game()
cha14 计分
14-2 14-3
子弹击中砖块就消失
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
from random import randint
from time import sleep
import pygame.font
class Settings():
"""储存 击砖块 的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width =900
self.screen_height = 600
#设置背景色
self.bg_color = (230,230,230)
#砖块的设置
self.brick_color = (250, 150, 50)
self.brick_width = 40
self.brick_height = 10
self.permit_missing_times = 3
#是否暂停,1为不暂停
self.pause = 1
#飞船的上下 移动
self.moving_up = False
self.moving_down = False
self.moving_speed = 1 #要比较小的数值
#子弹的设置
self.bullet_width = 20
self.bullet_height = 5
self.bullet_color = (60, 60, 60)
#以什么速度加快游戏-砖块、子弹
self.speedup_scale =1.1
self.initialize_dynamic_settings()
def initialize_dynamic_settings(self):
self.bullet_speed_factor = 5
self.brick_speed_factor = 1
def increase_speed(self):
self.bullet_speed_factor *= self.speedup_scale
self.brick_speed_factor *= self.speedup_scale
class Rocket():
def __init__(self, ai_settings, screen) :
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图像,并设置其rect属性
self.image = pygame.image.load('rocket.bmp')
self.rect = self.image.get_rect()
#飞船设置在屏幕左端中间
self.screen_rect = self.screen.get_rect()
self.rect.x = self.screen_rect.left
self.rect.y = self.screen_rect.centery
def update(self, ai_settings):
"""控制上下移动"""
if ai_settings.moving_up and self.rect.y >=0 :
self.rect.y -= self.ai_settings.moving_speed
if ai_settings.moving_down and self.rect.bottom <= self.screen_rect.bottom:
self.rect.y += self.ai_settings.moving_speed
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image, self.rect)
class Brick(Sprite):
"""一个对砖块进行管理的类"""
def __init__(self, ai_settings, screen) :
super(Brick, self).__init__()
self.screen = screen
self.screen_rect = self.screen.get_rect()
self.ai_settings = ai_settings
self.moving_downward = 1
#绘制砖块图像,并设置其rect属性
self.rect = pygame.Rect(0, 0, ai_settings.brick_width,
ai_settings.brick_height)
#砖块在屏幕右边 纵坐标随机
self.screen_rect = self.screen.get_rect()
self.rect.y = randint(0, self.screen_rect.right)
self.rect.x = self.screen_rect.right - ai_settings.brick_width
#存储砖块的准确位置
self.y = float(self.rect.y)
def draw_brick(self):
"""在指定位置绘制砖块"""
pygame.draw.rect(self.screen, self.ai_settings.brick_color, self.rect)
def update(self):
if self.ai_settings.pause == 1 :
"""向上或者向下移动砖块"""
if self.check_edges():
self.moving_downward *= -1
#更新表示砖块位置
self.rect.y += int(self.moving_downward * self.ai_settings.brick_speed_factor)
self.draw_brick()
def check_edges(self):
"""如果砖块超出上下屏幕,返回True"""
screen_rect = self.screen.get_rect()
if self.rect.bottom >= screen_rect.bottom or self.rect.top <= screen_rect.top:
return True
class Bullet(Sprite):
"""一个对飞船发射的子弹进行管理的类"""
def __init__(self, ai_settings, screen, rocket):
super(Bullet, self).__init__()
self.screen = screen
#在(0,0)处创建一个表示子弹的矩形,在设置正确的位置
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
ai_settings.bullet_height)
self.rect.centery = rocket.rect.centery
self.rect.x = rocket.rect.right
self.color = ai_settings.bullet_color
self.speed_factor = ai_settings.bullet_speed_factor
def update(self, ai_settings):
"""向右移动子弹"""
#更新表示子弹位置的小数值
self.rect.x += self.speed_factor
#更新表示子弹的rect的位置
#self.rect.x = self.x
def draw_bullet(self) :
"""在屏幕上绘制子弹"""
pygame.draw.rect(self.screen, self.color, self.rect)
class GameStats():
"""跟踪游戏的统计信息"""
def __init__(self, ai_settings):
"""初始化统计信息"""
self.ai_settings = ai_settings
self.game_active = False
self.reset_stats()
def reset_stats(self):
"""初始化在游戏运行期间可能变化的统计信息"""
self.missing_shooting_times = 0
class Button():
def __init__(self, ai_settings, screen, msg):
"""初始化按钮的属性"""
self.ai_settings = ai_settings
self.screen = screen
self.screen_rect = self.screen.get_rect()
#设置按钮的尺寸和其它属性
self.width, self.height = 200, 50
self.button_color = (0, 255, 0)
self.text_color = (255, 255, 255)
self.font = pygame.font.SysFont(None, 48)
#创建按钮的rect对象,并使其居中
self.rect = pygame.Rect(0, 0, self.width, self.height)
self.rect.center = self.screen_rect.center
#按钮的标签只需要创建一次
self.prep_msg(msg)
def prep_msg(self, msg):
self.msg_image = self.font.render(msg, True, self.text_color,
self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
self.screen.fill(self.button_color, self.rect)
self.screen.blit(self.msg_image, self.msg_image_rect)
def check_keyup_events(event, ai_settings):
"""响应按键"""
if event.key == pygame.K_UP:
ai_settings.moving_up = False
elif event.key == pygame.K_DOWN:
ai_settings.moving_down = False
def check_keydown_events(event, ai_settings, screen, rocket, bullets):
"""响应按键"""
if event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_UP:
ai_settings.moving_up = True
elif event.key == pygame.K_DOWN:
ai_settings.moving_down = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(ai_settings, screen, rocket)
bullets.add(new_bullet)
def check_events(ai_settings, screen, stats, rocket, bullets, play_button):
"""相应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT :
sys.exit()
#按下箭头
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ai_settings, screen, rocket, bullets)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ai_settings)
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
check_play_button(ai_settings, stats, bullets, play_button, mouse_x, mouse_y)
def check_play_button(ai_settings, stats, bullets, play_button, mouse_x, mouse_y):
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
if button_clicked and not stats.game_active:
ai_settings.initialize_dynamic_settings()
stats.game_active = True
pygame.mouse.set_visible(False)
stats.reset_stats()
bullets.empty()
def check_shooting_brick(ai_settings, stats, brick, bullets):
#如果击中,子弹加速 并且 子弹消失
if pygame.sprite.spritecollide(brick, bullets, True):
ai_settings.increase_speed()
for bullet in bullets:
if bullet.rect.left >= brick.rect.right:
stats.missing_shooting_times +=1
bullets.remove(bullet)
if stats.missing_shooting_times >= ai_settings.permit_missing_times:
stats.game_active = False
pygame.mouse.set_visible(True)
def update_bullets(ai_settings, screen, stats, bullets, brick):
"""检查子弹是否有位于屏幕边缘,并更新子弹的位置"""
for bullet in bullets.sprites():
bullet.update(ai_settings)
check_shooting_brick(ai_settings, stats, brick, bullets)
def update_screen(ai_settings, screen, stats, rocket, brick, bullets, play_button):
"""更新屏幕上的图像,并切换屏幕"""
#每次循环时都重绘屏幕
screen.fill(ai_settings.bg_color)
#绘制飞船
rocket.blitme()
#绘制砖块
brick.draw_brick()
#绘制子弹
for bullet in bullets.sprites():
bullet.draw_bullet()
if not stats.game_active:
play_button.draw_button()
#让最近绘制的屏幕可见
pygame.display.flip()
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Shoot Brick")
#创建一个储存游戏统计信息的实例
stats = GameStats(ai_settings)
#创建一个飞船
rocket = Rocket(ai_settings, screen)
#创建砖块
brick = Brick(ai_settings, screen)
bullets = Group()
play_button = Button(ai_settings, screen, "Play")
#开始游戏的主循环
while True:
"""相应按键和鼠标事件"""
check_events(ai_settings, screen, stats, rocket, bullets, play_button)
if stats.game_active:
brick.update()
update_bullets(ai_settings, screen, stats, bullets, brick)
rocket.update(ai_settings)
"""更新屏幕上的图像,并切换屏幕"""
update_screen(ai_settings, screen, stats, rocket, brick, bullets, play_button)
run_game()