Arrow Key Movement in Pygame - python

I am starting with pygame and can't seem to figure out how to implement continuous movement. This is my current code:
import pygame
pygame.init()
window = pygame.display.set_mode(((500, 500)))
pygame.display.set_caption(("First Game"))
x = 50
y = 50
width = 40
height = 60
vel = 10
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
window.fill((0, 0, 0))
pygame.draw.rect(window, (200, 23, 255), (350, 350, width, height))
pygame.display.update()
pygame.quit()
As I have just started, I can't think of any possible solutions. Would be really nice of you if you can resolve this issue of mine. I know there is going to be some really stupid bug.

You need to draw the rectangle x, y instead of constant 350, 350:
pygame.draw.rect(window, (200, 23, 255), (350, 350, width, height))
pygame.draw.rect(window, (200, 23, 255), (x, y, width, height))
For a smooth movement you need to set vel to 1 and decrease the delay in the application loop.
Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
import pygame
pygame.init()
window = pygame.display.set_mode(((500, 500)))
pygame.display.set_caption(("First Game"))
x, y = 50, 50
width, height = 40, 60
vel = 1
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
window.fill((0, 0, 0))
pygame.draw.rect(window, (200, 23, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()

Draw your rectangle at x and y coordinates as origin.

Related

How can I make directional movement in pygame smooth?

I am making a game in pygame where you are a jellyfish and you can swim around. I've managed to being able to turn and go in the direction the jellyfish is rotated towards. But when I go in that direction the player image is shaking. Can I fix this somehow?
Where self.list[int(self.current)] is the current image of the animation and dt delta time.
if pygame.key.get_pressed()[pygame.K_UP]:
self.rotr = math.radians(self.rot)
self.ysp = math.cos(self.rotr)
self.xsp = math.sin(self.rotr)
self.x -= self.xsp*dt*20
self.y -= self.ysp*dt*20
self.image = pygame.transform.rotate(self.list[int(self.current)], self.rot)
self.rect = self.image.get_rect(center = (x, y))
if pygame.key.get_pressed()[pygame.K_LEFT]:
self.rot += math.pi*dt*7
if pygame.key.get_pressed()[pygame.K_RIGHT]:
self.rot -= math.pi*dt*7
You may have seen tutorials for how to move objects in PyGame, which rely on integer X and Y values. This is not a great way to achieve smooth motion. An example of NOT smooth motion is below - notice how the velocity and position values are integers:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("Moving rectangle")
x = 200 #integer value
y = 200 #integer value
width = 20
height = 20
vel = 10 # integer value
run = True
while run:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
win.fill((0, 0, 0))
#int values are directly used for screen position
pygame.draw.rect(win, (255, 0, 0), (x, y, width, height))
pygame.display.update()
pygame.quit()
This is a simple fix, though:
x = 200.0 #now a float
y = 200.0 #now a float
width = 20
height = 20
vel = 10.0 #now a float
run = True
while run:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
win.fill((0, 0, 0))
#now converting X and Y from floats to integers, rounding first
pygame.draw.rect(win, (255, 0, 0), (int(round(x)), int(round(y)), width, height))
Notice how when we draw the rect, we round the X and Y coordinates. The rounded coordinates are the display coordinates. Your X and Y values that you use internally don't even have to correspond to pixel values 1:1; you're in control of how the conversion from position coordinates to screen coordinates happens. This is just the simplest case.
Even smoother motion can be achieved using acceleration, friction, etc. There are many tutorials on that though.

Move two rects seperately with wasd and arrow keys in pygame?

I am new to programming with pygame and python itself. I was trying to make a simple local multiplayer game using pygame. I wrote my code while watching a tutorial on moving only one rectangle because I did not find anything on what I am trying to do. When I finished, I copied the part of the script with the variables and the movement for the rectangle and then pasted it and changed the variable names so it does not crash or something. Now, here comes my problem: because the movement is simple, it would print a new rectangle, if I press the buttons to move. Because of that, the background is refreshing its color all the time (or something like that) so only the one rectangle I want to move is shown. But if there is a second rect, the color covers it, and only one is visible all the time. How can I fix that?
Here is the code:
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
#variables player 1
X = 200
Y = 200
Width = 40
Height = 60
Vel = 5
#variables player 2
x = 50
y = 50
width = 40
height = 60
vel = 5
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
#player 1
if keys[pygame.K_a]:
X -= Vel
if keys[pygame.K_d]:
X += Vel
if keys[pygame.K_w]:
Y -= Vel
if keys[pygame.K_s]:
Y += Vel
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (X, Y, Width, Height))
pygame.display.update()
#player 2
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
When you call win.fill((0, 0, 0)) the entire display is cleared. You have to draw the rectangles at once after clearing the display.
Update of the display at the end of the application loop. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering (see Why is the PyGame animation is flickering).
Simplify the code and use pygame.Rect objects to represent the players. Use pygame.Rect.clamp_ip to prevent the player from leaving the screen.
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
clock = pygame.time.Clock()
player1 = pygame.Rect(200, 200, 40, 60)
vel1 = 1
player2 = pygame.Rect(50, 40, 40, 60)
vel2 = 1
run = True
while run:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
player1.x += (keys[pygame.K_d] - keys[pygame.K_a]) * vel1
player1.y += (keys[pygame.K_s] - keys[pygame.K_w]) * vel1
player2.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel2
player2.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel2
player1.clamp_ip(win.get_rect())
player2.clamp_ip(win.get_rect())
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), player1)
pygame.draw.rect(win, (255, 255, 255), player2)
pygame.display.update()
pygame.quit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
You are doing win.fill((0, 0, 0)) right after displaying player 1. Remove this code before you display the second character. Also, keep the fill line at the top of your app loop. This would give:
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("local multiplayer")
#variables player 1
X = 200
Y = 200
Width = 40
Height = 60
Vel = 5
#variables player 2
x = 50
y = 50
width = 40
height = 60
vel = 5
run = True
while run:
win.fill((0, 0, 0))
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
#player 1
if keys[pygame.K_a]:
X -= Vel
if keys[pygame.K_d]:
X += Vel
if keys[pygame.K_w]:
Y -= Vel
if keys[pygame.K_s]:
Y += Vel
pygame.draw.rect(win, (255, 255, 255), (X, Y, Width, Height))
#player 2
if keys[pygame.K_LEFT]:
x -= vel
if keys[pygame.K_RIGHT]:
x += vel
if keys[pygame.K_UP]:
y -= vel
if keys[pygame.K_DOWN]:
y += vel
pygame.draw.rect(win, (255, 255, 255), (x, y, width, height))
pygame.display.update()
pygame.quit()
It is also good practice to only update the screen once per loop. Another thing I would do is put the input all in the same if block (but that is not necessary). To further improve your code- consider making a player class that has a render function to display itself, along with an update function to handle control.

