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.
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()