How to Move a Sprite in Pygame - python

I have the following class:
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.init()
pygame.sprite.Sprite.__init__(self)
# Basic variables
self.speed = [2,2]
# Sets up the image and Rect
self.bitmap = pygame.image.load("badguy.png")
self.bitmap.set_colorkey((0,0,0))
self.shipRect = self.bitmap.get_rect()
self.shipRect.topleft = [100,200]
def move(self, x, y):
self.shipRect.center = (x,y)
def render(self):
screen.blit(self.bitmap, (self.shipRect))
Now, I want to have it move whenever I hit an arrow key. However, there's a big problem with my move function. It simply moves the center of the ship to the coordinates fed into the function. In case you aren't seeing the problem, it's that I'm trying to call it like this:
if event.key == K_RIGHT:
enemy.x += 5
if event.key == K_LEFT:
enemy.move(-5,0)
if event.key == K_UP:
enemy.move(0,5)
if event.key == K_DOWN:
enemy.move(0,-5)
I was expecting it to move my five in the direction of the key that I hit. However, it shoots to the top left of the screen because I'm making the center set at zero on one axis and +- 5 on the other axis.
What method can be used to make it move in the correct direction and still give me the ability to put the sprites at a starting position on the screen that I choose.
Any help is much appreciated.

change move to:
def move(self, x, y):
self.shipRect.center[0] += x
self.shipRect.center[1] += y
This way it just increments the position by the move amount you specify.

move_ip and centerx/yis what you want:
if event.key == K_RIGHT:
enemy.centerx.move_ip(5,0)
if event.key == K_LEFT:
enemy.centerx.move_ip(-5,0)
if event.key == K_UP:
enemy.centerx.move_ip(0,5)
if event.key == K_DOWN:
enemy.centerx.move_ip(0,-5)

Related

Trying to program a basic snake game in python (keeps "crashing")

So I'm trying to teach myself a little bit of python for fun following this tutorial: https://www.youtube.com/watch?v=8dfePlONtls
I made it to the point where the dot keeps moving automatically (left, right, up or down) depending on which arrow key I pressed last. But for some reason it all stops after a few seconds unless I keep inputting random keys or even just hovering the mouse over the window will do the trick. If I stop doing anything, the program "stops".
I also noticed the CPU usage going up to 22% for the program when I stop doing anything, but goes back down when I start inputting keys or moving the mouse again.
I've tried following exactly what was done in the video but I can't find any error and pycharm doesn't detect any obvious error in my code.
Here is what I have so far:
import pygame
from pygame.locals import *
import time
class Snake:
def __init__(self, parent_screen):
self.parent_screen = parent_screen
self.block = pygame.image.load("resources/block.jpg").convert()
self.x = 100
self.y = 100
self.direction = 'down'
def move_left(self):
self.direction = 'left'
def move_right(self):
self.direction = 'right'
def move_up(self):
self.direction = 'up'
def move_down(self):
self.direction = 'down'
def draw(self):
self.parent_screen.fill((117, 17, 8))
self.parent_screen.blit(self.block, (self.x, self.y))
pygame.display.update()
def walk(self):
if self.direction == 'left':
self.x -= 10
if self.direction == 'right':
self.x += 10
if self.direction == 'up':
self.y -= 10
if self.direction == 'down':
self.y += 10
self.draw()
class Game:
def __init__(self):
pygame.init()
self.surface = pygame.display.set_mode((500, 500))
self.surface.fill((117, 17, 8))
self.snake = Snake(self.surface)
self.snake.draw()
def run(self):
running = True
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.key == K_UP:
self.snake.move_up()
if event.key == K_DOWN:
self.snake.move_down()
if event.key == K_LEFT:
self.snake.move_left()
if event.key == K_RIGHT:
self.snake.move_right()
elif event.type == QUIT:
running = False
self.snake.walk()
time.sleep(0.2)
if __name__ == "__main__":
game = Game()
game.run()
Thanks in advance!
while running:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
if event.key == K_UP:
self.snake.move_up()
if event.key == K_DOWN:
self.snake.move_down()
if event.key == K_LEFT:
self.snake.move_left()
if event.key == K_RIGHT:
self.snake.move_right()
elif event.type == QUIT:
running = False
self.snake.walk()
time.sleep(0.2)
Your original code indentation means that you are handling keypresses every pygame event, but also updating your snake every pygame event. Removing the indent on the last two lines which move the snake means they will execute in the outer while loop instead of the event loop. This means the snake will update its position each time the loop runs instead of only when an event occurs.

