码迷,mamicode.com
首页 > 编程语言 > 详细

Python实现寻宝小游戏

时间:2020-03-08 20:18:44      阅读:84      评论:0      收藏:0      [点我收藏+]

标签:direct   ber   vector   ini   click   pow   clear   raw   and   

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Treasure Hunter

In this game, you will play as a treasure hunter to find a mysterious treasure. 
In order to find the treasure, you need to defeat a great number of monsters with 
time limitation.

Created by Group ShowMaker

"""

import os
import pygame
import random
import numpy

#Initialise Screen
pygame.init()
pygame.mixer.init()
pygame.display.init()
pygame.font.init()
pygame.display.set_caption(‘Treasure Hunter‘)
FPS = 13
width = 960
height = 540
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
dt = clock.tick(FPS) / 1000 #the time interval of two images in the animation

# assets folder
img_dir = ‘assets/pictures‘
music_dir = ‘assets/music‘

# sound effects
shooting_sound = pygame.mixer.Sound(os.path.join(music_dir, ‘shoot.wav‘))
boss_bgm = os.path.join(music_dir, ‘boss_bgm.wav‘)
regular_bgm = os.path.join(music_dir, ‘regular_bgm.wav‘)
die_sound = pygame.mixer.Sound(os.path.join(music_dir, ‘enemy_die.wav‘))
boss_entry = pygame.mixer.Sound(os.path.join(music_dir, ‘boss_entry.wav‘))
boss_die = pygame.mixer.Sound(os.path.join(music_dir, ‘boss_die.wav‘))
level_up = pygame.mixer.Sound(os.path.join(music_dir, ‘level_up.wav‘))
open_chest = pygame.mixer.Sound(os.path.join(music_dir, ‘open_chest.wav‘))
time_limit=pygame.mixer.Sound(os.path.join(music_dir, ‘time_limit.wav‘))

#game background images
background = pygame.image.load(os.path.join(img_dir, ‘bg1.png‘))
background2 = pygame.image.load(os.path.join(img_dir, ‘bg2.jpg‘))
background3 = pygame.image.load(os.path.join(img_dir, ‘bg1.png‘))
background4 = pygame.image.load(os.path.join(img_dir, ‘bg3.jpg‘))

#menu related images
menu_image1 = pygame.image.load(os.path.join(img_dir, ‘main1.jpg‘))
menu_image2 = pygame.image.load(os.path.join(img_dir, ‘main2.jpg‘))
button_quit = pygame.image.load(os.path.join(img_dir, ‘button_quit2.png‘))
button_start = pygame.image.load(os.path.join(img_dir, ‘button_start2.png‘))
button_normal = pygame.image.load(os.path.join(img_dir, ‘normal.png‘))
button_difficult = pygame.image.load(os.path.join(img_dir, ‘difficult.png‘))
die_image = pygame.image.load(os.path.join(img_dir, ‘died.jpg‘))
final1 = pygame.image.load(os.path.join(img_dir, ‘congrats.jpg‘))
bginfo = pygame.image.load(os.path.join(img_dir, ‘bginfo.jpg‘))

#hero images
heroimages = [pygame.image.load(os.path.join(img_dir, ‘h1.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘h2.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘h3.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘h4.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘h5.png‘))]
#enemy images
e1images = [pygame.image.load(os.path.join(img_dir, ‘boss01_1.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss01_2.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss01_3.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss01_4.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss01_5.png‘))]
e2images = [pygame.image.load(os.path.join(img_dir, ‘boss05_1.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss05_2.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss05_3.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss05_4.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss05_5.png‘))]
e3images = [pygame.image.load(os.path.join(img_dir, ‘boss02_1.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss02_2.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss02_3.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss02_4.png‘)),
            pygame.image.load(os.path.join(img_dir, ‘boss02_5.png‘))]
bossimages = [pygame.image.load(os.path.join(img_dir, ‘boss08_1.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘boss08_2.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘boss08_3.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘boss08_4.png‘)),
              pygame.image.load(os.path.join(img_dir, ‘boss08_5.png‘))]

#bullet images
bull1 = pygame.image.load(os.path.join(img_dir, ‘bullet1.png‘))
bull2 = pygame.image.load(os.path.join(img_dir, ‘bullet2.png‘))

#props
warning_img = pygame.image.load(os.path.join(img_dir, ‘warning.png‘))
chest = pygame.image.load(os.path.join(img_dir, ‘chest.png‘))
book = pygame.image.load(os.path.join(img_dir, ‘book.png‘))
weapon = pygame.image.load(os.path.join(img_dir, ‘weapon.png‘))
gatei1 = pygame.image.load(os.path.join(img_dir, ‘gate_1.png‘))
heart = pygame.image.load(os.path.join(img_dir, ‘heart.png‘))

def main_menu():
    """
    Generate three screens:
        first screen: Start or quit the game
        Second screen: Instruction and Difficulty selection
        Third screen: Background Story (Press Enter to enter the game)
    """
    global mode, screen
    screen.blit(menu_image1,(0, 0))
    clock.tick(FPS)
    pygame.mixer.music.load(regular_bgm)
    pygame.mixer.music.play(-1)
    menu_layer = 1
    while True:
        #Mouse detection method
        buttons = pygame.mouse.get_pressed()
        x1, y1 = pygame.mouse.get_pos()
        #Start screen
        if menu_layer == 1:
            screen.blit(button_start, (370, 300))
            screen.blit(button_quit, (370, 400))
            if 370 <= x1 <= 610 and 300 <= y1 <= 385: #Hit button start
                if buttons[0]:
                    menu_layer = 2
            elif 370 <= x1 <= 610 and 400 <= y1 <= 490: #Hit button quit
                if buttons[0]:
                    os._exit(0)
            pygame.display.update()
        #Select Difficulty Level
        elif menu_layer == 2:
            screen.blit(menu_image2, (0, 0))
            screen.blit(button_normal, (550, 70))
            screen.blit(button_difficult, (550, 200))
            if 620 <= x1 <= 830 and 110 <= y1 <= 210: #click button normal
                if buttons[0]:
                    mode = ‘normal‘
                    menu_layer = 3
            elif 620 <= x1 <= 830 and 230 <= y1 <= 330: #click button difficult
                if buttons[0]:
                    mode = ‘difficult‘        
                    menu_layer = 3
            pygame.display.update()
        #Backgroud story
        elif menu_layer == 3:
            screen.blit(bginfo, (0, 0))
            if pygame.key.get_pressed()[pygame.K_RETURN]:
                break
            pygame.display.update()
        #Quit method
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(0)
    pygame.mixer.music.stop()
    
def draw_hero_health(hp):
    """
    Draw several hearts on the top left corner of the screen to represent the hp of hero
    """
    for i in range(int(hp) + 1):
        if i > 0:
            screen.blit(heart, (35*i, 10))

def draw_boss_health(health):
    """
    Draw a health bar on the top right corner of the screen
    """
    if health > 0: #the coordinates of the health bar
        WIDTH = 100
        HEIGHT = 20
        space = 20
        pygame.draw.rect(screen, pygame.Color("green"), pygame.Rect(width-WIDTH-space, space, WIDTH + 4, HEIGHT))
        pygame.draw.rect(screen, pygame.Color("red"), pygame.Rect(width-WIDTH-space + 2, space+2, WIDTH/boss_health*health, HEIGHT-4))

def gen_enemy(num):
    """
    Generate given number of mob and add to sprite group all_sprites
    """
    for i in range(num): 
        mob_element = Mob()
        all_sprites.add(mob_element)
        mobs.add(mob_element)

def ticktock(limit,ticks,font):   
    """
    show the time before hero die, display at the top of the screen
    """
    text = font.render("Time Remaining    " + str((limit-ticks)//60000) + ":" +
							   str((limit-ticks)//1000%60).zfill(2), True, (0,255,0))
    Rect = text.get_rect()
    Rect = (300, 10)     #position of the time display
    screen.blit(text,Rect)  
    
class animated_sprite(pygame.sprite.Sprite):
    """
    parent class of all animated objects, take a list of images and automaticlly generate a list of
    mirrored images.
    use current_time and animation_time to achieve looping images inside the list
    """
    def __init__(self, images): # Call the parent class (Sprite) constructor
        super().__init__()
        self.images = images
        self.animation_time = 0.01
        self.current_time = 0 #keep track of time
        self.index = 0 #used to keep track of which image is in use
        self.image = images[self.index] #current image of the animation
        self.images_right = self.images #images face right in default
        self.images_left = [] #turn the image to face left and store in a list
        for image in images:
            self.images_left.append(pygame.transform.flip(image, True, False))
        
class Hero(animated_sprite):
    """
    The object player will control, hero is an animated object with ability to 
    move and shoot
    Attributes:
        update: use WASD to move the character on the screen, two lists of left and right images 
            will be automatically switched
        shoot: use key arrows to fire a bullet, maximum speen is one bullet per 0.8 second
    """
    def __init__(self, position, images, speed = 18, shoot_delay = 800):
        super().__init__(images)
        size = (39, 37)  # The size of the images
        self.health = hero_health
        self.rect = pygame.Rect(position, size)
        self.velocity = pygame.math.Vector2(0, 0)
        self.shoot_delay = shoot_delay
        self.last_shot = pygame.time.get_ticks()
        self.bull_image = bull1
        self.speed = speed
    def update(self, dt):
        #Move
        if pygame.key.get_pressed()[pygame.K_a] and self.rect.center[0] > boundaryx[0] - 120:
            self.velocity.x = -self.speed
        elif pygame.key.get_pressed()[pygame.K_d] and self.rect.center[0] < boundaryx[1]:
            self.velocity.x = self.speed
        else:
            self.velocity.x = 0   
        if pygame.key.get_pressed()[pygame.K_s] and self.rect.center[1] <boundaryy[1]:
            self.velocity.y = self.speed
        elif pygame.key.get_pressed()[pygame.K_w] and self.rect.center[1] > boundaryy[0]:
            self.velocity.y = -self.speed
        else:
            self.velocity.y = 0
        #Shoot
        if pygame.key.get_pressed()[pygame.K_UP]:
            self.shoot(1)		
        elif pygame.key.get_pressed()[pygame.K_DOWN]:
            self.shoot(2)		
        elif pygame.key.get_pressed()[pygame.K_LEFT]:
            self.shoot(3)			
        elif pygame.key.get_pressed()[pygame.K_RIGHT]:
            self.shoot(4)
        #Update frame 
        if self.velocity.x > 0:  # Use the right images if sprite is moving right.
            self.images = self.images_right
        elif self.velocity.x < 0: 
            self.images = self.images_left
        #Looping the images in the list
        self.current_time += dt
        if self.current_time >= self.animation_time and self.velocity != (0,0):
            self.current_time = 0
            self.index = (self.index + 1) % len(self.images)
            self.image = self.images[self.index]
        else:
            self.image = self.images[3]
        self.rect.move_ip(*self.velocity)

    def shoot(self,dir):
        now = pygame.time.get_ticks()
        if now - self.last_shot > self.shoot_delay: #set the shoot frequate of bullet 
            self.last_shot = now
            shooting_sound.play()
            bullet = Bullet(self.rect.center[0],self.rect.center[1],self.bull_image,dir)  #create new bullet
            all_sprites.add(bullet)
            bullets.add(bullet)

class Mob(animated_sprite):
    """
    the class of regular enemy, move towards the hero if close enough, otherwise will wander around

    attributes:
        update: animation method (automatically switch left and right images) and move method.
    """
    def __init__(self, size = (40,40)):
        self.images = random.choice([e1images, e2images, e3images])
        super().__init__(self.images)
        self.rect = pygame.Rect((0,0),size)
        self.image = self.images[self.index]
        self.rect.centerx = random.randrange(boundaryx[0],boundaryx[1])
        self.rect.centery = random.randrange(boundaryy[0],boundaryy[1])
        self.speedy = 8   
        self.speedx = 8
        self.speed = 8

    def update(self, dt):
        distanceX = hero.rect.center[0] - self.rect.centerx
        distanceY = hero.rect.center[1] - self.rect.centery
        distance = numpy.sqrt(pow(distanceX,2) + pow(distanceY,2))
        # if enemies are too far away from the hero, they will just wander around
        if distance > 400:
            self.rect.centerx += self.speedx
            self.rect.centery += self.speedy
            if self.speedx > 0:  # Use the right images if sprite is moving right.
                self.images = self.images_right
            elif self.speedx < 0:
                self.images = self.images_left
        # if enemies is close enough to the hero, they will go towards him
        else:
            self.rect.centerx += int(self.speed * distanceX /(distance+0.001))
            self.rect.centery += int(self.speed * distanceY /(distance+0.001))
        
            if distanceX > 0:
                self.images = self.images_right
            else:
                self.images = self.images_left
        # if touch the boundary
        if self.rect.centerx < boundaryx[0] or self.rect.centerx > boundaryx[1]:
            self.speedx = -self.speedx
        if self.rect.centery < boundaryy[0] or self.rect.centery > boundaryy[1]:
            self.speedy = -self.speedy
        #Update frame        
        self.current_time += dt
        if self.current_time >= self.animation_time:
            self.current_time = 0
            self.index = (self.index + 1) % len(self.images)
            self.image = self.images[self.index]

class Boss(animated_sprite):
    """
    The boss will move towards hero, and have a much bigger size than mobs
    Attributes:
        update: animation and move method
    """
    def __init__(self, images, health, speed, position = (600, 270)):
        super().__init__(images)
        size = (50,100)
        self.rect = pygame.Rect(position,size)
        self.health = health
        self.speed = speed

    def update(self, dt):
        distanceX = hero.rect.center[0] - self.rect.centerx
        distanceY = hero.rect.center[1] - self.rect.centery
        distance = numpy.sqrt(pow(distanceX,2) + pow(distanceY,2))
        self.rect.centerx += int(self.speed * distanceX /(distance+0.001))
        self.rect.centery += int(self.speed * distanceY /(distance+0.001))
        #Update frame
        if distanceX > 0:
            self.images = self.images_right
        else:
            self.images = self.images_left
        self.current_time += dt
        if self.current_time >= self.animation_time:
            self.current_time = 0
            self.index = (self.index + 1) % len(self.images)
            self.image = self.images[self.index]

class Bullet(pygame.sprite.Sprite):
    """
    after the hero fire, bullet will fly toward the direction set by the arrow key
    Attributes:
        update: move method
    """
    def __init__(self, x, y, pic, dir):
        pygame.sprite.Sprite.__init__(self)
        self.image = pic #Initialise the image of bullet
        self.speed = 40  #the speed of bullet
        self.rect = self.image.get_rect() 
        #Initialise the direction and original position of bullet
        if dir == 1:   #up
            self.vel = (0, -1) 
            self.rect.centerx = x
            self.rect.bottom = y  
        elif dir == 2: #down
            self.vel = (0, 1) 
            self.rect.centerx = x
            self.rect.top = y  
        elif dir == 3: #left
            self.vel = (-1, 0)
            self.rect.centery = y
            self.rect.right = x  
        elif dir == 4: #right
            self.vel = (1,0) 
            self.rect.centery = y
            self.rect.left = x
            
    def update(self,dt):   #Update the position of bullet
        self.rect.move_ip(int(self.speed * self.vel[0]), int(self.speed * self.vel[1]))

class gate(pygame.sprite.Sprite):
    """
    sprite used to represent teleport gate (sprite adopted for collision detection)
    """
    def __init__(self, pic, x, y):
        super().__init__()
        self.image = pic
        self.rect = self.image.get_rect()
        self.x = x
        self.y = y
    def update(self, dt):
        self.rect.centerx = self.x
        self.rect.bottom = self.y

class treasure(pygame.sprite.Sprite):
    """
    sprite used to represent weapon upgrade and chest that will generate props
    """
    def __init__(self,pic,x,y):
        super().__init__()
        self.image = pic
        self.rect = self.image.get_rect()
        self.rect.centerx = x #position of the props
        self.rect.centery = y 
    
tickfont = pygame.font.Font(None, 40)
boundaryx = (170,920)
boundaryy = (170,510)
mode = ‘normal‘
diesound_play = False


while True:
    level = 1
    main_menu()
    if mode == ‘normal‘:
        hero_health = 5
        boss_health = 5
        #the number of enemy in each level
        l1_enemy = random.randint(4,6)
        l2_enemy = random.randint(5,8)
        l3_enemy = random.randint(1,3)
    elif mode == ‘difficult‘: 
        hero_health = 3
        boss_health = 10
        l1_enemy = random.randint(5,8)
        l2_enemy = random.randint(8,12)
        l3_enemy = random.randint(3,6)
    #load sprites
    gate1 = gate(gatei1, 454, 180)
    gate2 = gate(gatei1, 674, 180)
    gate3 = gate(gatei1, 450, 180)
    fake_gate = gate(gatei1, 10, 300)
    hero = Hero((100, 300), heroimages)
    all_sprites = pygame.sprite.Group(hero)
    bullets = pygame.sprite.Group()
    mobs = pygame.sprite.Group()
    boss1 = Boss(bossimages, boss_health, 10)
    chest1= treasure(chest,600,260)
    chest2 = treasure(weapon,random.randrange(boundaryx[0],boundaryx[1]),random.randrange(boundaryy[0],boundaryy[1]))
    # game start
    background_i = background
    gen_enemy(l1_enemy)
    pygame.mixer.music.play(-1)
    # time limit conditions
    timelimit = (l1_enemy + l2_enemy + l3_enemy + boss1.health + 10) * 2000  #set time limit(millisecond) in the battle levels
    clock_limit = pygame.time.Clock() 
    ticks = 0
    timewarning = 5  # set the play times of time warning music
    
    while True:
        #Quit method
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                os._exit(0)
        #Game Loop
        clock.tick(FPS)
        all_sprites.update(dt)
        screen.blit(background_i, (0, 0))
        draw_hero_health(str(hero.health))
        all_sprites.draw(screen)
        #Display time remaining
        if level < 4 and hero.health != 0:   #count down 
            clock_limit.tick()
            ticks += clock_limit.get_time() 
            ticktock(timelimit, ticks, tickfont) #update the time left
            if timewarning > 0 and (timelimit-ticks)/(timewarning*1000) <= 1:
                time_limit.play()
                timewarning -= 1
            if ticks >= timelimit: #hero die if exceed the time limit
                hero.health = 0   
        #if a bullet hits an enemy
        if len(pygame.sprite.groupcollide(mobs, bullets, True, True)) != 0:
            die_sound.play()
        #if hero get hit by an enemy
        if len(pygame.sprite.spritecollide(hero, mobs, True)) != 0:
            die_sound.play()
            hero.health -= 1
        #if hero died, play sound
        if hero.health <= 0 and not diesound_play:
            boss_entry.play()
            boss_entry.play()
            diesound_play = True
        #restart the game
        if hero.health <= 0 and diesound_play:
            all_sprites.empty()
            screen.blit(die_image, (0, 0))
            level = 1
            pygame.mixer.music.stop()
            if pygame.key.get_pressed()[pygame.K_RETURN]:
                diesound_play = False
                break
        #First level
        if len(mobs.sprites()) < 1 and level == 1:#clear the first level
            all_sprites.add(gate1)
            if pygame.sprite.collide_rect(hero, gate1):#teleport to next level
                bullets.empty()
                background_i = background2
                all_sprites.add(fake_gate)
                hero.rect.center = (10, 280)
                gate1.rect.centerx = 18000
                gate1.kill()
                gen_enemy(l2_enemy)
                level = 2
        #Level 2, opportunity to upgrade weapon after clear the stage
        if len(mobs.sprites()) < 1 and level == 2:
            fake_gate.kill()
            all_sprites.add(gate2)
            screen.blit(warning_img, (285, 230))
            pygame.mixer.music.stop()
            all_sprites.add(chest2)
            if pygame.sprite.collide_rect(hero, chest2):
                screen.blit(warning_img, (285, 230))
                hero.bull_image = bull2
                level_up.play()
                chest2.kill()
                level=2.2
            elif pygame.sprite.collide_rect(hero, gate2):
                level = 2.2
        #Teleport to Boss scene, set background pic and music
        if level == 2.2:
            screen.blit(warning_img, (285, 230))
            if pygame.sprite.collide_rect(hero, gate2):
                chest2.kill()
                gate2.kill()
                bullets.empty()
                background_i = background3
                hero.rect.center = (10, 280)
                all_sprites.add(boss1)
                all_sprites.add(fake_gate)
                gen_enemy(l3_enemy)
                boss_entry.play()
                pygame.mixer.music.load(boss_bgm)
                pygame.mixer.music.play(-1)
                level = 3
        #Level 3, boss scene
        if level == 3:
            draw_boss_health(boss1.health)  
            if pygame.sprite.collide_rect(hero, boss1):
                hero.health = 0
            if len(pygame.sprite.spritecollide(boss1, bullets, True)) != 0:     
                boss1.health -= 1
                boss_entry.play()
            if boss1.health <= 0:
                boss1.kill()
                all_sprites.remove(mobs, bullets)
                mobs.empty()
                fake_gate.kill()
                boss_die.play()
                boss_die.play()
                boss_die.play()
                level = 3.1
        #Teleport to next level
        if level == 3.1:
            all_sprites.add(gate3) 
            if pygame.sprite.collide_rect(hero, gate3):
                gate3.kill()
                background_i = background4
                hero.rect.center = (40,280)
                level = 4
        #Level 4, Treasure Cave
        if level == 4:
             all_sprites.add(chest1) 
             if pygame.sprite.collide_rect(hero,chest1):
                 open_chest.play()
                 chest1.kill()
                 level = 5
                 pygame.time.delay(500)
        #Level 5, final scene of the game
        if level == 5:
            screen.blit(final1,(0,0))
            if pygame.key.get_pressed()[pygame.K_RETURN]:
                pygame.mixer.music.stop()
                break
      
        pygame.display.update()

  

Python实现寻宝小游戏

标签:direct   ber   vector   ini   click   pow   clear   raw   and   

原文地址:https://www.cnblogs.com/Stephanie-boke/p/12444208.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!