پیش گفتار
در این بخش بازی مهاجمان فضایی را به پایان می بریم. این بازی از مفاهیم شی گرایی استفاده می کند و از این نظر با بازی های پیشین متفاوت است.
ادامه آموزش بازی
اگر بازی را اجرا کنیم می بینیم که سفینه در جای مناسبی قرار ندارد. برای تغییر جای مانع در فایل main.py داریم:
self.create_obstacle(40,480) def create_obstacle(self,x_start,y_start): for row_index,row in enumerate(self.shape): for col_index,col in enumerate(row): if col =='x': x=x_start + col_index*self.block_size y=y_start + row_index*self.block_size block=obstacle.Block(self.block_size,(241,79,80),x,y) self.blocks.add(block)
اگر بازی را دوباره اجرا کنیم تصویر زیر را خواهیم دید:
برای ایجاد مانع های گوناگون تغییرهای زیر را فایل main.py اعمال می کنیم:
# obstacle setup self.shape=obstacle.shape self.block_size=6 self.blocks=pygame.sprite.Group() self.create_multiple_obstacles(0,480,0,100,200) def create_obstacle(self,x_start,y_start,offset_x): for row_index,row in enumerate(self.shape): for col_index,col in enumerate(row): if col =='x': x=x_start + col_index*self.block_size + offset_x y=y_start + row_index*self.block_size block=obstacle.Block(self.block_size,(241,79,80),x,y) self.blocks.add(block) def create_multiple_obstacles(self,x_start,y_start,*offset): for offset_x in offset: self.create_obstacle(x_start,y_start,offset_x)
اگر بازی را دوباره اجرا کنیم تغییر زیر را خواهیم داشت:
با نگاه به تصویر بالا متوجه خواهیم شد که مانع سمت چپ از پنجره فاصله ای ندارد. برای ایجاد فاصله میان مانع ها تغییر زیر را در کد اعمال می کنیم:
self.create_multiple_obstacles(0,100,200,x_start=0,y_start=480) def create_obstacle(self,x_start,y_start,offset_x): for row_index,row in enumerate(self.shape): for col_index,col in enumerate(row): if col =='x': x=x_start + col_index*self.block_size + offset_x y=y_start + row_index*self.block_size block=obstacle.Block(self.block_size,(241,79,80),x,y) self.blocks.add(block) def create_multiple_obstacles(self,*offset,x_start,y_start,): for offset_x in offset: self.create_obstacle(x_start,y_start,offset_x)
سپس داریم:
self.obstacle_amount=4 self.obstacle_x_positions= [num * (WIDTH / self.obstacle_amount) for num in range(self.obstacle_amount)] self.create_multiple_obstacles(*self.obstacle_x_positions,x_start=0,y_start=480)
و برای ایجاد فاصله از چپ داریم:
self.create_multiple_obstacles(*self.obstacle_x_positions,x_start=WIDTH / 15 ,y_start=480)
کد فایل main.py تا این لحظه:
import pygame,sys from player import Player import obstacle class Game: def __init__(self): player_sprite=Player((WIDTH/2,HEIGHT),WIDTH,5) self.player=pygame.sprite.GroupSingle(player_sprite) # obstacle setup self.shape=obstacle.shape self.block_size=6 self.blocks=pygame.sprite.Group() self.obstacle_amount=4 self.obstacle_x_positions= [num * (WIDTH / self.obstacle_amount) for num in range(self.obstacle_amount)] self.create_multiple_obstacles(*self.obstacle_x_positions,x_start=WIDTH / 15 ,y_start=480) def create_obstacle(self,x_start,y_start,offset_x): for row_index,row in enumerate(self.shape): for col_index,col in enumerate(row): if col =='x': x= x_start + col_index*self.block_size + offset_x y= y_start + row_index*self.block_size block=obstacle.Block(self.block_size,(241,79,80),x,y) self.blocks.add(block) def create_multiple_obstacles(self,*offset,x_start,y_start,): for offset_x in offset: self.create_obstacle(x_start,y_start,offset_x) def run(self): self.player.draw(SCREEN) self.player.sprite.lasers.draw(SCREEN) self.player.update() self.blocks.draw(SCREEN) if __name__ == "__main__": pygame.init() WIDTH=600 HEIGHT=600 SCREEN=pygame.display.set_mode((WIDTH,HEIGHT)) Clock=pygame.time.Clock() game=Game() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() SCREEN.fill((30,30,30)) game.run() pygame.display.flip() Clock.tick(60)
ساخت بیگانگان
یک فایل جدید به نام alien.py در پوشه code می سازیم:
import pygame class Alien(pygame.sprite.Sprite): def __init__(self,color,x,y): super().__init__() file_path=r'C:/Users/Rahmani/Desktop/space_invaders/graphics/' + color + '.png' self.image=pygame.image.load(file_path).convert_alpha() self.rect=self.image.get_rect(topleft=(x,y))
سپس در فایل main داریم:
import pygame,sys,os from player import Player import obstacle from alien import Alien class Game: def __init__(self): # player setup player_sprite=Player((WIDTH/2,HEIGHT),WIDTH,5) self.player=pygame.sprite.GroupSingle(player_sprite) # obstacle setup self.shape=obstacle.shape self.block_size=6 self.blocks=pygame.sprite.Group() self.obstacle_amount=4 self.obstacle_x_positions= [num * (WIDTH / self.obstacle_amount) for num in range(self.obstacle_amount)] self.create_multiple_obstacles(*self.obstacle_x_positions,x_start=WIDTH / 15 ,y_start=480) # Alien setup self.aliens=pygame.sprite.Group() self.alien_setup(rows=6,cols=8) def create_obstacle(self,x_start,y_start,offset_x): for row_index,row in enumerate(self.shape): for col_index,col in enumerate(row): if col =='x': x=x_start + col_index*self.block_size + offset_x y=y_start + row_index*self.block_size block=obstacle.Block(self.block_size,(241,79,80),x,y) self.blocks.add(block) def create_multiple_obstacles(self,*offset,x_start,y_start,): for offset_x in offset: self.create_obstacle(x_start,y_start,offset_x) def alien_setup(self,rows,cols): for row_index,row in enumerate(range(rows)): for col_index,col in enumerate(range(cols)): x= col_index y= row_index alien_sprite=Alien('red',x,y) self.aliens.add(alien_sprite) def run(self): self.player.update() self.player.sprite.lasers.draw(SCREEN) self.player.draw(SCREEN) self.blocks.draw(SCREEN) self.aliens.draw(SCREEN) if __name__ == "__main__": pygame.init() WIDTH=600 HEIGHT=600 SCREEN=pygame.display.set_mode((WIDTH,HEIGHT)) Clock=pygame.time.Clock() game=Game() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() SCREEN.fill((30,30,30)) game.run() pygame.display.flip() Clock.tick(60)
بیگانگان در شش سطر و هشت ستون خواهند بود:
# Alien setup self.aliens=pygame.sprite.Group() self.alien_setup(rows=6,cols=8)
تابع alien_setup برای رسم بیگانگان به کار می رود:
def alien_setup(self,rows,cols): for row_index,row in enumerate(range(rows)): for col_index,col in enumerate(range(cols)): x= col_index y= row_index alien_sprite=Alien('red',x,y) self.aliens.add(alien_sprite)
فعلا بیگانه قرمز رنگ را نمایش می دهیم.اگر بازی را اجرا کنیم نتیجه زیر را خواهیم دید:
تغییر زیر را در متد alien_setup در فایل main.py می دهیم تا همه بیگانگان نشان داده شوند و در جای مناسب قرار گیرند:
def alien_setup(self,rows,cols,x_distance=60,y_distance=48,x_offset=70,y_offset=100): for row_index,row in enumerate(range(rows)): for col_index,col in enumerate(range(cols)): x= col_index * x_distance + x_offset y= row_index * y_distance + y_offset self.aliens.add(alien_sprite)
با اجرای کد بالا همه بیگانگان نمایش داده می شوند:
برای نمایش بیگانگان با رنگ های گوناگون کد زیر را به فایل alien.py می افزاییم:
import pygame class Alien(pygame.sprite.Sprite): def __init__(self,color,x,y): super().__init__() file_path = r'C:/Users/Rahmani/Desktop/space_invaders/graphics/' + color + '.png' self.image = pygame.image.load(file_path).convert_alpha() self.rect = self.image.get_rect(topleft = (x,y)) if color == 'red': self.value = 100 elif color == 'green': self.value = 200 else: self.value = 300
سپس در فایل main.py داریم:
def alien_setup(self,rows,cols,x_distance=60,y_distance=48,x_offset=70,y_offset=100): for row_index,row in enumerate(range(rows)): for col_index,col in enumerate(range(cols)): x= col_index * x_distance + x_offset y= row_index * y_distance + y_offset if row_index == 0 : alien_sprite=Alien('yellow',x,y) elif 1 <= row_index <= 2: alien_sprite = Alien('green',x,y) else: alien_sprite=Alien('red',x,y) self.aliens.add(alien_sprite)
اگر بازی را اجرا کنیم بیگانگان را با رنگ های گوناگون خواهیم دید:
حرکت بیگانگان
سپس متد update را به فایل alien.py می افزاییم:
def update(self,direction): self.rect.x += direction
سپس کد زیر را به main.py اضافه می کنیم:
# Alien setup self.aliens=pygame.sprite.Group() self.alien_setup(rows=6,cols=8) self.alien_direction = 1
سپس در متد run داریم :
def run(self): self.player.update() self.aliens.update(self.alien_direction)
برای حرکت بیگانگان به چپ و راست داریم متد alien_position_checker را به main.py اضافه می کنیم:
def alien_position_checker(self): all_aliens=self.aliens.sprites() for alien in all_aliens: if alien.rect.right >= WIDTH: self.alien_direction = -1 elif alien.rect.left <= 0: self.alien_direction = 1
برای حرکت بیگانگان به پایین متد alien_move_down را به main.py اضافه می کنیم:
def alien_position_checker(self): all_aliens=self.aliens.sprites() for alien in all_aliens: if alien.rect.right >= WIDTH: self.alien_direction = -1 self.alien_move_down(2) elif alien.rect.left <= 0: self.alien_direction = 1 self.alien_move_down(2) def alien_move_down(self,distance): if self.aliens: for alien in self.aliens.sprites(): alien.rect.y += distance
ساخت لیزر برای بیگانگان
ابتدا ماژول random را وارد main.py می کنیم:
from random import choice, randint
سپس Laser را وارد main.py می کنیم:
from laser import Laser
سپس خط زیر را اضافه می کنیم:
# Alien setup self.aliens=pygame.sprite.Group() self.alien_lasers=pygame.sprite.Group() self.alien_setup(rows=6,cols=8) self.alien_direction = 1
سپس متد alien_shoot را می سازیم:
def alien_shoot(self): if self.aliens.sprites(): random_alien=choice(self.aliens.sprites()) laser_sprite=Laser(random_alien.rect.center,6,HEIGHT) self.alien_lasers.add(laser_sprite)
سپس باید لیزرها را نمایش بدهیم:
def run(self): self.player.update() self.aliens.update(self.alien_direction) self.alien_position_checker() self.alien_shoot() self.alien_lasers.update() self.player.sprite.lasers.draw(SCREEN) self.player.draw(SCREEN) self.blocks.draw(SCREEN) self.aliens.draw(SCREEN) self.alien_lasers.draw(SCREEN)
اگر بازی را اجرا کنیم بیگانگان بی امان تیر شلیک خواهند کرد.برای درست کردن این مشکل باید از زمان سنج(timer) استفاده کنیم:
if __name__ == "__main__": pygame.init() WIDTH=600 HEIGHT=600 SCREEN=pygame.display.set_mode((WIDTH,HEIGHT)) Clock=pygame.time.Clock() game=Game() ALIENLASER=pygame.USEREVENT + 1 pygame.time.set_timer(ALIENLASER, 800) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == ALIENLASER: game.alien_shoot() SCREEN.fill((30,30,30)) game.run() pygame.display.flip() Clock.tick(60)
سپس متد alien_shoot در متد run را comment می کنیم:
# self.alien_shoot() self.alien_lasers.update()
برای افزودن بیگانگان بیش تر در فایل alien.py داریم:
class Extra(pygame.sprite.Sprite): def __init__(self,side,screen_width): super().__init__() self.image=pygame.image.load(r'C:/Users/Rahmani/Desktop/space_invaders/graphics/extra.png').convert_alpha() if side == 'right': x = screen_width + 50 self.speed = -3 else: x = -50 self.speed = 3 self.rect= self.image.get_rect(topleft = (x,80)) def update(self): self.rect.x += self.speed
سپس در فایل main.py داریم:
from alien import Alien,Extra
سپس داریم:
# Alien setup self.aliens=pygame.sprite.Group() self.alien_lasers=pygame.sprite.Group() self.alien_setup(rows=6,cols=8) self.alien_direction = 1 # extra setup self.extra=pygame.sprite.GroupSingle() self.extra_spawn_time=randint(400,800)
سپس متد زیر را برای بیگانه آبی رنگ داریم:
def extra_alien_timer(self): self.extra_spawn_time -= 1 if self.extra_spawn_time <= 0: self.extra.add(Extra(choice(['right','left']),WIDTH)) self.extra_spawn_time=randint(400,800)
پس از آن داریم:
# self.alien_shoot() self.alien_lasers.update() self.extra_alien_timer()
سپس نوبت نمایش آن است:
def run(self): self.player.update() self.aliens.update(self.alien_direction) self.alien_position_checker() # self.alien_shoot() self.alien_lasers.update() self.extra_alien_timer() self.extra.update() self.player.sprite.lasers.draw(SCREEN) self.player.draw(SCREEN) self.blocks.draw(SCREEN) self.aliens.draw(SCREEN) self.alien_lasers.draw(SCREEN) self.extra.draw(SCREEN)
اگر بازی را اجرا کنیم بیگانه آبی رنگ را خواهیم دید:
برخوردها
برای بررسی برخورد تیر بازیکن به مانع ها در فایل main.py داریم:
def collision_checks(self): #player lasers if self.player.sprite.lasers: for laser in self.player.sprite.lasers: # obstacle collisions if pygame.sprite.spritecollide(laser, self.blocks,True): laser.kill()
سپس باید این متد را فراخوانی کنیم:
# self.alien_shoot() self.alien_lasers.update() self.extra_alien_timer() self.extra.update() self.collision_checks()
برای برخورد تیر بازیکن به بیگانگان داریم:
def collision_checks(self): #player lasers if self.player.sprite.lasers: for laser in self.player.sprite.lasers: # obstacle collisions if pygame.sprite.spritecollide(laser, self.blocks,True): laser.kill() # alien collisions if pygame.sprite.spritecollide(laser, self.aliens,True): laser.kill()
برای برخورد تیر بازیکن به سفینه بیگانه داریم:
# extra collisions if pygame.sprite.spritecollide(laser, self.extra,True): laser.kill()
برای برخورد تیر بیگانه به بازیکن کد زیر را داریم:
#alien lasers if self.alien_lasers: for laser in self.alien_lasers: # obstacle collisions if pygame.sprite.spritecollide(laser, self.blocks,True): laser.kill() if pygame.sprite.spritecollide(laser, self.player,False): laser.kill() print("dead")
می خواهیم وقتی صف بیگانگان به سفینه ما می رسد بازی پایان یابد.پس داریم:
#aliens if self.aliens: for alien in self.aliens: pygame.sprite.spritecollide(alien, self.blocks,True) if pygame.sprite.spritecollide(alien, self.player,False): sys.exit()
افزودن سیستم تندرستی (health system)
برای پیاده سازی سیستم تندرستی کد زیر را به تابع __init__ در فایل main.py می افزاییم:
def __init__(self): # player setup player_sprite=Player((WIDTH/2,HEIGHT),WIDTH,5) self.player=pygame.sprite.GroupSingle(player_sprite) # health and score setup self.lives = 3 self.live_surf = pygame.image.load(r'C:/Users/Rahmani/Desktop/space_invaders/graphics/player.png').convert_alpha() self.live_x_start_pos = WIDTH - (self.live_surf.get_size()[0] * 2 + 20)
سپس برای نمایش سیستم سلامتی داریم:
def display_lives(self): for live in range(self.lives - 1): x = self.live_x_start_pos + (live * (self.live_surf.get_size()[0] + 10)) SCREEN.blit(self.live_surf,(x,8))
برای نمایش نهایی باید تابع بالا را فراخوانی کنیم:
def run(self): self.player.update() self.aliens.update(self.alien_direction) self.alien_position_checker() # self.alien_shoot() self.alien_lasers.update() self.extra_alien_timer() self.extra.update() self.collision_checks() self.display_lives()
می خواهیم با هر برخورد تیر به سفینه یکی از جان های بازیکن کم شود پس داریم:
#alien lasers if self.alien_lasers: for laser in self.alien_lasers: # obstacle collisions if pygame.sprite.spritecollide(laser, self.blocks,True): laser.kill() if pygame.sprite.spritecollide(laser, self.player,False): laser.kill() if self.lives <= 0: pygame.quit() sys.exit()
افزودن سیستم امتیاز
برای نشان دادن امتیاز کد زیر را به متد __init__ می افزاییم:
self.score = 0 self.font = pygame.font.Font(r'C:/Users/Rahmani/Desktop/space_invaders/font/Pixeled.ttf', 20)
برای نمایش سیستم امتیاز داریم:
def display_score(self): score_surf = self.font.render(f'score : {self.score}', False, 'white') score_rect=score_surf.get_rect(topleft=(10,-10)) SCREEN.blit(score_surf,score_rect)
برای نمایش امتیاز تغییرهای زیر را در متد run انجام می دهیم:
def run(self): self.player.update() self.aliens.update(self.alien_direction) self.alien_position_checker() # self.alien_shoot() self.alien_lasers.update() self.extra_alien_timer() self.extra.update() self.collision_checks() self.player.sprite.lasers.draw(SCREEN) self.player.draw(SCREEN) self.blocks.draw(SCREEN) self.aliens.draw(SCREEN) self.alien_lasers.draw(SCREEN) self.extra.draw(SCREEN) self.display_lives() self.display_score()
می خواهیم برای زدن هر بیگانه با یک رنگ خاص یک امتیاز ویژه را قرار بدهیم. برای این کار در درفایل alien.py داریم:
def __init__(self,color,x,y): super().__init__() file_path=r'C:/Users/Rahmani/Desktop/space_invaders/graphics/' + color + '.png' self.image=pygame.image.load(file_path).convert_alpha() self.rect=self.image.get_rect(topleft=(x,y)) if color == 'red' : self.value = 100 elif color == 'green' : self.value = 200 else: self.value = 300
سپس در فایل main.py در متد check_collision داریم:
def collision_checks(self): #player lasers if self.player.sprite.lasers: for laser in self.player.sprite.lasers: # obstacle collisions if pygame.sprite.spritecollide(laser, self.blocks,True): laser.kill() # alien collisions aliens_hit=pygame.sprite.spritecollide(laser, self.aliens,True) if aliens_hit: for alien in aliens_hit: self.score += alien.value laser.kill() # extra collisions if pygame.sprite.spritecollide(laser, self.extra,True): self.score += 500 laser.kill()
افزودن استایل دهی CRT
کلاس CRT رادر فایل main.py می سازیم:
class CRT: def __init__(self): self.tv = pygame.image.load(r'C:/Users/Rahmani/Desktop/space_invaders/graphics/tv.png').convert_alpha() def draw(self): SCREEN.blit(self.tv,(0,0))
برای نمایش تصویر تلویزیون داریم:
crt=CRT() ALIENLASER=pygame.USEREVENT + 1 pygame.time.set_timer(ALIENLASER, 800) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == ALIENLASER: game.alien_shoot() SCREEN.fill((30,30,30)) game.run() crt.draw()
اگر بازی را اجرا کنیم تصویر تلویزیون دارای مشکل خواهد بود.برای حل این مشکل داریم:
class CRT: def __init__(self): self.tv = pygame.image.load(r'C:/Users/Rahmani/Desktop/space_invaders/graphics/tv.png').convert_alpha() self.tv = pygame.transform.scale(self.tv,(WIDTH, HEIGHT)) def draw(self): self.tv.set_alpha(randint(75,90)) SCREEN.blit(self.tv,(0,0))
برای ایجاد خطوط crt در پنجره بازی داریم:
class CRT: def __init__(self): self.tv = pygame.image.load(r'C:/Users/Rahmani/Desktop/space_invaders/graphics/tv.png').convert_alpha() self.tv = pygame.transform.scale(self.tv,(WIDTH, HEIGHT)) def create_crt_lines(self): line_height = 3 line_amount = int(HEIGHT / line_height) for line in range(line_amount): y_pos = line * line_height pygame.draw.line(self.tv,'black',(0,y_pos),(WIDTH,y_pos),1) def draw(self): self.tv.set_alpha(randint(25,90)) self.create_crt_lines() SCREEN.blit(self.tv,(0,0))
افزودن موزیک
کد زیر را به متد __init__ در فایل main می افزاییم:
# audio music = pygame.mixer.Sound(r'C:/Users/Rahmani/Desktop/space_invaders/audio/music.wav') music.set_volume(0.2) music.play(loops = -1)
سپس داریم:
# Audio music = pygame.mixer.Sound(r'C:/Users/Rahmani/Desktop/space_invaders/audio/music.wav') music.set_volume(0.2) music.play(loops = -1) self.laser_sound = pygame.mixer.Sound(r'C:/Users/Rahmani/Desktop/space_invaders/audio/laser.wav') self.laser_sound.set_volume(0.5) self.explosion_sound = pygame.mixer.Sound(r'C:/Users/Rahmani/Desktop/space_invaders/audio/explosion.wav') self.explosion_sound.set_volume(0.3)
در ادامه داریم:
# alien collisions aliens_hit = pygame.sprite.spritecollide(laser,self.aliens,True) if aliens_hit: for alien in aliens_hit: self.score += alien.value laser.kill() self.explosion_sound.play()
افزودن صفحه پیروزی
اگر همه بیگانگان در صفحه نابود شوند باید پیام پیروزی نمایش داده شود:
def victory_message(self): if not self.aliens.sprites(): victory_surf = self.font.render('You won',False,'white') victory_rect = victory_surf.get_rect(center = (screen_width / 2, screen_height / 2)) screen.blit(victory_surf,victory_rect)
تصویر نهایی بازی به شکل زیر خواهد شد:
کد کامل بازی را می توانید از نشانی دانلود کنید.