【Python编程:从入门到实践】第十三章练习题

13-1  星星 :找一幅星星图像,并在屏幕上显示一系列整齐排列的星星。
13-2  更逼真的星星 :为让星星的分布更逼真,可随机地放置星星。

合并为一个程序“满天星”,效果图如下:

代码:

settings.py(定义一些必须的基本属性和初始值)

class Settings():
	def __init__(self):
		self.screen_width = 1200
		self.screen_height = 600

star.py(为了实现星星大小不一,使用smoothscale进行缩放,缩放值随机)

import pygame
from pygame.sprite import Sprite
from random import randint

class Star(Sprite):
	def __init__(self):
		# 继承父类
		super(Star, self).__init__()
		# 加载图片
		self.image = pygame.image.load('../images/star.png')
		# 平滑缩放到(宽,高)
		random_number = randint(10, 30)
		self.image = pygame.transform.smoothscale(self.image, (random_number, random_number))
		self.rect = self.image.get_rect()

game_functions.py(可修改数字5来控制星星显示疏密)

from star import Star
from random import randint

def create_stars(settings, stars):
	star = Star()
	# 数字5(越大越少)控制疏密
	number_stars_x = int(settings.screen_width / (5 * star.rect.width))
	number_stars_y = int(settings.screen_height / (5 * star.rect.height))
	for number_y in range(number_stars_y):
		for number_x in range(number_stars_x):
			random_number_x = randint(0, settings.screen_width)
			random_number_y = randint(0, settings.screen_height)
			star = Star()
			# # 规则排列
			# star.rect.x = 2 * star.rect.width * number_x
			# star.rect.y = 2 * star.rect.height * number_y
			# 不规则排列
			star.rect.x = random_number_x
			star.rect.y = random_number_y
			stars.add(star)

babysbreath.py(主函数)

import pygame
import sys
from pygame.sprite import Group
from settings import Settings
import game_functions as gf

def run_game():
	pygame.init()
	settings = Settings()
	screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))
	# # 全屏显示
	# screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
	pygame.display.set_caption('满天星')

	stars = Group()
	gf.create_stars(settings, stars)
	stars.draw(screen)

	while True:
		# 需加事件,不然秒退
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				sys.exit()
		# 让最近绘制的屏幕可见
		pygame.display.flip()

run_game()

13-4  连绵细雨 :修改为完成练习 13-3 而编写的代码,使得一行雨滴消失在屏幕底端后,屏幕顶端又出现一行新雨滴,并开始往下落。

优化为“下雨天”,效果如下图:

代码:

settings.py(定义一些必须的基本属性和初始值)

class Settings():
	def __init__(self):
		self.screen_width = 1200
		self.screen_height = 600

raindrop.py(为了效果更逼真,雨滴落下速度使用随机数random_number / 5)

import pygame
from pygame.sprite import Sprite
from random import randint

class Raindrop(Sprite):
	def __init__(self):
		# 继承父类
		super(Raindrop, self).__init__()
		# 加载图片
		self.image = pygame.image.load('../images/raindrop.png')
		# 平滑缩放到(宽,高)
		random_number = randint(10, 30)
		self.image = pygame.transform.smoothscale(self.image, (random_number, random_number))
		self.rect = self.image.get_rect()
	def update(self):
		"""向下移动雨滴"""
		random_number = randint(1, 10)
		self.rect.y += random_number / 5

game_functions.py(使用random_number_y = randint(0, 300),让雨从半空飘落)

from raindrop import Raindrop
from random import randint

def create_raindrops(settings, raindrops):
	"""创建很多雨滴"""
	raindrop = Raindrop()
	# 数字4(越大越少)控制稀疏
	number_raindrops_x = int(settings.screen_width / (4 * raindrop.rect.width))
	number_raindrops_y = int(settings.screen_height / (4 * raindrop.rect.height))
	for number_y in range(number_raindrops_y):
		for number_x in range(number_raindrops_x):
			create_raindrop(raindrops)
def update_raindrops(screen, raindrops):
	"""更新所有雨滴的位置"""
	screen_rect = screen.get_rect()
	for raindrop in raindrops.sprites():
		if raindrop.rect.bottom >= screen_rect.bottom:
			raindrops.remove(raindrop)
			create_raindrop(raindrops)
	raindrops.update()
def create_raindrop(raindrops):
	"""创建单个雨滴"""
	random_number_x = randint(0, 1200)
	random_number_y = randint(0, 300)
	raindrop = Raindrop()
	# 不规则排列
	raindrop.rect.x = random_number_x
	raindrop.rect.y = random_number_y
	raindrops.add(raindrop)

rain.py(主函数)

