Python training program - how to fly gracefully?(python练手项目-如何优雅的打飞机 )

in programming •  7 years ago 

准备用python写一个打飞机的游戏,相信能够写完这个项目,我对python的学习应该也算可以了。

首先,我们要使用python的一个pygame的库来写,这个库的安装比较简单就是普通的pip安装就可以了。

先安装pip3 sudo apt install pip3

再装 sudo pip3 install pygame

先看一下项目结构

print ("打飞机游戏")
加载背景音乐
播放背景音乐(设置单曲循环)
加载我方飞机
interval=0————设置敌方飞机的刷新时间
while True:
    if 用户点击关闭按钮:
        退出程序
    interval+=1 
    if interval==50:
        加载敌方飞机
        interval=0
    敌方飞机移动
    屏幕刷新
    if 用户鼠标发生移动:
        鼠标位置==我方飞机的位置
        屏幕刷新
    if 我方飞机的位置==敌方飞机的位置:
        播放撞机音乐
        加载飞机爆炸的图片
        print ("游戏结束")
        关闭背景音乐(设置淡出)

敌军,也就是体型稍微大点的,在上方左右移动,并且有规律向下移动。我军目标,消灭所有飞机。但是屏幕上最多只展现3颗子弹。 一旦,我军飞机与敌军飞机碰撞,或者敌军飞机抵达底部。我军损失一条生命,一共三条。 敌军飞机全部消灭完,则到下一关,移动速度会更快。 我军每消灭一架敌军飞机获得积分,积分最高者会在界面显示。

游戏源码如下:


#alien_invasion.py  
#主程序文件

"""
创建Pygame窗口响应以及用户输入
"""


import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
from pygame.sprite import Group
from alien import Alien
from game_stats import GameStats
from button import Button
from Scoreboard import Scoreboard


def run_game():
    
    #初始化游戏并且创建一个屏幕对象
    pygame.init()
    
    ai_settings = Settings()
    
    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))
    
    pygame.display.set_caption("Alien Invasion")

    #创建play按钮
    play_button = Button(ai_settings, screen, "PLAY~")
    
    #创建一个用户存储游戏统计信息的实例
    stats = GameStats(ai_settings)

    sb = Scoreboard(ai_settings, screen, stats)

    #创建一艘飞船
    ship = Ship(ai_settings,screen)
    
    #创建一个用户存储子弹的编组
    bullets = Group()
    
    #创建一个外星人
    aliens = Group()

    #创建外星人群
    gf.create_fleet(ai_settings, screen,ship, aliens)


    #开始游戏主循环
    while True:
        
        #监视键盘和鼠标事件
        gf.check_events(ai_settings, screen, stats,sb, play_button, ship, aliens,bullets)
        
        if stats.game_active:
            ship.update()

        
            #删除已消失的子弹
            gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens, bullets)

            gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets)

        gf.update_screen(ai_settings, screen,stats, sb, ship, aliens, bullets, play_button)

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

run_game()


#alien.py

import pygame
from pygame.sprite import Sprite


class Alien(Sprite):
    def __init__(self,ai_settings, screen ):
        """初始化外星人并且设置起始位置"""
        super().__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        #加载外星人图像,并且设置其rect属性
        self.image = pygame.image.load("images/alien.png")
        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 blitme(self):
        """在指定位置绘制外星人"""
        self.screen.blit(self.image, self.rect)

    def check_edges(self):
        """如果外星人出于屏幕边缘,就返回True"""
        screen_rect = self.screen.get_rect()
        if self.rect.right >=  screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True

    def update(self):
        """向左或者右移动的外星人"""
        self.x += (self.ai_settings.alien_speed_factor * 
            self.ai_settings.fleet_direction)
        self.rect.x = self.x


#bullet.py


import pygame
from   pygame.sprite   import Sprite  

