Why won't my Movement code work? - python

I am trying to make a character move around.
My problem is that when I run the program it immediately stops responding so I don't even know what the problem is.
Here is my code.
import pygame, sys
from pygame.locals import*
pygame.init()
DISPLAYSURF = pygame.display.set_mode((780, 500), 0, 32)
FPS = 30
fpsClock = pygame.time.Clock()
sprite = pygame.image.load('CharacterFront.png')
spritex = 50
spritey = 50
charLeft = False
charRight = False
charUp = False
charDown = False
while True:
DISPLAYSURF.blit(sprite,(spritex,spritey))
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if (event.key == K_LEFT):
charLeft = True
elif (event.key == K_d):
charRight = True
elif (event.key == K_w):
charUp = True
elif (event.key == K_s):
charDown = True
if event.type == KEYUP:
if (event.key == K_LEFT):
charLeft = False
elif (event.key == K_d):
charRight = False
elif (event.key == K_w):
charUp = False
elif (event.key == K_s):
charDown = False
while charLeft == True:
spritex -= 10
sprite=pygame.image.load('CharacterLeft.png')
while charRight == True:
spritex += 10
sprite=pygame.image.load('CharacterRight.png')
while charUp == True:
spritey -= 10
sprite=pygame.image.load('CharacterBack.png')
while charDown == True:
spritey += 10
sprite=pygame.image.load('CharacterFront.png')
pygame.display.update()
fpsClock.tick(FPS)
I have already tried many different ways to do this but the closest I got caused the character to get pasted over and over and I had to spam the directions to actually move more than 10 pixels.

Your while char.. loops never end. You are already looping (while True: at the top). Just make one move (e.g. spritey -= 10) and allow the outer loop to keep running.
For ideas on how to keep your character moving while a key is held, see this question.

Apart from what jonrsharpe said, you should not load the sprite every time a keypress is done.
Instead load all your images before, and just blit them when necessary.
So your code will look like this:
sprite_back = pygame.image.load('CharacterBack.png')
sprite_front = pygame.image.load('CharacterFront.png')
sprite_right = pygame.image.load('CharacterRight.png')
sprite_left = pygame.image.load('CharacterLeft.png')
sprite = sprite_front
while True:
DISPLAYSURF.blit(sprite,(spritex,spritey))
if charLeft == True:
spritex -= 10
elif charRight == True:
spritex += 10
elif charUp == True:
spritey -= 10
elif charDown == True:
spritey += 10
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if (event.key == K_LEFT):
charLeft = True
sprite=sprite_left
elif (event.key == K_d):
charRight = True
sprite=sprite_right
elif (event.key == K_w):
charUp = True
sprite=sprite_back
elif (event.key == K_s):
charDown = True
sprite=sprite_front
if event.type == KEYUP:
if (event.key == K_LEFT):
charLeft = False
elif (event.key == K_d):
charRight = False
elif (event.key == K_w):
charUp = False
elif (event.key == K_s):
charDown = False

Related

How do I fix diagonal movement?

