Pygame-及时将敌人随机掉落

时间:2019-11-20 12:25:11

标签: python pygame

我正在尝试使用Python和Pygame设计我的第一款游戏,以提高我的编码技能。

基本上,玩家有4个圆圈,目标是通过使用键盘箭头杀死魔方来阻止魔方(或敌人)到达屏幕中间。

游戏运行良好:圆圈完美移动,随着级别的提高,立方体的速度更快,计分系统还可以,等等...

我不知道的最后一步是使“多维数据集”随机掉落一些,否则太容易了。当前,当一个立方体被杀死时,它会立即重新出现在屏幕的四个边缘之一上。我想出了如何随机放置立方体的方法,但是计时不起作用。

我尝试了Python睡眠,但是它冻结了屏幕。我尝试添加一行以指定“ delay = random.random()”的延迟,并在if语句中添加“ delay <0.1” if条件。我的最后一个想法是使用一个等于clock.tick()的计时器,并在if语句中添加一个条件:timecounter> 3000。所有这些尝试都不适合我。

有什么主意吗?到目前为止,这是我的代码:

    # ---------- Packages and Inits ----------

import pygame, random, math, sys
pygame.init()

# ---------- Settings ----------

SCREEN_WIDTH  = 600
SCREEN_HEIGHT = 600
FPS = 60 
SPEED = 1
CIRCLE_RADIUS = 50
ENEMY_SIZE = 40

# Colors
RED    = (255,000,000)
BLUE   = (000,000,255)
YELLOW = (255,255,000)
GREEN  = (000,128,000)
BLACK  = (000,000,000)

# ---------- Classes ----------

class Enemies:

    def __init__( self, x, y, size=ENEMY_SIZE, thick=5, color=BLUE, speed=1, position="top"):

        self.rect = pygame.Rect(0, 0, size, size)
        if ( x == 0 and y == 0 ):
            self.randomise()

        self.rect.centerx = x
        self.rect.centery = y
        self.size = size
        self.thick = thick
        self.color = color
        self.speed = speed
        self.calcDirection()
        self.position = position

    def calcDirection( self ):
        self.x_float = 1.0 * self.rect.centerx
        self.y_float = 1.0 * self.rect.centery

        # Determine direction vector from (x,y) to the centre of the screen
        self.position_vector = pygame.math.Vector2( self.x_float, self.y_float )
        self.velocity_vector = pygame.math.Vector2( SCREEN_WIDTH/2 - self.x_float, SCREEN_HEIGHT/2 - self.y_float )
        self.velocity_vector = self.velocity_vector.normalize()

    def update( self ):
        x_delta = self.speed * self.velocity_vector[0]
        y_delta = self.speed * self.velocity_vector[1]
        self.x_float += x_delta
        self.y_float += y_delta
        self.rect.centerx = int( self.x_float )
        self.rect.centery = int( self.y_float )

    def draw( self, screen):
        pygame.draw.rect(screen, self.color, self.rect )

    def reachedPoint( self, x, y ):
        return self.rect.collidepoint( x, y )

    def randomise( self ):

        self.rect.centerx = SCREEN_WIDTH//2
        self.rect.centery = SCREEN_HEIGHT//2
        side = random.randint( 0, 4 )
        if ( side == 0 ):
            self.rect.centery = SCREEN_HEIGHT
            self.color = GREEN
            self.position= "bot"
        elif ( side == 1 ):
            self.rect.centery = 0
            self.color = YELLOW
            self.position= "top"
        elif ( side == 2 ):
            self.rect.centerx = 0
            self.color = BLUE
            self.position= "left"
        else:
            self.rect.centerx = SCREEN_WIDTH
            self.color = RED
            self.position= "right"
        self.calcDirection()

    def set_speed( self, score):
        if   score < 25 : self.speed = 0.5
        elif score < 50 : self.speed = 0.75
        elif score < 100: self.speed = 1
        elif score < 250: self.speed = 1.25
        elif score < 500: self.speed = 1.5
        else:             self.speed = 2
        return self.speed

