使用pygame开发一个弹幕射击游戏(一)

本文作为开发过程记录用。

目前游戏画面:

下一个添加的功能:敌机可以进行射击。

 

 

 

弹幕类

from pygame.sprite import Sprite
from pygame import transform
import math

class Barrage(Sprite):
    def __init__(self,raiden_settings,screen,ship,enemy,angle=0):
        self.barrage_type = enemy.barrage_type
        self.screen = screen
        self.raiden_settings = raiden_settings
        
        self.ship = ship

        self.image = pygame.image.load(raiden_settings. \
            barrage_image[barrage_type-1])
            
        self.rect = self.image.get_rect()
        
        self.rect.x = enemy.rect.x
        self.rect.y = enemy.rect.y
        
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        
        self.angle = angle
        
        if self.barrage_type == 1:
            self.image = pygame.transform.rotate(self.image, 
                raiden_settings.direction_angle)
                
    def update(self):
        if self.barrage_type == 1 or self.barrage_type == 2:
            self.x += self.raiden_settings.barrage_speed_factor * \
                math.sin(self.angle)
            self.y += self.raiden_settings.barrage_speed_factor * \
                math.cos(self.angle)
        if self.barrage_type == 3:
            tmp = ((self.x - self.ship.x) ** 2 + (self.y -self.ship.y) \
            ** 2) ** 0.5
            self.x += self.raiden_settings.barrage_speed_factor * \
                (self.ship.x - self.x)/tmp
            self.y += self.raiden_settings.barrage_speed_factor * \
                (self.y - self.ship.y)/tmp
        self.rect.x = self.x
        self.rect.y = self.y
        
        

 

子弹类

import pygame
from pygame.sprite import Sprite
import math
from pygame import transform

class Bullet(Sprite):
    def __init__(self,raiden_settings,screen,ship,angle):
        super().__init__()
        self.screen = screen
        self.image = pygame.image.load(raiden_settings.bullet_image)
        self.image = pygame.transform.rotate(self.image,angle)
        self.rect = self.image.get_rect()
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        
        self.y = float(self.rect.y) 
        self.x = float(self.rect.x)
        
        self.angle = angle
        self.speed_factor = raiden_settings.bullet_speed_factor
        
    def update(self):
        self.y -=self.speed_factor * math.cos(self.angle)
        self.x +=self.speed_factor * math.sin(self.angle)
        self.rect.y = self.y
        self.rect.x = self.x
        
    def draw_bullet(self):
        pygame.draw.rect(self.screen,self.color,self.rect)

 

 

按钮类

import pygame.font

class Button():
    
    def __init__(self,raiden_settings,screen,msg):
        self.screen = screen
        self.screen_rect = screen.get_rect()
        
        self.width = raiden_settings.button_width
        self.height = raiden_settings.button_height
        self.button_color = raiden_settings.button_color
        self.text_color = raiden_settings.button_text_color
        self.font = pygame.font.SysFont(None,
            raiden_settings.button_font_size)
        
        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)

 

掉落物类

import pygame
from pygame.sprite import Sprite

class DropItem(Sprite):
    def __init__(self,raiden_settings,screen,enemy,ship):
        super().__init__()
        self.screen = screen
        self.raiden_settings = raiden_settings
        self.image = pygame.image.load( \
            raiden_settings.dropitem_image[ship.arms_level - 1]). \
            convert_alpha()
        self.rect = self.image.get_rect()
        self.rect.centerx = enemy.rect.centerx
        self.rect.top = enemy.rect.bottom
        self.y = self.rect.y
        self.speed_factor = raiden_settings.dropitem_speed_factor
        self.level = ship.arms_level + 1
        
    def update(self):
        self.y +=self.speed_factor
        self.rect.y = self.y
        
    def draw_dropitem(self):
        self.screen.blit(self.image,self.rect)

 

敌机类

import pygame
from pygame.sprite import Sprite
from pygame import transform
from random import randint

