Search code examples
pythonpygameresizewindowcharacter

I am trying to move my character but instead of that the player wont move


I am trying to move my character. I wrote it just like in a tutorial(https://www.youtube.com/watch?v=FfWpgLFMI7w). It doesn't work. My character just wont move. I do not see any errors neither! Did I forget to add something to my code - in the KEYDOWN section? So the whole Code is here but the problem probably is in the KEYDOWN section or the player coordinates. Here is the code:

import pygame
from pygame.locals import *

pygame.init()

WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600

SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))

pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)

centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)

playerImg = pygame.image.load("RobiS.png")
playerX = 370
playerY = 500
playerX_change = 0

def player(x,y):
    win.blit(playerImg, (x, y))

class button():
    def __init__(self, color, x, y, width, height, text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self, win, outline=None):
        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('comicsans', 60)
            text = font.render(self.text, 1, (0, 0, 0))
            win.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))

    def isOver(self, pos):
        # Pos is the mouse position or a tuple of (x,y) coordinates
        if pos[0] > self.x and pos[0] < self.x + self.width:
            if pos[1] > self.y and pos[1] < self.y + self.height:
                return True

        return False

    def rescale(self):
        new_size = int(WINDOW_WIDTH * self.scale_factor)
        x, y = self.rect.center
        self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)

    def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
        self.width = WINDOW_WIDTH
        self.height = WINDOW_HEIGHT
        self.x = x
        self.y = y


def redrawMenuWindow():
    win.fill((0, 255, 110))
    greenButton.draw(win, (0, 0, 0))
    redButton.draw(win, (0, 0, 0))
    cyanButton.draw(win, (0, 0, 0))

def redrawGameWindow():
    win.fill((0, 150, 210))
    pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
    win.blit(playerImg, (370, 400))


def redrawShopWindow():
    win.fill((200, 100, 30))

greenButton = button((0, 255, 0), 275, 285, 250, 80, "Start")
redButton = button((255, 0, 0), 275, 475, 250, 80, "Quit")
cyanButton = button((20, 210, 180), 275, 380, 250, 80, "Shop")

game_state = "menu"
run = True
while run:
    if game_state == "menu":
        redrawMenuWindow()
    elif game_state == "game":
        redrawGameWindow()
    elif game_state == "shop":
        redrawShopWindow()
        pygame.display.update()

    for event in pygame.event.get():
        pos = pygame.mouse.get_pos()

        if event.type == pygame.QUIT:
            run = False
            pygame.quit()
            quit()
        elif event.type == pygame.VIDEORESIZE:
            WINDOW_WIDTH = event.w
            WINDOW_HEIGHT = event.h
            win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
            greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)

        if event.type == pygame.MOUSEBUTTONDOWN:
            if greenButton.isOver(pos):
                print("clicked the button")
                game_state = "game"
            if redButton.isOver(pos):
                print("clicked the 2button")
                run = False
                pygame.quit()
                quit()
            if cyanButton.isOver(pos):
                print("clicked the 3button")
                game_state = "shop"


        if event.type == pygame.MOUSEMOTION:
            if greenButton.isOver(pos):
                greenButton.color = (105, 105, 105)
            else:
                greenButton.color = (0, 255, 0)
            if redButton.isOver(pos):
                redButton.color = (105, 105, 105)
            else:
                redButton.color = (255, 0, 0)
            if cyanButton.isOver(pos):
                cyanButton.color = (105, 105, 105)
            else:
                cyanButton.color = (20, 210, 180)

        if event.type == pygame.KEYDOWN:
            playerX_change = -0.3
            print("Left arrow is pressed")
            if event.key == pygame.K_RIGHT:
                 playerX_change = 0.3
                 print("Right arrow is pressed")
         if event.type == pygame.KEYUP:
            if event.key == pygame.K_a or event.key == pygame.K_d:
                playerX_change = 0.1
                print("Keystroke has been released")

    pygame.display.update()

    playerX += playerX_change
    player(playerX, playerY)

pygame.display.update()