How to put an image on this rectangle? [duplicate]

This question already has an answer here:
How can I add an image or icon to a button rectangle in Pygame?
(1 answer)
Closed 1 year ago.
How can I stick an image to a rectangle? I think it has something to do with the blit function. I want to blit the image onto the rectangle on line 50.
import pygame
import sys
pygame.init()
FPS = 60
start_smallfont = pygame.font.SysFont('Corbel', 45)
start_text = start_smallfont.render('Start', True, (255, 255, 255))
rect_smallfont = pygame.font.SysFont('Corbel', 33)
rect_text = rect_smallfont.render('You', True, (255, 255, 255))
x = 375
y = 335
vel = 0.1
startWIDTH, startHEIGHT = 170, 80
screenWIDTH, screenHEIGHT = 800, 720
WIN = pygame.display.set_mode((screenWIDTH, screenHEIGHT))
pygame.display.set_caption(":D")
def main():
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if 800/2-85 <= mouse[0] <= 800/2-85+startWIDTH and 720/2-40 <= mouse[1] <= 720/2-40+startHEIGHT:
clock.tick(FPS)
run = False
while True:
global x, y
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
WIN.fill((0, 0, 0))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel:
x -= vel
if keys[pygame.K_RIGHT] and x < screenWIDTH - 50 - vel:
x += vel
if keys[pygame.K_UP] and y > vel:
y -= vel
if keys[pygame.K_DOWN] and y < screenHEIGHT - 50 - vel:
y += vel
pygame.draw.rect(WIN, (255, 0, 0), (x, y, 50, 50))
pygame.display.update()
mouse = pygame.mouse.get_pos()
if 800/2-85 <= mouse[0] <= 800/2-85+startWIDTH and 720/2-40 <= mouse[1] <= 720/2-40+startHEIGHT:
pygame.draw.rect(WIN, (255, 91, 91), (800/2-85, 720/2-40, startWIDTH, startHEIGHT))
else:
pygame.draw.rect(WIN, (255, 0, 0), (800/2-85, 720/2-40, startWIDTH, startHEIGHT))
WIN.blit(start_text, (800/2-85+42,720/2-40+20))
pygame.display.update()
if __name__ == "__main__":
main()
Any basic tutorial like this one shows how to do it, so it's not clear what you're having trouble with, since you didn't specify what issues you're having. This should work in your code though:
# goes at the top of the script:
image_to_draw = pygame.image.load('something.png')
# to draw the image:
WIN.blit(image_to_draw, (x, y, 50, 50))

