为炒股而努力自学Python ->项目1:外星人入侵

项目1:外星人入侵
本项目用到 pygame 模块,安装都很简单,有关该模块比较详细的介绍请打开链接:
https://blog.csdn.net/weixin_45728976/article/details/104347294
啥都不如敲代码来的实在,遇到不明白的知识点、过不去的坎再加以解决,慢慢就长知识了。

# -*- coding: utf-8 -*-
"""
文件名:alien_invasion.py

Created on Mon Mar  8 14:26:47 2021

@author: Administrator
"""

import sys
import pygame

def run_game():
    # 初始化游戏并创建一个屏幕对象
    # pygame.init()  # 这行被注释掉好象也没啥影响
    # 创建一600,400的屏幕,原文1200,800,在我的屏幕上过于大了点
    screen = pygame.display.set_mode((600, 400))
    pygame.display.set_caption("Alien Invasion") # 这是给窗口设置一个标题

    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # 原文没这行,因为点击窗口右上角的“X”无法关闭,加上后可以关闭了
                pygame.quit()
                sys.exit()

        # 让最近绘制的屏幕可见
        pygame.display.flip()


run_game()

运行该代码会出现一个背景为黑色的窗口

学习该项目的目的是:掌握代码重构的方法。所以并不会深究pygame的各种功能及方法,因为,本人学习Python的目的是至力于股票方面的,而不是开发游戏,好象pygame对于股票方面也没太大用处。
接下来首次重构下代码
我对代码重构的理解是:在主程序足够大的时候,因为显得比较杂乱,就把其中的一部分或几部分具有一定功能的代码块提炼出来,重新定义为类或函数,单独放在一个或几个具有特定功能的程序文件中,也就是所谓的模块中,然后再回到主程序中调用该模块并做些相应的操作,这样做的目的主要是为了便于日后维护、添加功能、修改等等,更是为了主程序的更加简练,便于使其更容易扩展。
比如,针对该项目,目前有必要针对各种设置进行提炼,单独定义为一个或几个类或者函数模块,只所以要定义类,是因为类更有利于变量(类中称作为属性)在该类中通用,免得老是把参数设置来设置去,费话少说,自们还是来真格的:
项目设计到此代码如下:

# -*- coding: utf-8 -*-
"""
文件名:alien_invasion.py

Created on Tue Mar  9 11:28:49 2021

@author: Administrator
"""

import sys
import pygame


class Ship():

    def __init__(self, screen):
        """ 初始化飞船并设置其初始位置"""
        self.screen = screen  # 该参数指定了飞船绘制的位置

        # 加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images/ship.bmp')  # 加载飞船位图
        self.rect = self.image.get_rect()  # 获取相应surface的属性rect
        self.screen_rect = screen.get_rect()  # 将表示屏幕的矩形存储在self.screen_rect中

        # 将每般新飞船放在屏幕底部中央
        self.rect.centerx = self.screen_rect.centerx  # 将飞船的中心坐标与屏幕矩形的属性centerx对齐
        self.rect.bottom = self.screen_rect.bottom  # 将飞船的下边缘对齐屏幕的属性bottom

    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)


def run_game():
    # 初始化游戏并创建一个屏幕对象
    # pygame.init
    """
    既然上面这行可有可无,依然还是将其注释掉吧!
    等有用的时候再将其恢复
    也许用到的模块在该用到的时候自己就初始化了呢
    没必要的东西我不想让其再显示在程序文件中,显得多余且乱
    """
    size = width, height = 600, 400
    screen = pygame.display.set_mode(size)

    # 设置背景色
    bg_color = 255, 255, 255
    
    # 实例化飞船
    ship = Ship(screen)

    pygame.display.set_caption("Alien Invasion")

    # 开始游戏的主循环
    while True:

        # 监视键盘和鼠标事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()  # 这行必加,不然点击窗口右上角的“X”不能关闭窗口
                sys.exit()

        # 每次循环时都重绘屏幕
        screen.fill(bg_color)

		# 绘制飞船        
        ship.blitme()

        # 让最近绘制的屏幕可见
        pygame.display.flip()


