Search code examples
pythonpython-2.7timepygamepygame-clock

How can I use time to make random arrows in pygame?


Im trying to make a code in pygame that shows the arrow sprites randomly (like DDR). I had the idea to use time, but sleep pauses the whole program and i just want one arrow to be paused.

I have tried to make a random list type caller, but that doesnt work becaus the arrows need to make it to the end before they disapear.

import pygame, sys
from pygame.locals import *
from random import randint
from time import sleep

#Variables
WIDTH = 800
HEIGHT = 450
FPS = 30
running = True
BLACK = (0, 0, 0)
SALMON = (253, 171, 159)

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Tempoify")

pygame.init()
pygame.mixer.init()
clock = pygame.time.Clock()

#####################################
# Gray Arrows

class ArrowRightGray(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("gray right.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (750, 25)


class ArrowLeftGray(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("gray left.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (750, 125)


class ArrowUpGray(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("gray up.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (750, 250)

class ArrowDownGray(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("gray down.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (750, 375)

class ArrowRight(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("red right.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (25, 25)

  def update(self):
    self.rect.x += 5
    if (self.rect.left > (WIDTH + 50)):
        self.rect.right = 0

class ArrowLeft(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("blue left.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (25, 125)

  def update(self):
    self.rect.x += 5
    if (self.rect.left > (WIDTH + 50)):
        self.rect.right = 0

class ArrowUp(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("green up.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (25, 250)

  def update(self):
    self.rect.x += 5
    if (self.rect.left > (WIDTH + 50)):
        self.rect.right = 0

class ArrowDown(pygame.sprite.Sprite):

  def __init__(self):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.image.load("yellow down.png").convert()
    self.image.set_colorkey(BLACK)
    self.rect = self.image.get_rect()
    self.rect.center = (25, 375)

  def update(self):
    self.rect.x += 5
    if (self.rect.left > (WIDTH + 50)):
        self.rect.right = 0

allArrows = pygame.sprite.Group()
a1g = ArrowRightGray()
a1 = ArrowRight()

a2g = ArrowLeftGray()
a2 = ArrowLeft()

a3g = ArrowUpGray()
a3 = ArrowUp()

a4g = ArrowDownGray()
a4 = ArrowDown()

allArrows.add(a1g)
allArrows.add(a1)
allArrows.add(a2g)
allArrows.add(a2)
allArrows.add(a3g)
allArrows.add(a3)
allArrows.add(a4g)
allArrows.add(a4)

while running:
  clock.tick(FPS)

  #Update
  allArrows.update()

  keys = pygame.key.get_pressed()

  for event in pygame.event.get():
      if keys[pygame.K_RIGHT]:
          if pygame.sprite.collide_rect(a1, a1g):
              a1.rect.center = (900, 600)
      elif keys[pygame.K_LEFT]:
          if pygame.sprite.collide_rect(a2, a2g):
              a2.rect.center = (900, 600)
      elif keys[pygame.K_UP]:
          if pygame.sprite.collide_rect(a3, a3g):
              a3.rect.center = (900, 600)
      elif keys[pygame.K_DOWN]:
          if pygame.sprite.collide_rect(a4, a4g):
              a4.rect.center = (900, 600)
  #draw
  screen.fill(SALMON)
  allArrows.draw(screen)

  pygame.display.flip()

pygame.quit()

In the end, the arrows should make it to the end of the screen and show up randomly. They should also disappear when they collide with the grey arrows.


Solution

  • First of all don't create on class for each arrow. A class is an object with attributes. Use the attributes of a class and create instances of the class with different appearance and behavior. Add parameters to the signature of the constructor and use the the parameters to the initialize the attributes.

    Add parameters for the position and image filename:

    class ArrowGray(pygame.sprite.Sprite):
    
        def __init__(self, pos, imagename):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.image.load(imagename).convert()
            self.image.set_colorkey(BLACK)
            self.rect = self.image.get_rect()
            self.rect.center = pos
    
    class Arrow(pygame.sprite.Sprite):
    
        def __init__(self, pos, imagename):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.image.load(imagename).convert()
            self.image.set_colorkey(BLACK)
            self.rect = self.image.get_rect()
            self.rect.center = pos
    
        def update(self):
            self.rect.x += 5
            if (self.rect.left > (WIDTH + 50)):
                self.rect.right = 0
    
    a1g = ArrowGray((750, 25), "gray right.png")
    a2g = ArrowGray((750, 125), "gray left.png")
    a3g = ArrowGray((750, 250), "gray up.png")
    a4g = ArrowGray((750, 375), "gray down.png")
    
    a1 = Arrow((25, 25), "red right.png")
    a2 = Arrow((25, 125), "blue left.png")
    a3 = Arrow((25, 250), "green up.png")
    a4 = Arrow((25, 375), "yellow down.png")
    

    I recommend to use a timer event. Use pygame.time.set_timer() to repeatedly create an USEREVENT. e.g.:

    arrowGrayList = [a1g, a2g, a3g, a4g]
    arrowList = [a1, a2, a3, a4]
    allArrows = pygame.sprite.Group()
    
    millisecondsDelay = 500 # 0.5 seconds
    arrowTimerEvent = pygame.USEREVENT + 1
    pygame.time.set_timer(arrowTimerEvent, millisecondsDelay)
    spawned = 0
    
    while running:
        clock.tick(FPS)
    
        #Update
        allArrows.update()
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
    
            if event.type == arrowTimerEvent:
                if spawned < len(arrowList):
                    allArrows.add(arrowGrayList[spawned])
                    allArrows.add(arrowList[spawned])
                    spawned += 1
    
        keys = pygame.key.get_pressed()
        if keys[pygame.K_RIGHT]:
            if pygame.sprite.collide_rect(a1, a1g):
                a1.rect.center = (900, 600)
        if keys[pygame.K_LEFT]:
            if pygame.sprite.collide_rect(a2, a2g):
                a2.rect.center = (900, 600)
        if keys[pygame.K_UP]:
            if pygame.sprite.collide_rect(a3, a3g):
                a3.rect.center = (900, 600)
        if keys[pygame.K_DOWN]:
            if pygame.sprite.collide_rect(a4, a4g):
                a4.rect.center = (900, 600)
        #draw
        screen.fill(SALMON)
        allArrows.draw(screen)
    
        pygame.display.flip()
    
    pygame.quit()
    

    Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to start at pygame.USEREVENT. In this case pygame.USEREVENT+1 is the event id for the timer event, which spawns the arrows.