PyGame Collisions does only work on one side of the rectangle [duplicate]

This question already has an answer here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I'm just trying something with collisions and found the way to check one side of the rectangle with the other side.
I have the following problem:
If I move my game character (pink box) from the left against the object, my game character just moves through it:
If I come from the other side, everything works and my game character stops.
I mean to say that I need the same code for both sides but have to change the sides from if not player_rect.left == other_rect.right: to if not player_rect.right == other_rect.left:. But this does not work for one side.
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode([1200, 800])
pygame.display.set_caption("Collision Test")
x = 300
y = 300
width = 48
height = 96
velocity = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
is_pressed = pygame.key.get_pressed()
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if is_pressed[pygame.K_d]:
if not player_rect.right == other_rect.left:
x += velocity
if is_pressed[pygame.K_a]:
if not player_rect.left == other_rect.right:
x -= velocity
window.fill((100, 150, 50))
pygame.draw.rect(window, (255, 50, 100), player_rect)
pygame.draw.rect(window, (255, 100, 50), other_rect)
pygame.display.update()
clock.tick(60)
Use collideRect().
Move the object and test if the rectangles are colliding. When a collision is detected, change the position of the object according to the moving direction:
is_pressed = pygame.key.get_pressed()
move_right = is_pressed[pygame.K_d]
move_left = is_pressed[pygame.K_a]
if move_right:
x += velocity
if move_left:
x -= velocity
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if player_rect.colliderect(other_rect):
if move_right:
player_rect.right = other_rect.left
x = player_rect.left
if move_left:
player_rect.left = other_rect.right
x = player_rect.left
For a smooth movement you've to do evaluate pygame.key.get_pressed() in the application loop rather than the event loop.
See also What all things happens inside pygame when I press a key? When to use pygame.event==KEYDOWN.
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode([1200, 800])
pygame.display.set_caption("Collision Test")
x = 300
y = 300
width = 48
height = 96
velocity = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
is_pressed = pygame.key.get_pressed()
move_right = is_pressed[pygame.K_d]
move_left = is_pressed[pygame.K_a]
if move_right:
x += velocity
if move_left:
x -= velocity
player_rect = pygame.Rect(x, y, width, height)
other_rect = pygame.Rect(400, 300, 50, 50)
if player_rect.colliderect(other_rect):
if move_right:
player_rect.right = other_rect.left
x = player_rect.left
if move_left:
player_rect.left = other_rect.right
x = player_rect.left
window.fill((100, 150, 50))
pygame.draw.rect(window, (255, 50, 100), player_rect)
pygame.draw.rect(window, (255, 100, 50), other_rect)
pygame.display.update()
clock.tick(60)

Image rotation not working as expected

