简体   繁体   中英

drop several cubes in pygame

I started Python last week and I'm trying to create a game to learn. There are 4 moving circles in the screen, moving from the middle of the screen to the 4 edges. I got this part I think.

Now I'm trying to drop cubes from the 4 edges to the middle. The goal is to stop those cubes from reaching the middle of the screen, by pressing keyboard arrows. If one cube reaches the center, it's game over.

I managed to drop 4 cubes to the middle at the same time, but the idea is to drop randomly a few cubes.

Any idea how I should proceed to create this? or what should I learn to make this happen?

here's my work so far:

# ---------- Packages ----------

import pygame, random
pygame.init()

# ---------- Constants ----------

SCREEN_WIDTH  = 600
SCREEN_HEIGHT = 600
FPS = 60 
SPEED = 1
SPEED_ENEMIES = 1
CIRCLE_RADIUS = 50
ENNEMY_SIZE = 40

red    = (255,000,000)
blue   = (000,000,255)
yellow = (255,255,000)
green  = (000,128,000)
pink   = (255,192,203)
black  = (000,000,000)
transparent = (0, 0, 0, 0)

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

class Ennemies:

    def __init__(self, x, y, size=ENNEMY_SIZE, thick=5, color=blue, speed=SPEED_ENEMIES):

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

        self.rect.centerx = x
        self.rect.centery = y
        self.size = size
        self.thick = thick
        self.color = color
        self.speed = speed

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

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

    def move_up(self):
        self.rect.y -= self.speed

        if self.rect.centery < int(SCREEN_HEIGHT/2) - self.size/2:
            self.color = transparent

    def move_down(self):
        self.rect.y += self.speed

        if self.rect.centery > int(SCREEN_HEIGHT/2) - self.size/2:
            self.color = transparent

    def move_left(self):
        self.rect.x -= self.speed

        if self.rect.centerx < int(SCREEN_WIDTH/2) - self.size/2:
            self.color = transparent

    def move_right(self):
        self.rect.x += self.speed

        if self.rect.centerx > int(SCREEN_WIDTH/2) - self.size/2:
            self.color = transparent

class Circle:

    def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=blue, speed=SPEED):

        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

        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_top(self):
        self.rect.y -= self.speed

        if self.rect.top <= 0  and self.direction == 'up':
            self.direction = 'down'
            self.speed = -self.speed

        if self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius  and self.direction == 'down':
            self.direction = 'up'
            self.speed = -self.speed

    def swing_bot(self):
        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

        if self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
            self.direction = 'up'
            self.speed = -self.speed

    def swing_left(self):
        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

        if self.rect.left <= 0 and self.directionX == 'right':
            self.directionX = 'left'
            self.speed = -self.speed

    def swing_right(self):
        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

        if self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
            self.directionX = 'right'
            self.speed = -self.speed

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

def main():

    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    screen_rect = screen.get_rect()

    enemyTop = [
        Ennemies(int(SCREEN_WIDTH/2)-ENNEMY_SIZE/2, 0, color=yellow)
    ]
    enemyBot = [
        Ennemies(int(SCREEN_WIDTH/2)-ENNEMY_SIZE/2, SCREEN_HEIGHT-ENNEMY_SIZE, color=green)
    ]
    enemyLeft = [
        Ennemies(0, int(SCREEN_HEIGHT/2)-ENNEMY_SIZE/2, color=blue)
    ]
    enemyRight = [
        Ennemies(SCREEN_WIDTH-ENNEMY_SIZE, int(SCREEN_HEIGHT/2)-ENNEMY_SIZE/2, color = red)
    ]

    circleTop = [
        Circle(screen_rect.centerx, screen_rect.centery - 2*CIRCLE_RADIUS)
    ]

    circleBot = [
        Circle(screen_rect.centerx, screen_rect.centery + 2*CIRCLE_RADIUS)
    ]

    circleRight = [
        Circle(screen_rect.centerx + 2*CIRCLE_RADIUS, screen_rect.centery)
    ]

    circleLeft = [
        Circle(screen_rect.centerx - 2*CIRCLE_RADIUS, screen_rect.centery)
    ]

    clock = pygame.time.Clock()

    game_over = False

    while not game_over:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True

        for item in enemyTop:
            item.move_down()
        for item in enemyBot:
            item.move_up()
        for item in enemyLeft:
            item.move_right()
        for item in enemyRight:
            item.move_left()

        for item in circleTop:
            item.swing_top()
        for item in circleBot:
            item.swing_bot()
        for item in circleLeft:
            item.swing_left()
        for item in circleRight:
            item.swing_right()

        screen.fill(black)

        for item in enemyTop:
            item.draw(screen)
        for item in enemyBot:
            item.draw(screen)
        for item in enemyLeft:
            item.draw(screen)
        for item in enemyRight:
            item.draw(screen)

        for item in circleTop:
            item.draw(screen)
        for item in circleBot:
            item.draw(screen)
        for item in circleLeft:
            item.draw(screen)
        for item in circleRight:
            item.draw(screen)

        pygame.display.update()

        clock.tick(FPS)

main()
pygame.quit()

Thanks

I think the answer here is to modify your Enemies object so that it works better as a more generic object.

