Moving a sprite using event commands - python

I'm trying to blit an image as a background, and then have a sprite moving in all directions and rotate. So far, I have the following:
import pygame, sys
from pygame.locals import *
BGimageName = 'joker.jpg'
FGimageName = 'bmanicon.tga'
pygame.init()
DisWidth = 900
DisHeight = 600
x = -500
y = -300
spriteROT = 1.0
SPHpos = (DisWidth//2, DisHeight//2)
DISPLAYSURF = pygame.display.set_mode((DisWidth, DisHeight), 0, 32)
BGimage = pygame.image.load(BGimageName).convert()
FGimage = pygame.image.load(FGimageName).convert_alpha()
def main():
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
move_x = -1
elif event.key == K_RIGHT:
move_x = +1
elif event.key == K_UP:
move_y = -1
elif event.key == K_DOWN:
move_y = +1
elif event.key == K_r:
rotationDIR = + 1.0
elif event.key == K_w:
rotationDIR = - 1.0
elif event.type == KEYUP:
if event.key == K_LEFT:
move_x = 0
elif event.key == K_RIGHT:
move_x = 0
elif event.key == K_UP:
move_y = 0
elif event.key == K_DOWN:
move_y = 0
elif event.key == K_r:
rotationDIR = 0
elif event.key == K_w:
rotationDIR = 0
DISPLAYSURF.blit(BGimage, (x, y))
RotSPH = pygame.transform.rotate(FGimage, spriteROT)
w, h = RotSPH.get_size()
spriteDrawPos = (SPHpos[0] - w // 2, SPHpos[1] - h // 2)
DISPLAYSURF.blit(RotSPH, spriteDrawPos)
pygame.display.update()
main()
This is all pretty new to me. Most of it was provided by our professor, and we then had to figure out the rest and personalize it. Unfortunately I wasn't present the day of class where we discussed events, so I don't really understand them. I think that I currently have everything working because the background and the sprite both display, but the sprite doesn't move when I press any buttons. How can I get Python to recognize that I want the sprite to move?
I tried to put FGimage.move_x and such in the event keys, i.e.
if event.key == K_LEFT:
FGimage.move_x = -1
but that doesn't work, giving me the error
Attribute Error: 'pygame.Surface' object has no attribute 'move_x'
I think I'm close, but I'm still missing the last step.

The reason why you are not moving the sprite is because you are not changing any variables with the events.
Specifically the location variable spriteDrawPos is not changing because the line spriteDrawPos = (SPHpos[0] - w // 2, SPHpos[1] - h // 2) which modifies it is not changing because SPHpos is never going to change because spriteROT never changes.
To fix this modify the code to work with the variables you changed in the event.
spriteROT += rotationDIR
RotSPH = pygame.transform.rotate(FGimage, spriteROT)
w, h = RotSPH.get_size()
spriteDrawPos = (SPHpos[0] - w // 2 + move_x, SPHpos[1] - h // 2 + move_y)
DISPLAYSURF.blit(RotSPH, spriteDrawPos)
This will hopefully allow your sprite to move, but probably too fast.

Related

Adding boundaries in Pygame with movable characters/images

I have been creating a game where an image moves according to player input with Keydown and Keyup methods. I want to add boundaries so that the user cannot move the image/character out of the display (I dont want a game over kind of thing if boundary is hit, just that the image/character wont be able to move past that boundary)
import pygame
pygame.init()#initiate pygame
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
display_width = 1200
display_height = 800
display = pygame.display.set_mode((display_width,display_height))
characterimg_left = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/characterimg_left.png')
characterimg_right = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/characterimg_right.png')
characterimg = characterimg_left
def soldier(x,y):
display.blit(characterimg, (x,y))
x = (display_width * 0.30)
y = (display_height * 0.2)
pygame.display.set_caption('No U')
clock = pygame.time.Clock()#game clock
flip_right = False
x_change = 0
y_change = 0
bg_x = 0
start = True
bg = pygame.image.load(r'/Users/ye57324/Desktop/Make/coding/python/bg.png').convert()
class player:
def __init__(self, x, y):
self.jumping = False
p = player(x, y)
while start:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
start = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change += -4
if flip_right == True:
characterimg = characterimg_left
flip_right = False
x += -150
elif event.key == pygame.K_RIGHT:
x_change += 4
if flip_right == False:
characterimg = characterimg_right
flip_right = True
x += 150
elif event.key == pygame.K_UP:
y_change += -4
elif event.key == pygame.K_DOWN:
y_change += 4
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change += 4
elif event.key == pygame.K_RIGHT:
x_change += -4
elif event.key == pygame.K_UP:
y_change += 4
elif event.key == pygame.K_DOWN:
y_change += -4
x += x_change
y += y_change
display.fill(white)
soldier(x,y)
pygame.display.update()
clock.tick(120)#fps
pygame.quit()
I have tried several times including switching to the key pressed method but they all failed. Help please, thank you.
Basically you want to limit the player's movement.
So everytime you want to "move" the player (I'm guessing this is "x_change" / "y_change") you need to check whether they would still be inside your boundaries after the move.
Example: Your display x boundary is 0 pixels on the left of your screen and 500 to the right. I only allow the actual movement if the result of the movement is within my boundaries.
boundary_x_lower = 0
boundary_x_upper = 500
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if boundary_x_lower < (x_change - 4):
# I allow the movement if I'm still above the lower boundary after the move.
x_change -= 4
elif event.key == pygame.K_RIGHT:
if boundary_x_upper > (x_change +4):
# I allow the movement if I'm still below the upper boundary after the move.
x_change += 4
PS: I am confused by your code as you subtract when you move to the right... I am used to 2D games where you increment the player's position if you move to the right... and subtract if you go to the left.
Feel free to adapt the code to fit your project. The basic principle applies also to the y-axis movement: with boundary_y_lower & _y_upper. if you have further questions, just ask!
Just clamp the x and y values between 0 and the display width and height.
# In the main while loop after the movement.
if x < 0:
x = 0
elif x + image_width > display_width:
x = display_width - image_width
if y < 0:
y = 0
elif y + image_height > display_height:
y = display_height - image_height
I also recommend checking out how pygame.Rects work. You could define a rect with the size of the display,
display_rect = display.get_rect()
and a rect for the character which will be used as the blit position:
rect = characterimg_left.get_rect(center=(x, y))
Then move and clamp the rect in this way:
rect.move_ip((x_change, y_change))
rect.clamp_ip(display_rect)
display.fill(white)
# Blit the image at the `rect.topleft` coordinates.
display.blit(characterimg, rect)

Player movement stops when direction reverses in Pygame

I am messing around with pygame and I am eventually working towards a pong clone. I implemented player movement with the arrow keys and when ever I switch from going up to immediately going down, my player freezes and won't move again until I press that direction key again. Here is my code:
import sys, pygame
pygame.init()
display_width = 640
display_height = 480
display = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("Test Game")
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
running = True
class Player:
def __init__(self,x,y,hspd,vspd,color,screen):
self.x = x
self.y = y
self.hspd = hspd
self.vspd = vspd
self.color = color
self.screen = screen
def draw(self):
pygame.draw.rect(self.screen,self.color,(self.x,self.y,32,32))
def move(self):
self.x += self.hspd
self.y += self.vspd
player = Player(0,0,0,0,black,display)
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
player.hspd = 0
if event.key == pygame.K_LEFT:
player.hspd = 0
if event.key == pygame.K_UP:
player.vspd = 0
if event.key == pygame.K_DOWN:
player.vspd = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.hspd = 4
if event.key == pygame.K_LEFT:
player.hspd = -4
if event.key == pygame.K_UP:
player.vspd = -4
if event.key == pygame.K_DOWN:
player.vspd = 4
#Clear the screen
display.fill(white)
#Move objects
player.move()
#Draw objects
player.draw()
#Update the screen
pygame.display.flip()
print "I made it!"
pygame.quit()
sys.exit()
I suggest you work with key.get_pressed() to check for the current set of pressed keys.
In your scenario - when you press down and release up (in that order) - the speed is set to 0, so you need to inspect the keys pressed not just by the current event.
Here is a working version of the relevant part:
def current_speed():
# uses the fact that true = 1 and false = 0
currently_pressed = pygame.key.get_pressed()
hdir = currently_pressed[pygame.K_RIGHT] - currently_pressed[pygame.K_LEFT]
vdir = currently_pressed[pygame.K_DOWN] - currently_pressed[pygame.K_UP]
return hdir * 4, vdir * 4
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
player.hspd, player.vspd = current_speed()
#Clear the screen
display.fill(white)
#Move objects
player.move()
#Draw objects
player.draw()
#Update the screen
pygame.display.flip()
To expand on LPK's answer, your key down (for event.key == pygame.K_DOWN) is likely being processed before your key up (from event.key == pygame.K_UP) is processed. So while both are down (and you can confirm this), you may experience movement, until you release the up key.
your problem is here:
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
player.hspd = 0
if event.key == pygame.K_LEFT:
player.hspd = 0
if event.key == pygame.K_UP:
player.vspd = 0
if event.key == pygame.K_DOWN:
player.vspd = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.hspd = 4
if event.key == pygame.K_LEFT:
player.hspd = -4
if event.key == pygame.K_UP:
player.vspd = -4
if event.key == pygame.K_DOWN:
player.vspd = 4
I am guessing that your key event down is still consumed when u switch the keys immediately, meaning no other key down event is getting triggered as long as the first event didn't fire its key up event yet.
EDIT: maybe its better to check if the player is moving and if so just reverse speed . Then you would only need to check the down event.
Otherwise your event will be consumed and not checked properly.
For your method you would need to store the occurred key events since the last frame and check that list.

Detecting whether the player has collided w/ the bottom of an object (rectangles)

I'm trying to create a bird's-eye-view game (e.g. hotline miami) in pygame. I've gotten stuck at the collision detection. I'm trying to to see if the player hits a block on the left, right, in front or behind . I've gotten only to doing the 'in front' collision but that doesn't work; the player will hit the block 'head first', stop, but is then able to move through the block if he spams the arrow key. I know what the problem is (in the if else statement in the collision detection) but I can't for the life of me find the solution. Everything I tried doesn't seem to work. Help! Any help would be greatly appreciated, thanks in advance! (btw this is my first time on stack overflow, so sorry if I'm not asking the question well) (I removed some of the unnecessary code like the pygame.init() and variables)
def drawBlock(block_width,block_height,x,y):
pygame.draw.rect(gameDisplay, red, [x,y,block_width,block_height])
def gameLoop(x,y):
while not gameExit:
level = ["W","W","W","W","W","W","W","W","W","W","W","W",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","P","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","P","N","N","L",
"N","N","N","N","P","N","N","N","N","N","N","N","L",
"N","N","N","N","N","N","N","N","N","N","N","N","L","S"]
#EVENT HANDLING
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if canMoveUp:
if event.key == pygame.K_UP:
y_change = -player_movement
if canMoveDown:
if event.key == pygame.K_DOWN:
y_change = player_movement
if event.key == pygame.K_LEFT:
x_change = -player_movement
if event.key == pygame.K_RIGHT:
x_change = player_movement
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y_change = 0
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
pX += x_change
pY += y_change
gameDisplay.fill(black)
#CALCULATING THE SIZE OF THE BLOCKS SO THEY FIT W/ A VARIETY OF RESOLUTIONS
if calculateBlockX:
for element in level:
if element == "W":
W_count += 1
if element == "S":
block_width = (display_width/W_count)
calculateBlockX = False
if calculateBlockY:
for element in level:
if element == "L":
L_count += 1
if element == "S":
block_height = (display_height/L_count)
calculateBlockY = False
#COUNTING HOW MANY BLOCKS THERE ARE IN THE LEVEL ARRAY (P)
if P_countFunction:
for element in level:
if element == "P":
P_count += 1
if element == "S":
print(P_count)
P_countFunction = False
#ALL THE X AND Ys OF ALL THE BLOCKS IN THE LEVEL, AND ACTUALLY DRAWING THEM
blockXY = []
for element in level:
if element == "N":
x += block_width
if element == "L":
y += block_height
x = 0
if element == "P":
drawBlock(block_width,block_height,x,y)
blockXY.append(x)
blockXY.append(y)
if appendBlockXY:
if len(collisionArray) > P_count:
del(collisionArray[P_count])
print(collisionArray)
appendBlockXY = False
collisionArray.append(blockXY)
blockXY = []
x += block_width
if element == "S":
y = 0
#COLLISION DETECTION
for XnY in collisionArray:
if pX >= XnY[0] and pX <= XnY[0] + block_width and pY + playerSize <= XnY[1] or pX + playerSize >= XnY[0] and pX <= XnY[0] + block_width:
if pY - block_height == XnY[1]:
canMoveUp = False
y_change = 0
if pY - block_height != XnY[1]:
canMoveUp = True
else:
if pY - block_height >= XnY[1]:
canMoveUp = True
#gameDisplay.blit(img,[pX,pY])
pygame.draw.rect(gameDisplay, green, [pX,pY,playerSize,playerSize])
clock.tick(60)
pygame.display.update()
pygame.quit()
quit()
gameLoop(x,y)
pygame.display.update()
Your collision detection is written in a way that allows the last iteration to override all earlier checks. Instead of that, have canMoveUp set to True before the loop, and the loop should only set it to False or leave it alone.

How would I make a car move the direction it's pointing (After use of pygame.translation.rotate)

Okay so I'm making a test for making a racing game...
And I want the car to move in the direction it's pointing.
Here is my code.
import pygame, sys
from pygame.locals import *
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
while True:
rect2 = pygame.rect = (100,100,50,50)
if right == True:
degree -= 2
if left == True:
degree += 2
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('a'):
left = True
if event.key == ord('d'):
right = True
if event.type == KEYUP:
if event.key == ord('a'):
left = False
if event.key == ord('d'):
right = False
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
screen.blit(thing2,(100,100))
pygame.display.update()
mainClock.tick(60)
So like I said I want to know how to move the car in the direction it's pointing.
I tried to think of a way but I couldn't think of anything. So there isn't really anything to correct.
(If there are any questions I'll edit my question to answer it.) Please make sure you know pygame before answering.
You'll want to use trigonometry to calculate how much you want to move in the x and y directions, so that the car ends up moving in the correct direction. To calculate this, you can do this:
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
position = (position[0] + dx * SPEED, position[1] - dy * SPEED)
Note that you'll also need to initialize a position variable somewhere at the start of your code like this:
position = (100, 100)
Then, you have to change the blit line of code so you draw at the position variable, instead of at (100, 100) all of the time:
screen.blit(thing2, position)
Edit: Working example
import pygame, sys
from pygame.locals import *
import math
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
position = (100, 100)
while True:
rect2 = pygame.rect = (100,100,50,50)
if right == True:
degree -= 2
if left == True:
degree += 2
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('a'):
left = True
if event.key == ord('d'):
right = True
if event.type == KEYUP:
if event.key == ord('a'):
left = False
if event.key == ord('d'):
right = False
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
position = (position[0] + dx, position[1] - dy)
screen.blit(thing2, position)
pygame.display.update()
mainClock.tick(60)
Working example to kabb answer
import pygame, sys
from pygame.locals import *
import math # math library
pygame.init()
mainClock = pygame.time.Clock()
degree = 0
WHITE = 250,250,250
rect2 = pygame.rect = (100,100,50,50)
WINDOWWIDTH = 1200
WINDOWHEIGHT = 750
thing = pygame.image.load('car.png')
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Teh test')
left = False
right = False
forward = False
backward = False
thing2_x = 100
thing2_y = 100
speed = 20
while True:
rect2 = pygame.rect = (100,100,50,50)
if right: # don't need == True
degree -= 2
while degree < 0:
degree += 360
elif left: # don't need == True
degree += 2
while degree > 359:
degree -= 360
dx = math.cos(math.radians(degree))
dy = math.sin(math.radians(degree))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == K_a: # use constants K_a
left = True
elif event.key == K_d: # use constants K_d
right = True
elif event.key == K_w: # use constants K_w
forward = True
elif event.key == K_s: # use constants K_s
backward = True
if event.type == KEYUP:
if event.key == K_a: # use constants K_a
left = False
elif event.key == K_d: # use constants K_d
right = False
elif event.key == K_w: # use constants K_w
forward = False
elif event.key == K_s: # use constants K_s
backward = False
if forward:
thing2_y -= int(speed * dx)
thing2_x -= int(speed * dy)
elif backward:
thing2_y += int(speed * dx)
thing2_x += int(speed * dy)
pygame.draw.rect(screen,WHITE,rect2)
screen.fill((40, 40, 40))
thing2 = pygame.transform.rotate(thing,degree)
screen.blit(thing2,(thing2_x,thing2_y))
pygame.display.update()
mainClock.tick(60)

Making an image move arrond the screen with key presses

I had this script working before but now it doesnt work. Earlier, the image moved around the screen fine but now it wont even move, the image just stays in the corner not moving at all when i press up or down or left or right keys
import pygame, sys
from pygame.locals import *
pygame.init()
bifl = 'screeing.jpg'
milf = 'char_fowed_walk1.png'
screen = pygame.display.set_mode((640, 480))
background = pygame.image.load(bifl).convert()
mouse_c = pygame.image.load(milf).convert_alpha()
x, y = 0, 0
movex, movey = 0, 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
movex =- 0.3
elif event.key == K_RIGHT:
movex =+ 0.3
elif event.key == K_UP:
movey =- 0.3
elif event.key == K_DOWN:
movey =+ 0.3
if event.type == KEYDOWN:
if event.key == K_LEFT:
movex = 0
elif event.key == K_RIGHT:
movex = 0
elif event.key == K_UP:
movey = 0
elif event.key == K_DOWN:
movey = 0
x += movex
y += movey
screen.blit(background, (0, 0))
screen.blit(mouse_c, (x, y))
pygame.display.update()
I am using python 2.7
All you need to do is change the second KEYDOWN to KEYUP so that your movement speed doesn't get set to 0 whenever you press a key.
EDIT: Additionally you have some strange syntax in your code. =- and =+ are not Python operators. I think you meant += and -=. Also remember to use elif statements instead of if statements whenever possible. Not only does this optimize your code, it also makes it easier to understand and debug.
import pygame, sys
from pygame.locals import *
pygame.init()
bifl = 'screeing.jpg'
milf = 'char_fowed_walk1.png'
screen = pygame.display.set_mode((640, 480))
background = pygame.image.load(bifl).convert()
mouse_c = pygame.image.load(milf).convert_alpha()
x, y = 0, 0
movex, movey = 0, 0
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
movex -= 0.3
elif event.key == K_RIGHT:
movex += 0.3
elif event.key == K_UP:
movey -= 0.3
elif event.key == K_DOWN:
movey += 0.3
elif event.type == KEYUP:
if event.key == K_LEFT:
movex = 0
elif event.key == K_RIGHT:
movex = 0
elif event.key == K_UP:
movey = 0
elif event.key == K_DOWN:
movey = 0
x += movex
y += movey
screen.blit(background, (0, 0))
screen.blit(mouse_c, (x, y))
pygame.display.update()

Categories

Resources