run_game()

项目到此,我们定义了一个Ship类,将飞船的位图添加到窗口中,运行该代码会打开一个窗口,在该窗口的底部中央位置出现一般飞船,接下来,我们对此代码重构:
首先将class Ship() 类提取出来,放在 ship.py程序文件中,并将有关设置也提取出来,放在 settings.py 中,当然这一切都是在Spyder 中进行的,它会自动将这些文件(模块)放在同目录(文件夹:alien_invasion 中)之下,就象如下:

飞船的相关程序文件:
ship.py

# -*- coding: utf-8 -*-
"""
文件名:ship.py

Created on Tue Mar  9 13:23:11 2021

@author: Administrator
"""

import pygame


class Ship():

    def __init__(self, screen):
        """ 初始化飞船并设置其初始位置"""
        self.screen = screen  # 该参数指定了飞船绘制的位置

        # 加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images/ship.bmp')  # 加载飞船位图
        self.rect = self.image.get_rect()  # 获取相应surface的属性rect
        self.screen_rect = screen.get_rect()  # 将表示屏幕的矩形存储在self.screen_rect中

        # 将每般新飞船放在屏幕俱底部中央
        self.rect.centerx = self.screen_rect.centerx  # 将飞船的中心坐标与屏幕矩形的属性centerx对齐
        self.rect.bottom = self.screen_rect.bottom  # 将飞船的下边缘对齐屏幕的属性bottom

    def blitme(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)

有了这个文件,我们就可以在主程序文件中去掉相应的代码块,用该类的实例替换。相关的飞船图片如下,请将该图片下载之后存放在该目录下的文件夹 images中,如果还没有该文件夹那就自己建一个呗,并将该图片命名为:ship.bmp:
ship.bmp
相关设置程序文件:
settings.py

# -*- coding: utf-8 -*-
"""
文件名:settings.py

Created on Tue Mar  9 11:28:03 2021

@author: Administrator
"""


class Settings():
    """存储《外星人入侵》所有设置的类"""

    def __init__(self):
        """初始化游戏设置"""
        # 屏幕设置
        self.screen_width = 600
        self.screen_height = 400
        self.bg_color = 255, 255, 255

我们同样可以将主程序中的相关该设置的代码块去掉,用实例代替

接下来,我们将主程序中用到的一些函数也存放在游戏函数文件中,如下:
文件名: game_functions.py

# -*- coding: utf-8 -*-
"""
文件名:game_functions.py

Created on Tue Mar  9 15:28:44 2021

@author: Administrator
"""

import sys
import pygame


def check_events():
    """响应按键和鼠标事件"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()


def update_screen(ai_settings, screen, ship):
    """更新屏幕上的图像,并切换到新屏幕"""
    # 每次循环时都重绘屏幕
    screen.fill(ai_settings.bg_color)
    ship.blitme()

    # 让最近绘制的屏幕可见
    pygame.display.flip()

接下来,我们可以对主程序简化了:

# -*- coding: utf-8 -*-
"""
文件名:alien_invasion.py

Created on Tue Mar  9 11:28:49 2021

