Journey to the alien_invasion

 写在前面:

1、创建一个项目,首先要做宏观的规划,先想想它里面的一些元素功能以及逻辑性的迭代与布局,

再进行必要的分块封装调用和实例的新建

2、在不断学习的过程中发现,复盘是一个很有效且重要的东西!!

在这个项目中,我称为对游戏过程的模拟、假设与思考

思路微展示:

# 首先运行程序之后一个not active的界面,会分别有play和help的按钮,
​
# 然后进行对按钮的考量,按钮是创建的button的模块,然后上面有文字渲染的字样,然后再把制draw在屏幕上
​
# 然后是优化问题,会不会进行update,按钮比赛开始的时候是否需要隐藏?免误触
​
# 进入到游戏里面,首先是对整个屏幕的大小像素的一个绘制,对不同区域上存放成额,成绩,分数,还有飞机外星人图样的一个整体的布局,他们的外接矩形有一个总体的轮廓与方位
​
# 然后再详细模拟,在按键过程中,用户输入响应的问题是调用的哪个module的哪个函数,是否有效,是否更新
​
# 在优化的过程中,是否考虑到了所有的情况,对于不同情况的健壮性是否完备?
​
# 对于屏幕整体效果的优化是否有效?游戏进行的每一步是否符合逻辑?是否按构想进行?
​
# 比如子弹的发射、撞毁、消失、重构、生命的衰减、记分板的更新、敌机的重构,速度的一个加持
# ......

宏观布局图:

1、各个位置的确定方法,计算&坐标法,存储规则,边界的范围,循环与更新update

2、图示:

main:

创建空的 pygame 窗口--调用三大库

-*- coding: utf-8 -*-
import sys
from time import sleep
import pygame
from settings import Settings
from game_stats import GameStats
from scoreboard import Scoreboard
from button import Button
from ship import Ship
from bg import Bg
from bullet import Bullet
from alien import Alien
from music import Music
​
class AlienInvasion:
    def run_game(self):
    def _update_screen(self):
    def _check_events(self):        
    def _check_keydown_events(self, event):
    def _check_keyup_events(self, event):
    def _check_mousebuttondown_events(self, event):
    def _fire_bullet(self):
    def _update_bullets(self):
    # 以下两个def依次为:create个体、群组
    def _create_alien(self, alien_number, row_number):
    def _create_fleet(self):
    # 以下两个def依次为:检测边缘、左右横跳改变方向
    def _create_alien(self, alien_number, row_number):
    def _change_fleet_direction(self):
    # 以下def检查hit依次为:bullet_alien、ship_alien、alien_bottom、最后的update
    def _check_bullet_alien_collisions(self):
    def _ship_hit(self):
    def _check_aliens_bottom(self):
    def _update_aliens(self):
        
if __name__ == '__main__':
    # 创建游戏实例并运行游戏
    ai = AlienInvasion()
    ai.run_game()
​

settings:(注意点)

class Settings:
    def __init__(self):
        # 生命的数量 ship_limit = 3
        # 未消失允许的子弹数self.bullets_allowed = 10
        # 外星人设置 fleet_drop_speed = 10,主函数中_change_fleet_direction在此定义
        # 加快游戏节奏的速度 speedup_scale = 1.2
        # 外行人分数提高速度 self.score_scale = 1.5
        self.initialize_dynamic_settings()
        
    def initialize_dynamic_settings(self):
        '''初始化随游戏进行而变化的设置,仅举一个例子'''
        self.ship_speed = 1.5
        # 计分
        self.alien_points = 1
​
    def increase_speed(self):
        '''提高速度设置和外星人分数,'''
        self.ship_speed *= self.speedup_scale
        # 将分数累加后,因为有小数,再转化为int型,分数美观
        self.alien_points = int(self.alien_points * self.score_scale)

game_starts

矩形的绘制要先出示一个rect,再进行数据的更新

class GameStats:
    '''跟踪游戏的统计信息,包括开始和一直在更新的统计信息'''
    def __init__(self, ai_game):
        self.settings = ai_game.settings
        self.reset_stats()
    def reset_stats(self):
        # 初始化在游戏运行期间可能发生的统计信息
        # 为了只创建一个gamestarts实例,而需要初始化的统计信息放在reset_start()
        # 所以如下几个变量会标黄弱警告,但self的信息应该就在reset里而非init里面
        self.ships_left = self.settings.ship_limit
        self.score = 0
        self.level = 1

ship

先调用模块创建一个的实例,进行添加绘制,再通过计算出一群并在不断的响应移动后群动后进行更新与绘制

# Sprite 的调用,建群
class Ship(Sprite):
    def __init__(self, ai_game):
        '''初始化飞船并设置其初始位置'''
        super().__init__()
        self.screen_rect = ai_game.screen.get_rect()
        self.image = pygame.image.load('images/ship.bmp')
        # self.image = pygame.transform.scale(self.image, (128, 128))
        self.rect = self.image.get_rect()
        
        # 对于每搜新飞船,都将其放在屏幕底部中央
        self.rect.midbottom = self.screen_rect.midbottom
        self.x = float(self.rect.x)     # 在飞船的属性x中存储float
        self.moving_right = False       # 移动标志
        self.moving_left = False
    def update(self):
    def center_ship(self):
    def blitme(self):
        self.screen.blit(self.image, self.rect)
        # 在指定位置绘制飞船,surface.blit(image,(x,y),rect)
        # pygame.surface.blit方法将一个图像(Surface实例)
        # 绘制到另一个图像(Surface实例)上。如screen是一个Surface实例

细节展示部分:

1、self.screen 的对象是surface,所有游戏元素都对应着一个surface,

当active的时候,对应surface能够重绘更新,开始定义在主函数里的run_game

