Move_ip does not work, moving Sprites - python

I am trying to make my Sprite move on the screen, I have created function that should make it happen but it does not work> the problem lies in move_ip function, but I don't know how to fix it. These are my first attempts with classes so any suggestions are welcome.
import pygame
pygame.init()
finish = False
white = ( 255, 255, 255)
black = (0, 0, 0)
grey = (211, 211, 211)
font = pygame.font.Font("C:/Windows/Fonts/BRITANIC.TTF", 20)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Game")
class Sprite(object):
def __init__(self, name):
self.health = 3
self.name = name
self.points = 0
self.x = 25
self.y = 25
def printName(self):
print (self.name)
class Dog(Sprite):
def __init__(self, name):
super(Dog, self).__init__(name)
self.dog_img = pygame.image.load("dog_left.png")
self.dog_rect = self.dog_img.get_rect()
def drawDog(self, screen):
screen.blit(self.dog_img, (self.x, self.y))
def takeBone(self, sp1, sp2):
takebone = pygame.sprite.collide_rect(sp1, sp2)
if takebone == True:
self.points += 1
def moving(self):
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_img.move_ip(player_move_x, player_move_y)
class Bone(Sprite):
def __init__(self, name):
super(Bone, self).__init__(name)
self.neme = "Bone"
self.bone = pygame.image.load("bone.png")
self.bone_rect = self.bone.get_rect()
self.x = 250
self.y = 250
def drawBone(self, screen):
screen.blit(self.bone, (self.x, self.y))
end_pos = 170
player_x = 10
player_y = 10
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
screen2 = pygame.display.set_mode(size)
player = Dog("Tom")
bone = Bone("Bone")
timer = pygame.time.Clock()
while finish == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_move_x = -5
if event.key == pygame.K_RIGHT:
player_move_x = 5
if event.key == pygame.K_UP:
player_move_y = -5
if event.key == pygame.K_DOWN:
player_move_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
player_move_x = 0
if event.key == pygame.K_RIGHT:
player_move_x = 0
if event.key == pygame.K_UP:
player_move_y = 0
if event.key == pygame.K_DOWN:
player_move_y = 0
screen.blit(background, background_rect)
player.drawDog(screen)
bone.drawBone(screen)
pygame.display.flip()
timer.tick(25)
pygame.quit()
I have made changes to my code:
import pygame
pygame.init()
finish = False
white = ( 255, 255, 255)
black = (0, 0, 0)
grey = (211, 211, 211)
font = pygame.font.Font("C:/Windows/Fonts/BRITANIC.TTF", 20)
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Game")
class Sprite(object):
def __init__(self, name):
self.health = 3
self.name = name
self.points = 0
self.x = 25
self.y = 25
def printName(self):
print (self.name)
class Dog(Sprite):
def __init__(self, name):
super(Dog, self).__init__(name)
self.dog_img = pygame.image.load("dog_left.png")
self.dog_rect = self.dog_img.get_rect()
def drawDog(self, screen):
screen.blit(self.dog_img, (self.x, self.y))
def takeBone(self, sp1, sp2):
takebone = pygame.sprite.collide_rect(sp1, sp2)
if takebone == True:
self.points += 1
def moving(self):
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_rect.move_ip(self.player_move_x, self.player_move_y)
class Bone(Sprite):
def __init__(self, name):
super(Bone, self).__init__(name)
self.neme = "Bone"
self.bone = pygame.image.load("bone.png")
self.bone_rect = self.bone.get_rect()
self.x = 250
self.y = 250
def drawBone(self, screen):
screen.blit(self.bone, (self.x, self.y))
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
screen2 = pygame.display.set_mode(size)
player = Dog("Tom")
bone = Bone("Bone")
timer = pygame.time.Clock()
while finish == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finish = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.player_move_x = -5
if event.key == pygame.K_RIGHT:
self.player_move_x = 5
if event.key == pygame.K_UP:
player.dog_rect.move_ip(-5, 0)
player_move_y = -5
if event.key == pygame.K_DOWN:
self.player_move_y = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
self.player_move_x = 0
if event.key == pygame.K_RIGHT:
self.player_move_x = 0
if event.key == pygame.K_UP:
player.dog_rect.move_ip(0, 0)
player_move_y = 0
if event.key == pygame.K_DOWN:
self.player_move_y = 0
screen.blit(background, background_rect)
player.drawDog(screen)
player.moving()
bone.drawBone(screen)
pygame.display.flip()
timer.tick(25)
pygame.quit()