I have been learning pygame from a youtuber called dafluffypotatoe and I have written my own code for player movement I was wondeirng if it would be possible to fix the diagonal movement? Because it goes twice as fast when I go diagonal.
also I am new to stack over flow.
Here is my paste bin for the code I used
import pygame, sys
from pygame.locals import *
# init pygame
pygame.init()
# clock
clock = pygame.time.Clock()
WINDOW_SIZE = 1024, 512
# screen and display
screen = pygame.display.set_mode(WINDOW_SIZE)
display = pygame.Surface((512, 256))
FPS = 60
moving_left = False
moving_right = False
moving_up = False
moving_down = False
player_x_loc = 50
player_y_loc = 50
def load_map(path):
f = open(path + '.txt', 'r')
data = f.read()
f.close()
data = data.split('\n')
game_map = []
for row in data:
game_map.append(list(row))
return game_map
game_map = load_map('map')
# player
player_img = pygame.image.load('player.png')
# blocks
block_basic = pygame.image.load('blocck.png')
# game loop
while True:
# colour screen
display.fill((33, 15, 15))
# load tiles
tile_rects = []
y = 0
for row in game_map:
x = 0
for tile in row:
if tile == '1':
display.blit(block_basic, (x * 32, y * 32))
if tile == '0':
tile_rects.append(pygame.Rect(x * 32, y * 32, 32, 32))
x += 1
y += 1
# basic speed x
if moving_left == True:
player_x_loc -= 4
if moving_right == True:
player_x_loc += 4
else:
player_x_loc == 0
# basic speed y
if moving_up == True:
player_y_loc -= 4
if moving_down == True:
player_y_loc += 4
else:
player_y_loc == 0
display.blit(player_img, (player_x_loc, player_y_loc))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# keydown
if event.type == KEYDOWN:
if event.key == K_a:
moving_left = True
if event.key == K_d:
moving_right = True
if event.key == K_w:
moving_up = True
if event.key == K_s:
moving_down = True
# keyup
if event.type == KEYUP:
if event.key == K_a:
moving_left = False
if event.key == K_d:
moving_right = False
if event.key == K_w:
moving_up = False
if event.key == K_s:
moving_down = False
screen.blit(pygame.transform.scale(display, WINDOW_SIZE), (0, 0))
pygame.display.update()
clock.tick(FPS)
You must move the player with a normalized directional vector and a constant speed. The simplest method is to use pygame.math.Vector2.scale_to_length:
while True:
# [...]
move_vec = pygame.math.Vector2(
moving_right - moving_left,
moving_down - moving_up)
if move_vec.x != 0 or move_vec.y != 0:
move_vec.scale_to_length(4)
player_x_loc += move_vec.x
player_y_loc += move_vec.y
# [...]

How can I apply a limit on input(not more than 20 letters) and the input value can be just alphabet? [duplicate]

This question already has answers here:
How can I check if character in a string is a letter? (Python)
(6 answers)
Closed 2 years ago.
def save_load_page():
bg = pygame.image.load(resource_path("./Game_Assets/Backgrounds/menu_background.png"))
bg = pygame.transform.scale(bg,(900,600))
ogre_set = pygame.image.load(resource_path("./Game_Assets/Character_Name/Ogre_Character_Overview.png"))
ogre_set = pygame.transform.scale(ogre_set,(844,420))
name_input = ''
change_click = False
click = False
while True:
mx, my = pygame.mouse.get_pos()
screen.blit(bg,(0,0))
screen.blit(ogre_set,(22,140))
text_surface = base_font.render(name_input,True,(255,255,255))
screen.blit(text_surface,(60, 445))
# Logic goes here
change_click = False
click = False
# Event Collections
for event in pygame.event.get():
# Function to quit game
'''if event.type == QUIT:
event.quit()
sys.exit()'''
if event.type == KEYDOWN:
if event.key == K_RETURN:
pass
elif event.key == K_KP_ENTER:
ogre1_name = name_input
break
elif event.unicode == K_alpha:
name_input += event.Ascii
if len(name_input) <= 21:
pass
while name == '' or len(name) > 20 or name in names_list:
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
change_click = True
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
click = True
pygame.display.update()
clock.tick(120)
You have to evaluate if the length of the text is less than 20, before you add the new character. isalpha() can be used to test whether a character is a letter (see How can I check if character in a string is a letter?):
if event.type == KEYDOWN:
if event.key == K_RETURN:
# [...]
elif event.key == K_KP_ENTER:
# [...]
elif len(name_input) < 20 and event.unicode.isalpha():
name_input += event.unicode

"if cond1 or cond2" statement not running second condition in Python

