Skip to content

Commit cab8484

Browse files
committed
Update to Chapter 14
1 parent 818811c commit cab8484

File tree

9 files changed

+339
-0
lines changed

9 files changed

+339
-0
lines changed

Chapter 14/14.2-14.3/Rectangle.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import pygame
2+
from pygame.sprite import Sprite
3+
4+
class Rectangle():
5+
"""表示单个矩形的类"""
6+
def __init__(self, ai_settings, screen):
7+
"""初始化矩形并设置其起始位置"""
8+
self.ai_settings = ai_settings
9+
self.screen = screen
10+
self.screen_rect = screen.get_rect()
11+
# 设置矩形的尺寸和其他属性
12+
self.width, self.height = 50, 200
13+
self.rect_color = (0, 255, 0)
14+
# 创建矩形使其居中
15+
self.rect = pygame.Rect(0, 0, self.width, self.height)
16+
self.rect.centery = self.screen_rect.centery
17+
self.rect.right = self.screen_rect.right
18+
self.y = float(self.rect.y)
19+
20+
def draw_rect(self):
21+
# 绘制一个用颜色填充的按钮,再绘制文本
22+
self.screen.fill(self.rect_color, self.rect)
23+
24+
def check_edges(self):
25+
"""如果矩形位于屏幕边缘,就返回True"""
26+
screen_rect = self.screen.get_rect()
27+
if self.rect.bottom >= screen_rect.bottom:
28+
return True
29+
elif self.rect.top <= 0:
30+
return True
31+
else:
32+
return False
33+
34+
def update(self):
35+
self.y += (self.ai_settings.rect_speed_factor *
36+
self.ai_settings.rect_direction)
37+
self.rect.y = self.y
38+
39+
def center_rect(self):
40+
self.center = self.screen_rect.centery

Chapter 14/14.2-14.3/bullet.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pygame
2+
from pygame.sprite import Sprite
3+
4+
class Bullet(Sprite):
5+
"""一个对飞船发射的子弹进行管理的类"""
6+
def __init__(self, ai_settings, screen, ship):
7+
"""在飞船所在位置创建一个子弹对象"""
8+
super().__init__()
9+
self.screen = screen
10+
# 在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
11+
self.rect = pygame.Rect(0, 0, ai_settings.bullet_width,
12+
ai_settings.bullet_height)
13+
self.rect.centery = ship.rect.centery
14+
self.rect.right = ship.rect.right
15+
# 存储用小数表示的子弹位置
16+
self.x = float(self.rect.x)
17+
18+
self.color = ai_settings.bullet_color
19+
self.speed_factor = ai_settings.bullet_speed_factor
20+
def update(self):
21+
"""向上移动子弹"""
22+
# 更新表示子弹位置的小数值
23+
self.x += self.speed_factor
24+
# 更新表示子弹的rect的位置
25+
self.rect.x = self.x
26+
27+
def draw_bullet(self):
28+
"""在屏幕上绘制子弹"""
29+
pygame.draw.rect(self.screen, self.color, self.rect)

Chapter 14/14.2-14.3/button.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pygame.font
2+
3+
class Button():
4+
def __init__(self, ai_settings, screen, msg):
5+
"""初始化按钮的属性"""
6+
self.screen = screen
7+
self.screen_rect = screen.get_rect()
8+
# 设置按钮的尺寸和其他属性
9+
self.width, self.height = 200, 50
10+
self.button_color = (0, 255, 0)
11+
self.text_color = (255, 255, 255)
12+
self.font = pygame.font.SysFont(None, 48)
13+
# 创建按钮的rect对象,并使其居中
14+
self.rect = pygame.Rect(0, 0, self.width, self.height)
15+
self.rect.center = self.screen_rect.center
16+
# 按钮标签只需创建一次
17+
self.prep_msg(msg)
18+
19+
def prep_msg(self, msg):
20+
"""将msg渲染为图像,并使其在按钮上居中"""
21+
self.msg_image = self.font.render(msg, True, self.text_color,
22+
self.button_color)
23+
self.msg_image_rect = self.msg_image.get_rect()
24+
self.msg_image_rect.center = self.rect.center
25+
26+
def draw_button(self):
27+
# 绘制一个用颜色填充的按钮,再绘制文本
28+
self.screen.fill(self.button_color, self.rect)
29+
self.screen.blit(self.msg_image, self.msg_image_rect)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import sys
2+
from time import sleep
3+
import pygame
4+
from random import randint
5+
6+
from bullet import Bullet
7+
from Rectangle import Rectangle
8+
9+
def fire_bullet(ai_settings, screen, ship, bullets):
10+
"""如果还没有达到限制,就发射一颗子弹"""
11+
# 创建新子弹,并将其加入到编组bullets中
12+
if len(bullets) < ai_settings.bullets_allowed:
13+
new_bullet = Bullet(ai_settings, screen, ship)
14+
bullets.add(new_bullet)
15+
16+
def check_keydown_events(event, ai_settings, screen, ship, bullets):
17+
"""响应按键"""
18+
if event.key == pygame.K_DOWN:
19+
ship.moving_down = True
20+
elif event.key == pygame.K_UP:
21+
ship.moving_up = True
22+
elif event.key == pygame.K_SPACE:
23+
fire_bullet(ai_settings, screen, ship, bullets)
24+
elif event.key == pygame.K_q:
25+
sys.exit()
26+
27+
def check_keyup_events(event, ai_settings, screen, stats, ship,
28+
rect, bullets):
29+
"""响应松开"""
30+
if event.key == pygame.K_DOWN:
31+
ship.moving_down = False
32+
elif event.key == pygame.K_UP:
33+
ship.moving_up = False
34+
elif event.key == pygame.K_p and not stats.game_active:
35+
start_game(ai_settings, screen, stats, ship, rect, bullets)
36+
37+
def start_game(ai_settings, screen, stats, ship, rect, bullets):
38+
ai_settings.initialize_dynamic_settings()
39+
# 隐藏光标
40+
pygame.mouse.set_visible(False)
41+
# 重置游戏统计信息
42+
stats.reset_stats()
43+
stats.game_active = True
44+
#清空子弹列表
45+
bullets.empty()
46+
# 矩形居中,并让飞船居中
47+
rect.center_rect()
48+
ship.center_ship()
49+
50+
def check_play_button(ai_settings, screen, stats, play_button,
51+
ship, rect, bullets, mouse_x, mouse_y):
52+
"""在玩家单击play按钮时开始新游戏"""
53+
button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
54+
if button_clicked and not stats.game_active:
55+
start_game(ai_settings, screen, stats, ship, rect, bullets)
56+
57+
def check_events(ai_settings, screen, stats, play_button, ship,
58+
rect, bullets):
59+
"""响应按键和鼠标事件"""
60+
for event in pygame.event.get():
61+
if event.type == pygame.QUIT:
62+
sys.exit()
63+
elif event.type == pygame.KEYDOWN:
64+
check_keydown_events(event, ai_settings, screen, ship, bullets)
65+
elif event.type == pygame.KEYUP:
66+
check_keyup_events(event, ai_settings, screen, stats, ship,
67+
rect, bullets)
68+
elif event.type == pygame.MOUSEBUTTONDOWN:
69+
mouse_x, mouse_y = pygame.mouse.get_pos()
70+
check_play_button(ai_settings, screen, stats, play_button,
71+
ship, rect, bullets, mouse_x, mouse_y)
72+
73+
def update_screen(ai_settings, screen, stats, ship, rect, bullets,
74+
play_button):
75+
"""更新屏幕上的图像,并切换到新屏幕"""
76+
# 每次循环时都重绘屏幕
77+
screen.fill(ai_settings.bg_color)
78+
ship.blitme()
79+
# 在飞船和外星人后面重绘所有子弹
80+
for bullet in bullets.sprites():
81+
bullet.draw_bullet()
82+
rect.draw_rect()
83+
# 如果游戏处于非活动状态,就绘制Play按钮
84+
if not stats.game_active:
85+
play_button.draw_button()
86+
# 让最近绘制的屏幕可见
87+
pygame.display.flip()
88+
89+
def check_bullet_rect_collisions(ai_settings, screen, ship, rect, bullets):
90+
"""响应子弹和矩形的碰撞"""
91+
collision = pygame.sprite.spritecollideany(rect, bullets)
92+
# 改变矩形的颜色,删除子弹
93+
if collision:
94+
ai_settings.increase_speed()
95+
bullets.remove(collision)
96+
rect.rect_color = (randint(0, 255), randint(0, 255), randint(0, 255))
97+
98+
def update_bullets(ai_settings, screen, stats, ship, rect, bullets):
99+
"""更新子弹的位置,并删除已消失子弹"""
100+
# 更新子弹位置
101+
bullets.update()
102+
# 删除已消失子弹
103+
for bullet in bullets.copy():
104+
if bullet.rect.right >= screen.get_rect().right:
105+
if stats.ships_left > 0:
106+
stats.ships_left -= 1
107+
bullets.remove(bullet)
108+
else:
109+
stats.game_active = False
110+
pygame.mouse.set_visible(True)
111+
check_bullet_rect_collisions(ai_settings, screen, ship, rect, bullets)
112+
113+
def change_rect_direction(ai_settings, rect):
114+
ai_settings.rect_direction *= -1
115+
116+
def check_rect_edges(ai_settings, rect):
117+
if rect.check_edges():
118+
change_rect_direction(ai_settings, rect)
119+
120+
def update_rect(ai_settings, stats, screen, ship, rect, bullets):
121+
check_rect_edges(ai_settings, rect)
122+
rect.update()
123+