First of all, you shouldn't name your class Sprite, since the name collides with the Sprite class of pygame.
Also, if you want to work with the Rect class, your classes don't need a x and y field to store its position, since you can use the Rect for that.
Let's look at the moving function:
self.player_move_x = 0
self.player_move_y = 0
self.move = self.dog_rect.move_ip(self.player_move_x, self.player_move_y)
Here you set player_move_x and player_move_y to 0, then you want to move dog_rect with these values. Beside the fact that you never actually use dog_rect for blitting the image at the right position, moving a Rect by 0, 0 doesn't do anything.
There are some more errors in both code sample you've given, but your code should probably look like this (I added some comments for explanation):
import pygame
pygame.init()
background = pygame.image.load("grass.png")
background_rect = background.get_rect()
size = background.get_size()
# only call set_mode once
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Game")
# no need for three different classes
class MySprite(pygame.sprite.Sprite):
def __init__(self, name, img_path, pos):
super(MySprite, self).__init__()
self.name = name
self.image = pygame.image.load(img_path)
self.rect = self.image.get_rect(topleft=pos)
# use rect for drawing
def draw(self, screen):
screen.blit(self.image, self.rect)
# use rect for moving
def move(self, dir):
self.rect.move_ip(dir)
player = MySprite("Tom", "dog_left.png", (10, 10))
bone = MySprite("Bone", "bone.png", (250, 250))
timer = pygame.time.Clock()
def main():
points = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return points
# get all pressed keys
pressed = pygame.key.get_pressed()
# pressed[some_key] is 1 if the key some_key is pressed
l, r, u, d = [pressed[k] for k in pygame.K_a, pygame.K_d, pygame.K_w, pygame.K_s]
# create a tuple describing the direction of movement
# TODO: normalizing/different speed
player.move((-l + r, -u + d))
if pygame.sprite.collide_rect(player, bone):
points += 1
screen.blit(background, background_rect)
player.draw(screen)
bone.draw(screen)
pygame.display.flip()
timer.tick(25)
if __name__ == '__main__':
print main()

You don't seem to have any calls to moving from your main loop. This probably is the issue.

Related

Improve performance while executing pygame?