class Circle:

    def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=BLUE, speed=SPEED, position="top"):

        self.rect = pygame.Rect(0, 0, 2*radius, 2*radius)

        self.rect.centerx = x
        self.rect.centery = y
        self.radius = radius
        self.thick = thick
        self.color = color
        self.speed = speed
        self.position = position

        if speed >= 0:
            self.directionX = 'right'
            self.direction = 'up'
        else:
            self.directionX = 'left'
            self.direction = 'down'

    def draw(self, screen):
        pygame.draw.circle(screen, self.color, self.rect.center, self.radius, self.thick)

    def swing(self):
        if self.position == "top":
            self.rect.y -= self.speed
            if self.rect.top <= 0  and self.direction == 'up':
                self.direction = 'down'
                self.speed = -self.speed
            elif self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius  and self.direction == 'down':
                self.direction = 'up'
                self.speed = -self.speed

        if self.position == "bot":
            self.rect.y -= self.speed
            if self.rect.top < int(SCREEN_HEIGHT/2) + self.radius  and self.direction == 'up':
                self.direction = 'down'
                self.speed = -self.speed
            elif self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
                self.direction = 'up'
                self.speed = -self.speed

        if self.position == "left":
            self.rect.x -= self.speed
            if self.rect.right > int(SCREEN_WIDTH/2) - self.radius and self.directionX == 'left':
                self.directionX = 'right'
                self.speed = -self.speed
            elif self.rect.left <= 0 and self.directionX == 'right':
                self.directionX = 'left'
                self.speed = -self.speed

        if self.position == "right":
            self.rect.x -= self.speed
            if self.rect.left < int(SCREEN_WIDTH/2) + self.radius  and self.directionX == 'right':
                self.directionX = 'left'
                self.speed = -self.speed
            elif self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
                self.directionX = 'right'
                self.speed = -self.speed

    def isCollision(self, enemyX, enemyY, circleX, circleY):
        distance = math.sqrt((math.pow(enemyX-circleX,2))+(math.pow(enemyY-circleY,2)))
        if distance < 65:
            return True
        else:
            return False


# ---------- Other Functions ----------

def set_number_of_enemies(score):
        if   score < 25 : number_of_enemies = 3
        elif score < 50 : number_of_enemies = 4
        elif score < 100: number_of_enemies = 5
        elif score < 250: number_of_enemies = 6
        elif score < 500: number_of_enemies = 7
        else:             number_of_enemies = 8
        return number_of_enemies

# ---------- Main ----------