Please tell me the code . If you just tell me what the problem is, I maybe wouldn't know how to fix it. It would be best if you could tell me what's wrong and then write the correct code (not necessarily the whole code, just the part I need). If then the real problem is me because I forgot something or made a typo, then I am sorry for asking this question.


Solution

  • First problem is you draw player in main loop after update() so it updates image on monitor before you draw player. And finally it draws player before fill() which removes it from Surface and update() displays Surface without this player on monitor.

    You draw second player in redrawGameWindow (before update() and this player is visible on screen but this player use (370, 400) so it never moves.


    Full code with other changes.

    Some of changes based on PEP 8 -- Style Guide for Python Code

    import pygame
    #from pygame.locals import * # PEP8: `import *` is not preferred (but you don't even need it
    
    # --- constants --- (UPPER_CASE_NAMES) # PEP8
    
    WINDOW_WIDTH = 800
    WINDOW_HEIGHT = 600
    SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
    
    
    # --- classes --- (CamerCaseNames) # PEP8
    
    class Button():
    
        def __init__(self, color, x, y, width, height, text=''):
            self.color = color
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.text = text
    
        def draw(self, win, outline=None):
            # Call this method to draw the button on the screen
            if outline:
                pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
    
            pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
    
            if self.text != '':
                font = pygame.font.SysFont('comicsans', 60)
                text = font.render(self.text, 1, (0, 0, 0))
                win.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
    
        def is_over(self, pos):
            # Pos is the mouse position or a tuple of (x,y) coordinates
            if pos[0] > self.x and pos[0] < self.x + self.width:
                if pos[1] > self.y and pos[1] < self.y + self.height:
                    return True
    
            return False
    
        def rescale(self):
            new_size = int(WINDOW_WIDTH * self.scale_factor)
            x, y = self.rect.center
            self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
            self.rect = self.image.get_rect()
            self.rect.center = (x, y)
    
        def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
            self.width = WINDOW_WIDTH
            self.height = WINDOW_HEIGHT
            self.x = x
            self.y = y
    
    # --- functions --- (lower_case_names) # PEP8
    
    def player(x,y):
        win.blit(playerImg, (x, y))
    
    def redraw_menu_window():
        win.fill((0, 255, 110))
        green_button.draw(win, (0, 0, 0))
        red_button.draw(win, (0, 0, 0))
        cyan_button.draw(win, (0, 0, 0))
    
    def redraw_game_window():
        win.fill((0, 150, 210))
        pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
        win.blit(player_img, (player_x, player_y)) # use playerX, playerY
    
    def redraw_shop_window():
        win.fill((200, 100, 30))
    
    # --- main ---
    
    pygame.init()
    
    win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
    win.fill((0, 180, 210))
    
    pygame.display.set_caption("Baloon War!")
    icon = pygame.image.load("Baloon war icon.png")
    pygame.display.set_icon(icon)
    
    #centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
    center_point = win.get_rect().center 
    
    player_img = pygame.image.load("RobiS.png")
    player_x = 370
    player_y = 500
    player_x_change = 0
    
    green_button = Button((0, 255, 0), 275, 285, 250, 80, "Start")
    red_button = Button((255, 0, 0), 275, 475, 250, 80, "Quit")
    cyan_button = Button((20, 210, 180), 275, 380, 250, 80, "Shop")
    
    game_state = "menu"
    run = True
    while run:
    
        # --- draws ---
    
        if game_state == "menu":
            redraw_menu_window()
        elif game_state == "game":
            player_x += player_x_change
            redraw_game_window()
        elif game_state == "shop":
            redraw_shop_window()
    
        pygame.display.update()
    
        for event in pygame.event.get():
            pos = pygame.mouse.get_pos()
    
            if event.type == pygame.QUIT:
                run = False
                pygame.quit()
                quit()
    
            elif event.type == pygame.VIDEORESIZE:
                WINDOW_WIDTH = event.w
                WINDOW_HEIGHT = event.h
                win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
                greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
    
            elif event.type == pygame.MOUSEBUTTONDOWN: # you can use `elif`
                if game_state == "menu":
                    if green_button.is_over(pos):
                        print("clicked the button")
                        game_state = "game"
                    if red_button.is_over(pos):
                        print("clicked the 2button")
                        run = False
                        pygame.quit()
                        quit()
                    if cyan_button.is_over(pos):
                        print("clicked the 3button")
                        game_state = "shop"
                elif game_state == "shop": # it has to be `elif` because in previous line is `game_state = "shop"` which could run it at once.
                    game_state = "menu"
    
            elif event.type == pygame.MOUSEMOTION: # you can use `elif`
                if game_state == "menu":
                    if green_button.is_over(pos):
                        green_button.color = (105, 105, 105)
                    else:
                        green_button.color = (0, 255, 0)
                    if red_button.is_over(pos):
                        red_button.color = (105, 105, 105)
                    else:
                        red_button.color = (255, 0, 0)
                    if cyan_button.is_over(pos):
                        cyan_button.color = (105, 105, 105)
                    else:
                        cyan_button.color = (20, 210, 180)
    
            elif event.type == pygame.KEYDOWN: # you can use `elif`
                if game_state == "game":
                    if event.key == pygame.K_LEFT:
                        print("Left arrow is pressed")
                        player_x_change = -0.3
                    if event.key == pygame.K_RIGHT:
                        player_x_change = 0.3
                        print("Right arrow is pressed")
    
            elif event.type == pygame.KEYUP: # you can use `elif`
                if game_state == "game":
                    if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                        player_x_change = 0
                        print("Keystroke has been released")
    
    # -- end ---
    

    BTW: you shouls see pygame.Rect() which is used to keep position and size and it has rect.right which you can use instead of x + width. And it has funcitons to check collision and you can use it if mouse is over button.


    EDIT: Code with more changes.

    I use pygame.Rect to keep position and size, and to check collision in Button. I also created class Player and I check events inside classes Button and Player. Classes have also method update(), draw(), handle_events so you could keep them on list or pygame.sprite.Group and use for-loop to execute these functions for all objects.

    import pygame
    
    # --- constants --- (UPPER_CASE_NAMES) # PEP8
    
    WINDOW_WIDTH = 800
    WINDOW_HEIGHT = 600
    SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
    
    # --- classes --- (CamerCaseNames) # PEP8
    
    class Button():
    
        def __init__(self, color, hover_color, x, y, width, height, text='', outline=None, action=None):
            self.normal_color = color
            self.hover_color = hover_color
    
            self.color = self.normal_color
    
            self.rect = pygame.Rect(x, y, width, height)
            self.text = text
    
            self.rect_outline = self.rect.copy()
            self.rect_outline.x -= 2
            self.rect_outline.y -= 2
            self.rect_outline.width  += 4
            self.rect_outline.height += 4
    
            self.font = pygame.font.SysFont('comicsans', 60)
            self.text_image = self.font.render(self.text, 1, (0, 0, 0))
            self.text_rect = self.text_image.get_rect(center=self.rect.center)
    
            self.outline = outline
            self.action = action
    
        def draw(self, win):
            # Call this method to draw the button on the screen
            if self.outline:
                pygame.draw.rect(win, self.outline, self.rect_outline, 0)
    
            pygame.draw.rect(win, self.color, self.rect, 0)
    
            if self.text != '':
                win.blit(self.text_image, self.text_rect)
    
        def is_over(self, pos):
            return self.rect.collidepoint(pos)
    
        def rescale(self):
            new_size = int(WINDOW_WIDTH * self.scale_factor)
            x, y = self.rect.center
            self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
            self.rect = self.image.get_rect(center=(x, y))
    
        def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
            self.rect.width = WINDOW_WIDTH
            self.rect.height = WINDOW_HEIGHT
            self.rect.x = x
            self.rect.y = y
    
        def handle_event(self, event):
            if event.type == pygame.MOUSEBUTTONDOWN:
                if self.rect.collidepoint(event.pos):
                    if self.action:
                        self.action() # execute callback fuction
            if event.type == pygame.MOUSEMOTION:
                if self.is_over(event.pos):
                    self.color = self.hover_color
                else:
                    self.color = self.normal_color
    
    
    class Player():
    
        def __init__(self, x, y):
            #self.image = pygame.image.load("RobiS.png")
            self.image = pygame.image.load("Obrazy/images/square-1.png")
            self.rect = self.image.get_rect(x=x, y=y)
            self.player_x_change = 0
            # you need because you use float values to move player but `self.rect` can keep only int values
            self.x = x
            self.y = y
            self.x_change = 0
    
        def draw(self, win):
            self.rect.x = int(self.x)
            self.rect.y = int(self.y)
            win.blit(self.image, self.rect)
    
        def update(self):
            self.x += self.x_change
    
        def handle_event(self, event):
            if event.type == pygame.KEYDOWN: # you can use `elif`
                if event.key == pygame.K_LEFT:
                    print("Left arrow is pressed")
                    self.x_change = -0.3
                elif event.key == pygame.K_RIGHT:
                    self.x_change = 0.3
                    print("Right arrow is pressed")
    
            elif event.type == pygame.KEYUP: # you can use `elif`
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                    self.x_change = 0
                    print("Keystroke has been released")
    
    # --- functions --- (lower_case_names) # PEP8
    
    def redraw_menu_window():
        win.fill((0, 255, 110))
        green_button.draw(win)
        red_button.draw(win)
        cyan_button.draw(win)
    
    def redraw_game_window():
        win.fill((0, 150, 210))
        pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
        player.draw(win)
        back_to_menu_button.draw(win)
    
    def redraw_shop_window():
        win.fill((200, 100, 30))
        back_to_menu_button.draw(win)
    
    def callback_green_button():
        global game_state
    
        print("clicked the button")
        game_state = "game"
    
    def callback_red_button():
        global run
    
        print("clicked the 2button")
        run = False
    
    def callback_cyan_button():
        global game_state
    
        print("clicked the 3button")
        game_state = "shop"
    
    def callback_back_button():
        global game_state
    
        print("back button")
        game_state = "menu"
    
    # --- main ---
    
    pygame.init()
    
    win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
    win.fill((0, 180, 210))
    
    pygame.display.set_caption("Baloon War!")
    #icon = pygame.image.load("Baloon war icon.png")
    icon = pygame.image.load("Obrazy/images/ball.png")
    pygame.display.set_icon(icon)
    
    #centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
    center_point = win.get_rect().center 
    
    player = Player(370, 500)
    
    green_button = Button((0, 255, 0), (105, 105, 105), 275, 285, 250, 80, "Start", (0, 0, 0), callback_green_button)
    red_button = Button((255, 0, 0), (105, 105, 105), 275, 475, 250, 80, "Quit", (0, 0, 0), callback_red_button)
    cyan_button = Button((20, 210, 180), (105, 105, 105), 275, 380, 250, 80, "Shop", (0, 0, 0), callback_cyan_button)
    
    back_to_menu_button = Button((20, 210, 180), (105, 105, 105), 275, 380, 250, 80, "BACK", (0, 0, 0), callback_back_button)
    
    game_state = "menu"
    run = True
    while run:
    
        # --- draws ---
    
        if game_state == "menu":
            redraw_menu_window()
        elif game_state == "game":
            redraw_game_window()
        elif game_state == "shop":
            redraw_shop_window()
    
        pygame.display.update()
    
        # --- events ---
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
            elif event.type == pygame.VIDEORESIZE:
                WINDOW_WIDTH = event.w
                WINDOW_HEIGHT = event.h
                win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
                green_button.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
    
            if game_state == "menu":
                green_button.handle_event(event)
                red_button.handle_event(event)
                cyan_button.handle_event(event)
            elif game_state == "game":
                player.handle_event(event)
                back_to_menu_button.handle_event(event)
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        game_state = "menu"
            elif game_state == "shop":
                back_to_menu_button.handle_event(event)
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        game_state = "menu"
    
        # --- updates ---
    
        if game_state == "menu":
            #green_button.update()
            #red_button.update()
            #cyan_button.update()
            pass
        elif game_state == "game":
            player.update()
        elif game_state == "shop":
            pass
    
    # -- end ---
    pygame.quit()
    quit()