class Bullet(Sprite):
    """一个对飞船发射的子弹进行管理的类"""
    """Bullet类继承了我们从模块pygame.sprite中导入的Sprite类"""

    def __init__(self, ai_settings, screen, ship):
        """在飞船所处的位置创建一个子弹对象"""

        """为创建子弹实例,需要向__init__()传递
        ai_settings、screen和ship实例,还调用了super()来继承Sprite。
        """
        super().__init__()
        self.screen = screen

        """
        在(0.0)处创建一个表示子弹的矩形,再设置正确的位置
        我们创建了子弹的属性rect。子弹并非基于图像的,因此我们必须使用pygame.Rect()
        类从空白开始创建一个矩形
        """
        self.rect = pygame.Rect(
            0,0,ai_settings.bullet_width,ai_settings.bullet_height)
        self.rect.centerx = ship.rect.centerx  #将子弹的centerx设置为飞船的rect.centerx
        self.rect.top = ship.rect.top         #子弹的rect的top属性设置为飞船的rect的top属性


        #存储用小数表示的子弹位置
        self.y = float(self.rect.y)

        self.color = ai_settings.bullet_color
        self.speed_factor = ai_settings.bullet_speed_factor


    def update(self):
        """向上移动子弹"""
        #更新表示移动子弹的位置的小数值
        self.y -= self.speed_factor
        #更新表示子弹的rect的位置
        self.rect.y = self.y

    def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)


#button.py


import pygame.font

class Button():
    def __init__(self, ai_settings, screen, msg):
        """初始化按钮的属性"""
        self.screen = screen
        self.screen_rect = screen.get_rect()

        #设置按钮的尺寸和其他属性
        self.width, self.height = 200, 50
        self.button_color = (0, 250, 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):

        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)


#game_functions.py


import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep

def check_keydown_events(event, ai_settings,screen,ship,bullets):
    """响应按键"""
    if event.key == pygame.K_RIGHT:
        #向右→移动
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        #向左移动
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        # 创建一颗子弹,并将其加入到编组bullets中
        fire_bullet(ai_settings, screen, ship, bullets)
    elif event.key == pygame.K_q:
        sys.exit()


def check_keyup_events(event, ship):
    """响应松开"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right =  False
    elif event.key == pygame.K_LEFT:
        ship.moving_left =  False


def check_events(ai_settings, screen, stats,sb, play_button, ship, aliens,bullets):
    """响应和鼠标按键"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        elif event.type == pygame.KEYDOWN:
            
            check_keydown_events(event, ai_settings, screen, ship, bullets)
        elif event.type ==  pygame.KEYUP:
            check_keyup_events(event, ship)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x,mouse_y = pygame.mouse.get_pos()
            check_play_button(ai_settings, screen, stats, sb, play_button, ship,aliens, bullets, mouse_x, mouse_y)

def check_play_button(
    ai_settings, screen, stats, sb, play_button, ship, aliens,bullets, mouse_x, mouse_y):
    
    button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)
    if button_clicked and not stats.game_active:
        # 重置游戏设置
        ai_settings.initialize_dynamic_settings()
        # 隐藏光标
        pygame.mouse.set_visible(False)
        #重置游戏
        stats.reset_start()
        stats.game_active = True

        #重置记分牌图像
        sb.prep_score()
        sb.prep_high_score()
        sb.prep_level()
        sb.prep_ships()


        # 清空外星人列表和子弹列表
        aliens.empty()
        bullets.empty()

        # 创建一群新的外星人,并让飞船居中
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()



def update_screen(ai_settings, screen, stats, sb, ship, aliens, bullets,play_button):
    """更新屏幕的图像,并且切换到新的屏幕"""
    #每次循环时都会重新绘屏
    screen.fill(ai_settings.bg_color)
    for bullet in bullets.sprites():
        bullet.draw_bullet()

    ship.blitme()
    aliens.draw(screen)
    #显示得分
    sb.show_score()
    
    # 如果游戏处于非活动状态,就绘制Play按钮
    if not stats.game_active:
        play_button.draw_button()

    #让最近绘制的屏幕可见
    pygame.display.flip()
def update_bullets(ai_settings, screen,stats, sb, ship, aliens, bullets):
    """更新子弹的位置,并且删除已消失的子弹
    在for循环中,不应从列表或编组中删除条目,因此必须遍历编组的副本。
    我们使用了方法copy()来设置for循环
    """
    bullets.update()
    for  bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    check_bullet_alien_collisions(ai_settings, screen, stats, sb, ship, aliens, bullets)



