requirements.txt
pygame== 1.9 .6
background.py
from image import Image
class Background :
def __init__ ( self) :
self. image = Image. background
self. rect = self. image. get_rect( )
self. y = float ( self. rect. y)
def update ( self) :
if self. y < self. rect. height:
self. y += 1.5
else :
self. y = 0
self. rect. y = self. y
def draw ( self, display_surface) :
display_surface. blit( self. image, ( 0 , self. rect. y) )
display_surface. blit( self. image, ( 0 , self. rect. y - self. rect. height) )
bullet.py
import pygame
from pygame. sprite import Sprite
from image import Image
class Bullet ( Sprite) :
def __init__ ( self, hero_rect) :
super ( ) . __init__( )
self. image = Image. bullet
self. mask = pygame. mask. from_surface( self. image)
self. rect = self. image. get_rect( )
self. rect. midtop = hero_rect. midtop
def update ( self) :
self. rect. top -= 12
if self. rect. bottom <= 0 :
self. kill( )
button.py
import pygame
class Button :
def __init__ ( self, screen_rect, text) :
self. border_color = ( 96 , 96 , 96 )
self. border_rect = pygame. Rect( 0 , 0 , 180 , 40 )
self. border_rect. center = screen_rect. center
if text == "Start" :
self. border_rect. centery += 80
elif text == "Restart" :
self. border_rect. centery += 80
elif text == "Exit" :
self. border_rect. centery += 140
text_color = self. border_color
font = pygame. font. SysFont( None , 40 )
self. text_image = font. render( text, True , text_color)
self. text_rect = self. text_image. get_rect( )
self. text_rect. center = self. border_rect. center
def draw ( self, display_surface) :
pygame. draw. rect( display_surface, self. border_color, self. border_rect, 3 )
display_surface. blit( self. text_image, self. text_rect)
def is_hit ( self, pos) :
return self. border_rect. collidepoint( pos)
enemy.py
import pygame
from pygame. sprite import Sprite
from image import Image
class Enemy ( Sprite) :
def __init__ ( self, topleft, screen_rect, stats) :
super ( ) . __init__( )
self. screen_rect = screen_rect
self. stats = stats
self. image_index = 0
self. image = self. images[ self. image_index]
self. mask = pygame. mask. from_surface( self. image)
self. rect = pygame. Rect( topleft, self. get_max_size( ) )
self. current_hp = self. max_hp
self. is_hit_bullet = False
def update ( self) :
self. rect. top += 2
if self. rect. top >= self. screen_rect. bottom:
self. kill( )
def hit_by_bullet ( self) :
if self. current_hp > 0 :
self. current_hp -= 1
self. is_hit_bullet = True
@classmethod
def get_max_size ( cls) :
max_width_image = max ( cls. images, key= lambda x: x. get_width( ) )
max_height_image = max ( cls. images, key= lambda x: x. get_height( ) )
return max_width_image. get_width( ) , max_height_image. get_height( )
class EnemySmall ( Enemy) :
type = 1
max_hp = 1
score = 2
images = Image. small_enemies
def update ( self) :
super ( ) . update( )
if self. current_hp > 0 :
self. image_index = 0
else :
if self. image_index < len ( self. images) - 1 :
self. image_index += 1
else :
self. kill( )
self. stats. score += self. score
self. image = self. images[ self. image_index]
class EnemyMiddle ( Enemy) :
type = 2
max_hp = 10
score = 10
images = Image. mid_enemies
def update ( self) :
super ( ) . update( )
if self. current_hp > 0 :
if self. is_hit_bullet:
self. image_index = 1
self. is_hit_bullet = False
else :
self. image_index = 0
else :
if self. image_index < len ( self. images) - 1 :
self. image_index += 1
else :
self. kill( )
self. stats. score += self. score
self. image = self. images[ self. image_index]
class EnemyBig ( Enemy) :
type = 3
max_hp = 25
score = 100
images = Image. big_enemies
def update ( self) :
super ( ) . update( )
if self. current_hp > 0 :
if self. is_hit_bullet:
self. image_index = 2
self. is_hit_bullet = False
else :
self. image_index = ( self. image_index + 1 ) % 2
else :
if self. image_index < len ( self. images) - 1 :
self. image_index += 1
else :
self. kill( )
self. stats. score += self. score
self. image = self. images[ self. image_index]
game.py
import sys
import random
import pygame
from pygame. sprite import Group
from stats import Stats
from background import Background
from hero import Hero
from bullet import Bullet
from enemy import EnemySmall, EnemyMiddle, EnemyBig
from button import Button
from widgets import Logo, EndPrompt, Scoreboard, PauseResume
from sound import Sound
class Game :
def __init__ ( self) :
pygame. init( )
self. surface = pygame. display. set_mode( ( 480 , 852 ) )
pygame. display. set_caption( "Plane Wars" )
try :
icon = pygame. image. load( "../res/image/icon.ico" )
except pygame. error:
pass
else :
pygame. display. set_icon( icon)
self. clock = pygame. time. Clock( )
self. stats = Stats( )
self. bg = Background( )
self. hero = Hero( self. surface. get_rect( ) , self. stats)
self. bullets = Group( )
self. enemies = Group( )
buttons_name = [ "Start" , "Restart" , "Exit" ]
self. buttons = { name: Button( self. surface. get_rect( ) , name) for name in buttons_name}
widgets_name = [ "Logo" , "EndPrompt" , "Scoreboard" , "PauseResume" ]
self. widgets = { name: eval ( name) ( self. surface. get_rect( ) , self. stats) for name in widgets_name}
self. sounds = Sound( )
self. frames = 0
def reset ( self) :
self. stats. reset( )
self. hero. reset( )
self. widgets[ "PauseResume" ] . reset( )
def run ( self) :
while True :
self. handle_events( )
if self. stats. state == Stats. RUN:
self. bg. update( )
self. update_bullets( )
self. update_enemies( )
self. handle_collision( )
self. update_screen( )
self. clock. tick( 60 )
def handle_events ( self) :
for event in pygame. event. get( ) :
if event. type == pygame. QUIT:
pygame. quit( )
sys. exit( )
elif event. type == pygame. MOUSEBUTTONDOWN:
self. handle_mousedown_event( event)
elif event. type == pygame. MOUSEMOTION:
self. handle_mousemotion_event( event)
def handle_mousedown_event ( self, event) :
if self. stats. state == Stats. WELCOME:
if self. buttons[ "Start" ] . is_hit( event. pos) :
self. stats. state = Stats. RUN
self. sounds. play( "bg" )
elif self. stats. state == Stats. RUN:
if self. widgets[ "PauseResume" ] . is_hit( event. pos) :
self. widgets[ "PauseResume" ] . update_click( )
self. stats. state = Stats. PAUSE
self. sounds. pause( "bg" )
elif self. stats. state == Stats. PAUSE:
if self. widgets[ "PauseResume" ] . is_hit( event. pos) :
self. widgets[ "PauseResume" ] . update_click( )
self. stats. state = Stats. RUN
self. sounds. unpause( "bg" )
elif self. stats. state == Stats. GAMEOVER:
if self. buttons[ "Restart" ] . is_hit( event. pos) :
self. reset( )
self. stats. state = Stats. RUN
self. sounds. play( "bg" )
elif self. buttons[ "Exit" ] . is_hit( event. pos) :
pygame. quit( )
sys. exit( )
def handle_mousemotion_event ( self, event) :
if self. stats. state == Stats. RUN:
if event. buttons[ 0 ] :
self. hero. update( event. pos)
self. widgets[ "PauseResume" ] . update_mouse_motion( event. pos)
elif self. stats. state == Stats. PAUSE:
self. widgets[ "PauseResume" ] . update_mouse_motion( event. pos)
def update_bullets ( self) :
self. frames += 1
if not ( self. frames % 5 ) :
self. bullets. add( Bullet( self. hero. rect) )
self. sounds. play( "bullet" )
self. bullets. update( )
def update_enemies ( self) :
if len ( self. enemies) < 18 :
screen_rect = self. surface. get_rect( )
weighted_list = [ EnemySmall] * 30 + [ EnemyMiddle] * 3 + [ EnemyBig] * 1
enemy = random. choice( weighted_list)
left = random. randint( 0 , screen_rect. width - enemy. get_max_size( ) [ 0 ] )
top = random. randint( - screen_rect. height, - enemy. get_max_size( ) [ 1 ] )
self. enemies. add( enemy( ( left, top) , screen_rect, self. stats) )
self. enemies. update( )
def handle_collision ( self) :
collide_dict = pygame. sprite. groupcollide( self. bullets, self. enemies, True , False , pygame. sprite. collide_mask)
collide_enemies_list = [ ]
if collide_dict:
for collide_enemies in collide_dict. values( ) :
collide_enemies_list. extend( collide_enemies)
if collide_enemies_list:
for collide_enemy in collide_enemies_list:
if collide_enemy. current_hp == 1 :
self. sounds. play( "enemy" + str ( collide_enemy. type ) + "_down" )
collide_enemy. hit_by_bullet( )
enemy = pygame. sprite. spritecollideany( self. hero, self. enemies, pygame. sprite. collide_mask)
if enemy:
self. hero. is_collide = True
self. bullets. empty( )
self. enemies. empty( )
self. widgets[ "EndPrompt" ] . update_score_num( )
self. sounds. fadeout( "bg" )
self. sounds. play( "game_over" )
def update_screen ( self) :
self. bg. draw( self. surface)
if self. stats. state == Stats. WELCOME:
self. widgets[ "Logo" ] . draw( self. surface)
self. buttons[ "Start" ] . draw( self. surface)
elif self. stats. state == Stats. RUN or self. stats. state == Stats. PAUSE:
self. hero. draw( self. surface)
self. bullets. draw( self. surface)
self. enemies. draw( self. surface)
self. widgets[ "PauseResume" ] . draw( self. surface)
self. widgets[ "Scoreboard" ] . draw( self. surface)
elif self. stats. state == Stats. GAMEOVER:
self. widgets[ "EndPrompt" ] . draw( self. surface)
self. buttons[ "Restart" ] . draw( self. surface)
self. buttons[ "Exit" ] . draw( self. surface)
pygame. display. flip( )
hero.py
import pygame
from stats import Stats
from image import Image
class Hero :
def __init__ ( self, screen_rect, stats) :
self. screen_rect = screen_rect
self. stats = stats
self. images = Image. heros
self. image = self. images[ 0 ]
self. mask = pygame. mask. from_surface( self. image)
self. rect = self. image. get_rect( )
self. reset( )
def reset ( self) :
self. rect. midbottom = self. screen_rect. midbottom
self. image_index = 0
self. is_collide = False
def draw ( self, display_surface) :
if self. is_collide:
if self. image_index < len ( self. images) - 1 :
self. image_index += 1
else :
pygame. time. delay( 200 )
self. stats. state = Stats. GAMEOVER
else :
self. image_index = not self. image_index
self. image = self. images[ self. image_index]
display_surface. blit( self. image, self. rect)
def update ( self, pos) :
if self. rect. collidepoint( pos) :
self. rect. center = pos
image.py
import pygame
class Image :
pygame. init( )
pygame. display. set_mode( ( 480 , 852 ) )
heros_name = [ "hero1" , "hero2" , "hero_blowup_n1" , "hero_blowup_n2" , "hero_blowup_n3" , "hero_blowup_n4" ]
small_enemies_name = [ "enemy1" , "enemy1_down1" , "enemy1_down2" , "enemy1_down3" , "enemy1_down4" ]
mid_enemies_name = [ "enemy2" , "enemy2_hit" , "enemy2_down1" , "enemy2_down2" , "enemy2_down3" , "enemy2_down4" ]
big_enemies_name = [ "enemy3_n1" , "enemy3_n2" , "enemy3_hit" , "enemy3_down1" , "enemy3_down2" , "enemy3_down3" ,
"enemy3_down4" , "enemy3_down5" , "enemy3_down6" ]
pause_resume_name = [ "game_pause_nor" , "game_pause_pressed" , "game_resume_nor" , "game_resume_pressed" ]
try :
background = pygame. image. load( "../res/image/background.png" ) . convert( )
bullet = pygame. image. load( "../res/image/bullet1.png" ) . convert_alpha( )
heros = [ pygame. image. load( image. join( [ "../res/image/" , ".png" ] ) ) . convert_alpha( ) for image in heros_name]
small_enemies = [ pygame. image. load( image. join( [ "../res/image/" , ".png" ] ) ) . convert_alpha( ) for image in small_enemies_name]
mid_enemies = [ pygame. image. load( image. join( [ "../res/image/" , ".png" ] ) ) . convert_alpha( ) for image in mid_enemies_name]
big_enemies = [ pygame. image. load( image. join( [ "../res/image/" , ".png" ] ) ) . convert_alpha( ) for image in big_enemies_name]
logo = pygame. image. load( "../res/image/logo.png" ) . convert_alpha( )
pause_resume = [ pygame. image. load( image. join( [ "../res/image/" , ".png" ] ) ) . convert_alpha( ) for image in pause_resume_name]
except pygame. error:
raise SystemExit( pygame. get_error( ) )
plane_wars.py
from game import Game
if __name__ == "__main__" :
plane_wars_game = Game( )
plane_wars_game. run( )
sound.py
from collections import defaultdict
import pygame
class DummySound :
def play ( self, * args) :
pass
def pause ( self) :
pass
def unpause ( self) :
pass
def fadeout ( self, * args) :
pass
class Sound :
def __init__ ( self) :
try :
pygame. mixer. music. load( "../res/sound/game_music.wav" )
except pygame. error as e:
self. music = DummySound( )
print ( e)
else :
self. music = pygame. mixer. music
self. sounds = defaultdict( DummySound)
sounds_name = [ "bullet" , "enemy1_down" , "enemy2_down" , "enemy3_down" , "game_over" ]
for sound in sounds_name:
try :
self. sounds[ sound] = pygame. mixer. Sound( sound. join( [ "../res/sound/" , ".wav" ] ) )
except pygame. error as e:
print ( e)
def play ( self, name) :
if name == "bg" :
self. music. play( - 1 )
else :
self. sounds[ name] . play( )
def pause ( self, name) :
if name == "bg" :
self. music. pause( )
def unpause ( self, name) :
if name == "bg" :
self. music. unpause( )
def fadeout ( self, name) :
if name == "bg" :
self. music. fadeout( 1000 )
stats.py
class Stats :
WELCOME, RUN, GAMEOVER, PAUSE = range ( 4 )
def __init__ ( self) :
self. state = Stats. WELCOME
self. score = 0
def reset ( self) :
self. score = 0
widgets.py
import pygame
from image import Image
class Logo :
def __init__ ( self, * args) :
screen_rect = args[ 0 ]
self. image = Image. logo
self. rect = self. image. get_rect( )
self. rect. centerx = screen_rect. centerx
self. rect. centery = screen_rect. centery - 150
def draw ( self, display_surface) :
display_surface. blit( self. image, self. rect)
class Scoreboard :
def __init__ ( self, * args) :
self. stats = args[ 1 ]
self. score_color = ( 0 , 0 , 0 )
try :
self. font = pygame. font. Font( "../res/font/comici.ttf" , 35 )
except Exception as e:
print ( e)
self. font = pygame. font. SysFont( None , 50 )
def draw ( self, display_surface) :
score_image = self. font. render( str ( self. stats. score) , True , self. score_color)
display_surface. blit( score_image, ( 80 , 0 ) )
class PauseResume :
PAUSE_NORMAL, PAUSE_PRESSED, RESUME_NORMAL, RESUME_PRESSED = range ( 4 )
def __init__ ( self, * args) :
self. images = Image. pause_resume
self. state = PauseResume. PAUSE_NORMAL
self. rect = self. images[ self. state] . get_rect( )
self. rect. topleft = ( 0 , 5 )
def reset ( self) :
self. state = PauseResume. PAUSE_NORMAL
def draw ( self, display_surface) :
display_surface. blit( self. images[ self. state] , self. rect)
def is_hit ( self, pos) :
return self. rect. collidepoint( pos)
def update_click ( self) :
if self. state == PauseResume. PAUSE_NORMAL or self. state == PauseResume. PAUSE_PRESSED:
self. state = PauseResume. RESUME_NORMAL
else :
self. state = PauseResume. PAUSE_NORMAL
def update_mouse_motion ( self, pos) :
is_mouse_on = self. is_hit( pos)
if is_mouse_on:
if self. state == PauseResume. PAUSE_NORMAL:
self. state = PauseResume. PAUSE_PRESSED
elif self. state == PauseResume. RESUME_NORMAL:
self. state = PauseResume. RESUME_PRESSED
else :
if self. state == PauseResume. PAUSE_PRESSED:
self. state = PauseResume. PAUSE_NORMAL
elif self. state == PauseResume. RESUME_PRESSED:
self. state = PauseResume. RESUME_NORMAL
class EndPrompt :
def __init__ ( self, * args) :
screen_rect = args[ 0 ]
self. stats = args[ 1 ]
self. border_color = ( 96 , 96 , 96 )
self. border_rect = pygame. Rect( 0 , 0 , 350 , 300 )
self. border_rect. centerx = screen_rect. centerx
self. border_rect. centery = screen_rect. centery + 40
self. score_color = self. border_color
self. font = pygame. font. SysFont( None , 40 )
self. score_text_image = self. font. render( "Score:" , True , self. score_color)
self. score_text_top = self. border_rect. top + 30
self. score_text_left = self. border_rect. left + 30
self. update_score_num( )
def update_score_num ( self) :
self. score_num_image = self. font. render( str ( self. stats. score) , True , self. score_color)
self. score_num_rect = self. score_num_image. get_rect( )
self. score_num_rect. centerx = self. border_rect. centerx
self. score_num_rect. centery = self. border_rect. top + 80
def draw ( self, display_surface) :
pygame. draw. rect( display_surface, self. border_color, self. border_rect, 3 )
display_surface. blit( self. score_text_image, ( self. score_text_left, self. score_text_top) )
display_surface. blit( self. score_num_image, self. score_num_rect)