class Enemy(Sprite):
    
    def __init__(self,raiden_settings,screen):
        super().__init__()
        self.screen = screen
        self.raiden_settings = raiden_settings
        self.enemy_type = randint(1,3)
        
        self.image = pygame.image.load(raiden_settings. \
            enemy_image[self.enemy_type - 1]).convert_alpha()
        self.image = transform.smoothscale(self.image,
            raiden_settings.enemy_image_rect)
        self.image = pygame.transform.rotate(self.image, 
            raiden_settings.direction_angle)
        self.rect = self.image.get_rect()
        
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        
        
        self.barrage_type = self.enemy_type
        
        self.set_enemy_rect()
        
    def blitme(self):
        self.screen.blit(self.image,self.rect)
        
    def update(self):
        # ~ self.x += (self.raiden_settings.enemy_speed_factor *
            # ~ self.raiden_settings.fleet_direction)
        # ~ self.rect.x = self.x
        if self.enemy_type == 1:
            self.y += self.raiden_settings.enemy_speed_factor 
        if self.enemy_type == 2:
            if self.x < 100 :
                self.x += self.raiden_settings.enemy_speed_factor
            elif self.x >self.screen.get_rect().right - 100:
                self.x -= self.raiden_settings.enemy_speed_factor
        if self.enemy_type == 3:
            if self.x <= self.screen.get_rect().right:
                self.x += self.raiden_settings.enemy_speed_factor
            else:
                self.x -= self.raiden_settings.enemy_speed_factor
            self.y += self.raiden_settings.enemy_speed_factor
            
        self.rect.x = self.x
        self.rect.y = self.y
        
    def check_edges(self):
        screen_rect = self.screen.get_rect()
        if self.rect.right >= screen_rect.right:
            return True
        elif self.rect.left <= 0:
            return True
    
    def set_enemy_rect(self):
        if self.enemy_type == 1:
            self.x = randint(0,self.screen.get_rect().width)
            self.y = 0
        elif self.enemy_type == 2:
            self.y = 200
            if randint(1,2) == 1:
                self.x = 0
            else:
                self.x = self.screen.get_rect().right
        elif self.enemy_type == 3:
            self.y = randint(0,300)
            if randint(1,2) == 1:
                self.x = 0
            else:
                self.x = self.screen.get_rect().right
        self.rect.x = self.x
        self.rect.y = self.y

 

游戏内功能函数类

import sys
import pygame


from Bullet import Bullet
from Enemy import Enemy
from time import sleep
from dropitem import DropItem
from random import random
from barrage import Barrage



#检查输入
def check_events(raiden_settings,screen,stats,ship,enemys,bullets,
    play_button,sprites):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_event(event,raiden_settings,screen,ship,
                bullets,sprites)
        elif event.type == pygame.KEYUP:
            check_keyup_event(event,ship)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x,mouse_y = pygame.mouse.get_pos()
            check_play_button(raiden_settings,stats,screen,play_button,
                mouse_x,mouse_y)
        elif event.type == pygame.USEREVENT:
            create_enemy(raiden_settings,screen,enemys,sprites)
            
            
            
#更新屏幕
def update_screen(screen,stats,play_button,sprites):
    if not stats.game_active:
        play_button.draw_button()
    else:
        updates = sprites.draw(screen)
        pygame.display.update(updates)
    pygame.display.flip()


    
#检查按下输入
def check_keydown_event(event,raiden_settings,screen,ship,bullets,
    sprites):
    if event.key == pygame.K_d:
        ship.moving_right = True
    elif event.key == pygame.K_a:
        ship.moving_left = True
    elif event.key == pygame.K_SPACE:
        fire_bullet(raiden_settings,screen,ship,bullets,sprites)
    elif event.key == pygame.K_w:
        ship.moving_up = True
    elif event.key == pygame.K_s:
        ship.moving_down = True
    elif event.key == pygame.K_q:
        sys.exit()
 
 

#检查放开输入
def check_keyup_event(event,ship):
    if event.key == pygame.K_d:
        ship.moving_right = False
    elif event.key == pygame.K_a:
        ship.moving_left = False
    elif event.key == pygame.K_w:
        ship.moving_up = False
    elif event.key == pygame.K_s:
        ship.moving_down = False


        
#更新子弹
def update_bullets(raiden_settings,screen,stats,ship,enemys,bullets,
    dropitems,scoreboard,sprites):
    for bullet in bullets.copy():
        if bullet.rect.bottom <=0 or  bullet.rect.x <= 0 or \
            bullet.rect.x >= raiden_settings.screen_width:
            bullets.remove(bullet)
    collisions = pygame.sprite.groupcollide(bullets,enemys,True,True)
    if collisions:
        enemy_hit(raiden_settings,screen,stats,ship,enemys,dropitems,
            scoreboard,collisions,sprites)


                    