I am very new to python/pygame, and would like some help. I am trying to make two cars automatically move forward(which I have completed successfully) however I cannot manage to make the cars turn left/right when a certain key is pressed. I would love someone to help me with this. As I said, I am new to this, so if anyone was kind enough to help, please can you edit my code so it is successful as well as an explanation to what is going wrong, thank you so very much in advance. https://i.stack.imgur.com/zrlUT.png
https://i.stack.imgur.com/q6Hb9.png
https://i.stack.imgur.com/MGR3N.jpg
P.S. There is no error message to my code, as there is no wrong in it, the rotate function is simply not working
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((1150, 800))
pygame.display.set_caption("Car Football")
degrees = 180
x = 70
y = 70
x1 = 1000
y1 = 400
width = 70
height = 70
vel = 15
vel1 = 15
def rotatedleft():
pygame.transform.rotate(redcar, (15))
def rotatedright():
pygame.transform.rotate(redcar, (-15))
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((0, 0, 0))
bgImg = pygame.image.load("Football_pitch.png").convert()
screen.blit(bgImg, [0,0])
redcar = pygame.image.load("redcar.png")
screen.blit(redcar, (x, y))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
rotatedleft = True
if run:
x += vel
if keys[pygame.K_RIGHT]:
rotatedright = True
pygame.display.flip()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if run:
x1 -= vel1
if keys[pygame.K_d] and x1 < 1150:
x1 += vel1
if keys[pygame.K_w]:
y1 -= vel1
if keys[pygame.K_s]:
y1 += vel1
bluecar = pygame.image.load("Bluecarss.png")
screen.blit(bluecar, (x1, y1))
circleball = pygame.draw.circle(screen, (255, 255, 255), (300, 140), 50, 0)
pygame.display.update()
pygame.display.flip()
pygame.quit()
sys.exit()
You need to know trigonometry or vectors if you want to rotate a car in your game and move it in the direction it is facing (I'm using vectors in the following example). The position and the velocity should be vectors and you have to add the vel to the pos vector every frame to move the car forward. You also need a pygame.Rect which is used as the blit position (the rect makes it easier to center the car and can be used for collision detection).
When the user presses ← or →, you have to rotate the angle and the vel vector (vel is also the direction) and then use the angle to rotate the image/pygame.Surface. As for the image rotation, you should keep a reference to the original image in order to preserve the quality of the image. Pass it to pygame.transform.rotate together with the current angle of the car and you'll get a rotated surface. This surface will have different dimensions, so you need to create a new rect (with pygame.Surface.get_rect) to update the blit position (top left coordinates).
import pygame
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((1150, 800))
clock = pygame.time.Clock() # A clock to limit the frame rate.
# Load your images once at the beginning of the program.
REDCAR_ORIGINAL = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(
REDCAR_ORIGINAL, (200, 0, 0), [(0, 0), (50, 10), (50, 20), (0, 30)])
redcar = REDCAR_ORIGINAL
# Use vectors for the position and the velocity.
pos = Vector2(70, 70) # Center position of the car.
vel = Vector2(2, 0)
# This rect serves as the blit position of the redcar image.
rect = redcar.get_rect(center=pos)
angle = 0 # Current angle of the car.
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
# When a key gets pressed, increment the angle, rotate
# the vector and create a new rotated car image.
# The angle is rotated in the opposite direction because
# pygame's y-axis is flipped.
angle += 3
vel.rotate_ip(-3)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, angle)
# Also, get a new rect because the image size was changed.
# Pass the pos vector as the `center` argument to keep the
# image centered.
rect = redcar.get_rect(center=pos)
elif keys[pygame.K_RIGHT]:
angle -= 3
vel.rotate_ip(3)
redcar = pygame.transform.rotate(REDCAR_ORIGINAL, angle)
rect = redcar.get_rect(center=pos)
# Move the car by adding the velocity to the position.
pos += vel
rect.center = pos # Update the rect as well.
screen.fill((30, 30, 30))
screen.blit(redcar, rect) # Blit the car at the `rect.topleft` coords.
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.
pygame.quit()
if keys[pygame.K_LEFT]:
rotatedleft = True
You're assigning True to rotatedleft, which you've previously defined as a function, try calling the function, like so:
if keys[pygame.K_LEFT]:
rotatedleft()
Now it's kinda turning, I'm pretty sure it's still not quite what you're looking for but hey, baby steps. Best of luck with your game.
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((1150, 800))
pygame.display.set_caption("Car Football")
degrees = 180
x = 70
y = 70
x1 = 1000
y1 = 400
width = 70
height = 70
vel = 15
vel1 = 15
run = True
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((0, 0, 0))
bgImg = pygame.image.load("Football_pitch.png").convert()
screen.blit(bgImg, [0,0])
redcar = pygame.image.load("redcar.png")
screen.blit(redcar, (x, y))
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
redcar = pygame.transform.rotate(redcar, 15)
screen.blit(redcar, (x, y))
if run:
x += vel
if keys[pygame.K_RIGHT]:
redcar = pygame.transform.rotate(redcar, -15)
screen.blit(redcar, (x, y))
pygame.display.flip()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if run:
x1 -= vel1
if keys[pygame.K_d] and x1 < 1150:
x1 += vel1
if keys[pygame.K_w]:
y1 -= vel1
if keys[pygame.K_s]:
y1 += vel1
bluecar = pygame.image.load("Bluecarss.png")
screen.blit(bluecar, (x1, y1))
circleball = pygame.draw.circle(screen, (255, 255, 255), (300, 140), 50, 0)
pygame.display.update()
pygame.display.flip()
pygame.quit()
sys.exit()

Categories