之前碰了Qt,winforms,wpf. 主要是想接触一下GUI
我都不知道该干啥了
这个项目是在《Python编程从入门到实践》上摘写的 个人推荐这本书还有同系列的蟒蛇书
后面想写写matplotlib和其他的python库,不过Python这个语言是真的舒服.
pygame介绍
1.创建界面
import sys
import pygame
class AlienInvasions:
''''管理游戏资源和行为的类'''
def __init__(self):
'''初始化游戏并创建游戏资源'''
pygame.init()
self.screen = pygame.display.set_mode((1200,800))
pygame.display.set_caption("Alien Invasion")
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#让最近绘制的屏幕可见
pygame.display.flip()
if __name__ == '__main__':
#创建游戏实例并运行
ai = AlienInvasions()
ai.run_game()
pygame.init() 初始化背景设置 让pygame正常工作
pygame.display.set_mode() 创建一个显示窗口,游戏的所有图形元素都将在其中绘制 (1200,800)是一个元组 宽1200像素 高800像素
赋给self.screen的对象是一个Surface.是屏幕的一部分,用于显示游戏元素
激活游戏的动画循环后,每经过一次循环都将自动重绘这个Surface 将用户输入触发的所有变化都反映出来
run_game()包含一个while循环 监视事件
pygame.event.get()返回一个列表 包含它在上一次被调用发生的所有事件
所有键盘和鼠标事件都将倒是这个for循环进行 如果检查到pygame.QUIT则退出pygame.display.flip()将不断更新屏幕,以显示元素的新位置,并且在原来的位置隐藏元素,从而营造平滑的移动效果
#设置屏幕背景颜色
self.bg_color = (230,230,230) #rgb三元组
self.screen.fill(self.bg_color)
fill处理Surface,填充颜色
2.创建设置类
class Settings:
'''存储游戏中所设置的类'''
def __init__(self):
'''初始化游戏的设置'''
# 屏幕的设置
self.screen_width = 1200
self.screen_height = 800
self.bg_color = (230,230,230)
创建setting.py文件 这些变量可用于其他文件访问
这样写从代码上便于分离
from settings import Settings
self.settings = Settings()
self.screen = pygame.display.set_mode(
(self.settings.screen_width,self.settings.screen_height)
)
self.screen.fill(self.settings.bg_color)
3.创建飞船类
import pygame
class Ship:
'''管理飞船的类'''
def __init__(self,ai_game):
'''初始化飞船并设置其初始位置'''
self.screen = ai_game.screen()
self.screen_rect = ai_game.screen.get_rect()
# 加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/rocket.bmp')
self.rect = self.image.get_rect()
#对于每艘新飞船 初始化位置 放在屏幕底部中央
self.rect.midbottom = self.screen_rect.midbottom
def blitme(self):
'''在指定位置绘制飞船'''
self.screen.blit(self.image,self.rect)
我们将屏幕和飞船都当作矩形,因为这样处理比较简单
参数有self,ai_game 后者指向当前AlienInvasion实例引用 访问定义中的游戏资源
rect对象有属性x,y,center,centerx,centery,top,bottom等
blit方法将图像self.rect绘制到指定位置
飞船的移动
主要是利用self.ship.rect.x等属性
将run_game()分为两个部分
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
# 更新屏幕
self.ship.update()
self._update_screen()
'''辅助方法'''
def _check_events(self):
'''响应鼠标和键盘事件'''
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
# 向右移动飞船
# self.ship.rect.x += 10
self.ship.moving_right = True
# if event.type == pygame.K_LEFT:
# self.ship.rect.x -=10
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
def _update_screen(self):
self.screen.fill(self.settings.bg_color)
# self.screen.fill(self.bg_color)
self.ship.blitme()
# 让最近绘制的屏幕可见
pygame.display.flip()
注意event.key这个东西,用来控制飞船的移动
要实现连续移动可以给一个moving_right的flag控制
只要按下就能连续移动
当然,要将这个东西加入while循环监视
加快飞船速度
将速度改为1.5像素 由于rect.x为int值
将改变后的值赋给self.x 再赋值给self.rect.x 只存储整数部分
但问题不大
限制飞船活动范围
主要利用rect.right等限制
rect.right返回距离飞船外接矩形右边缘的x坐标
def update(self):
'''根据移动标志调整飞船位置'''
if self.moving_right and self.rect.right<self.screen_rect.right:
self.x += self.settings.ship_speed
if self.moving_left and self.rect.left>0:
self.x -= self.settings.ship_speed
# 根据self.x更新rect对象
self.rect.x = self.x
重构事件
def _check_keydown_events(self, event):
'''响应按键'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
def _check_keyup_events(self, event):
'''相应松开'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = False
elif event.key == pygame.K_LEFT:
self.ship.moving_left = False
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
self._check_keydown_events(event)
elif event.type == pygame.KEYUP:
self._check_keyup_events(event)
按Q键退出
def _check_keydown_events(self, event):
'''响应按键'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_q:
sys.exit()
全屏
self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
# self.settings.screen_width = self.screen.get_rect().width
# self.settings.screen_height = self.screen.get_rect().height
创建子弹类
import pygame
from pygame.sprite import Sprite
class Bullet(Sprite):
'''管理飞船所发射子弹的类'''
def __init__(self,ai_game):
'''在飞船当前位置创建一个子弹对象'''
super.__init__()
self.screen = ai_game.screen
self.settings = ai_game.settings
self.color = self.settings.bullet_color
#在(0,0)处创建一个表示子弹的矩形,再设置正确的位置
self.rect = pygame.Rect(0,0,self.settings.bullet_width,
self.settings.bullet_height)
self.rect.midtop = ai_game.ship.rect.midtop
#存储用小数表示的子弹位置
self.y = float(self.rect.y) def update(self):
'''向上移动子弹'''
# 更新表示子弹位置的小数值
self.y -= self.settings.bullet_speed
# 更新表示子弹的rect位置
self.rect.y = self.y
def draw_bullet(self):
'''在屏幕上绘制子弹'''
pygame.draw.rect(self.screen, self.color, self.rect)
def update(self):
'''向上移动子弹'''
# 更新表示子弹位置的小数值
self.y -= self.settings.bullet_speed
# 更新表示子弹的rect位置
self.rect.y = self.y
def _fire_bullet(self):
'''创建一颗子弹 将其加入编组中'''
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
def _update_screen(self):
# self.screen.fill(self.settings.bg_color)
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
def _check_keydown_events(self, event):
'''响应按键'''
if event.key == pygame.K_RIGHT:
self.ship.moving_right = True
elif event.key == pygame.K_LEFT:
self.ship.moving_left = True
elif event.key == pygame.K_q:
sys.exit()
elif event.key == pygame.K_SPACE:
self._fire_bullet() #发射子弹
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
# 更新屏幕
self.ship.update()
self.bullets.update()#更新位置
self._update_screen()
删除消失的子弹
子弹没有消除,所以会消耗内存
for bullet in self.bullets.copy():
if bullet.rect.bottom <=0:
self.bullets.remove(bullet)
使用copy是因为遍历的数组不能变化
限制子弹数量
settings.py设置
self.bullet_allowed = 3
def _fire_bullet(self):
'''创建一颗子弹 将其加入编组中'''
#限制数量 当子弹数量小于限制数量时
if len(self.bullets)<self.settings.bullet_allowed:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
重构代码
def _updata_bullets(self):
'''更新子弹位置并删除消失子弹'''
self.bullets.update()
# 删除消失的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
# 更新屏幕
self.ship.update()
self._updata_bullets()
self._update_screen()
创建外星人
import pygame
from pygame.sprite import Sprite
class Alien(Sprite):
'''表示单个外星人'''
def __init__(self,ai_game):
'''初始化外星人'''
super().__init__()
self.screen = ai_game.screen
#加载外星人图像并设置大小位置
self.image = pygame.image.load('./images/ufo.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 _create_fleet(self):
'''创建外星人群'''
alien = Alien(self)
alien_width = alien.rect.width
available_space_x = self.settings.screen_width - (2 * alien_width)
number_aliens_x = available_space_x // (2 * alien_width)
# 创建一行外星人
for alien_number in range(number_aliens_x):
self._create_alien(alien_number)
def _create_alien(self, alien_number):
# 创建一个外星人
alien = Alien(self)
alien_width = alien.rect.width
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
self.aliens.add(alien)
在__init__中加入
self.aliens = pygame.sprite.Group()
self._create_fleet()
同时
def _update_screen(self):
# self.screen.fill(self.settings.bg_color)
self.screen.fill(self.settings.bg_color)
self.ship.blitme()
for bullet in self.bullets.sprites():
bullet.draw_bullet()
self.aliens.draw(self.screen)
# 让最近绘制的屏幕可见
pygame.display.flip()
使用sprits.draw方法
重构
def _create_fleet(self):
'''创建外星人群'''
alien = Alien(self)
alien_width,alien_height = alien.rect.size
available_space_x = self.settings.screen_width - (2 * alien_width)
number_aliens_x = available_space_x // (2 * alien_width)
ship_hight = self.ship.rect.height
available_space_y = (self.settings.screen_height-(3*alien_height)-ship_hight)
number_rows = available_space_y//(2*alien_height)
# 创建外星人群
for row_number in range(number_rows):
for alien_number in range(number_aliens_x):
self._create_alien(alien_number,row_number)
def _create_alien(self, alien_number,row_number):
# 创建一个外星人
alien = Alien(self)
alien_width = alien.rect.width
alien.x = alien_width + 2 * alien_width * alien_number
alien.rect.x = alien.x
alien.rect.y = alien.rect.height+2*alien.rect.height*row_number
self.aliens.add(alien)
让外星人移动
def update(self):
'''向右移动外星人'''
self.x += self.settings.alien_speed
self.rect.x = self.x
检查边界 到达边界后向另一个方向走并向下走
def _update_alien(self):
'''更新外星人群中所有外星人的位置'''
self._check_fleet_edges()
self.aliens.update()
def _check_fleet_edges(self):
for alien in self.aliens.sprites():
if alien.check_edges():
self._change_fleet_direction()
break
def _change_fleet_direction(self):
'''将整群外星人下移动 并换左右方向'''
for alien in self.aliens.sprites():
alien.rect.y += self.settings.fleet_drop_speed
self.settings.fleet_direction *= -1
def update(self):
'''向右移动外星人'''
self.x += (self.settings.alien_speed * self.settings.fleet_direction)
self.rect.x = self.x
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
射击外星人
设计碰撞
sprits.groupcollide()
def _updata_bullets(self):
'''更新子弹位置并删除消失子弹'''
self.bullets.update()
# 删除消失的子弹
for bullet in self.bullets.copy():
if bullet.rect.bottom <= 0:
self.bullets.remove(bullet)
self._check_bullet_alien_collisions()
def _check_bullet_alien_collisions(self):
'''相应子弹和外星人碰撞'''
collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True)
if not self.aliens:
# 删除现有的所有子弹 并创建外星人
self.bullets.empty()
self._create_fleet()
飞船与ufo相碰撞
def _update_aliens(self):
'''更新外星人群中所有外星人的位置'''
self._check_fleet_edges()
self.aliens.update()
if pygame.sprite.spritecollideany(self.ship,self.aliens):
self._ship_hit()
def _ship_hit(self):
'''响应飞船被外星人碰撞'''
# 将left-1
self.stats.ships_left -= 1
# 清空余下的外星人和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一群新的外星人 并将飞船放到屏幕的底端
self._create_fleet()
self.ship.center_ship()
# 暂停
sleep(0.5)
class GameStats:
'''跟踪游戏统计信息'''
def __init__(self,ai_game):
'''初始化统计信息'''
self.settings = ai_game.settings
self.reset_stats()
def reset_stats(self):
'''初始化在游戏运行期间可能变化的统计信息'''
self.ships_left = self.settings.ship_limit
def center_ship(self):
"""让飞船在底端中央"""
self.rect.midbottom = self.screen_rect.midbottom
self.x = float(self.rect.x)
碰撞后飞船消失
检查外星人到屏幕底端
def _check_aliens_bottom(self):
# 检查外星人是否到达底端
screen_rect = self.screen.get_rect()
for alien in self.aliens.sprites():
if alien.rect.bottom >= screen_rect.bottom:
# 像飞船被撞到一样处理
self._ship_hit()
break
def _update_aliens(self):
'''更新外星人群中所有外星人的位置'''
self._check_fleet_edges()
self.aliens.update()
if pygame.sprite.spritecollideany(self.ship, self.aliens):
self._ship_hit()
self._check_aliens_bottom()
游戏结束
添加一个标志
当数量小于0时设为False
def _ship_hit(self):
'''响应飞船被外星人碰撞'''
# 将left-1
if self.stats.ships_left>0:
self.stats.ships_left -= 1
# 清空余下的外星人和子弹
self.aliens.empty()
self.bullets.empty()
# 创建一群新的外星人 并将飞船放到屏幕的底端
self._create_fleet()
self.ship.center_ship()
# 暂停
sleep(0.5)
else:
self.stats.game_active = False
def run_game(self):
'''开始游戏的主循环'''
while True:
# 监视键盘和鼠标事件
self._check_events()
# 更新屏幕
if self.stats.game_active:
self.ship.update()
# self.bullets.update()
self._updata_bullets()
self._update_screen()
self._update_aliens()
# for bullet in self.bullets.copy():
# if bullet.rect.bottom <= 0:
# self.bullets.remove(bullet)
先写到这里,后面再补
https://github.com/drowning-in-codes/pygame.git
github地址
本文由mdnice多平台发布