#敌人被击中
def enemy_hit(raiden_settings,screen,stats,ship,enemys,dropitems,
    scoreboard,collisions,sprites):
    for bullet,enemy_list in collisions.items():
        stats.score += raiden_settings.score_up_factor
        scoreboard.prep_score()
        scoreboard.show_score()
        if check_drop(raiden_settings):
            for enemy in enemy_list:
                new_dropitem = DropItem(raiden_settings,screen,enemy,
                    ship)
                dropitems.add(new_dropitem)
                sprites.add(new_dropitem)


   
#更新掉落物
def update_dropitems(raiden_settings,screen,stats,ship,dropitems,
    sprites):
    for dropitem in dropitems.copy():
        if dropitem.rect.bottom <= 0:
            sprites.remove(dropitem)
            dropitems.remove(dropitem)
    collision = pygame.sprite.spritecollideany(ship,dropitems)
    if collision:
        sprites.remove(collision)
        dropitems.remove(collision)
        if collision.level == ship.arms_level + 1:
            ship.update_arms()




#开火
def fire_bullet(raiden_settings,screen,ship,bullets,sprites):
    bullet_list = []
    if ship.arms_level == raiden_settings.arms_1_level:
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.vertical_angle))
    elif ship.arms_level == raiden_settings.arms_2_level:
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.left_deflectical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.right_deflectical_angle))
    elif ship.arms_level == raiden_settings.arms_3_level:
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.vertical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.left_deflectical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.right_deflectical_angle))
    elif ship.arms_level == raiden_settings.arms_4_level:
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.vertical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.left_deflectical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.right_deflectical_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.left_horizontal_angle))
        bullet_list.append(Bullet(raiden_settings,screen,ship,
            raiden_settings.right_horizontal_angle))
    for bullet in bullet_list:
        bullets.add(bullet)
        sprites.add(bullet)



#创建敌人
def create_enemy(raiden_settings,screen,enemys,sprites):
    enemy = Enemy(raiden_settings,screen)
    enemys.add(enemy)
    sprites.add(enemy)


    
def update_enemys(raiden_settings,stats,lifeboard,screen,ship,enemys,
    bullets,sprites):
    if pygame.sprite.spritecollideany(ship,enemys):
        ship_hit(raiden_settings,stats,lifeboard,screen,ship,enemys,
            bullets,sprites)
    


#玩家被击中
def ship_hit(raiden_settings,stats,lifeboard,screen,ship,enemys,
    bullets,sprites):
    if stats.ships_left > 0:
        stats.ships_left -= 1
        ship.reset_ship()
        lifeboard.dead(stats,sprites)
        reset_game(raiden_settings,screen,ship,enemys,bullets,sprites)
        sleep(1)
    else:
        stats.game_active = False
        pygame.mouse.set_visible(False)
        stats.ship_left = raiden_settings.ship_init_life
        stats.score = 0
        stats.reset_stats()
        ship.reset_ship()
        reset_game(raiden_settings,screen,ship,enemys,bullets,sprites)
        pygame.mouse.set_visible(True)
        lifeboard.dead(stats,sprites)



#重置游戏
def reset_game(raiden_settings,screen,ship,enemys,bullets,sprites):
    for enemy in enemys:
        sprites.remove(enemy)
    enemys.empty()
    for bullet in bullets:
        sprites.remove(bullet)
    bullets.empty()
    sprites.clear(screen,clear_callback)
    ship.center_ship()
    


#检查玩家是否点击play按钮
def check_play_button(raiden_settings,stats,screen,play_button,
    mouse_x,mouse_y):
    if play_button.rect.collidepoint(mouse_x,mouse_y) and not \
        stats.game_active:
        stats.game_active = True
        pygame.mouse.set_visible(False)
        screen.fill(raiden_settings.bg_color)



#是否掉落物品
def check_drop(raiden_settings):
    if random() < raiden_settings.chance:
        return True
    else:
        return False



#检查掉落物是否到达屏幕底
def check_dropitem_bottom(raiden_settings,stats,screen,dropitems):
    screen_rect = screen.get_rect()
    for dropitem in dropitems.sprite():
        if dropitem.rect.bottom >= screen_rect.bottom:
            dropitems.remove(dropitem)


            
#清除子图形
def clear_callback(surf, rect):
    bg = 255,255,255
    surf.fill(bg, rect)
    

    

 

生命值记录板类