To this end I modified the class so that a "cube" starts at a random position at the side, and always heads into the middle (I'm, not sure if this is exactly what you planned, but it's my interpretation of your game description).

This is achieved by calculating a direction vector (since it could now be a diagonal line), and then adding this amount (times speed) to the location each "tick". One problem this creates, is that if the component of the direction is very small - say 0.1 pixels/tick, then the addition of this amount is always rounded away to nothing. So the class keeps the location as a floating point number, and only converts back to integer when the Rect is updated.

The code now keeps a list of Enemies objects. This makes it easy to iterate through this list, updating, drawing and checking positions. To add more enemies, simply add extras to this list - perhaps as levels get harder.

The next change was for the Enemy to start in a random position if the supplied co-ordinates are (0,0). This allows the code to re-set the old enemies to a new random starting position, or add new ones.

# ---------- Packages ----------

import pygame, random
pygame.init()

# ---------- Constants ----------

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

red    = (255,000,000)
blue   = (000,000,255)
yellow = (255,255,000)
green  = (000,128,000)
pink   = (255,192,203)
black  = (000,000,000)
transparent = (0, 0, 0, 0)

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

class Enemies:

    def __init__(self, x, y, size=ENEMY_SIZE, thick=5, color=blue, speed=SPEED_ENEMIES):

        self.rect = pygame.Rect(0, 0, size, size)
        # if x and y are zero, choose a random starting point
        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()

    def calcDirection( self ):
        """ Work out the direction vector to (0,0) """
        self.x_float = 1.0 * self.rect.centerx  # keep these to stop rounding errors
        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()
        #print("Velocity Vector = "+str(self.velocity_vector) )

    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 ):
        """ Pick a random starting point """
        self.rect.centerx = random.randint( 0, SCREEN_WIDTH )
        self.rect.centery = random.randint( 0, SCREEN_HEIGHT )
        side = random.randint( 0, 4 )
        if ( side == 0 ):   # top
            self.rect.centery = SCREEN_HEIGHT
        elif ( side == 1 ): # bottom
            self.rect.centery = 0
        elif ( side == 2 ): # left
            self.rect.centerx = 0
        else:               # right
            self.rect.centerx = SCREEN_WIDTH
        self.calcDirection()



class Circle:

    def __init__(self, x, y, radius=CIRCLE_RADIUS, thick=5, color=blue, speed=SPEED):

        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

        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_top(self):
        self.rect.y -= self.speed

        if self.rect.top <= 0  and self.direction == 'up':
            self.direction = 'down'
            self.speed = -self.speed

        if self.rect.bottom > int(SCREEN_HEIGHT/2) - self.radius  and self.direction == 'down':
            self.direction = 'up'
            self.speed = -self.speed

    def swing_bot(self):
        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

        if self.rect.bottom >= SCREEN_HEIGHT and self.direction == 'down':
            self.direction = 'up'
            self.speed = -self.speed

    def swing_left(self):
        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

        if self.rect.left <= 0 and self.directionX == 'right':
            self.directionX = 'left'
            self.speed = -self.speed

    def swing_right(self):
        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

        if self.rect.right >= SCREEN_WIDTH and self.directionX == 'left':
            self.directionX = 'right'
            self.speed = -self.speed

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

def main():

    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    screen_rect = screen.get_rect()

    # Start with 4 enemies
    all_enemies = [
        Enemies(random.randint(1,SCREEN_WIDTH), 1, color=yellow),                           # bottom
        Enemies(random.randint(1,SCREEN_WIDTH), SCREEN_HEIGHT-ENEMY_SIZE, color=green),     # top
        Enemies(1, random.randint(1,SCREEN_HEIGHT), color=blue),                            # left
        Enemies(SCREEN_WIDTH-ENEMY_SIZE, random.randint(1,SCREEN_HEIGHT), color = red)      # right
    ]

    circleTop = [
        Circle(screen_rect.centerx, screen_rect.centery - 2*CIRCLE_RADIUS)
    ]

    circleBot = [
        Circle(screen_rect.centerx, screen_rect.centery + 2*CIRCLE_RADIUS)
    ]

    circleRight = [
        Circle(screen_rect.centerx + 2*CIRCLE_RADIUS, screen_rect.centery)
    ]

    circleLeft = [
        Circle(screen_rect.centerx - 2*CIRCLE_RADIUS, screen_rect.centery)
    ]

    clock = pygame.time.Clock()

    game_over = False

    while not game_over:

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                game_over = True

        for item in circleTop:
            item.swing_top()
        for item in circleBot:
            item.swing_bot()
        for item in circleLeft:
            item.swing_left()
        for item in circleRight:
            item.swing_right()

        screen.fill(black)

        for e in all_enemies:
            e.update()
            # Did the enemy make it to the centre?
            if ( e.reachedPoint( SCREEN_WIDTH//2, SCREEN_HEIGHT//2 ) ):
                # Game over?
                print("Game Over?")
                e.randomise()
            e.draw( screen )

        for item in circleTop:
            item.draw(screen)
        for item in circleBot:
            item.draw(screen)
        for item in circleLeft:
            item.draw(screen)
        for item in circleRight:
            item.draw(screen)

        pygame.display.update()

        clock.tick(FPS)

main()
pygame.quit()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM