python
$ python -m pip install --user pygame
1、画游戏框
python
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
python
import sys
import pygame
from settings import Settings
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
# 绘制
def _update_screen(self):
# 绘制背景
self.screen.fill(self.settings.bg_color)
# 绘制课件
pygame.display.flip()
# 运行
def run_game(self):
while True:
self._update_screen()
AlienInvasion().run_game()
这笔记是我把程序写完才落成笔记的,复盘
这里闪退,百思不得其解
python
在 Pygame 中,如果不处理事件(如关闭窗口事件),程序会因为无法响应这些事件而立即退出。
问题分析:
缺少事件处理:你的 run_game 方法中没有处理任何事件,包括关闭窗口的事件。因此,当窗口关闭事件发生时,程序没有机会响应,导致立即退出。
缺少必要的更新:虽然你有 _update_screen 方法来更新屏幕,但没有处理游戏逻辑和用户输入。
2、造飞机
在ship类定义飞机属性
python
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
self.ship = Ship(self)
# 绘制
def _update_screen(self):
# 绘制背景
self.screen.fill(self.settings.bg_color)
# 绘制小飞船
self.ship.blitme()
# 绘制课件
pygame.display.flip()
AlienInvasion().run_game()
python
# 管理飞船类
class Ship:
def __init__(self, ai_name):
# 飞船和初始位置
self.screen = ai_name.screen
self.screen_rect = ai_name.screen.get_rect()
# 加载飞船图形
self.image = pygame.image.load("ship.bmp")
self.rect = self.image.get_rect()
def blitme(self):
# 绘制飞船
self.screen.blit(self.image, self.rect)
def center_ship(self):
# 生成飞船在居中底端
self.rect.midbottom=self.screen_rect.midbottom
self.x=float(self.rect.x)
3、开飞机
python
import sys
import pygame
from settings import Settings
from ship import Ship
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
self.ship = Ship(self)
def run_game(self):
while True:
self._check_event()
self.ship.update()
self._update_screen()
# 监控外设
def _check_event(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_key_down(event)
elif event.type == pygame.KEYUP:
self._check_key_up(event)
# 按键按下监控
def _check_key_down(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
if event.key == pygame.K_LEFT:
self.ship.moving_left = True
if event.key == pygame.K_UP:
self.ship.moving_up = True
if event.key == pygame.K_DOWN:
self.ship.moving_down = True
if event.key == pygame.K_SPACE:
self.bullet.launch = True
# 按键松开监控
def _check_key_up(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
if event.key == pygame.K_UP:
self.ship.moving_up = False
if event.key == pygame.K_DOWN:
self.ship.moving_down = False
def run_game(self):
while True:
self._check_event()
self.ship.update()
self._update_screen()
AlienInvasion().run_game()
python
import pygame
# 管理飞船类
class Ship:
def __init__(self, ai_name):
# 飞船和初始位置
self.screen = ai_name.screen
self.screen_rect = ai_name.screen.get_rect()
# 加载飞船图形
self.image = pygame.image.load("C:/Users/MGL/Desktop/py_test/Alien/ship.bmp")
self.rect = self.image.get_rect()
# 底部中央
self.rect.midbottom = self.screen_rect.midbottom
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
# 持续移动 并设置限制
def update(self):
if self.moving_right and self.rect.right < self.screen_rect.right:
self.rect.x += 1
elif self.moving_left and self.rect.left > self.screen_rect.left:
self.rect.x -= 1
elif self.moving_up and self.rect.y > self.screen_rect.top:
# self.screen_rect.top为0
self.rect.y -= 1
elif self.moving_down and self.rect.y < self.screen_rect.bottom - 100:
self.rect.y += 1
4、造导弹
python
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
self.ship = Ship(self)
self.bullet = Bullet(self)
def run_game(self):
while True:
self._check_event()
self.ship.update()
self.bullet.bullets.update()
# self._update_aliens()
self._update_screen()
# 监控外设
def _check_event(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_key_down(event)
elif event.type == pygame.KEYUP:
self._check_key_up(event)
# 按键按下监控
def _check_key_down(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
if event.key == pygame.K_LEFT:
self.ship.moving_left = True
if event.key == pygame.K_UP:
self.ship.moving_up = True
if event.key == pygame.K_DOWN:
self.ship.moving_down = True
if event.key == pygame.K_SPACE:
self.bullet.launch = True
# 按键松开监控
def _check_key_up(self, event):
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
if event.key == pygame.K_LEFT:
self.ship.moving_left = False
if event.key == pygame.K_UP:
self.ship.moving_up = False
if event.key == pygame.K_DOWN:
self.ship.moving_down = False
if event.key == pygame.K_SPACE:
self.bullet.launch = False
# 绘制
def _update_screen(self):
# 绘制背景
self.screen.fill(self.settings.bg_color)
# 绘制小飞船
self.ship.blitme()
self.bullet.launch_bullet(self)
# 绘制课件
pygame.display.flip()
AlienInvasion().run_game()
python
# 设置类
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 子弹设置
self.bullet_speed = 2
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullet_allowed = 5
python
import pygame
from pygame.sprite import Sprite
# 管理发射子弹类
class Bullet(Sprite):
def __init__(self, ai_name):
super().__init__()
self.screen = ai_name.screen
self.settings = ai_name.settings
self.color = self.settings.bullet_color
# 连续射击标识符
self.launch = False
# 绘画子弹
self.rect = pygame.Rect(
0, 0, self.settings.bullet_width, self.settings.bullet_height
)
# 子弹在飞船上面
self.rect.midtop = ai_name.ship.rect.midtop
# 子弹位置
self.y = float(self.rect.y)
# 装弹弹夹
self.bullets = pygame.sprite.Group()
def update(self):
# 子弹移动
self.y -= self.settings.bullet_speed
self.rect.y = self.y
# 装弹
def _fire_bullet(self, alien):
if len(self.bullets) < self.settings.bullet_allowed:
new_bullet = Bullet(alien)
self.bullets.add(new_bullet)
# 连续发射
def launch_bullet(self, alien):
if self.launch:
self._fire_bullet(alien)
for bullet in self.bullets.sprites():
# 删除触顶的子弹
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
bullet.draw_bullet()
# 绘制子弹
def draw_bullet(self):
pygame.draw.rect(self.screen, self.color, self.rect)
5、出现敌机
python
# 设置类
class Settings:
def __init__(self):
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230, 230, 230)
# 子弹设置
self.bullet_speed = 2
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = (60, 60, 60)
self.bullet_allowed = 5
self.alien_sheep = 0.3
self.fleet_drop_speed = 1
# # 1 右移 -1 左移
self.fleet_drop_direction = 1
python
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
self.ship = Ship(self)
self.bullet = Bullet(self)
self.alien = Alien(self)
def run_game(self):
while True:
self._check_event()
self.ship.update()
self.bullet.bullets.update()
self._update_aliens()
self._update_screen()
# 忽略其他代码
def _create_fleet(self):
alien_n = Alien(self)
alien_width = self.alien.rect.width
alien_height = self.alien.rect.height
# 一行敌机占多少宽度 给屏幕两边留有移动空间
available_space_x = self.settings.screen_width - (2 * alien_width)
# 计算可以放多少量敌机 (每个外星人间隔一个外星人宽度的距离)所以 2 * alien_width
number_aliens_x = available_space_x // (2 * alien_width)
# 计算屏幕可容纳多少行
ship_height = self.ship.rect.height
# 敌机占据的高度
available_space_y = (
self.settings.screen_height - (3 * alien_height) - ship_height
)
# 间隔有个敌机
number_rows = available_space_y // (2 * alien_height)
# 创建敌机
for row_num in range(number_rows):
for alien_num in range(number_aliens_x):
self._create_alien(alien_num, row_num, alien_width)
def _create_alien(self, alien_num, row_num, alien_width):
alien = Alien(self)
# 2 * alien_width * alien_num 定位起始位置
alien.x = alien_width + 2 * alien_width * alien_num
alien.rect.x = alien.x
alien.rect.y = alien.rect.height + 2 * alien.rect.height * row_num
self.alien.aliens.add(alien)
def _update_aliens(self):
self.alien._check_fleet_edges()
self.alien.aliens.update()
def _update_bullets(self):
# 打完敌机再来一群
if not self.alien.aliens:
# 清空弹夹并新建敌机
self.bullet.bullets.empty()
self._create_fleet()
# 绘制
def _update_screen(self):
# 绘制背景
self.screen.fill(self.settings.bg_color)
# 绘制小飞船
self.ship.blitme()
self.bullet.launch_bullet(self)
self.alien.aliens.draw(self.screen)
self._update_bullets()
# 绘制课件
pygame.display.flip()
AlienInvasion().run_game()
python
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
def __init__(self, ai_name):
super().__init__()
self.screen = ai_name.screen
self.screen_rect = ai_name.screen.get_rect()
self.image = pygame.image.load("alien.bmp")
self.rect = self.image.get_rect()
self.settings = ai_name.settings
# 敌机 最初位置
self.rect.x = self.rect.width
self.rect.y = self.rect.height
self.x = float(self.rect.x)
self.aliens = pygame.sprite.Group()
def update(self):
# 左移右移
self.x += self.settings.alien_sheep * self.settings.fleet_drop_direction
self.rect.x = self.x
def _check_fleet_edges(self):
# 有外星人到达边缘时采取相应的措施。
# self.aliens.sprites() 遍历
for alien in self.aliens.sprites():
if alien._check_edges():
self._change_fleet_direction()
break
def _check_edges(self):
# 如果外星人位于屏幕边缘,就返回True
# 获取游戏框信息
screen_rect = self.screen.get_rect()
# 判断是否有敌机超出游戏框范围
if self.rect.right >= screen_rect.right or self.rect.left <= 0:
return True
def _change_fleet_direction(self):
# 将整群外星人下移,并改变它们的方向
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
alien.rect.y += 1
self.settings.fleet_drop_direction *= -1
6、打敌机
敌机打完重新开局,敌机接触到底部重新开局
python
# pygame.sprite.groupcollide(group1, group2, dokill1, dokill2, collided=None)
# group1: 第一个精灵组。通常是一个 pygame.sprite.Group 对象。
# group2: 第二个精灵组。通常也是一个 pygame.sprite.Group 对象。
# dokill1: 一个布尔值,表示是否在发生碰撞后从 group1 中移除发生碰撞的精灵。如果设置为 True,则发生碰撞的精灵会被自动删除。
# dokill2: 一个布尔值,表示是否在发生碰撞后从 group2 中移除发生碰撞的精灵。如果设置为 True,则发生碰撞的精灵会被自动删除。
# collided: 可选参数,一个函数,用于确定两个精灵是否发生碰撞。默认情况下,Pygame 使用矩形碰撞检测。如果提供了一个函数,该函数应该接受两个精灵作为参数,并返回一个布尔值。
pygame.sprite.spritecollideany 是 Pygame 中用于检测单个精灵与一个精灵组之间是否发生碰撞的函数
sprite: 单个精灵对象。通常是一个 pygame.sprite.Sprite 的子类实例。
group: 精灵组。通常是一个 pygame.sprite.Group 对象。
collided: 可选参数,一个函数,用于确定两个精灵是否发生碰撞。默认情况下,Pygame 使用矩形碰撞检测。如果提供了一个函数,该函数应该接受两个精灵作为参数,并返回一个布尔值。
如果 sprite 与 group 中的任何一个精灵发生碰撞,返回 True;否则返回 False。
python
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
import time
class AlienInvasion:
# 忽略其他代码
def _update_aliens(self):
self.alien._check_fleet_edges()
self.alien.aliens.update()
# 与敌机碰撞判断
if pygame.sprite.spritecollideany(self.ship, self.alien.aliens):
self._ship_hit()
# 检查敌机是否到底部
self._check_aliens_bottom()
def _update_bullets(self):
# 检查是否击中敌机 如果是 则删除
#
collisions = pygame.sprite.groupcollide(
self.bullet.bullets, self.alien.aliens, True, True
)
# 打完敌机再来一群
if not self.alien.aliens:
# 清空弹夹并新建敌机
self.bullet.bullets.empty()
self._create_fleet()
def _ship_hit(self):
self.alien.aliens.empty()
self.bullet.bullets.empty()
self._create_fleet()
self.ship.center_ship()
time.sleep(0.5)
def _check_aliens_bottom(self):
# 检查是否有外星人到达了屏幕底端
screen_rect = self.screen.get_rect()
for alien in self.alien.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
# 像飞船被撞到一样处理。
self._ship_hit()
break
7、记分
python
class GameStats:
def __init__(self, ai_name):
self.settings = ai_name.settings
self.reset_stats()
def reset_stats(self):
self.score = 0
python
import pygame.font
class ScoreBoard:
# 显示得分信息的类
def __init__(self, ai_game):
# 初始化显示得分涉及的属性
self.screen = ai_game.screen
self.screen_rect = self.screen.get_rect()
self.settings = ai_game.settings
self.stats = ai_game.stats
# 显示得分信息时使用的字体设置
self.text_color = (30, 30, 30)
self.font = pygame.font.SysFont(None, 48)
# 准备初始得分图像
self.prep_score()
def prep_score(self):
# 将得分转换为一幅渲染的图像
score_str = str(self.stats.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 - 20
self.score_rect.top = 20
def show_score(self):
# 在屏幕上显示得分
self.screen.blit(self.score_image, self.score_rect)
python
import sys
import pygame
from settings import Settings
from ship import Ship
from bullet import Bullet
from alien import Alien
from game_stats import GameStats
import time
from score_board import ScoreBoard
class AlienInvasion:
def __init__(self):
pygame.init()
self.settings = Settings()
# 设置边框 创建一个屏幕对象,并设置其宽度和高度。
self.screen = pygame.display.set_mode(
(self.settings.screen_width, self.settings.screen_height)
)
# 设置窗口标题
pygame.display.set_caption("外星战机游戏")
self.ship = Ship(self)
self.bullet = Bullet(self)
self.alien = Alien(self)
self.stats = GameStats(self)
self.score = ScoreBoard(self)
# 忽略部分代码
def _update_bullets(self):
# 检查是否击中敌机 如果是 则删除
collisions = pygame.sprite.groupcollide(
self.bullet.bullets, self.alien.aliens, True, True
)
# 打完敌机再来一群
if not self.alien.aliens:
# 清空弹夹并新建敌机
self.bullet.bullets.empty()
self._create_fleet()
if collisions:
self.stats.score += self.settings.alien_points
self.score.prep_score()
def _ship_hit(self):
# self.stats.ship_left -= 1
self.alien.aliens.empty()
self.bullet.bullets.empty()
self._create_fleet()
self.ship.center_ship()
self.stats.score = 0
self.score.prep_score()
time.sleep(0.5)
# 绘制
def _update_screen(self):
# 绘制背景
self.screen.fill(self.settings.bg_color)
# 绘制小飞船
self.ship.blitme()
self.bullet.launch_bullet(self)
self.alien.aliens.draw(self.screen)
self._update_bullets()
# 显示得分
self.score.show_score()
# 绘制课件
pygame.display.flip()
AlienInvasion().run_game()
8、番外
- 按键
python
import pygame.font
class Button:
def __init__(self, ai_name, msg):
self.screen = ai_name.screen
self.screen_rect = ai_name.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):
# 将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)
python
# from button import Button
#self.play_button = Button(self, "Play")
## 绘制按钮
# self.play_button.draw_button()
## 隐藏鼠标光标
# pygame.mouse.set_visible(false)