My pygame is running way too slow. Without using class oop it was running perfectly but now using oop its very slow.
I have tested putting that separate class file in main file also but the result was same.
import pygame
from snake import Snake
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
dis_surf.fill((255, 255, 255))
game = Snake(dis_surf, x, y, x_change, y_change)
x = game.x
y = game.y
another file:
import pygame
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
self.draw()
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
pygame.display.update()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
print(event)
self.x += self.x_change
self.y += self.y_change
x_change = game.x_change
y_change = game.y_change
pygame.display.update()
clock.tick(60)
game_loop()
A few things are wrong.
1) You are instantiating a new Snake class every game loop when you do game = Snake() inside of the while loop. This in combination with number 2 is your main problem. I moved this line outside of the while loop for you.
2) You are calling run() inside of __init__. This is something you should never do in a constructor, constructors generally should only be used for setting initial data. This also contributed to problem number 1 significantly because this was happening every game loop. I removed the call self.run() inside __init__ for you.
3) pygame.display.update() was being called twice. Not the cause of your problem, but still unnecessary.
Made some small corrections for you.
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
dis_surf = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
run = True
def game_loop():
x = 255
y = 255
x_change = 0
y_change = 0
game = Snake(dis_surf, x, y, x_change, y_change)
while run:
dis_surf.fill((255, 255, 255))
game.draw()
class Snake():
def __init__(self, dis_surf, x, y, x_change, y_change):
self.dis_surf = dis_surf
self.x = x
self.y = y
self.width = 20
self.height = 20
self.x_change = x_change
self.y_change = y_change
self.vel = 5
def draw(self):
pygame.draw.rect(self.dis_surf, (0, 255, 0), (self.x, self.y, self.width, self.height))
self.run()
def run(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.x += self.x_change
self.y += self.y_change
pygame.display.update()
clock.tick(60)
game_loop()
If you want to use OOP in pygame, use pygame's Sprite class. It's made exactly for this purpose.
Your code should look like this (I tried to change not too much):
import pygame
pygame.init()
surf_width = 800
surf_height = 600
clock = pygame.time.Clock()
screen = pygame.display.set_mode((surf_width, surf_height))
pygame.display.set_caption("snake game")
class Snake(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((20, 20))
self.image.fill(pygame.Color('orange'))
self.rect = self.image.get_rect(topleft=pos)
self.x_change = 0
self.y_change = 0
self.vel = 5
def update(self, events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.x_change = self.vel
self.y_change = 0
elif event.key == pygame.K_LEFT:
self.x_change = -self.vel
self.y_change = 0
elif event.key == pygame.K_UP:
self.y_change = -self.vel
self.x_change = 0
elif event.key == pygame.K_DOWN:
self.y_change = self.vel
self.x_change = 0
self.rect.move_ip(self.x_change, self.y_change)
def main():
snake = Snake((0, 0))
snakes = pygame.sprite.Group(snake)
while True:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
return
snakes.update(events)
screen.fill((30, 30, 30))
snakes.draw(screen)
pygame.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
Ensure to only call pygame.display.flip() and pygame.event.get() once every frame.
If you want to handle events in other parts of your code, just store the current frame's events in a variable and pass them around. Using a Group makes this easy.
See how we cleanly seperated the logic of the game:
The main loop does only the three things it's supposed to do. Handling events, updating the game state, and drawing to the screen. It does so without "knowing what actually happens" in the game.
The Snake sprite only reacts when told so by the main loop (when its update method is called), and it does not care where the events come from and how and where it is actually displayed.

How to make a brake function for a car pygame [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
i am new to python and i wanted to know how to make the car have a braking function by pressing spacebar. I have put controls to make the car go left right forward and reverse, but slowing down is what i need using the spacebar. I don't know if my code is required to answer the question but here it is anyways.
Thanks
import math
import random
import pygame
WHITE = pygame.Color('white')
VEHICLE1 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE1.fill((130, 180, 20))
#blitting car onto 'rectangle car'
VEHICLE1 = pygame.image.load("YellowLambo.png")
screen.blit(VEHICLE1,(0,0))
pygame.display.update()
VEHICLE2 = pygame.Surface((40, 70), pygame.SRCALPHA)
VEHICLE2.fill((200, 120, 20))
#blitting computer's car
VEHICLE2 = pygame.image.load("RedLambo.png")
screen.blit(VEHICLE2,(0,0))
pygame.display.update()
BACKGROUND = pygame.Surface((1280, 800))
BACKGROUND.fill((127, 69, 2))
BACKGROUND = pygame.image.load("track2.png").convert()
screen.blit(BACKGROUND,(0,0))
pygame.display.update()
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class VehicleSprite(Entity):
MAX_FORWARD_SPEED = 10
MAX_REVERSE_SPEED = 2
ACCELERATION = 0.05
TURN_SPEED = 0.000000000001
def __init__(self, image, position):
Entity.__init__(self)
self.src_image = image
self.image = image
self.rect = self.image.get_rect(center=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = self.direction = 0
self.k_left = self.k_right = self.k_down = self.k_up = 0
def update(self, time):
# SIMULATION
self.speed += self.k_up + self.k_down
# To clamp the speed.
self.speed = max(-self.MAX_REVERSE_SPEED,
min(self.speed, self.MAX_FORWARD_SPEED))
# Degrees sprite is facing (direction)
self.direction += (self.k_right + self.k_left)
rad = math.radians(self.direction)
self.velocity.x = -self.speed*math.sin(rad)
self.velocity.y = -self.speed*math.cos(rad)
self.position += self.velocity
self.image = pygame.transform.rotate(self.src_image, self.direction)
self.rect = self.image.get_rect(center=self.position)
class Background(pygame.sprite.Sprite):
def __init__(self, image, location):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect(topleft=location)
def game_loop():
bike = VehicleSprite(VEHICLE1, rect.center)
ball = VehicleSprite(VEHICLE2, rect.center)
bike_group = pygame.sprite.Group(bike)
ball_group = pygame.sprite.Group(ball)
all_sprites = pygame.sprite.Group(bike_group, ball_group)
background = Background(BACKGROUND, [0, 0])
camera = pygame.math.Vector2(0, 0)
done = False
while not done:
time = clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
# Bike Input (Player 1)
if event.key == pygame.K_d:
bike.k_right = -5
elif event.key == pygame.K_a:
bike.k_left = 5
elif event.key == pygame.K_w:
bike.k_up = 2
elif event.key == pygame.K_s:
bike.k_down = -2
elif event.key == pygame.K_ESCAPE:
done = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d:
bike.k_right = 0
elif event.key == pygame.K_a:
bike.k_left = 0
elif event.key == pygame.K_w:
bike.k_up = 0
elif event.key == pygame.K_s:
bike.k_down = 0
camera -= bike.velocity
#screen.blit(background.image, background.rect)
all_sprites.update(time)
screen.fill(WHITE)
screen.blit(background.image, background.rect.topleft+camera)
for sprite in all_sprites:
screen.blit(sprite.image, sprite.rect.topleft+camera)
pygame.display.flip()
game_loop()
pygame.quit()
Just add a self.k_break attribute, set it to True when the player breaks and then decrease the self.speed if it's greater than 0 and increase it if it's less than 0. Use max and min, so that it stops at 0.
def update(self, time):
self.speed += self.k_up + self.k_down
if self.k_break:
if self.speed > 0:
self.speed = max(0, self.speed-0.5)
elif self.speed < 0:
self.speed = min(0, self.speed+0.5)

Pygame: bullets sticks to the screen

My problem is very simple. The bullets I fire sticks to the screen if I shoot fast. If I shoot slowly, they don't stick. Anyone have an idea how this phenomenon occurs?
screenshot of the bullets sticking to the screen
Below I have entered the code. I follow this default game flowchart:
I am curious about the origin of the problem. Is it the code or hardware?
import sys
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# pygame initializing
pygame.init()
#create the screen surface
screen = pygame.display.set_mode((800, 700))
class Color():
def __init__(self):
self.black = (0, 0, 0)
self.white = (255, 255, 255)
self.red = (255, 0, 0)
self.green = (0, 255, 0)
self.green_lambda = (10, 255, 150)
self.blue = (0, 0, 255)
# set up the colors
color = Color() # make an instance of this class - this makes some colors available
class Spaceship(Sprite):
"""
This class represents the Spaceship.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
""" Constructor"""
# Call the parent class (Sprite) constructor
super().__init__()
width = 22
height = 32
self.screen = screen
self.image = pygame.Surface((width, height))
self.image.fill(color.black)
self.image.set_colorkey(color.black)
pygame.draw.polygon(self.image, color.green_lambda, [[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]],2)
self.rect = self.image.get_rect()
self.screen_rect = self.screen.get_rect()
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# As the rect method only take integers we store a
# This value is only used at the beginning, i.e. before the game loop starts
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
class Bullet(Sprite):
"""
This class represents the bullets.
It derives from the "Sprite" class in Pygame.
"""
def __init__(self):
# Call the parent class (Sprite) constructor
super().__init__()
self.image = pygame.Surface((8,10))
self.image.fill(color.red)
self.image.set_colorkey((color.red))
pygame.draw.ellipse(self.image, color.green, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect()
self.rect.centerx = defender.rect.centerx
self.rect.bottom = defender.rect.top
# def function to move the bullets
def update_pos(self):
self.rect.y -= bullet_speed
# create spaceship instance
defender = Spaceship()
# create group to store sprites in
all_sprites_list = Group()
all_sprites_list.add(defender)
ship_speed = 0.5
bullet_speed = 3
def run_game():
m_right = False
m_left = False
m_up = False
m_down = False
new_bullet = False
while True:
"""This is the user interaction section"""
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
elif event.key == pygame.K_RIGHT:
m_right = True
elif event.key == pygame.K_LEFT:
m_left = True
elif event.key == pygame.K_UP:
m_up = True
elif event.key == pygame.K_DOWN:
m_down = True
elif event.key == pygame.K_SPACE:
new_bullet = Bullet()
#print(dir(new_bullet))
all_sprites_list.add(new_bullet)
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
m_right = False
elif event.key == pygame.K_LEFT:
m_left = False
elif event.key == pygame.K_UP:
m_up = False
elif event.key == pygame.K_DOWN:
m_down = False
"""Below is the game logic, which gets input from the user interaction
section and more"""
# Movement of spaceship depending on the flag boolean value and on screen width and height
if m_right and defender.rect.right < defender.screen_rect.right:
defender.center_x += ship_speed
if m_left and defender.rect.left > defender.screen_rect.left:
defender.center_x -= ship_speed
if m_up and defender.rect.top > defender.screen_rect.top:
defender.center_y -= ship_speed
if m_down and defender.rect.bottom < defender.screen_rect.bottom:
defender.center_y += ship_speed
# The cumulative value (which is a float number) for the spaceships movement
# is given to the spaceship rect variable (which can only be integer) now.
# This enables fine adjusting of the speed
defender.rect.centerx = defender.center_x
defender.rect.centery = defender.center_y
all_sprites_list.update()
screen.fill(color.black)
if new_bullet:
new_bullet.update_pos()
# Below the bullets which leaves the screen display are deleted
if new_bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(new_bullet)
all_sprites_list.draw(screen)
print(all_sprites_list)
pygame.display.flip()
run_game()
instead of just updating the position of new_bullet
# if new_bullet:
# new_bullet.update_pos()
# # Below the bullets which leaves the screen display are deleted
# if new_bullet.rect.bottom < defender.screen_rect.top:
# all_sprites_list.remove(new_bullet)
update the position of all bullets
for bullet in all_sprites_list:
if isinstance(bullet,Bullet):
bullet.update_pos()
if bullet.rect.bottom < defender.screen_rect.top:
all_sprites_list.remove(bullet)
del bullet
Joran Beasley's answer is correct. I'd just like to point out that you can also put the behavior of the sprites into their update methods which get called automatically when you call all_sprites_list.update(). You can actually move most of the code in the while loop to the update methods.
I've got an example with these changes and some more tips in the comments (a quick code review):
import pygame
from pygame.sprite import Sprite
from pygame.sprite import Group
# I'd just define some global constants for the colors.
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
GREEN_LAMBDA = (10, 255, 150)
class Spaceship(Sprite):
"""This class represents the Spaceship."""
def __init__(self, screen):
"""Constructor"""
super().__init__()
self.screen = screen
# pygame.SRCALPHA makes the surface transparent.
self.image = pygame.Surface((22, 32), pygame.SRCALPHA)
pygame.draw.polygon(
self.image, GREEN_LAMBDA,
[[10,0],[15,22],[20,30],[10,27],[0,30],[5,22]], 2
)
self.screen_rect = self.screen.get_rect()
# You can pass the position as the midbottom argument to `get_rect`.
self.rect = self.image.get_rect(midbottom=self.screen_rect.midbottom)
self.center_x = self.rect.centerx
self.center_y = self.rect.centery
# I've removed the `m_right`, etc. variables and just set the speed
# of the sprite in the event loop.
self.max_speed = 3.5
self.speed_x = 0
self.speed_y = 0
def update(self):
# Move the sprite.
self.center_x += self.speed_x
self.center_y += self.speed_y
self.rect.centerx = self.center_x
self.rect.centery = self.center_y
# Keep the sprite on the screen.
if not self.screen_rect.contains(self.rect):
self.rect.clamp_ip(self.screen_rect)
self.center_x, self.center_y = self.rect.center
class Bullet(Sprite):
"""This class represents the bullets."""
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((8, 10), pygame.SRCALPHA)
pygame.draw.ellipse(self.image, GREEN, [1, 0, 5, 8], 2)
self.rect = self.image.get_rect(midbottom=pos)
self.speed = 3 # The speed is now an attribute.
def update(self):
self.rect.y -= self.speed
if self.rect.top < 0:
self.kill() # Remove the sprite from all groups.
def run_game():
pygame.init()
screen = pygame.display.set_mode((800, 700))
clock = pygame.time.Clock() # Use a clock to limit the frame rate.
defender = Spaceship(screen)
all_sprites = Group() # Changed the name because groups are not lists.
all_sprites.add(defender)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return
elif event.key == pygame.K_RIGHT:
defender.speed_x = defender.max_speed
elif event.key == pygame.K_LEFT:
defender.speed_x = -defender.max_speed
elif event.key == pygame.K_UP:
defender.speed_y = -defender.max_speed
elif event.key == pygame.K_DOWN:
defender.speed_y = defender.max_speed
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(defender.rect.midtop) # Pass the pos.
all_sprites.add(new_bullet)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and defender.speed_x > 0:
defender.speed_x = 0
elif event.key == pygame.K_LEFT and defender.speed_x < 0:
defender.speed_x = 0
elif event.key == pygame.K_UP and defender.speed_y < 0:
defender.speed_y = 0
elif event.key == pygame.K_DOWN and defender.speed_y > 0:
defender.speed_y = 0
all_sprites.update() # Calls the update methods of all sprites.
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.
run_game()

How to move a rectangle in python using pygame in this code?

I want to move a rectangle with the arrow keys, so far I only can draw the rectangle but I don't get the keyhandler to work.
I'm a newbie in python and pygame.
This is my main.py:
import pygame
import time
import random
from Player import *
# Initialize Pygame
pygame.init()
game_over = False
# Color
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (192, 192, 192)
# Setting up the window
surfaceWidth = 800
surfaceHeight = 500
surface = pygame.display.set_mode((surfaceWidth, surfaceHeight))
pygame.display.set_caption("Rectangle Runner")
clock = pygame.time.Clock()
#Player(surface, surface_height, surface_width, size, jump_height, color)
player = Player(surface, surfaceHeight, surfaceWidth, 50, 200, BLACK)
# Game Loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if game_over == True:
pygame.quit()
quit()
surface.fill(GRAY)
#Player.draw()
player.keyHandling()
player.checkBoundaries()
player.draw()
#Obstacle.draw()
pygame.display.update()
clock.tick(60)
# This code shall be unreachable
pygame.quit()
quit()
This is the Player.py:
import pygame
class Player:
def __init__(self, surface, surface_height, surface_width, size, jump_height, color):
self.surface = surface
self.surface_height = surface_height
self.surface_width = surface_width
self.size = size
self.jump_height = jump_height
self.color = color
self.x = (0 + (self.surface_width/10))
self.y = self.surface_height - self.size
self.x_move = 0
self.y_move = 0
self.rect = pygame.draw.rect(self.surface, self.color, [self.x, self.y, self.size, self.size])
def keyHandling(self):
# Draw the player
#pygame.draw.rect(self.surface, self.color,
#[self.x, self.y, self.size, self.size])
# KeyListener
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.y_move = -10
#self.y += self.y_move
#self.rect.move_ip(0, -10)
if event.key == pygame.K_LEFT:
self.x_move = -5
#self.x += self.x_move
#self.rect.move_ip(-5, 0)
if event.key == pygame.K_RIGHT:
self.x_move = 5
#self.x += self.x_move
#self.rect.move_ip(5, 0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
self.y_move = 0
#self.y += self.y_move
#self.rect.move_ip(0, 10)
if event.key == pygame.K_LEFT:
self.x_move = 0
if event.key == pygame.K_RIGHT:
self.x_move = 0
self.x += self.x_move
self.y += self.y_move
def checkBoundaries(self):
# Checking for Boundaries
#if self.y <= self.jump_height:
# self.y_move = -10
if self.y > self.surface_height - self.size:
self.y_move = 0
if self.y <= self.jump_height + self.size:
self.y_move = -10
def draw(self):
pygame.draw.rect(self.surface, self.color, [self.x, self.y, self.size, self.size])
#pygame.draw.rect(self.surface, self.color,[self.x, self.y, self.size, self.size])
I need help. I'm thinking thru this the whole day.
Thanks in advance :D
The problem in your code is that pygame.event.get() is a generator. Each item that is obtained from it can ONLY be obtained once. Hence, each time the clock ticks, you are grabbing everything within the events generator and they are all destroyed. Next, when the Player object iterates over pygame.event.get, it does nothing, as the generator was already made empty. See this about generators.
What you need to do is catch the KEYDOWN event in the main.py module and then pass key information onto the Player object.
Replace the main loop in main.py with the following:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
player.keyDown(event.key)
if game_over == True:
pygame.quit()
quit()
surface.fill(GRAY)
player.checkBoundaries()
player.draw()
pygame.display.update()
clock.tick(60)
Remove the keyHandling method from Player.py and replace with the following method:
def keyDown(self, key):
if key == pygame.K_w:
self.y -= 10
elif key == pygame.K_a:
self.x -= 10
elif key == pygame.K_d:
self.x += 10
This now removes the issue with the generator.
Full code

pygame/python sprite not moving? What have i done wrong? (no errors)

Alright, so here's my code, I get no errors but my sprite (player) is not moving
import pygame,sys
import random
import time
#Colors
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
class Block(pygame.sprite.Sprite):
def __init__(self, color = blue, width = 50, height = 50):
super(Block, self).__init__()
self.image = pygame.Surface((width, height))
self.image.fill(color)
self.rect = self.image.get_rect()
def set_position(self, x , y):
self.rect.x = x
self.rect.y = y
def set_image(self, filename = None):
if(filename != None):
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect()
if (__name__ == "__main__"):
pygame.init()
window_size = window_width, window_height = 640,480
window = pygame.display.set_mode(window_size)
pygame.display.set_caption('Test')
window.fill(white)
clock = pygame.time.Clock()
#important variables
pos_x = 300
pos_y = 200
pos_x_change = 0
pos_y_change = 0
block_group = pygame.sprite.Group()
player = Block()
player.set_image('player.png')
player.set_position(pos_x,pos_y) #Player variable for pos
another_block = Block(red)
another_block.set_position(100,100)
block_group.add(player, another_block)
block_group.draw(window)
pygame.display.update()
running = True
while(running):
for event in pygame.event.get():
if (event.type == pygame.QUIT):
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
pos_x_change = -10
if event.key == pygame.K_RIGHT:
pos_x_change = 10
if event.key == pygame.K_UP:
pos_y_change -10
if event.key == pygame.K_DOWN:
pos_y_change = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
pos_x_change = 0
if event.key == pygame.K_RIGHT:
pos_x_change = 0
if event.key == pygame.K_UP:
pos_y_change == 0
if event.key == pygame.K_DOWN:
pos_y_change == 0
pos_x += pos_x_change
pos_y += pos_y_change
clock.tick(60)
pygame.quit
quit()
As you can see, I clearly added the pos_x and pos_y
and set it to pos_x += pos_x_change
and pos_y += pos_y_change
but the sprite is still not moving.
I'm guessing it's a misplacement of code because python heavily relies on indentation? Please explain to me what i have done wrong, It would be greatly appreciated.
It looks like you're updating the variables that contain the players x and y coordinates, but you're not updating the display. That's why it looks like the position isn't changing. I believe calling player.set_position(pos_x,pos_y) just above the clock.tick(60) statement will fix the problem.

Categories