def main():

    # Settings
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    screen_rect = screen.get_rect()
    myFont = pygame.font.SysFont("monospace", 25)
    clock = pygame.time.Clock()
    game_over = False

    # Variables
    lifes = 5
    score = 0
    number_of_enemies = 3

    # We create an empty list of enemies, as we want them to drop randomly
    all_enemies = []

    # Start with 4 circles
    all_circles = [
        Circle ( screen_rect.centerx                   , screen_rect.centery - 2*CIRCLE_RADIUS , position = "top"  ),
        Circle ( screen_rect.centerx                   , screen_rect.centery + 2*CIRCLE_RADIUS , position = "bot"  ),
        Circle ( screen_rect.centerx + 2*CIRCLE_RADIUS , screen_rect.centery                   , position = "right"),
        Circle ( screen_rect.centerx - 2*CIRCLE_RADIUS , screen_rect.centery                   , position = "left" )]

    while not game_over:

        screen.fill(BLACK) # This has to be inside the while not game_over loop 
        time_counter = clock.tick()
        print(time_counter)

        # Circles
        for c in all_circles:
            c.draw(screen)     # Place circles on the screen
            c.swing()          # Move circles from center to edges, and from edges to center, back and forth

        # Set number of enemies
        number_of_enemies = set_number_of_enemies(score) # Get the number of enemies we want, based on the score
        if len(all_enemies) < number_of_enemies and time_counter > 3000: # Add if necessary
            all_enemies.append(Enemies(int(SCREEN_WIDTH/2), 0, color = YELLOW, position = "top")) # We add a top enemy, but we randomise it right after
            for e in all_enemies:
                e.randomise()
            time_counter = 0

        # Enemies
        for e in all_enemies:
            e.draw(screen)     # Place enemies on the screen
            e.set_speed(score) # Set speed difficulty for enemies
            e.update()         # Move enemies from the edges of the screen towards the center
            if ( e.reachedPoint( SCREEN_WIDTH//2, SCREEN_HEIGHT//2 ) ): # If the enemy reaches the middle, you lose a lifepoint and a new enemy is generated
                lifes -=1
                e.randomise()

        # Scoring and lifepoints systems
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()

            for c in all_circles:

                if event.type == pygame.KEYDOWN:

                    # LEFT
                    if event.key == pygame.K_LEFT and c.position == "left":
                        hits = [e for e in all_enemies if c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)]
                        if not hits:
                            lifes -=1
                        for e in hits:
                            if len(hits) == 1: 
                                score +=1
                            if len(hits) == 2: 
                                score +=5/len(hits)
                            if len(hits) == 3: 
                                score +=10/len(hits)
                            e.randomise()

                    # RIGHT
                    if event.key == pygame.K_RIGHT and c.position == "right":
                        hits = [e for e in all_enemies if c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)]
                        if not hits:
                            lifes -=1
                        for e in hits:
                            if len(hits) == 1: 
                                score +=1
                            if len(hits) == 2: 
                                score +=5/len(hits)
                            if len(hits) == 3: 
                                score +=10/len(hits)
                            e.randomise()

                    # TOP
                    if event.key == pygame.K_UP and c.position == "top":
                        hits = [e for e in all_enemies if c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)]
                        if not hits:
                            lifes -=1
                        for e in hits:
                            if len(hits) == 1: 
                                score +=1
                            if len(hits) == 2: 
                                score +=5/len(hits)
                            if len(hits) == 3: 
                                score +=10/len(hits)
                            e.randomise()

                    # BOT
                    if event.key == pygame.K_DOWN and c.position == "bot":
                        hits = [e for e in all_enemies if c.isCollision(e.rect.centerx,e.rect.centery,c.rect.centerx,c.rect.centery)]
                        if not hits:
                            lifes -=1
                        for e in hits:
                            if len(hits) == 1: 
                                score +=1
                            if len(hits) == 2: 
                                score +=5/len(hits)
                            if len(hits) == 3: 
                                score +=10/len(hits)
                            e.randomise()

        # Game Over condition
        if lifes == 0:
            game_over = True

        # Score / Lifes / Number of Enemies                                        
        print_lifes = myFont.render("Lifes:" + str(round(lifes)), 1, RED)
        screen.blit(print_lifes, (10, SCREEN_HEIGHT-50))

        print_score = myFont.render("Score:" + str(round(score)), 1, RED)
        screen.blit(print_score, (10, 10))

        print_enemies = myFont.render("# of Enemies:" + str(round(number_of_enemies)), 1, RED)
        screen.blit(print_enemies, (10, 60))

        pygame.display.update()
        clock.tick(FPS)
main()
pygame.quit()

1 个答案:

答案 0 :(得分:1)

我建议使用计时器事件。使用pygame.time.set_timer()重复创建USEREVENT。例如:

milliseconds_delay = 3000
enemy_spawn_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_spawn_event, milliseconds_delay)

注意,在pygame中可以定义客户事件。每个事件都需要一个唯一的ID。用户事件的ID必须以pygame.USEREVENT开头。在这种情况下,pygame.USEREVENT+1是计时器事件的事件ID,它会产生敌人。

在事件循环中发生事件时创建新敌人:

milliseconds_delay = 3000
enemy_spawn_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_spawn_event, milliseconds_delay)

while not game_over:

    # [...]

    # Scoring and lifepoints systems
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

        if event.type == enemy_spawn_event and len(all_enemies) < number_of_enemies:
            all_enemies.append(Enemies(int(SCREEN_WIDTH/2), 0, color = YELLOW, position = "top"))
            for e in all_enemies:
                e.randomise()
            time_counter = 0