利用python做游戏

之前碰了Qt,winforms,wpf. 主要是想接触一下GUI

我都不知道该干啥了

这个项目是在《Python编程从入门到实践》上摘写的 个人推荐这本书还有同系列的蟒蛇书

后面想写写matplotlib和其他的python库,不过Python这个语言是真的舒服.

pygame介绍

Pygame游戏结构框架
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()

image-20210815132045490
image-20210815132045490

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)
image-20210815134354356
image-20210815134354356

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()
image-20210815150339152
image-20210815150339152

注意event.key这个东西,用来控制飞船的移动

要实现连续移动可以给一个moving_right的flag控制

只要按下就能连续移动

image-20210815150504599
image-20210815150504599

当然,要将这个东西加入while循环监视

image-20210815150714799
image-20210815150714799

加快飞船速度

image-20210815152117260
image-20210815152117260
image-20210815152142591
image-20210815152142591

将速度改为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((00), 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, TrueTrue)
    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

image-20210815201215794
image-20210815201215794
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 多平台发布

猜你喜欢

转载自blog.csdn.net/aqwca/article/details/130200016
今日推荐