I am making a game in Python that looks like this so far:
import pygame, sys, time, random, threading
from threading import Timer
from pygame.locals import *
pygame.init()
WINDOWHEIGHT = 720
WINDOWWIDTH = 1280
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Hitman Grandma')
plorp = 'true'
white = (255,255,255)
red = (255,0,0)
black = (0,0,0)
green = (0,255,0)
blue = (0,0,255)
cyan = (0,255,255)
windowSurface.fill(white)
pygame.display.update()
mainClock = pygame.time.Clock()
hgleft = False
hgright = False
hgup = False
speed = 4
hgair = True
hgjumpallowed = False
level = 0
def stop() :
hgbox.move_ip(0,0)
return
hgbox = pygame.Rect(0 ,13 ,36 ,72)
hitmangrandma = pygame.image.load('hgrd1copy.jpg')
hg = pygame.transform.scale(hitmangrandma, (36,72))
landbox1 = pygame.Rect(0,400,200,50)
li = pygame.image.load('hgland1.png')
land1 = pygame.transform.scale(li,(200,50))
landbox2 = pygame.Rect(230,400,200,50)
land2 = pygame.transform.scale(li,(200,50))
land = landbox1,landbox2
while True:
windowSurface.fill(white)
windowSurface.blit(land1,landbox1)
windowSurface.blit(land2,landbox2)
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_LEFT or event.key == K_a:
hgright = False
hgleft = True
if event.key == K_RIGHT or event.key == K_d:
hgleft = False
hgright = True
if event.key == K_UP or event.key == K_w:
hgair = True
hgup = True
hgupkey = True
if event.type == KEYUP:
if event.key == K_ESCAPE or K_q and pygame.key.get_mods() & pygame.KMOD_CTRL:
pygame.quit()
sys.exit()
exit
if event.key == K_LEFT or K_a:
hgleft = False
if event.key == K_RIGHT or K_d:
hgright = False
if hgup and hgbox.top > 0 and hgupkey == True and hgair == True and hgjumpallowed == True:
hgbox.top -= 100
hgair = True
if hgleft and hgbox.left > 0:
hgbox.left -= speed
if hgright and hgbox.right < WINDOWWIDTH:
hgbox.right += speed
if not hgbox.colliderect(landbox1) or not hgbox.colliderect(landbox2) and hgair == True:
hgair = False
hgbox.top += speed
hgjumpallowed = False
if hgbox.colliderect(landbox1) or hgbox.colliderect(landbox2):
hgjumpallowed = True
stop()
windowSurface.blit(hg, hgbox)
pygame.display.update()
mainClock.tick(40)
However, when I run my script, hgbox doesn't detect collision with landbox2, and just keeps falling. I think this problem is due to it only running the first part of the if statement, and not checking the other parts. What should I do to make it detect other parts of the if statement?
With an mcve I meant something like this (a minimal but complete example that we can copy, paste and run):
import sys
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
def stop() :
hgbox.move_ip(0, 0)
hgbox = pygame.Rect(0 ,13 ,36 ,72)
landbox1 = pygame.Rect(0,400,200,50)
landbox2 = pygame.Rect(230,400,200,50)
hgair = True
hgjumpallowed = False
hgup = False
hgupkey = False
speed = 9
clock = pygame.time.Clock()
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
hgup = True
hgbox.x += 50
hgbox.y -= 90
if hgup and hgbox.top > 0 and hgupkey == True and hgair == True and hgjumpallowed == True:
hgbox.top -= 100
hgair = True
if not hgbox.colliderect(landbox1) or not hgbox.colliderect(landbox2) and hgair == True:
hgair = False
hgbox.top += speed
hgjumpallowed = False
if hgbox.colliderect(landbox1) or hgbox.colliderect(landbox2):
hgjumpallowed = True
stop()
screen.fill(pygame.Color('gray12'))
pygame.draw.rect(screen, (120, 70, 70), landbox1)
pygame.draw.rect(screen, (120, 70, 70), landbox2)
pygame.draw.rect(screen, (50, 70, 170), hgbox)
pygame.display.flip()
clock.tick(30)
pygame.quit()
sys.exit()
The problem is caused by this line:
if not hgbox.colliderect(landbox1) or not hgbox.colliderect(landbox2) and hgair == True:
It's evaluated as
if (not hgbox.colliderect(landbox1)) or (not hgbox.colliderect(landbox2) and hgair == True):
The second part would be always False in the example above. The hgbox always falls unless the first part of the condition is False as well (not hgbox.colliderect(landbox1)), that means it can only stand on the left platform.
Try to change it to:
if not hgbox.colliderect(landbox1) and not hgbox.colliderect(landbox2):
# Move downwards.
Edit: Here's a complete example to show you how I would write the movement and jump code. Use x_speed and y_speed to move the player every frame (also accelerate the y_speed) and in the event loop just set the speeds to the desired values. If the player touches a platform set him to the .top of the platform rect and hgjumpallowed to True.
import pygame, sys
from pygame.locals import *
from pygame.color import THECOLORS
pygame.init()
windowSurface = pygame.display.set_mode((1280, 720), 0, 32)
pygame.display.update()
mainClock = pygame.time.Clock()
hitmangrandma = pygame.Surface((36, 72))
hitmangrandma.fill((250, 160, 50))
hgbox = hitmangrandma.get_rect(topleft=(10, 10))
y_speed = 0
x_speed = 0
hgjumpallowed = False
land_img = pygame.Surface((200, 50))
land_img.fill((50, 100, 250))
land = pygame.Rect(0,400,200,50), pygame.Rect(230,400,200,50)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT: # Quit game by pressing on the "x" button.
done = True
if event.type == KEYDOWN:
if event.key in (K_LEFT, K_a):
# Just set the x_speed and then move
# the rect in the while loop each frame.
x_speed = -4
if event.key in (K_RIGHT, K_d):
x_speed = 4
if (event.key == K_UP or event.key == K_w) and hgjumpallowed:
y_speed = -17
hgjumpallowed = False
if event.type == KEYUP:
if event.key == K_ESCAPE or K_q and pygame.key.get_mods() & pygame.KMOD_CTRL:
done = True
if event.key in (K_LEFT, K_a):
x_speed = 0
if event.key in (K_RIGHT, K_d):
x_speed = 0
y_speed += 1 # Accelerate downwards.
# Move the player.
hgbox.x += x_speed
hgbox.y += y_speed
# Check if player is on ground and can jump.
hgjumpallowed = False
for box in land:
if hgbox.colliderect(box): # If player touches ground.
hgjumpallowed = True
hgbox.bottom = box.top
y_speed = 0
windowSurface.fill(THECOLORS['white'])
for box in land:
windowSurface.blit(land_img, box)
windowSurface.blit(hitmangrandma, hgbox)
pygame.display.update()
mainClock.tick(40)
pygame.quit()
sys.exit()
There also was a mistake in the event loop: event.key == K_RIGHT or K_d is always True, because it's evaluated as (event.key == K_RIGHT) or (K_d) and K_d is a truthy value.
To ensure that Python evaluates the logical operators in the right order, add ().
if (not hgbox.colliderect(landbox1) or not hgbox.colliderect(landbox2)) and hgair == True:
This evaluates to True when there is no collision with either landbox1 or with landbox2, and when hgair == True.