How do i delete an image after moving it in pygame?

I am trying to delete the previous image after moving. This is the code of how i am moving the image (unit0
def Move(x, y):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Background.blit(RedInfantry,(-x*64, 0))
if event.key == pygame.K_RIGHT:
Background.blit(RedInfantry,(x*64, 0))
if event.key == pygame.K_UP:
Background.blit(RedInfantry,(0, -y*64))
if event.key == pygame.K_DOWN:
Background.blit(RedInfantry,(0, y*64))
The starting place is in the top left corner instead of where the image is . Furthermore i don't know how to delete the previous image once it has been moved. If i move twice in different directions it creates to separate images instead of deleting the last one.
How can i delete the previous image?
Base on one of your previous questions (Image loading using pygame), you have to change the position of the image in the grid:
if event.type == pygame.KEYDOWN:
new_x, new_y = x, y
if event.key == pygame.K_LEFT:
new_x -= 1
if event.key == pygame.K_RIGHT:
new_x += 1
if event.key == pygame.K_UP:
new_y -= 1
if event.key == pygame.K_DOWN:
new_x += 1
grid[new_x][new_y] = grid[x][y]
grid[x][y] = None
Of course you have to redraw the entire scene (the grid and the images) in every frame.
(Like in the answer to Image loading using pygame)

How to make your character move without tapping repeatedly on buttons?

I'm working on a racing game. I have been using this code but my player keeps moving once only. How do I solve this problem?
change = 7
dist = 7
change_r = 0
change_l = 0
dist_u = 0
dist_d = 0
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
change_r = True
elif event.key == pygame.K_LEFT:
change_l = True
elif event.key == pygame.K_UP:
dist_u = True
elif event.key == pygame.K_DOWN:
dist_d = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT or event.key == pygame.K_LEFT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
change_r = False
change_l = False
dist_u = False
dist_d = False
clock.tick(60)
if change_r == True:
x += change
if change_l == True:
x -= change
if dist_u == True:
y -= dist
if dist_d == True:
y += dist
There are different ways you could go about making move-able shapes/sprites using Pygame. The code you posted in your question seems overly complex. I'll give you two different ways that are simpler, and easier to use. Using a sprite class, and using a function.
It may not seem like I'm answering your question, but if I just told you what to fix in your code you posted, I'd just be knowingly steering you down a road that will lead to many problems, and much complexity in the future.
Method 1: Using a sprite class
To make a your race car sprite, you could use a sprite class like the one below.
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((50, 50))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.x = WIDTH / 2
self.rect.y = HEIGHT / 2
self.vx = 0
self.vy = 0
def update(self):
self.vx = 0
self.vy = 0
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.vx = -5
elif key[pygame.K_RIGHT]:
self.vx = 5
if key[pygame.K_UP]:
self.vy = -5
elif key[pygame.K_DOWN]:
self.vy = 5
self.rect.x += self.vx
self.rect.y += self.vy
Since your class is inheriting from Pygame's sprite class, You must name your image self.image and you must name your rectangle for the image self.rect. As you can also see, the class has two main methods. One for creating the sprite(__init__) and one for updating the sprite(update)
To use your class, make a Pygame sprite group to hold all your sprites, and then add your player object to the group:
sprites = pygame.sprite.Group()
player = Player()
sprtites.add(player)
And to actual render your sprites to the screen call sprites.update() and sprites.draw() in your game loop, where you update the screen:
sprites.update()
window_name.fill((200, 200, 200))
sprites.draw(window_name)
pygame.display.flip()
The reason i highly recommended using sprite classes, is that it will make your code look much cleaner, and be much easier to maintain. You could even move each sprite class to their own separate file.
Before diving fully into the method above however, you should read up on pygame.Rect objects and pygame.sprite objects, as you'll be using them.
Method 2: Using A function
If you prefer not to get into sprite classes, you can create your game entities using a function similar to the one below.
def create_car(surface, x, y, w, h, color):
rect = pygame.Rect(x, y, w, h)
pygame.draw.rect(surface, color, rect)
return rect
If you would still like to use a sprites, but don't want to make a class just modify the function above slightly:
def create_car(surface, x, y, color, path_to_img):
img = pygame.image.load(path_to_img)
rect = img.get_rect()
surface.blit(img, (x, y))
Here is an example of how i would use the functions above to make a movable rectangle/sprite:
import pygame
WIDTH = 640
HEIGHT = 480
display = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Moving Player Test")
clock = pygame.time.Clock()
FPS = 60
def create_car(surface, x, y, w, h, color):
rect = pygame.Rect(x, y, w, h)
pygame.draw.rect(surface, color, rect)
return rect
running = True
vx = 0
vy = 0
player_x = WIDTH / 2 # middle of screen width
player_y = HEIGHT / 2 # middle of screen height
player_speed = 5
while running:
clock.tick(FPS)
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
pygame.quit()
quit()
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_LEFT:
vx = -player_speed
elif e.key == pygame.K_RIGHT:
vx = player_speed
if e.key == pygame.K_UP:
vy = -player_speed
elif e.key == pygame.K_DOWN:
vy = player_speed
if e.type == pygame.KEYUP:
if e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT or\
e.key == pygame.K_UP or e.key == pygame.K_DOWN:
vx = 0
vy = 0
player_x += vx
player_y += vy
display.fill((200, 200, 200))
####make the player#####
player = create_car(display, player_x, player_y, 10, 10, (255, 0, 0))
pygame.display.flip()
As you may see above, your code for moving your race car can be simplified.
I should note, I'm assuming a few things with each method outlined above.
That your either using a circle, square, or some type of pygame shape object.
Or that your using a sprite.
If your not currently using any of the methods outlined above, I suggest that you do. Doing so will make your code much eaiser to maintain once you begin to build larger and more complex games.
You should have a global loop irrespective of your event handling. You should place your clock.tick() and your movement there. Namely:
#some constants here
while True:
pygame.display.update()
clock.tick(60)
#update you game state
if change_r == True:
x += change
if change_l == True:
x -= change
if dist_u == True:
y -= dist
if dist_d == True:
y += dist
for event in pygame.event.get():
# react to player input by changing the game state

How to shoot infinite bullets in game coded in Python?

I've got a really long code for my game, but I'll paste in the part that counts which is the bullet shooting part. The game is essentially a Mortal Kombat-esque game but with flying robots and bullets.
Before the game loop, I first predefined functions for the bullets and robots:
def robotr(xr,yr):
gameDisplay.blit(robrimg, (xr,yr))
def robotl(xl,yl):
gameDisplay.blit(roblimg, (xl,yl))
def bulletsr(xbr,ybr):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbr,ybr), 10)
def bulletsl(xbl,ybl):
pygame.draw.circle(gameDisplay, THECOLORS['orange'],(xbl,ybl), 10)
Then the numerous variables for the moving objects:
xr = 929
yr = 250
xl = 250
yl = 250
####
xbr=950
ybr=300
xbl=380
ybl=300
#####
xbr_change = 0
ybr_change = 0
ybl_change = 0
xbl_change = 0
####
xr_change = 0
yr_change = 0
xl_change = 0
yl_change = 0
robotr_speed = 3000
robotl_speed = 3000
After that, the code went for a really long run (about 300-400 lines more), but to the point where I shot the bullets I had an event like this to represent the bullets "moving" with the robot as it moved with the arrow keys.:
if event.type == pygame.KEYDOWN:
#-------PLAYER 1 MOVEMENT-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_a:
xr_change = -5
xbr_change = -5 #I have to change the position of the bullet as well so that it doesn't stay in one place and rather shoots from the robot (duh.)
And then a similar code to SHOOT the bullets:
#-------FIRE CANNON MK1-------
#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
if event.key == pygame.K_LSHIFT:
bulletsfx=pygame.mixer.Sound ('boomchickchickmp3.ogg')
bulletsfx.play()
bulletsfx.set_volume(0.2)
xbl_change = 5
if xbl_change == 5:
bulletsl(xbl,ybl)
xbl=xl
Of course, I defined such codes multiple times for the robot on the right as well.
Near the end of my program (this is as a short form of my end as I had extra variables so things wouldn't fall off the screen, but disregard that for now) I had a code like this so I could redefine the changes back to "0" so that the movements could be reused and so forth:
if event.type == pygame.KEYUP:
#Player 1 events
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN or event.key == pygame.K_RCTRL or event.key == pygame.K_DELETE: #or event.key == pygame.K_RSHIFT:
xr_change = 0
yr_change = 0
xbr_change= 0
ybr_change= 0
#Player 2 events
if event.key == pygame.K_a or event.key == pygame.K_d or event.key == pygame.K_w or event.key == pygame.K_s or event.key == pygame.K_LCTRL or event.key == pygame.K_f: #or event.key == pygame.K_LSHIFT:
xl_change = 0
yl_change = 0
xbl_change= 0
ybl_change= 0
##
xr += xr_change
yr += yr_change
xl += xl_change
yl += yl_change
##
xbr += xbr_change
ybr += ybr_change
xbl += xbl_change
ybl += ybl_change
##
bulletsr(xbr,ybr)
bulletsl(xbl,ybl)
robotr(xr,yr)
robotl(xl,yl)
pygame.display.update()
clock.tick(320)
Now my problem is that when I shoot the bullets, it shoots, but I can only shoot it once until it goes off the screen of my program (It's okay, I made it so it returns to the robots once it goes off the screen as well). Otherwise, if I keep hitting the key to shoot, it just returns the bullet coordinates back to where it originally should be (as in I shoot, and if I shoot again, I can see the bullet disappearing to return to its original location).
There is not an infinite number of bullets and I want to know how I can modify the function and some of the variables (probably) to make it so that happens.
You need to use sprites in your code which is missing. It can be done without sprites also but it will be difficult task.
Make a class of bullets so you can make different objects of this.
After you just make a instance to the bullet object every time shoot button is pressed and keep updating it.
In update method you will make bullet move.
Last step is to destroy the bullet object once its out of your screen. One easy way is to put an if statement to check if certain x or y length is achieved and if so delete that sprite or object (bullet in this case).
Here is an example of bullet class I used. In this the char is assumed to be on bottom of screen and shoot bullets upwards as y += -10
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super(Bullet, self).__init__()
self.image = pygame.Surface([10,40])
self.image.fill(RED)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 10
if you still need to see the full picture you can check out my code here : https://github.com/deepaksandhu/SpaceTurds/blob/master/game.py
also here is an excellent tutorial of making bullets:
http://programarcadegames.com/python_examples/show_file.php?file=bullets.py

Make an Image move one space with arrow keys in python / pygame

I am trying to create a game where "player_one.png" is controlled by the arrow keys to move around and dodge a bunch of randomly placed "player_two.png" that can move around on their own in random directions on a football field.
I have created a program that displays the field and the two images. I am having difficulty getting "player_two.png" display multiple copies on the field and cannot get them to move.
I also cannot get the "player_one.png" image to move based on the arrow key. I found a program using Sprites that moves a red block in the same way I want my player to move but cannot switch out the sprite with my image.
Here is my initial set-up which displays the field and the two images facing each other.
import pygame
import random
pygame.init()
#colors
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 100, 0)
red = (255, 0, 0)
size = [1000, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Tony's newest game attempt")
#boolean for while loop
done = False
#create clock
clock = pygame.time.Clock()
#declare font
font = pygame.font.Font(None, 25)
player_one = pygame.image.load("player_one.png").convert()
player_one.set_colorkey(white)
player_two = pygame.image.load("player_two.png").convert()
player_two.set_colorkey(white)
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(green)
for x in range(60,940,35):
pygame.draw.line(screen, white, [x, 0], [x, 500], 1)
score = 0
text = font.render("Score:" +str(score), True, black)
screen.blit(text, [0, 0])
screen.blit(player_one, [940, 240])
screen.blit(player_two, [60, 240])
pygame.display.flip()
clock.tick(20)
pygame.quit()
The sprite program that uses a class (something I could not get to work with images) moves the Player sprite using this code: (Please note this is not the entire program).
class Player(pygame.sprite.Sprite):
# Constructor function
def __init__(self, color, x, y):
# Call the parent's constructor
pygame.sprite.Sprite.__init__(self)
# Set height, width
self.image = pygame.Surface([35, 35])
self.image.fill(color)
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.rect.x = 930
self.rect.y = 250
def reset_player(self):
self.rect.x = 930
self.rect.y = 250
# Find a new position for the player
def update(self):
self.rect.x += self.change_y
self.rect.y += self.change_x
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.rect.x -= player.rect.width
elif event.key == pygame.K_RIGHT:
player.rect.x += player.rect.width
elif event.key == pygame.K_UP:
player.rect.y -= player.rect.height
elif event.key == pygame.K_DOWN:
player.rect.y += player.rect.height
# -- Draw everything
# Clear screen
screen.fill(green)
for x in range(60,940,35):
pygame.draw.line(screen, white, [x, 0], [x, 500], 1)
# Draw sprites
all_sprites_list.draw(screen)
text = font.render("Score: "+str(score), True, black)
screen.blit(text, [10, 10])
# Flip screen
pygame.display.flip()
# Pause
clock.tick(20)
pygame.quit()
Can someone please help me figure out how to get my image to move the way the sprite does. Or help me display "player_two.png" all over the field and move in random directions. It would be best if the "player_two.png" moved every once every 3 times I hit an arrow key. If this is vague please email me and I can send my code. I need to finish this game in 2 weeks!
Multiple comments on the game -
I don't see where self.change_y is defined. Also, shouldn't the update function be like - self.rect.x += self.change_x instead of self.rect.x += self.change_y?
Also, the main loop should be something like this
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done=True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if player.rect.x > 0:
player.rect.x -= player.rect.width
elif event.key == pygame.K_RIGHT:
if player.rect.x < screen_width: # the screen/game width
player.rect.x += player.rect.width
# Something similar for the up & down keys
I would recommend you to look at this question.
I think you have the right idea but aren't executing it well.
Try going to your game loop and when displaying an image, display like so:
gameDisplay.blit(player1, (player1X,player1Y))
This way, you can use a if statement to change playerX and player1Y. Insert the following code under the code that quits pygame:
elif e.type == pygame.KEYDOWN:
if e.key == pygame.K_LEFT:
player1X -= 5
pygame.display.update()
elif e.key == pygame.K_RIGHT:
player1X += 5
pygame.display.update()
The reason this works is because the variable that is defining X and Y are not staic. You can also do the same thing for up and down using:
elif e.key == pygame.K_UP:
or
elif e.key == pygame.K_DOWN:

Categories

Resources