zoukankan      html  css  js  c++  java
  • Python3+Pygame实现的射击游戏,很流畅,有音效

    之前看到过很多人写的飞机大战,当然了之前我也写过多个版本,总体来说功能是实现了,但总感觉不够“炫”

    今天浏览Python资料的时候,意外发现了这个很好的“射击”类游戏,看上去类似飞机大战,但更好玩

    一、游戏特点

    1. 运行非常流畅

    2. 默认有3条命,每条命的HP可以增加(吃补品)也可以减少(被击中)

    3. 有碰撞时的音效

    4. 有碰撞时的爆炸效果

    二、运行效果展示

    射击游戏

    三、完整代码

      1 from __future__ import division
      2 import pygame
      3 import random
      4 from os import path
      5 
      6 ## assets folder
      7 img_dir = path.join(path.dirname(__file__), 'assets')
      8 sound_folder = path.join(path.dirname(__file__), 'sounds')
      9 
     10 ###############################
     11 ## to be placed in "constant.py" later
     12 WIDTH = 480
     13 HEIGHT = 600
     14 FPS = 60
     15 POWERUP_TIME = 5000
     16 BAR_LENGTH = 100
     17 BAR_HEIGHT = 10
     18 
     19 # Define Colors 
     20 WHITE = (255, 255, 255)
     21 BLACK = (0, 0, 0)
     22 RED = (255, 0, 0)
     23 GREEN = (0, 255, 0)
     24 BLUE = (0, 0, 255)
     25 YELLOW = (255, 255, 0)
     26 ###############################
     27 
     28 ###############################
     29 ## to placed in "__init__.py" later
     30 ## initialize pygame and create window
     31 pygame.init()
     32 pygame.mixer.init()  ## For sound
     33 screen = pygame.display.set_mode((WIDTH, HEIGHT))
     34 pygame.display.set_caption("Space Shooter")
     35 clock = pygame.time.Clock()     ## For syncing the FPS
     36 ###############################
     37 
     38 font_name = pygame.font.match_font('arial')
     39 
     40 def main_menu():
     41     global screen
     42 
     43     menu_song = pygame.mixer.music.load(path.join(sound_folder, "menu.ogg"))
     44     pygame.mixer.music.play(-1)
     45 
     46     title = pygame.image.load(path.join(img_dir, "main.png")).convert()
     47     title = pygame.transform.scale(title, (WIDTH, HEIGHT), screen)
     48 
     49     screen.blit(title, (0,0))
     50     pygame.display.update()
     51 
     52     while True:
     53         ev = pygame.event.poll()
     54         if ev.type == pygame.KEYDOWN:
     55             if ev.key == pygame.K_RETURN:
     56                 break
     57             elif ev.key == pygame.K_q:
     58                 pygame.quit()
     59                 quit()
     60         else:
     61             draw_text(screen, "Press [ENTER] To Begin", 30, WIDTH/2, HEIGHT/2)
     62             draw_text(screen, "or [Q] To Quit", 30, WIDTH/2, (HEIGHT/2)+40)
     63             pygame.display.update()
     64 
     65     #pygame.mixer.music.stop()
     66     ready = pygame.mixer.Sound(path.join(sound_folder,'getready.ogg'))
     67     ready.play()
     68     screen.fill(BLACK)
     69     draw_text(screen, "GET READY!", 40, WIDTH/2, HEIGHT/2)
     70     pygame.display.update()
     71     
     72 
     73 def draw_text(surf, text, size, x, y):
     74     ## selecting a cross platform font to display the score
     75     font = pygame.font.Font(font_name, size)
     76     text_surface = font.render(text, True, WHITE)       ## True denotes the font to be anti-aliased 
     77     text_rect = text_surface.get_rect()
     78     text_rect.midtop = (x, y)
     79     surf.blit(text_surface, text_rect)
     80 
     81 
     82 def draw_shield_bar(surf, x, y, pct):
     83     # if pct < 0:
     84     #     pct = 0
     85     pct = max(pct, 0) 
     86     ## moving them to top
     87     # BAR_LENGTH = 100
     88     # BAR_HEIGHT = 10
     89     fill = (pct / 100) * BAR_LENGTH
     90     outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
     91     fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT)
     92     pygame.draw.rect(surf, GREEN, fill_rect)
     93     pygame.draw.rect(surf, WHITE, outline_rect, 2)
     94 
     95 
     96 def draw_lives(surf, x, y, lives, img):
     97     for i in range(lives):
     98         img_rect= img.get_rect()
     99         img_rect.x = x + 30 * i
    100         img_rect.y = y
    101         surf.blit(img, img_rect)
    102 
    103 
    104 
    105 def newmob():
    106     mob_element = Mob()
    107     all_sprites.add(mob_element)
    108     mobs.add(mob_element)
    109 
    110 class Explosion(pygame.sprite.Sprite):
    111     def __init__(self, center, size):
    112         pygame.sprite.Sprite.__init__(self)
    113         self.size = size
    114         self.image = explosion_anim[self.size][0]
    115         self.rect = self.image.get_rect()
    116         self.rect.center = center
    117         self.frame = 0 
    118         self.last_update = pygame.time.get_ticks()
    119         self.frame_rate = 75
    120 
    121     def update(self):
    122         now = pygame.time.get_ticks()
    123         if now - self.last_update > self.frame_rate:
    124             self.last_update = now
    125             self.frame += 1
    126             if self.frame == len(explosion_anim[self.size]):
    127                 self.kill()
    128             else:
    129                 center = self.rect.center
    130                 self.image = explosion_anim[self.size][self.frame]
    131                 self.rect = self.image.get_rect()
    132                 self.rect.center = center
    133 
    134 
    135 class Player(pygame.sprite.Sprite):
    136     def __init__(self):
    137         pygame.sprite.Sprite.__init__(self)
    138         ## scale the player img down
    139         self.image = pygame.transform.scale(player_img, (50, 38))
    140         self.image.set_colorkey(BLACK)
    141         self.rect = self.image.get_rect()
    142         self.radius = 20
    143         self.rect.centerx = WIDTH / 2
    144         self.rect.bottom = HEIGHT - 10
    145         self.speedx = 0 
    146         self.shield = 100
    147         self.shoot_delay = 250
    148         self.last_shot = pygame.time.get_ticks()
    149         self.lives = 3
    150         self.hidden = False
    151         self.hide_timer = pygame.time.get_ticks()
    152         self.power = 1
    153         self.power_timer = pygame.time.get_ticks()
    154 
    155     def update(self):
    156         ## time out for powerups
    157         if self.power >=2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME:
    158             self.power -= 1
    159             self.power_time = pygame.time.get_ticks()
    160 
    161         ## unhide 
    162         if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
    163             self.hidden = False
    164             self.rect.centerx = WIDTH / 2
    165             self.rect.bottom = HEIGHT - 30
    166 
    167         self.speedx = 0     ## makes the player static in the screen by default. 
    168         # then we have to check whether there is an event hanlding being done for the arrow keys being 
    169         ## pressed 
    170 
    171         ## will give back a list of the keys which happen to be pressed down at that moment
    172         keystate = pygame.key.get_pressed()     
    173         if keystate[pygame.K_LEFT]:
    174             self.speedx = -5
    175         elif keystate[pygame.K_RIGHT]:
    176             self.speedx = 5
    177 
    178         #Fire weapons by holding spacebar
    179         if keystate[pygame.K_SPACE]:
    180             self.shoot()
    181 
    182         ## check for the borders at the left and right
    183         if self.rect.right > WIDTH:
    184             self.rect.right = WIDTH
    185         if self.rect.left < 0:
    186             self.rect.left = 0
    187 
    188         self.rect.x += self.speedx
    189 
    190     def shoot(self):
    191         ## to tell the bullet where to spawn
    192         now = pygame.time.get_ticks()
    193         if now - self.last_shot > self.shoot_delay:
    194             self.last_shot = now
    195             if self.power == 1:
    196                 bullet = Bullet(self.rect.centerx, self.rect.top)
    197                 all_sprites.add(bullet)
    198                 bullets.add(bullet)
    199                 shooting_sound.play()
    200             if self.power == 2:
    201                 bullet1 = Bullet(self.rect.left, self.rect.centery)
    202                 bullet2 = Bullet(self.rect.right, self.rect.centery)
    203                 all_sprites.add(bullet1)
    204                 all_sprites.add(bullet2)
    205                 bullets.add(bullet1)
    206                 bullets.add(bullet2)
    207                 shooting_sound.play()
    208 
    209             """ MOAR POWAH """
    210             if self.power >= 3:
    211                 bullet1 = Bullet(self.rect.left, self.rect.centery)
    212                 bullet2 = Bullet(self.rect.right, self.rect.centery)
    213                 missile1 = Missile(self.rect.centerx, self.rect.top) # Missile shoots from center of ship
    214                 all_sprites.add(bullet1)
    215                 all_sprites.add(bullet2)
    216                 all_sprites.add(missile1)
    217                 bullets.add(bullet1)
    218                 bullets.add(bullet2)
    219                 bullets.add(missile1)
    220                 shooting_sound.play()
    221                 missile_sound.play()
    222 
    223     def powerup(self):
    224         self.power += 1
    225         self.power_time = pygame.time.get_ticks()
    226 
    227     def hide(self):
    228         self.hidden = True
    229         self.hide_timer = pygame.time.get_ticks()
    230         self.rect.center = (WIDTH / 2, HEIGHT + 200)
    231 
    232 
    233 # defines the enemies
    234 class Mob(pygame.sprite.Sprite):
    235     def __init__(self):
    236         pygame.sprite.Sprite.__init__(self)
    237         self.image_orig = random.choice(meteor_images)
    238         self.image_orig.set_colorkey(BLACK)
    239         self.image = self.image_orig.copy()
    240         self.rect = self.image.get_rect()
    241         self.radius = int(self.rect.width *.90 / 2)
    242         self.rect.x = random.randrange(0, WIDTH - self.rect.width)
    243         self.rect.y = random.randrange(-150, -100)
    244         self.speedy = random.randrange(5, 20)        ## for randomizing the speed of the Mob
    245 
    246         ## randomize the movements a little more 
    247         self.speedx = random.randrange(-3, 3)
    248 
    249         ## adding rotation to the mob element
    250         self.rotation = 0
    251         self.rotation_speed = random.randrange(-8, 8)
    252         self.last_update = pygame.time.get_ticks()  ## time when the rotation has to happen
    253         
    254     def rotate(self):
    255         time_now = pygame.time.get_ticks()
    256         if time_now - self.last_update > 50: # in milliseconds
    257             self.last_update = time_now
    258             self.rotation = (self.rotation + self.rotation_speed) % 360 
    259             new_image = pygame.transform.rotate(self.image_orig, self.rotation)
    260             old_center = self.rect.center
    261             self.image = new_image
    262             self.rect = self.image.get_rect()
    263             self.rect.center = old_center
    264 
    265     def update(self):
    266         self.rotate()
    267         self.rect.x += self.speedx
    268         self.rect.y += self.speedy
    269         ## now what if the mob element goes out of the screen
    270 
    271         if (self.rect.top > HEIGHT + 10) or (self.rect.left < -25) or (self.rect.right > WIDTH + 20):
    272             self.rect.x = random.randrange(0, WIDTH - self.rect.width)
    273             self.rect.y = random.randrange(-100, -40)
    274             self.speedy = random.randrange(1, 8)        ## for randomizing the speed of the Mob
    275 
    276 ## defines the sprite for Powerups
    277 class Pow(pygame.sprite.Sprite):
    278     def __init__(self, center):
    279         pygame.sprite.Sprite.__init__(self)
    280         self.type = random.choice(['shield', 'gun'])
    281         self.image = powerup_images[self.type]
    282         self.image.set_colorkey(BLACK)
    283         self.rect = self.image.get_rect()
    284         ## place the bullet according to the current position of the player
    285         self.rect.center = center
    286         self.speedy = 2
    287 
    288     def update(self):
    289         """should spawn right in front of the player"""
    290         self.rect.y += self.speedy
    291         ## kill the sprite after it moves over the top border
    292         if self.rect.top > HEIGHT:
    293             self.kill()
    294 
    295             
    296 
    297 ## defines the sprite for bullets
    298 class Bullet(pygame.sprite.Sprite):
    299     def __init__(self, x, y):
    300         pygame.sprite.Sprite.__init__(self)
    301         self.image = bullet_img
    302         self.image.set_colorkey(BLACK)
    303         self.rect = self.image.get_rect()
    304         ## place the bullet according to the current position of the player
    305         self.rect.bottom = y 
    306         self.rect.centerx = x
    307         self.speedy = -10
    308 
    309     def update(self):
    310         """should spawn right in front of the player"""
    311         self.rect.y += self.speedy
    312         ## kill the sprite after it moves over the top border
    313         if self.rect.bottom < 0:
    314             self.kill()
    315 
    316         ## now we need a way to shoot
    317         ## lets bind it to "spacebar".
    318         ## adding an event for it in Game loop
    319 
    320 ## FIRE ZE MISSILES
    321 class Missile(pygame.sprite.Sprite):
    322     def __init__(self, x, y):
    323         pygame.sprite.Sprite.__init__(self)
    324         self.image = missile_img
    325         self.image.set_colorkey(BLACK)
    326         self.rect = self.image.get_rect()
    327         self.rect.bottom = y
    328         self.rect.centerx = x
    329         self.speedy = -10
    330 
    331     def update(self):
    332         """should spawn right in front of the player"""
    333         self.rect.y += self.speedy
    334         if self.rect.bottom < 0:
    335             self.kill()
    336 
    337 
    338 ###################################################
    339 ## Load all game images
    340 
    341 background = pygame.image.load(path.join(img_dir, 'starfield.png')).convert()
    342 background_rect = background.get_rect()
    343 ## ^^ draw this rect first 
    344 
    345 player_img = pygame.image.load(path.join(img_dir, 'playerShip1_orange.png')).convert()
    346 player_mini_img = pygame.transform.scale(player_img, (25, 19))
    347 player_mini_img.set_colorkey(BLACK)
    348 bullet_img = pygame.image.load(path.join(img_dir, 'laserRed16.png')).convert()
    349 missile_img = pygame.image.load(path.join(img_dir, 'missile.png')).convert_alpha()
    350 # meteor_img = pygame.image.load(path.join(img_dir, 'meteorBrown_med1.png')).convert()
    351 meteor_images = []
    352 meteor_list = [
    353     'meteorBrown_big1.png',
    354     'meteorBrown_big2.png', 
    355     'meteorBrown_med1.png', 
    356     'meteorBrown_med3.png',
    357     'meteorBrown_small1.png',
    358     'meteorBrown_small2.png',
    359     'meteorBrown_tiny1.png'
    360 ]
    361 
    362 for image in meteor_list:
    363     meteor_images.append(pygame.image.load(path.join(img_dir, image)).convert())
    364 
    365 ## meteor explosion
    366 explosion_anim = {}
    367 explosion_anim['lg'] = []
    368 explosion_anim['sm'] = []
    369 explosion_anim['player'] = []
    370 for i in range(9):
    371     filename = 'regularExplosion0{}.png'.format(i)
    372     img = pygame.image.load(path.join(img_dir, filename)).convert()
    373     img.set_colorkey(BLACK)
    374     ## resize the explosion
    375     img_lg = pygame.transform.scale(img, (75, 75))
    376     explosion_anim['lg'].append(img_lg)
    377     img_sm = pygame.transform.scale(img, (32, 32))
    378     explosion_anim['sm'].append(img_sm)
    379 
    380     ## player explosion
    381     filename = 'sonicExplosion0{}.png'.format(i)
    382     img = pygame.image.load(path.join(img_dir, filename)).convert()
    383     img.set_colorkey(BLACK)
    384     explosion_anim['player'].append(img)
    385 
    386 ## load power ups
    387 powerup_images = {}
    388 powerup_images['shield'] = pygame.image.load(path.join(img_dir, 'shield_gold.png')).convert()
    389 powerup_images['gun'] = pygame.image.load(path.join(img_dir, 'bolt_gold.png')).convert()
    390 
    391 
    392 ###################################################
    393 
    394 
    395 ###################################################
    396 ### Load all game sounds
    397 shooting_sound = pygame.mixer.Sound(path.join(sound_folder, 'pew.wav'))
    398 missile_sound = pygame.mixer.Sound(path.join(sound_folder, 'rocket.ogg'))
    399 expl_sounds = []
    400 for sound in ['expl3.wav', 'expl6.wav']:
    401     expl_sounds.append(pygame.mixer.Sound(path.join(sound_folder, sound)))
    402 ## main background music
    403 #pygame.mixer.music.load(path.join(sound_folder, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
    404 pygame.mixer.music.set_volume(0.2)      ## simmered the sound down a little
    405 
    406 player_die_sound = pygame.mixer.Sound(path.join(sound_folder, 'rumble1.ogg'))
    407 ###################################################
    408 
    409 ## group all the sprites together for ease of update
    410 all_sprites = pygame.sprite.Group()
    411 player = Player()
    412 all_sprites.add(player)
    413 
    414 ## spawn a group of mob
    415 mobs = pygame.sprite.Group()
    416 for i in range(8):      ## 8 mobs
    417     # mob_element = Mob()
    418     # all_sprites.add(mob_element)
    419     # mobs.add(mob_element)
    420     newmob()
    421 
    422 ## group for bullets
    423 bullets = pygame.sprite.Group()
    424 powerups = pygame.sprite.Group()
    425 
    426 #### Score board variable
    427 score = 0
    428 
    429 ## TODO: make the game music loop over again and again. play(loops=-1) is not working
    430 # Error : 
    431 # TypeError: play() takes no keyword arguments
    432 #pygame.mixer.music.play()
    433 
    434 #############################
    435 ## Game loop
    436 running = True
    437 menu_display = True
    438 while running:
    439     if menu_display:
    440         main_menu()
    441         pygame.time.wait(3000)
    442 
    443         #Stop menu music
    444         pygame.mixer.music.stop()
    445         #Play the gameplay music
    446         pygame.mixer.music.load(path.join(sound_folder, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
    447         pygame.mixer.music.play(-1)     ## makes the gameplay sound in an endless loop
    448         
    449         menu_display = False
    450         
    451     #1 Process input/events
    452     clock.tick(FPS)     ## will make the loop run at the same speed all the time
    453     for event in pygame.event.get():        # gets all the events which have occured till now and keeps tab of them.
    454         ## listening for the the X button at the top
    455         if event.type == pygame.QUIT:
    456             running = False
    457 
    458         ## Press ESC to exit game
    459         if event.type == pygame.KEYDOWN:
    460             if event.key == pygame.K_ESCAPE:
    461                 running = False
    462         # ## event for shooting the bullets
    463         # elif event.type == pygame.KEYDOWN:
    464         #     if event.key == pygame.K_SPACE:
    465         #         player.shoot()      ## we have to define the shoot()  function
    466 
    467     #2 Update
    468     all_sprites.update()
    469 
    470 
    471     ## check if a bullet hit a mob
    472     ## now we have a group of bullets and a group of mob
    473     hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
    474     ## now as we delete the mob element when we hit one with a bullet, we need to respawn them again
    475     ## as there will be no mob_elements left out 
    476     for hit in hits:
    477         score += 50 - hit.radius         ## give different scores for hitting big and small metoers
    478         random.choice(expl_sounds).play()
    479         # m = Mob()
    480         # all_sprites.add(m)
    481         # mobs.add(m)
    482         expl = Explosion(hit.rect.center, 'lg')
    483         all_sprites.add(expl)
    484         if random.random() > 0.9:
    485             pow = Pow(hit.rect.center)
    486             all_sprites.add(pow)
    487             powerups.add(pow)
    488         newmob()        ## spawn a new mob
    489 
    490     ## ^^ the above loop will create the amount of mob objects which were killed spawn again
    491     #########################
    492 
    493     ## check if the player collides with the mob
    494     hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)        ## gives back a list, True makes the mob element disappear
    495     for hit in hits:
    496         player.shield -= hit.radius * 2
    497         expl = Explosion(hit.rect.center, 'sm')
    498         all_sprites.add(expl)
    499         newmob()
    500         if player.shield <= 0: 
    501             player_die_sound.play()
    502             death_explosion = Explosion(player.rect.center, 'player')
    503             all_sprites.add(death_explosion)
    504             # running = False     ## GAME OVER 3:D
    505             player.hide()
    506             player.lives -= 1
    507             player.shield = 100
    508 
    509     ## if the player hit a power up
    510     hits = pygame.sprite.spritecollide(player, powerups, True)
    511     for hit in hits:
    512         if hit.type == 'shield':
    513             player.shield += random.randrange(10, 30)
    514             if player.shield >= 100:
    515                 player.shield = 100
    516         if hit.type == 'gun':
    517             player.powerup()
    518 
    519     ## if player died and the explosion has finished, end game
    520     if player.lives == 0 and not death_explosion.alive():
    521         running = False
    522         # menu_display = True
    523         # pygame.display.update()
    524 
    525     #3 Draw/render
    526     screen.fill(BLACK)
    527     ## draw the stargaze.png image
    528     screen.blit(background, background_rect)
    529 
    530     all_sprites.draw(screen)
    531     draw_text(screen, str(score), 18, WIDTH / 2, 10)     ## 10px down from the screen
    532     draw_shield_bar(screen, 5, 5, player.shield)
    533 
    534     # Draw lives
    535     draw_lives(screen, WIDTH - 100, 5, player.lives, player_mini_img)
    536 
    537     ## Done after drawing everything to the screen
    538     pygame.display.flip()       
    539 
    540 pygame.quit()

    四、运行方式

    如果想要运行本程序,流程如下

    1. 下载上述代码 例如存储为xxxx.py

    2. 下载素材(图片、声音等)https://www.itprojects.cn/web/material/details.html?id=90

    3. 切换到安装有pygame模块的python虚拟环境(如果没有pygame可以pip install pygame安装)

    4. 使用命令运行 python3 xxxx.py

    别忘了点赞哦,谢谢大家支持。如果想要做更多的pygame相关的程序,请发私信或者留言  1小时必回复

  • 相关阅读:
    unicode字符集
    534,rgba()和opacity的透明效果有什么不同?
    1004,js中的fliter
    1003,js array map()方法
    JavaScript 数据类型和数据结构
    JavaScript实现浮点数运算问题
    Chrome浏览器不能正确加载更新后JavaScript和Css文件原因及解决方法
    MySQL安装版与压缩版安装方法
    VUE列表渲染 FOR-IN和FOR-OF的区别
    for、for-in、for-of、forEach的区别
  • 原文地址:https://www.cnblogs.com/dong4716138/p/14551450.html
Copyright © 2011-2022 走看看