from pygame.sprite import Sprite
from pygame.sprite import Group
from Ship import Ship
from pygame import transform

class Lifeboard(Sprite):
    
    def __init__(self,raiden_settings,screen,stats,sprites):
        super().__init__()
        self.stats = stats
        self.screen = screen
        self.rect = screen.get_rect()
        self.raiden_settings = raiden_settings
        self.ships = Group()
        self.ship_list = []
        self.prep_ships()
        
        for ship in self.ships:
            sprites.add(ship)
            ship.image = transform.smoothscale(ship.image,
            raiden_settings.lifeboard_image_rect)
            
    
    def prep_ships(self):
        for ship_number in range(self.stats.ships_left):
            ship = Ship(self.raiden_settings,self.screen)
            ship.center = self.raiden_settings.lifeboard_ship_center + \
                ship_number * self.raiden_settings. \
                lifeboard_ship_center_growth
            ship.bottom = self.raiden_settings.lifeboard_ship_bottom
            self.ships.add(ship)
            self.ship_list.append(ship)

            
    def dead(self,stats,sprites):
        self.ships.remove(self.ship_list[-1])
        sprites.remove(self.ship_list[-1])
        del self.ship_list[-1]
            

 

游戏类(主程序)

import sys
import pygame


from Settings import Settings
from Ship import Ship
import game_functions as gf
from pygame.sprite import Group
from Enemy import Enemy
from GameStats import GameStats
from Button import Button
from Scoreboard import Scoreboard
from Lifeboard import Lifeboard



def run_game():
    pygame.init()
    raiden_settings = Settings()
    screen = pygame.display.set_mode((raiden_settings.screen_width,
        raiden_settings.screen_height))
    
    EVENT_CREATE_ENEMY = pygame.USEREVENT 
    pygame.time.set_timer(EVENT_CREATE_ENEMY,300)
    
    
    pygame.display.set_caption("Raiden")
    play_button = Button(raiden_settings,screen,"Play!")
    ship = Ship(raiden_settings,screen)
    bullets = Group()
    enemys = Group()
    dropitems = Group()
    sprites = pygame.sprite.RenderUpdates()
    stats = GameStats(raiden_settings)
    scoreboard = Scoreboard(raiden_settings,screen,stats)
    lifeboard = Lifeboard(raiden_settings,screen,stats,sprites)
    screen.fill(raiden_settings.bg_color)
    sprites.add(ship)
    sprites.add(scoreboard)
    
    while True:
        gf.check_events(raiden_settings,screen,stats,ship,enemys,
            bullets,play_button,sprites)
        if stats.game_active:
            sprites.clear(screen,gf.clear_callback)
            sprites.update()
            gf.update_bullets(raiden_settings,screen,stats,ship,enemys,
                bullets,dropitems,scoreboard,sprites)
            gf.update_dropitems(raiden_settings,screen,stats,ship,
                dropitems,sprites)
            gf.update_enemys(raiden_settings,stats,lifeboard,screen,
                ship,enemys,bullets,sprites)
        gf.update_screen(screen,stats,play_button,sprites)

run_game()

 

计分板类

import pygame.font
from pygame.sprite import Sprite
from pygame.sprite import Group

from Ship import Ship

class Scoreboard(Sprite):
    def __init__(self,raiden_settings,screen,stats):
        super().__init__()
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.raiden_settings = raiden_settings
        self.stats = stats
        
        self.text_color = raiden_settings.scoreboard_text_color
        self.font = pygame.font.SysFont(None,
            raiden_settings.scoreboard_font_size)
    
        self.prep_score()
    
    def prep_score(self):
        score_str = str(self.stats.score)
        self.image = self.font.render(score_str,True,
            self.text_color,self.raiden_settings.bg_color)
            
        self.rect = self.image.get_rect()
        self.rect.right = self.screen_rect.right 
        self.rect.top = 0
        
    def show_score(self):
        self.screen.blit(self.image,self.rect)
        
    

 

常数类

import math