import pygame
import sys
from pygame.sprite import Group
from settings import Settings
import game_functions as gf

def run_game():
	pygame.init()
	settings = Settings()
	screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))	
	pygame.display.set_caption('下雨天')

	raindrops = Group()
	gf.create_raindrops(settings, raindrops)	

	while True:
		# 设置背景色(不设置会导致雨滴整个拖下来)
		screen.fill((125, 125, 125))
		# 需加事件,不然秒退
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				sys.exit()
		gf.update_raindrops(screen, raindrops)
		raindrops.draw(screen)
		# 让最近绘制的屏幕可见
		pygame.display.flip()

run_game()

13-5  抓球 :创建一个游戏,在屏幕底端放置一个玩家可左右移动的角色。让一个球出现在屏幕顶端,且水平位置是随机的,并让这个球以固定的速度往下落。如果角色与球发生碰撞(表示将球抓住了),就让球消失。每当角色抓住球或球因抵达屏幕底端而消失后,都创建一个新球。
13-6  游戏结束 :在为完成练习 13-5 而编写的代码中,跟踪玩家有多少次未将球接着。在未接着球的次数到达三次后,结束游戏。

合并为一个“抓球游戏”,效果图如下(详细查看https://jingyan.baidu.com/article/597a0643bcb5a5712a524311.html):

代码:

settings.py(定义一些必须的基本属性和初始值)

class Settings():
	def __init__(self):
		self.screen_width = 1200
		self.screen_height = 600
		self.bg_color = (230, 230, 230)
		# 人移动速度
		self.people_move_speed = 1.5
		# 球落下速度
		self.ball_drop_speed = 0.5

		#统计信息设置 
		# 游戏得分
		self.game_score = 0
		# 接到一个球多少分
		self.ball_score = 10
		# 丢失多少球结束游戏
		self.ball_miss_number = 3

ball.py(因为有两处用到球图片,只是大小不一致,定义一个缩放函数scale)

import pygame
from pygame.sprite import Sprite

class Ball(Sprite):
	def __init__(self, settings):
		super(Ball, self).__init__()
		self.settings = settings
		self.image = pygame.image.load('../images/ball.png')
		self.rect = self.image.get_rect()
		
		self.center = float(self.rect.centerx)
	def scale(self, multiple):
		# 图片缩放
		self.image = pygame.transform.smoothscale(self.image, (multiple, multiple))
	def update(self):
		# 球落下
		self.center += self.settings.ball_drop_speed
		self.rect.centery = self.center

people.py(self.center = float(self.rect.centerx),因为设置的移动速度存在小数位,这里要加上float,不然效果会有问题)

import pygame

class People():
	def __init__(self, settings, screen):
		self.settings = settings
		self.screen = screen
		self.image = pygame.image.load('../images/people.png')
		self.rect = self.image.get_rect()
		# 人初始位置
		self.screen_rect = self.screen.get_rect()
		self.rect.centerx = self.screen_rect.centerx
		self.rect.bottom = self.screen_rect.bottom
		 # 在飞船的属性 center 中存储小数值(不然会导致小数位不起作用)
		self.center = float(self.rect.centerx)
		# 移动标志
		self.moving_right = False
		self.moving_left = False
	def update(self):
	    """ 根据移动标志调整人的位置 """
	    # 更新人的 center 值,而不是 rect
	    if self.moving_right and self.rect.right < self.screen_rect.right:
	        self.center += self.settings.people_move_speed
	    if self.moving_left and self.rect.left > 0:
	        self.center -= self.settings.people_move_speed
	    # 根据 self.center 更新 rect 对象
	    self.rect.centerx = self.center
	def blitme(self):
		"""绘制人"""
		# blit绘制到缓冲区,不显示于屏幕(需要flip才能显示到屏幕)
		self.screen.blit(self.image, self.rect)

button.py

import pygame.font
class Button():
	def __init__(self, screen, msg):
		"""初始化按钮的属性"""
		self.screen = screen
		self.screen_rect = screen.get_rect()
		# 设置按钮的尺寸和其他属性
		self.width, self.height = 150, 50
		self.button_color = (125, 125, 125)
		self.text_color = (255, 255, 255)
		self.font = pygame.font.SysFont(None, 30)
		# 创建按钮的rect对象,并使其居中
		self.rect = pygame.Rect(0, 0, self.width, self.height)
		# 按钮的标签只需创建一次
		self.prep_msg(msg)
	def prep_msg(self, msg):
		"""将msg渲染为图像,并使其在按钮上居中"""
		self.rect.center = self.screen_rect.center
		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)

scoreboard.py(由于绘制左上角的球图片缩小了,所以球之间的间距也要按比例缩小“ball.rect.x”)