Pygame sprite jump with pressed key

I'm currently making a 2D platformer, I want the player sprite to jump when it touches the ground and the jump key is being pressed.
I had this at the begging, seeing it wasn't doing what I wanted, I wrote a new code using boolean values.
Original code:
if not (event == None):
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_UP or event.key == pygame.K_SPACE):
if (self.vspeed == 0):
self.vspeed = -(self.speed)*2
New code:
if not (event == None):
if(event.type == pygame.KEYDOWN):
if (event.key == pygame.K_UP or event.key == pygame.K_SPACE):
jump_pressed = True
elif (event.type == pygame.KEYUP):
if (event.key == pygame.K_UP or event.key == pygame.K_SPACE):
jump_pressed = False
elif (jump_pressed == True and self.vspeed == 0):
self.vspeed = -(self.speed)*2
print("jump is pressed")
Sadly, the new code doesn't work and I don't understand why. I did alot of research and tests over the past week without any success. The player jumps when I press the key but it doesn't jump again when it touches the ground.
I need to release the key and press it again to make the player jump. "jump is pressed" only gets printed when I press down.
Looking forward to your help :)
Your code correctly sets the jump_pressed variable here:
if not (event == None):
if(event.type == pygame.KEYDOWN):
if (event.key == pygame.K_UP or event.key == pygame.K_SPACE):
jump_pressed = True
elif (event.type == pygame.KEYUP):
if (event.key == pygame.K_UP or event.key == pygame.K_SPACE):
jump_pressed = False
However, this case
elif (jump_pressed == True and self.vspeed == 0):
self.vspeed = -(self.speed)*2
print("jump is pressed")
is (almost) never true: the only way it can enter in that condition is that
event is not None.
event.type is neither KEYDOWN nor `KEYUP
jump_pressed is True and self.vspeed is 0.
You have to change the structure into
if event is not None:
if event.type == pygame.KEYDOWN:
if event.key in [pygame.K_UP, pygame.K_SPACE]:
jump_pressed = True
elif event.type == pygame.KEYUP:
if event.key in [pygame.K_UP, pygame.K_SPACE]:
jump_pressed = False
if jump_pressed and self.vspeed == 0:
self.vspeed = -(self.speed)*2
print("jump is pressed")
So that the jump_pressed check is performed even when no events are triggered.
problem can be because you have last elif inside for event loop.
You need something like this:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key in (pygame.K_UP, pygame.K_SPACE):
jump_pressed = True
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_UP, pygame.K_SPACE):
jump_pressed = False
# after `for` loop
if jump_pressed and self.vspeed == 0:
self.vspeed = -(self.speed)*2
print("jump is pressed")

My sprite wont move right pygame

earlier my sprite wouldn't move at all so i posted the code and i got it fixed for the most part but now my up/down arrows work fine but my right key doesn't work. (Also, when you press two keys, and then let go of one, the walk animation doesn't work, but I'm not desperate right now to get that fixed.) Also i would prefer not to use user made classes. thanks in advance.
Here is the code:
from pygame.locals import *
import pygame._view
pygame.init()
clock = pygame.time.Clock()
height = 500
width = 500
screen = pygame.display.set_mode((width, height), 0, 32)
pygame.display.set_caption('placeholder text')
photo = 'grassbackground.png'
background = pygame.image.load(photo).convert()
rectexist = False
photo1 = 1
user = pygame.sprite.Sprite()
change = False
up = False
down = False
left = False
right = False
speed = 5
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_UP:
up = True
change = True
if event.key == K_DOWN:
down = True
change = True
if event.key == K_LEFT:
left = True
change = True
if event.type == K_RIGHT:
right = True
change = True
if event.type == KEYUP:
if event.key == K_UP:
up = False
change = False
if event.key == K_DOWN:
down = False
change = False
if event.key == K_LEFT:
left = False
change = False
if event.key == K_RIGHT:
right = False
change = False
if down and user.rect.bottom < height:
user.rect.top += speed
if up and user.rect.top > 0:
user.rect.top -= speed
if left and user.rect.left > 0:
user.rect.left -= speed
if right and user.rect.right < width:
user.rect.right += speed
if change == True:
pygame.time.wait(110)
photo1 += 1
if change == False:
photo1 = 1
if photo1 == 1:
user.image = pygame.image.load("1.png").convert()
if rectexist == False:
user.rect = user.image.get_rect()
rectexist = True
screen.blit(user.image, user.rect)
if photo1 == 2:
user.image = pygame.image.load("2.png").convert()
screen.blit(user.image, user.rect)
if photo1 == 3:
user.image = pygame.image.load("3.png").convert()
screen.blit(user.image, user.rect)
if photo1 >= 4:
photo1 = 1
thesprites = pygame.sprite.RenderPlain((user))
thesprites.update()
screen.blit(background, (0, 0))
thesprites.draw(screen)
pygame.display.update()
clock.tick(60)
In your code it says:
if event.type == K_RIGHT:
it should be:
if event.key == K_RIGHT:
To keep animating you'd need to change the code a little more, add a:
key_pressed = []
in the beginning. Then for each key-press block do:
key_pressed.append(event.key)
and key-release do:
key_pressed = [k for k in key_pressed if k != event.key]
instead of the change=True and change=False respectively. Then after the two segments of checking what was pressed and released have add these lines:
if len(key_pressed) > 0:
change = True
else:
change = False
That should fix most of your issues...
Use pressed = pygame.key.get_pressed() to get a dictionary (a tuple, actually, but the way things are structured you can think of it as a dictionary) of all keys that are currently pressed. You'd use it like this:
pressed = pygame.key.get_pressed()
if pressed[K_LEFT]:
# move left
elif pressed[K_RIGHT]:
# move right
# etc

Categories