class Settings():
    def __init__(self):
        #屏幕设置
        self.screen_width = 300
        self.screen_height = 600
        self.bg_color = (255,255,255)
        #飞行速度设置
        self.ship_speed_factor = 0.3
        self.enemy_speed_factor = 0.3
        self.fleet_drop_speed = 8
        self.enemy_speed_up_factor = 0.1
        self.bullet_speed_factor = 0.7
        self.barrage_speed_factor = 0.7
        #飞行方向设置
        self.fleet_direction = 1
        #生命值
        self.ship_init_life = 3
        #分数设置
        self.score_up_factor = 10
        #掉落物设置
        self.dropitem_speed_factor = 0.1
        #掉落指数设置
        self.chance = 0.5
        #武器等级设置
        self.init_arms_level = 1
        self.max_arms_level = 4
        self.arms_1_level = 1
        self.arms_2_level = 2
        self.arms_3_level = 3
        self.arms_4_level = 4
        #角度
        self.vertical_angle = 0
        self.right_deflectical_angle = math.pi/6
        self.left_deflectical_angle = -math.pi/6
        self.left_horizontal_angle = -math.pi/2
        self.right_horizontal_angle = math.pi/2
        self.direction_angle = 180
        self.angle_left_10 = -10
        self.angle_right_10 = 10
        #图片位置
        self.enemy_image = [
            'image/enemy1.png',
            'image/enemy2.png',
            'image/enemy3.png',
            ]
            
        self.ship_image = 'image/9.png'
        self.bullet_image = 'image/bullet.png'
        self.dropitem_image = [
            'image/dropitem1.png',
            'image/dropitem2.png',
            'image/dropitem3.png',
            'image/dropitem4.png',
            ]
        self.barrage_image  = [
            'image\barrage1.png',
            'image\barrage2.png',
            'image\barrage3.png',
            ]
        #enemy图片大小
        self.enemy_image_rect = (30,30)
        #lifeboard图片大小
        self.lifeboard_image_rect = (30,30)
        #ship图片大小
        self.ship_image_rect = (50,50)
        #计分板字体颜色
        self.scoreboard_text_color = (30,30,30)
        #计分板字体大小
        self.scoreboard_font_size = 48
        #计分板位置
        self.lifeboard_ship_center = 25
        self.lifeboard_ship_bottom = 50
        self.lifeboard_ship_center_growth = 15
        #button设置
        self.button_text_color = (255,255,255)
        self.button_color = (0,255,0)
        self.button_width = 200
        self.button_height = 50
        self.button_font_size = 48

 

飞船类

import pygame
from Settings import Settings
from pygame.sprite import Sprite
from pygame import transform

class Ship(Sprite):
    
    def __init__(self,raiden_settings,screen):
        super().__init__()
        self.screen = screen
        self.raiden_settings = raiden_settings
        
        self.image = pygame.image.load(raiden_settings.ship_image). \
            convert_alpha()
        self.image = transform.smoothscale(self.image,
            raiden_settings.ship_image_rect)
        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
        
        self.arms_level = raiden_settings.init_arms_level
        
        self.center = float(self.rect.centerx)
        self.bottom = float(self.rect.bottom)
        
        self.moving_right = False
        self.moving_left = False
        self.moving_up = False
        self.moving_down = False
        
    def update(self):
        if self.moving_right and self.rect.right < \
            self.screen_rect.right:
            self.center += self.raiden_settings.ship_speed_factor
        if self.moving_left and self.rect.left > 0:
            self.center -= self.raiden_settings.ship_speed_factor
        if self.moving_up and self.rect.top > 0:
            self.bottom -=self.raiden_settings.ship_speed_factor
        if self.moving_down and self.rect.bottom < \
            self.screen_rect.bottom:
            self.bottom +=self.raiden_settings.ship_speed_factor
        
        self.rect.centerx = self.center
        self.rect.bottom = self.bottom
        
    def blitme(self):
        self.screen.blit(self.image,self.rect)
        
    def center_ship(self):
        self.center = self.screen_rect.centerx
        
    def update_arms(self):
        if self.arms_level < self.raiden_settings.max_arms_level:
            self.arms_level += 1
            
    def reset_ship(self):
        self.rect.centerx = self.screen_rect.centerx
        self.rect.bottom = self.screen_rect.bottom
        self.center = self.screen_rect.centerx
        self.bottom = self.screen_rect.bottom
        self.arms_level = self.raiden_settings.init_arms_level

 

游戏内部记录类

class GameStats():
    def __init__(self,raiden_settings):
        self.raiden_settings = raiden_settings
        self.reset_stats()
        self.game_active = False
        self.score = 0
        
    def reset_stats(self):
        self.ships_left = self.raiden_settings.ship_init_life
        

 

posted @ 2018-10-30 16:46  东东欧尼酱  阅读(2295)  评论(2编辑  收藏  举报