后续因为需要时刻更新的东西太多→→封装在了专门的update_screen函数里

# 每次循环都重绘屏幕,显示屏幕内容及信息的重要一环
def _update_screen(self):   
    # 先绘制屏幕,再叠加surface
    self.screen.fill(self.settings.bg_color) 
    self.bg.blitme()
    self.ship.blitme()
    for bullet in self.bullets.sprites():
        bullet.draw_bullet()
    self.aliens.draw(self.screen)
        self.sb.show_score()
    # !!!最近绘制都可见
    pygame.display.flip()

2、考虑play键游戏中可能误触,只有在同时点击鼠标且游戏属于not active(False)的时候才为通路;考虑鼠标光标的问题,

在游戏中光标不要出现来影响效果,而在游戏结束时光标要立刻出现来选择是否要重新play或退出

if not self.stats.game_active:
    self.play_button.draw_button()
    self.help_button.draw_button()
if button_clicked and not self.stats.game_active:
    # 重置游戏设置
    self.settings.initialize_dynamic_settings()
    # 隐藏鼠标光标
    pygame.mouse.set_visible(False)

3、一个元素的生成过程:

首先继承+screen、settings、Image_load, 然后初始化一个rect矩形,

再通过坐标的方式或相对位置的方式来确定位置(存储浮点型或整数型)

最后,构建update函数,还有.......

class Alien(Sprite):
    def __init__(self, ai_game):
        super().__init__()
        self.screen = ai_game.screen
        self.settings = ai_game.settings
        self.image = pygame.image.load('images/alien.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 check_edges(self)
    def update(self):

4、响应后改变位置时调整矩形rect的坐标,self.rect.x只能存储整数,健壮性不好

在运用变量时不要随便,应该严谨考虑self.x,先叠加再储存,尽可能保存其数据的完整性

# 定义在__init__()里
   self.x = float(self.rect.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.rect.x = self.x

5、有关键盘与鼠标的响应问题,起初都简单的写在run_game的函数里,但随着功能\情况的增加,进行类的构造

调用了pygame里陌生的库,通过布尔值来判断敲击与否进行响应;

并作为中转站调用对应模块里面的函数,进行位置的改变,进而继发引起飞船的消失重构、计分变换等

   def _check_events(self):
        # 相应按键和鼠标事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()   # 程序直接退出,不捕捉异常
            elif event.type == pygame.KEYDOWN:
                self._check_keydown_events(event)
            elif event.type == pygame.KEYUP:
                self._check_keyup_events(event)
            elif event.type == pygame.MOUSEBUTTONDOWN:
                self._check_mousebuttondown_events(event)
                    
    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:
            pygame.quit()
            sys.exit()
    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
    # 中转站
    def _check_mousebuttondown_events(self, event):
        if event.button == 1:
        # event.pos为鼠标当前坐标值(x,y),相对左上角,相当于pygame.mouse.get_pos()
        button_clicked = self.play_button.rect.collidepoint(event.pos)
        buttonhelp_clicked = self.help_button.rect.collidepoint(event.pos)
        if button_clicked and not self.stats.game_active:
            # 重置游戏设置
            self.settings.initialize_dynamic_settings()
            # 重置游戏统计·信息
            self.stats.reset_stats()
            self.stats.game_active = True
            # 一堆调用
            self.sb.prep_score()
            self.sb.prep_level()
            self.aliens.empty()
            self._create_fleet()
            self.ship.center_ship()
            ......

6、逻辑合理性、多可能健壮性的考虑,比如说:

# 以下def检查hit依次为:bullet_alien、ship_alien、alien_bottom、最后的update
    def _check_bullet_alien_collisions(self):
        collisions = pygame.sprite.groupcollide(self.bullets, self.aliens, True, True)
        if collisions:
        if not self.aliens:
    def _ship_hit(self):
        if self.stats.ships_left > 0:
            # 将ship_left=生命减一并更新记分牌
            self.stats.ships_left -= 1
            self.aliens.empty()
        else: # 游戏结束,再次重置,需要再次点击play,要求显示光标
            self.stats.game_active = False
            pygame.mouse.set_visible(True)
    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

7、叠层视图

class Bg:
    def __init__(self, ai_game):
        self.screen = ai_game.screen
        ......
        # 加载背景图像2个!!
        self.image1 = pygame.image.load('images/bd3.jpg')
        self.image2 = pygame.image.load('images/bd3.jpg')
    def action(self):
        # 让背景随飞机动起来
        self.y1 = self.y1 + self.settings.bg_speed
        self.y2 = self.y2 + self.settings.bg_speed
        if self.y1 >= self.size[1]:
            self.y1 = 0
        if self.y2 >= 0:
            self.y2 = -self.size[1]
    def blitme(self):
        self.scene.blit(self.image1, (0, self.y1))
        self.scene.blit(self.image2, (0, self.y2))

advanced

1、超级武器

 # 超级武器设置
        self.bullet_width_s = 600
        self.bullet_height_s = 40
        self.bullet_color_s = (255, 0, 0)

2、音效

self._create_fleet()
            self.music.blitme()
            pygame.display.flip()
            # 控制飞船和外星人碰撞音效
            if self.control_sound:
                self.music.bow()
                self.nn = True
            elif not self.control_sound and self.nn:
                self.music.bow_stop()
                self.nn = not self.nn
            # 暂停2毫秒
            sleep(2)

3、最高分储存,仅仅举部分例子

 for event in pygame.event.get():
            if event.type == pygame.QUIT:
                # 将高分添加到txt中
                with open('high_score.txt', 'w') as file_object:
                    file_object.write(str(self.stats.high_score))
                    file_object.close()
                pygame.quit()
                sys.exit()   # 程序直接退出,不捕捉异常

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值