Chapter 14/14.2-14.3/game_stats.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class GameStats():
2+
"""跟踪游戏的统计信息"""
3+
def __init__(self, ai_settings):
4+
"""初始化统计信息"""
5+
self.ai_settings = ai_settings
6+
self.reset_stats()
7+
# 游戏刚启动时处于活动状态
8+
self.game_active = False
9+
10+
def reset_stats(self):
11+
"""初始化在游戏运行期间可能变化的统计信息"""
12+
self.ships_left = self.ai_settings.ship_limit

Chapter 14/14.2-14.3/images/ship.bmp

8.49 KB
Binary file not shown.

Chapter 14/14.2-14.3/settings.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class Settings():
2+
"""存储 外星人入侵 的所有设置的类"""
3+
def __init__(self):
4+
"""初始化游戏设置"""
5+
# 屏幕设置
6+
self.screen_width = 800
7+
self.screen_height = 600
8+
self.bg_color = (230, 230, 230)
9+
# 飞船设置
10+
self.ship_limit = 3
11+
# 子弹设置
12+
self.bullet_width = 15
13+
self.bullet_height = 3
14+
self.bullet_color = 60, 60, 60
15+
self.bullets_allowed = 3
16+
# 以什么样的速度加快游戏节奏
17+
self.speedup_scale = 1.1
18+
self.initialize_dynamic_settings()
19+
20+
def initialize_dynamic_settings(self):
21+
"""初始化随游戏进行而变化的设置"""
22+
self.ship_speed_factor = 1.5
23+
self.bullet_speed_factor = 3
24+
self.rect_speed_factor = 0.3
25+
self.rect_direction = 1
26+
27+
def increase_speed(self):
28+
"""提高速度设置"""
29+
self.ship_speed_factor *= self.speedup_scale
30+
self.bullet_speed_factor *= self.speedup_scale
31+
self.rect_speed_factor *= self.speedup_scale

Chapter 14/14.2-14.3/ship.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import pygame
2+
3+
class Ship():
4+
def __init__(self, ai_settings, screen):
5+
"""初始化飞船并设置其初始位置"""
6+
self.screen = screen
7+
self.ai_settings = ai_settings
8+
# 加载飞船图像并获取其外接矩形
9+
self.image = pygame.image.load('images/ship.bmp')
10+
self.rect = self.image.get_rect()
11+
self.screen_rect = screen.get_rect()
12+
# 将每艘新飞船放在屏幕底部中央
13+
self.rect.centery = self.screen_rect.centery
14+
self.rect.left = self.screen_rect.left
15+
# 在飞船的属性center中存储小数值
16+
self.center = float(self.rect.centery)
17+
# 移动标志
18+
self.moving_up = False
19+
self.moving_down = False
20+
21+
def update(self):
22+
"""根据移动标志调整飞船的位置"""
23+
# 更新飞船的center值,而不是rect
24+
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
25+
self.center += self.ai_settings.ship_speed_factor
26+
if self.moving_up and self.rect.top > 0:
27+
self.center -= self.ai_settings.ship_speed_factor
28+
# 根据self.center更新rect对象
29+
self.rect.centery = self.center
30+
31+
def blitme(self):
32+
"""在指定位置绘制飞船"""
33+
self.screen.blit(self.image, self.rect)
34+
35+
def center_ship(self):
36+
"""让飞船在屏幕居中"""
37+
self.center = self.screen_rect.centery

Chapter 14/14.2-14.3/shooting.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import sys
2+
import pygame
3+
4+
from settings import Settings
5+
from game_stats import GameStats
6+
from button import Button
7+
from ship import Ship
8+
import game_functions as gf
9+
from Rectangle import Rectangle
10+
11+
def run_game():
12+
# 初始化游戏、设置和屏幕对象
13+
pygame.init()
14+
ai_settings = Settings()
15+
screen = pygame.display.set_mode(
16+
(ai_settings.screen_width, ai_settings.screen_height))
17+
pygame.display.set_caption("Shooting")
18+
# 创建Play按钮
19+
play_button = Button(ai_settings, screen, "Play")
20+
# 创建一个用于存储游戏统计信息的实例
21+
stats = GameStats(ai_settings)
22+
# 创建一艘飞船、一个子弹编组和一个矩形
23+
ship = Ship(ai_settings, screen)
24+
bullets = pygame.sprite.Group()
25+
rect = Rectangle(ai_settings, screen)
26+
27+
# 开始游戏主循环
28+
while True:
29+
gf.check_events(ai_settings, screen, stats, play_button, ship,
30+
rect, bullets)
31+
if stats.game_active:
32+
ship.update()
33+
gf.update_bullets(ai_settings, screen, stats, ship, rect, bullets)
34+
gf.update_rect(ai_settings, stats, screen, ship, rect, bullets)
35+
gf.update_screen(ai_settings, screen, stats, ship, rect, bullets,
36+
play_button)
37+
38+
run_game()

0 commit comments

Comments
 (0)