@author: Administrator
"""

# import sys # 这里用不到该模块了,将其注释掉
import pygame

from settings import Settings
from ship import Ship
import game_functions as gf


# 初始化游戏并创建一个屏幕对象
# pygame.init
"""
既然上面这行可有可无,依然还是将其注释掉吧!
等有用的时候再将其恢复
也许用到的模块在该用到的时候自己就初始化了呢
没必要的东西我不想让其再显示在程序文件中,显得多余且乱
"""

# 创建一个Settings实例
ai_settings = Settings()

# 调用类Settings()中的属性
size = ai_settings.screen_width, ai_settings.screen_height
bg_color = ai_settings.bg_color

screen = pygame.display.set_mode(size)

# 创建一个飞船实例,并传送实参screen
ship = Ship(screen)

pygame.display.set_caption("Alien Invasion")

# 开始游戏的主循环
while True:

    # 调用game_function.py模块以监视键盘和鼠标事件
    gf.check_events()

    # 调用game_function.py中的update_screen()函数
    gf.update_screen(ai_settings, screen, ship)

原程序先是定义一个run_game函数,最后一行又调用该函数运行主程序,这不是多此一举吗?既然程序是从开头到结尾、从上到下一路运行下来的,是必须一步步执行的,所以,我将定义该函数的过程去掉了,这样岂不是又升了两行代码?
程序到此大体框架已然构成,接下来就是让飞船动起来,并添加了飞船发射子弹的功能,真正进入游戏过程,各程序文件代码如下:

# -*- coding: utf-8 -*-
"""
文件名:alien_invasion.py
一个外星人入侵的游戏
Created on Tue Mar  9 11:28:49 2021

@author: Administrator
"""

# import sys # 这里用不到该模块了,将其注释掉
import pygame
from pygame.sprite import Group

from settings import Settings
from ship import Ship
import game_functions as gf


# 初始化游戏并创建一个屏幕对象
# pygame.init
"""
既然上面这行可有可无,依然还是将其注释掉吧!
等有用的时候再将其恢复
也许用到的模块在该用到的时候自己就初始化了呢
没必要的东西我不想让其再显示在程序文件中,显得多余且乱
"""

# 创建一个Settings实例
ai_settings = Settings()

# 调用类Settings()中的属性
size = ai_settings.size
bg_color = ai_settings.bg_color

screen = pygame.display.set_mode(size)

# 创建一个飞船实例,并传送实参screen
ship = Ship(ai_settings, screen)
# 创建一个用于存储子弹的编组
bullets = Group()

pygame.display.set_caption("Alien Invasion")


# 开始游戏的主循环
while True:

    # 调用game_function.py模块以监视键盘和鼠标事件
    gf.check_events(ai_settings, screen, ship, bullets)
    ship.update()
    bullets.update()
    # 调用game_function.py中的update_screen()函数
    gf.update_screen(ai_settings, screen, ship, bullets)

# -*- coding: utf-8 -*-
"""
文件名:settings.py
一个游戏设置的类

Created on Tue Mar  9 11:28:03 2021

@author: Administrator
"""


class Settings():
    """存储《外星人入侵》所有设置的类"""

    def __init__(self):
        """初始化游戏设置"""
        # 屏幕设置
        self.size = 600, 400
        self.bg_color = 255, 255, 255

        # 飞船设置
        self.ship_speed_factor = 0.1

        # 子弹设置
        self.bullet_speed_factor = 2
        self.bullet_width = 3
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60

# -*- coding: utf-8 -*-
"""
文件名:ship.py
设置飞船

Created on Tue Mar  9 13:23:11 2021

@author: Administrator
"""

import pygame


class Ship():

    def __init__(self, ai_settings, screen):
        """ 初始化飞船并设置其初始位置"""
        self.screen = screen  # 该参数指定了飞船绘制的位置
        self.ai_settings = ai_settings

        # 加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images/ship.bmp')  # 加载飞船位图
        self.rect = self.image.get_rect()  # 获取相应surface的属性rect
        self.screen_rect = screen.get_rect()  # 将表示屏幕的矩形存储在self.screen_rect中

        # 将每般新飞船放在屏幕俱底部中央
        self.rect.centerx = self.screen_rect.centerx  # 将飞船的中心坐标与屏幕矩形的属性centerx对齐
        self.rect.bottom = self.screen_rect.bottom  # 将飞船的下边缘对齐屏幕的属性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.ai_settings.ship_speed_factor

        if self.moving_left and self.rect.left > 0:
            self.center -= self.ai_settings.ship_speed_factor

        # 根据self.center更新rect对象
        self.rect.centerx = self.center

    def blitme
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值