import pygame
from pygame.sprite import Group
from ball import Ball
class Scoreboard():
	"""docstring for Scoreboard"""
	def __init__(self, settings, screen):
		self.settings = settings
		self.screen = screen
		self.screen_rect = screen.get_rect()
		# 球缩放值
		self.scaleValue = 20
		# 显示得分信息时使用的字体设置
		self.text_color = (30, 30, 30)
		self.font = pygame.font.SysFont(None, 48)
		
		self.prep_score()
		self.prep_balls()

	def prep_score(self):
		"""将得分转换为渲染的图像"""
		rounded_score = int(round(self.settings.game_score, -1))
		score_str = '{:,}'.format(rounded_score)
		self.score_image = self.font.render(score_str, True, self.text_color, self.settings.bg_color)
		self.score_rect = self.score_image.get_rect()
		self.score_rect.right = self.screen_rect.right - 10
		self.score_rect.top = 10		

	def prep_balls(self):
		# 显示还能丢失多少球
		self.balls = Group()
		for number in range(self.settings.ball_miss_number):
			ball = Ball(self.settings)

			# 缩放球大小并赋值位置
			ball.scale(self.scaleValue)
			ball.rect.x = 10 + ball.rect.width * (self.scaleValue / ball.rect.width) * number
			ball.rect.y = 10

			self.balls.add(ball)

	def show_score(self):
		self.balls.draw(self.screen)
		self.screen.blit(self.score_image, self.score_rect)

game_functions.py

import sys
import pygame
from ball import Ball
from button import Button
from random import randint

# 事件
def check_events(people):
    """ 响应按键和鼠标事件 """
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, people)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, people)
def check_keydown_events(event, people):
    """ 响应按键 """
    if event.key == pygame.K_RIGHT:
        people.moving_right = True
    elif event.key == pygame.K_LEFT:
        people.moving_left = True
    elif event.key == pygame.K_q:
        sys.exit()
def check_keyup_events(event, people):
    """ 响应松开 """
    if event.key == pygame.K_RIGHT:
        people.moving_right = False
    elif event.key == pygame.K_LEFT:
        people.moving_left = False

# 球
def update_balls(settings, balls, people, screen, scoreboard):
	"""更新球的位置"""
    # 创建球(一直1个)
	if len(balls) == 0:
		create_ball(settings, balls, screen)

    # 球碰撞到人,就消失
	if pygame.sprite.spritecollideany(people, balls):
		balls.empty()
		settings.game_score += settings.ball_score
		scoreboard.prep_score()
    # 球到底则消失
	screen_rect = screen.get_rect()
	for ball in balls.sprites():
		if ball.rect.bottom >= screen_rect.bottom:
			balls.remove(ball)
			# 减少可落下的数量并更新显示球数量
			settings.ball_miss_number -= 1
			scoreboard.prep_balls()
	# 当球未接住的数据达到设置的数量,则绘制“Game Over”并结束游戏
	if settings.ball_miss_number == 0:
		button = Button(screen, 'Game Over')
		button.draw_button()
		return
	balls.update()
def create_ball(settings, balls, screen):
	"""创建单个球"""
	ball = Ball(settings)
	
	# 球初始位置(顶部,水平位置随机)
	screen_rect = screen.get_rect()
	number_x = randint(0, settings.screen_width)
	ball.rect.centerx = number_x
	ball.rect.top = screen_rect.top

	balls.add(ball)

catchball.py(主函数)

import pygame
from pygame.sprite import Group
from settings import Settings
import game_functions as gf
from people import People
from scoreboard import Scoreboard

def run_game():
	pygame.init()
	settings = Settings()
	# screen = pygame.display.set_mode((settings.screen_width, settings.screen_height))
	# 全屏显示
	screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
	pygame.display.set_caption('抓球')

	# 创建人和球
	people = People(settings, screen)	
	# 创建球的编组
	balls = Group()
	# 创建记分牌
	scoreboard = Scoreboard(settings, screen)

	while True:
		# 设置背景色
		screen.fill(settings.bg_color)
		# 检查玩家输入
		gf.check_events(people)
		# 更新人位置并绘制到屏幕
		people.update()
		people.blitme()
		# 更新球位置并绘制到屏幕
		gf.update_balls(settings, balls, people, screen, scoreboard)
		balls.draw(screen)
		# 显示得分
		scoreboard.show_score()
		
		# 让最近绘制的屏幕可见
		pygame.display.flip()

run_game()

  Tips:所使用的图标可自行上“https://www.iconfont.cn/”查找。

发布了31 篇原创文章 · 获赞 17 · 访问量 9706

猜你喜欢

转载自blog.csdn.net/king0964/article/details/103574353