1

So I don't know how to turn the rectangle representing the player into an image (spaceship). I know it must be simple, but after a few hours with this I'm a little frustrated, so I'm looking for help :(

bg_color = pygame.Color('black')
text_color = pygame.Color('darkgrey')
obstacles_color = pygame.Color('darkred')
player_color = pygame.Color('yellow')

fps = 60


window_height = 1200
window_width = 1200

player_speed = 4
player_size = 8
player_max_up = 125

obstacle_spawn_rate = 1
obstacle_min_size = 3
obstacle_max_size = 6
obstacle_min_speed = 2
obstacle_max_speed = 2




class Player:
    def __init__(self):
        self.size = player_size
        self.speed = player_speed
        self.color = player_color
        self.position = (window_width / 2, (window_height - (window_height / 10)))

    def draw(self, surface):
        r = self.get_rect()
        pygame.draw.rect(surface, self.color, r)


    def move(self, x, y):
        newX = self.position[0] + x
        newY = self.position[1] + y
        if newX < 0 or newX > window_width - player_size:
            newX = self.position[0]
        if newY < window_height - player_max_up or newY > window_height - player_size:
            newY = self.position[0]
        self.position = (newX, newY)

    def collision_detection(self, rect):
        r = self.get_rect()
        return r.colliderect(rect)

    def get_rect(self):
        return pygame.Rect(self.position, (self.size, self.size))


class Obstacles:
    def __init__(self):
        self.size = random.randint(obstacle_min_size, obstacle_max_size)
        self.speed = random.randint(obstacle_min_speed, obstacle_max_speed)
        self.color = obstacles_color
        self.position = (random.randint(0, window_width - self.size), 0 - self.size)

    def draw(self, surface):
        r = self.get_rect()
        pygame.draw.rect(surface, self.color, r)

    def move(self):
        self.position = (self.position[0], self.position[1] + self.speed)

    def is_off_window(self):
        return self.position[1] > window_height

    def get_rect(self):
        return pygame.Rect(self.position, (self.size, self.size))


class World:
    def __init__(self):
        self.reset()

    def reset(self):
        self.player = Player()
        self.obstacles = []
        self.gameOver = False
        self.score = 0
        self.obstacles_counter = 0
        self.moveUp = False
        self.moveDown = False
        self.moveLeft = False
        self.moveRight = False

    def is_game_over(self):
        return self.gameOver

    def update(self):
        self.score += 1

        if self.moveUp:
            self.player.move(0, - player_speed)
        if self.moveUp:
            self.player.move(0, player_speed)
        if self.moveLeft:
            self.player.move(-player_speed, 0)
        if self.moveRight:
            self.player.move(player_speed, 0)

        for each in self.obstacles:
            each.move()
            if self.player.collision_detection(each.get_rect()):
                self.gameOver = True
            if each.is_off_window():
                self.obstacles.remove(each)

        self.obstacles_counter += 1
        if self.obstacles_counter > obstacle_spawn_rate:
            self.obstacles_counter = 0
            self.obstacles.append(Obstacles())

    def draw(self, surface):
        self.player.draw(surface)
        for each in self.obstacles:
            each.draw(surface)

    def movement_keys(self, event):
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                self.moveUp = True
            if event.key == pygame.K_DOWN:
                self.moveDown = True
            if event.key == pygame.K_LEFT:
                self.moveLeft = True
            if event.key == pygame.K_RIGHT:
                self.moveRight = True

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                 self.moveUp = False
            if event.key == pygame.K_DOWN:
                 self.moveDown = False
            if event.key == pygame.K_LEFT:
                 self.moveLeft = False
            if event.key == pygame.K_RIGHT:
                 self.moveRight = False


def run():
    pygame.init()
    clock = pygame.time.Clock()
    window = pygame.display.set_mode((window_height, window_width))
    pygame.display.set_caption("Avoid Obstacles")
    surface = pygame.Surface(window.get_size())
    surface = surface.convert()

    world = World()

    font = pygame.font.SysFont("Times", 35, "bold")

    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN and event.key == ord("r"):
                world.reset()
            else:
                world.movement_keys(event)

        if not world.is_game_over():
            world.update()

        window.fill(bg_color)
        clock.tick(fps)
        world.draw(window)

        surface.blit(surface, (0, 0))
        text = font.render("Score {0}".format(world.score), 1, text_color)
        window.blit(text, (1, 1))
        if world.is_game_over():
            end = font.render("The end of your journey", 1, text_color)
            window.blit(end, (window_width / 2 - 220, window_height / 2))
            restart = font.render("Hit R to reset", 1, text_color)
            window.blit(restart, (window_width / 2 - 120, window_height / 2 + 45))
        pygame.display.update()


if __name__ == '__main__':
    run()
    pygame.quit()

I tried changing the draw function in the Player class, but still couldn't figure out how to do it correctly. I'm drawing an image of the spaceship on the screen/window, but I can't get it to move to the player rectangle.

RedPutron
  • 25
  • 1
  • 5
  • Where is your code that attempts to draw an image? Am I missing it, or is it not here? You need to show us what you're trying that isn't working for us to be able to tell you how to fix it. – CryptoFool Feb 12 '22 at 18:52
  • Stack overflow tends to frown upon 'full code', and usually asks for minimal examples. However in your case I wanted to say that your code was very clean and nice to read, and with the exception of a couple of imports, I could 'run it and see'. Thank you for making the effort to share clean code :) – Tasos Papastylianou Feb 12 '22 at 19:12

2 Answers2

1

I don't know what you've tried, but here's how to do this with a call to blit:

myimage = pygame.image.load("bar.png")

...

def draw(self, surface):
    r = self.get_rect()
    surface.blit(myimage, r)

The key point here is that you're giving blit the same coordinates that you were using to draw the rectangle. When I tried this, I got the correct/natural size of the image even though the r rectangle is of different dimensions. If that turns out to cause a problem, you could adjust the dimensions of the rectangle to be the same as the image. You also might want to adjust the coordinates of r such that the image is drawn centered on the location at which you wish to draw it.

CryptoFool
  • 21,719
  • 5
  • 26
  • 44
  • Thank you very much :). This solved my problem. I myself have been so close to solving this, but I think my brain is burned after so many hours with this.... – RedPutron Feb 12 '22 at 19:16
1

The 'draw' family of functions are convenience functions that create Surface objects and then paint pixels on it that correspond to basic shapes (like circles, rectangles etc, filled or otherwise).

Instead, you need to create a Surface where the pixels have been initialised via an image. For this, you need the "image" family of functions (see https://www.pygame.org/docs/ref/image.html for image functions).

Other than that, everything in pygame is a surface, and you're manipulating and updating surfaces on the display, so your code should not change, whether your surfaces were initialised via 'draw' or 'image'.

Tasos Papastylianou
  • 21,371
  • 2
  • 28
  • 57