def check_bullet_alien_collisions(
    ai_settings, screen, stats, sb, ship, aliens, bullets):
    #检查子弹是否打中飞机
    collisions = pygame.sprite.groupcollide(bullets, aliens, True, True)
    if len(aliens) == 0:
        #删除现有的子弹并新建一群外星人
        bullets.empty()
        ai_settings.increase_speed()  #新游戏加速
        #print(ai_settings.alien_speed_factor)
        create_fleet(ai_settings, screen, ship, aliens)

        stats.level += 1
        sb.prep_level()

    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_points * len(aliens)
            sb.prep_score()
        check_high_score(stats, sb)




def fire_bullet(ai_settings, screen, ship, bullets):
    """如果还没有到达限制,就发射一颗子弹"""
    #创建新子弹,并将其加入到编组bullets中
    if len(bullets) < ai_settings.bullets_allowed:
        new_bullet = Bullet(ai_settings, screen, ship)
        bullets.add(new_bullet)



def create_fleet(ai_settings, screen, ship, aliens):
    """创建外星人群"""
    #创建一个外星人并且计算一行可以容纳多少个外星人
    #外星人间距为外星人的宽度
    alien = Alien(ai_settings, screen)
    number_aliens_x = get_number_aliens_x(ai_settings,alien.rect.width)
    number_rows = get_number_rows(ai_settings, ship.rect.height, alien.rect.height)



    #创建第一行外星人
    for row_number in range(number_rows):

        for alien_number in  range(number_aliens_x):
            #创建一个外星人,并将其加入当前行列
            create_alien(ai_settings, screen, aliens, alien_number, row_number)



def get_number_aliens_x(ai_settings, alien_width):
    """计算每行可以容纳多少飞机"""
    available_space_x = ai_settings.screen_width - 2 * alien_width
    number_aliens_x = int(available_space_x / (2 * alien_width))
    return number_aliens_x



def create_alien(ai_settings, screen, aliens, alien_number, row_number):  #这里的row_number来自哪里?
    """创建一个外星人并把它放在当前行列"""
    alien = Alien(ai_settings, screen)
    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
    aliens.add(alien)



def get_number_rows(ai_settings, ship_height, alien_hight):
    """计算屏幕可以容纳几行外星人"""
    available_space_y = (
        ai_settings.screen_height - (3*alien_hight) - ship_height)
    number_rows = int(available_space_y / (2*alien_hight))
    return number_rows


def update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets):
    """更新外星人的位置"""
    check_fleet_edges(ai_settings,aliens)
    aliens.update()

    #检测外星人和飞船之间的碰撞
    if pygame.sprite.spritecollideany(ship, aliens):
        ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)

    check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens, bullets)


def check_fleet_edges(ai_settings, aliens):
    """有外星人撞到边缘时候采取的措施"""
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settings, aliens)
            break



def change_fleet_direction(ai_settings,aliens):
    """整体外星人向下移动,并且改变方向"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction *= -1

def ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets):
    """响应被外星人撞到的飞船"""
    #ship_left -1
    if stats.ship_left > 0:
        stats.ship_left -=1

        #清空外星人列表和子弹列表
        aliens.empty()
        bullets.empty()

        sb.prep_ships()

        #创建一群新的外星人,并将飞船放到屏幕底端中央
        create_fleet(ai_settings, screen, ship, aliens)
        ship.center_ship()

        #暂停
        sleep(0.5)

    else:
        stats.game_active = False
        pygame.mouse.set_visible(True)


def check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens,
    bullets):
    """检查是否有外星人到达了屏幕底端"""
    screen_rect = screen.get_rect()
    for alien in aliens.sprites():
        if alien.rect.bottom >= screen_rect.bottom:
            #和飞船被撞处理一样
            ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)
            break


def check_high_score(stats, sb):
    if stats.score > stats.high_score:
        stats.high_score = stats.score
        sb.prep_high_score()


#game_stats.py


class GameStats():
    """游戏统计信息"""

    def __init__(self,ai_settings):
        """初始化统计信息"""
        self.ai_settings = ai_settings
        self.reset_start()
        #游戏一开始就是非活动状态
        self.game_active = False
        # 在任何情况下都不应重置最高得分
        self.high_score = 0

    def reset_start(self):
        """初始化在游戏运行期间可能变化的统计信息"""
        self.ship_left = self.ai_settings.ship_limit
        self.score = 0
        self.level = 1


#Scoreboard.py


import pygame.font
from pygame.sprite import Group
from ship import Ship


class Scoreboard():
    """显示信息得分的类"""

    def __init__(self, ai_settings, screen, stats):

        self.screen  = screen
        self.screen_rect = screen.get_rect()
        self.ai_settings = ai_settings
        self.stats = stats

        #显示得分信息时使用的字体设置
        self.text_color = (30, 30, 30)
        self.font = pygame.font.SysFont(None, 48)

        
        #准备初始得分图像 和最高得分

        self.prep_score()
        self.prep_high_score()
        self.prep_level()
        self.prep_ships()



    def prep_score(self):
        rounded_score = int(round(self.stats.score, -1))
        score_str = "{:,}".format(rounded_score)
        self.score_image = self.font.render(
            score_str,True, self.text_color, self.ai_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)
        self.screen.blit(self.high_score_image, self.high_score_rect) 
        self.screen.blit(self.level_image, self.level_rect)
        self.ships.draw(self.screen)


    def prep_high_score(self):
        """渲染最高分为图像"""
        high_score = int(round(self.stats.high_score,-1))
        high_score_str = "{:,}".format(high_score)
        self.high_score_image = self.font.render(high_score_str, True,
            self.text_color, self.ai_settings.bg_color)

        #最高得分在顶部中央
        self.high_score_rect = self.high_score_image.get_rect()
        self.high_score_rect.centerx = self.screen_rect.centerx
        self.high_score_rect.top = self.screen_rect.top

    def prep_level(self):
        """将等级转换为渲染的图像"""
        self.level_image = self.font.render(str(self.stats.level), True, 
            self.text_color, self.ai_settings.bg_color)

        #位置
        self.level_rect = self.level_image.get_rect()
        self.level_rect.right = self.score_rect.right
        self.level_rect.top = self.score_rect.bottom + 10

    def prep_ships(self):

        self.ships = Group()
        for ship_number in range(self.stats.ship_left):
            ship = Ship(self.ai_settings, self.screen)
            ship.rect.x = 10 + ship_number * ship.rect.width
            ship.rect.y = 10
            self.ships.add(ship)


#settings.py



class Settings():
    """
    存储游戏所有设置的类
    """
    def __init__(self):
        """初始化游戏的设置"""
        #屏幕设置
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)
        # 飞船的设置
        self.ship_speed_factor = 1.5
        self.ship_limit = 3

        #子弹设置
        self.bullet_speed_factor = 3  
        self.bullet_width = 1    #这里更改子弹的宽度
        self.bullet_height = 15
        self.bullet_color = 60, 60, 60
        self.bullets_allowed = 300   #这里更改子弹的个数
        # 外星人设置

        self.fleet_drop_speed = 10         #默认10

        # 以什么样的速度加快游戏节奏
        self.speedup_scale = 1.1
        #分数的提高速度
        self.score_scale = 1.5

        self.initialize_dynamic_settings()


    def initialize_dynamic_settings(self):
        #初始化随游戏进行而变化的设置
        self.ship_speed_factor = 1.5
        self.bullet_speed_factor = 3
        self.alien_speed_factor = 1
        # fleet_direction为1表示向右;为-1表示向左
        self.fleet_direction = 1

        #积分
        self.alien_points = 50

    def increase_speed(self):
        #提高速度设置
        self.ship_speed_factor *= self.speedup_scale
        self.bullet_speed_factor *= self.speedup_scale
        self.alien_speed_factor *= self.speedup_scale
        self.alien_points = int(self.alien_points * self.score_scale)
        print(self.alien_points)


#ship.py



import pygame
from pygame.sprite import Sprite



class Ship(Sprite):

    def __init__(self, ai_settings, screen):
        """初始化飞船并设置其初始位置"""
        super(Ship, self).__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        #加载飞船图像并获取其外接矩形
        self.image = pygame.image.load('images/ship.png')       #加载图像
        self.rect = self.image.get_rect()           #获取图像的大小
        self.screen_rect = screen.get_rect()        #获取窗口的大小

        #将新船放在屏幕底部中央位置
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.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(self):
        """在指定位置绘制飞船"""
        self.screen.blit(self.image, self.rect)

    def center_ship(self):
        """让飞船在屏幕上居中"""
        self.center = self.screen_rect.centerx

可以说是非常的暴力,非常的简单。

希望不忘初心,再接再厉。

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  
  ·  7 years ago 

高难度的

Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
http://www.codeforge.com/read/474838/game_functions.py__html

搞事情呀