《Python编程从人们到实践》cha12 cha13

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
		
		#在(00)处创建一个表示子弹的矩形,在设置正确的位置
		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()

在这里插入图片描述

发布了20 篇原创文章 · 获赞 6 · 访问量 4631

猜你喜欢

转载自blog.csdn.net/better_eleven/article/details/104638905