how to move a rectangle in a pygame program [duplicate] - python

This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed last month.
Good day, I am writing a pygame program that uses sockets. Right now I am just trying to get the rectangles to move in the x-axis and I keep getting this error
self.rect.x += self.dx
AttributeError: 'tuple' object has no attribute 'x' ".
My goal is just to move the rect left and right. using the move method below.
import pygame
class Player():
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.rect = pygame.Rect((x, y, width, height))
self.vel = 3
self.dx = 0
self.dy = 0
self.jump = False
def draw(self, win):
pygame.draw.rect(win, self.color, self.rect)
def move(self, screen_width, screen_height):
SPEED = 10
dx = 0
dy = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.dx = -SPEED
if keys[pygame.K_RIGHT]:
self.dx = SPEED
self.update()
def update(self):
# update player position
self.rect.x += self.dx
self.rect.y += self.dy
self.rect = (self.x, self.y, self.width, self.height)
self.dx = 0
self.dy = 0

I see that you already created a pygame.Rect object and updated it correct, why recreate that object?
Change this:
def update(self):
# update player position
self.rect.x += self.dx
self.rect.y += self.dy
self.rect = (self.x, self.y, self.width, self.height)
self.dx = 0
self.dy = 0
To:
def update(self):
# update player position
self.rect.x += self.dx
self.rect.y += self.dy
self.dx = 0
self.dy = 0
Also you might want to remove this as it doesn't do anything:
self.x = x
self.y = y
Unless you need the position where it was first created

Related

How do I change rect size in pygame with sprites to improve accuracy of turrets? [duplicate]

This question already has answers here:
Can't figure out how to check mask collision between two sprites
(1 answer)
How to get the correct dimensions for a pygame rectangle created from an image
(2 answers)
Closed 3 days ago.
I am trying to make a game in pygame. I want to make a turret that will fire at the player. I have the formula to make this happen, but for some reason, it isn't completely accurate. I am running into the same problem with the player shooting as well. I am trying to use the mouse to aim, and it is off by a little bit.
Here is an image to help with understanding.
The cross is the turret and the ghost is the player. The rest is the bullets that should be hitting the player but it is hitting the rect top left it seems.
It is a bit of a mess but here is the code I am trying to test this with.
import pygame, math, random
pygame.init()
height,width = 1050,1000
clock = pygame.time.Clock()
screen = pygame.display.set_mode((height, width,))
pygame.display.set_caption("Vampires Suck")
pygame.display.flip()
running = True
class Crucifix2(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.sprite = pygame.image.load("image")
self.image = self.sprite
self.rect = self.image.get_rect()
self.rect.x =(450)
self.rect.y = (150)
self.mask = pygame.mask.from_surface(self.image)
def update(self):
pass
class MagicBullet2(pygame.sprite.Sprite):
def __init__(self, speed,x,y, targetx, targety):
super().__init__()
self.sprite = pygame.image.load("Image")
self.image = self.sprite
self.mask = pygame.mask.from_surface(self.image)
self.rect = self.image.get_rect()
angle = math.atan2(targety - y, targetx - x)
self.dx = math.cos(angle) * speed
self.dy = math.sin(angle) * speed
self.x = x
self.y = y
def update(self):
self.x = self.x + self.dx
self.y = self.y + self.dy
self.rect.x = int(self.x)
self.rect.y = int(self.y)
if self.rect.x < -50 or self.rect.x > width + 50 or self.rect.y < -50 or self.rect.y > height + 50:
self.kill()
def collide(self, spriteGroup):
if pygame.sprite.spritecollide(self, spriteGroup, True, pygame.sprite.collide_mask):
pass
class OurHero(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.sprite = pygame.image.load('image')
self.size = (400,400)
self.current_sprite = 0
self.image =pygame.transform.scale(self.sprite, self.size)
self.rect = self.image.get_rect(topleft = (580, 630))
self.rect.x = (430)
self.rect.y = (380)
self.mask = pygame.mask.from_surface(self.image)
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.rect.x -= 3
if keys[pygame.K_RIGHT]:
self.rect.x += 3
if keys[pygame.K_UP]:
self.rect.y -= 3
if keys[pygame.K_DOWN]:
self.rect.y += 3
if self.rect.x > 793:
self.rect.x -= 3
if self.rect.x < 75:
self.rect.x += 3
if self.rect.y < 87:
self.rect.y += 3
if self.rect.y > 789:
self.rect.y -=3
self.current_sprite += 0.027
class aim(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.sprite = pygame.image.load("image")
self.image = self.sprite
self.rect = self.image.get_rect(center = (300,300))
self.rect.inflate(-500,-500)
def update(self):
self.rect.center = pygame.mouse.get_pos()
class MagicBullet(pygame.sprite.Sprite):
def __init__(self, speed,x,y, targetx, targety):
super().__init__()
self.sprite = pygame.image.load("image")
self.image = self.sprite
self.mask = pygame.mask.from_surface(self.image)
self.rect = self.image.get_rect()
angle = math.atan2(targety - y, targetx - x)
self.dx = math.cos(angle) * speed
self.dy = math.sin(angle) * speed
self.x = x
self.y = y
def update(self):
self.x = self.x + self.dx
self.y = self.y + self.dy
self.rect.x = int(self.x)
self.rect.y = int(self.y)
if self.rect.x < -50 or self.rect.x > width + 50 or self.rect.y < -50 or self.rect.y > height + 50:
self.kill()
mouse_x, mouse_y = pygame.mouse.get_pos()
pygame.mouse.set_visible(False)
mouse = aim()
player = OurHero()
dude_sprite = pygame.sprite.Group()
dude_sprite.add(player)
dude_sprite.add(mouse)
bad = pygame.sprite.Group()
bad3 = pygame.sprite.Group()
bad2 = Crucifix2()
bad.add(bad2)
player_bullets = MagicBullet2(8, bad2.rect.x , bad2.rect.y+90 , player.rect.x, player.rect.y)
bullet_group = pygame.sprite.Group()
bad3.add(player_bullets)
distance_x = player.rect.x - bad2.rect.x
distance_y = player.rect.y - bad2.rect.y
angle = math.atan2(distance_y, distance_x)
dude2 = MagicBullet(5, player.rect.x, player.rect.y, mouse_x, mouse_y)
while running:
mouse_x, mouse_y = pygame.mouse.get_pos()
pygame.display.update()
player_bullets = MagicBullet2(8, bad2.rect.x , bad2.rect.y+90 , player.rect.x + 30, player.rect.y + 30)
bad3.add(player_bullets)
screen.fill('white')
bad3.update()
bad3.draw(screen)
dude_sprite.update()
dude_sprite.draw(screen)
bullet_group.draw(screen)
bad.update()
bad.draw(screen)
bullet_group.update()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
#bullet_group.add(player.creat_bullet())
dude2 = MagicBullet(8, player.rect.x , player.rect.y , mouse_x, mouse_y)
bullet_group.add(dude2)
if event.type == pygame.QUIT:
running = False
clock.tick(120)
I have been searching everywhere for an answer. I am not exactly sure what I am looking for. I am very new to game dev and I am still pretty new with python and pygame. I tried transform.scale() but that seemed to push the character off the screen when I put it into update().

Rect argument is invalid [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Pygame Drawing a Rectangle
(6 answers)
Closed 5 months ago.
I'm building a game with Sprites, using almost exactly the same code for all the sprites. But when it comes to my ship its telling me I have no rect or colliderect is invalid etc etc etc.
I tried to put a box around my 'rect' to make sure it was loaded correctly but I just get this error.
My code for the ship is
class Spaceship(pygame.sprite.Sprite):
def __init__(self, x, y, scale):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("ship.png")
self.image = pygame.transform.scale(self.image, (int(self.image.get_width() * scale), int(self.image.get_height() * scale)))
self.rect = self.image.get_rect() # isn't this correct to get a rect!?
self.rect.center = [x, y]
self.pos = pygame.mouse.get_pos()
self.alive = True
self.speed = 100
self.dx = 0
self.dy = 0
self.x = 0
self.y = 0
def update(self):
pygame.draw.rect(screen,(GREEN), self.rect, 2) # Trying to establish rect object
self.pos = pygame.mouse.get_pos()
self.dx = (self.pos[0])
self.dy = (self.pos[1])
if self.x +20 <= self.dx:
self.x += speed
if self.x +20 >= self.dx:
self.x -= speed
self.y = (self.pos[1])
if self.y +20 <= self.dy:
self.y += speed
if self.y +20 >= self.dy:
self.y -= speed
print(self.pos[0])
print(self.pos[1])
if self.x >= SW - 40:
self.x = SW - 40
if self.x <= 0:
self.x = 0
if self.y >= SH -40:
self.y = SH - 40
if self.y <= SH - 600:
self.y = SH - 600
self.blit = (self.x, self.y)
self.rect = (self.x, self.y)
If I can't get this rect right I can't check rect collisions.
Thanks for any thoughts.

Pygame diagonal movement not at correct angle

I would like my player to move diagonally at the same speed as it does when only moving horizontally or vertically. This does work when moving in a line with a negative gradient however, when moving along a positive gradient, the player doesn't move at a perfect 45 degree angle.
This is my code for moving the player:
def move(self, speed):
if self.direction.magnitude() != 0:
self.direction = self.direction.normalize()
self.rect.x += self.direction.x * speed
self.rect.y += self.direction.y * speed
As I said earlier, all I want is for the player to move diagonally at the same speed as it does in only the x or y direction.
Here is the full player class in case it is needed:
class Player:
def __init__(self, x, y):
self.image = pygame.Surface((30, 30))
self.image.fill((255, 255, 255))
self.rect = self.image.get_rect(center = (x, y))
self.direction = pygame.math.Vector2()
self.speed = 5
def input(self):
keys = pygame.key.get_pressed()
if keys[K_w]:
self.direction.y = -1
elif keys[K_s]:
self.direction.y = 1
else:
self.direction.y = 0
if keys[K_a]:
self.direction.x = -1
elif keys[K_d]:
self.direction.x = 1
else:
self.direction.x = 0
def move(self, speed):
if self.direction.magnitude() != 0:
self.direction = self.direction.normalize()
self.rect.x += self.direction.x * speed
self.rect.y += self.direction.y * speed
def update(self):
self.input()
self.move(self.speed)
def draw(self, screen):
screen.blit(self.image, self.rect.center)
Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the new position of the object is assigned to the Rect object. If you want to move the object with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location of the rectangle:
class Player:
def __init__(self, x, y):
self.image = pygame.Surface((30, 30))
self.image.fill((255, 255, 255))
self.rect = self.image.get_rect(center = (x, y))
self.direction = pygame.math.Vector2()
self.speed = 5
self.position = pygame.math.Vector2(x, y)
def input(self):
keys = pygame.key.get_pressed()
dx = keys[K_d] - keys[K_a]
dy = keys[K_s] - keys[K_w]
self.direction = pygame.math.Vector2(dx, dy)
if dx != 0 and dy != 0:
self.direction /= 1.41421
def move(self, speed):
self.position += self.direction * speed
self.rect.x = round(self.position.x)
self.rect.y = round(self.position.y)
def update(self):
self.input()
self.move(self.speed)
def draw(self, screen):
screen.blit(self.image, self.rect.center)
See also Pygame doesn't let me use float for rect.move, but I need it and moving with a normalized vector in pygame inconsistent?.
Note, that pygame.math.Vector2.magnitude and math.Vector2.normalize are expensive for performance. Try to avoid this operations. Normalization of the vector is only required when moving along both axes. Since the absolute value of the vector is √2 in this case, the normalization can be replaced by dividing by √2.
dx = keys[K_d] - keys[K_a] # dx is -1, 0 or 1
dy = keys[K_s] - keys[K_w] # dy is -1, 0 or 1
self.direction = pygame.math.Vector2(dx, dy)
if dx != 0 and dy != 0:
self.direction /= 1.41421 # sqrt(2) is ~1.41421

Why is my sprite not moving

My sprite should be moving from right to left across the screen, and there should be multiple of the same sprites moving from random Y co-ordinates, where as the X should stay the same. Instead, at the moment, there is no movement and there is only on of the sprites.
class Mob(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((90, 90)).convert_alpha()
self.image = pygame.image.load(badguy_file).convert_alpha()
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = pygame.Rect(x, y, 100, 100)
self.x = x
self.y = y
self.rect.x = random.randrange(800 - 100)
self.rect.y = random.randrange(-100, -40)
self.speedx = 5
self.mask = pygame.mask.from_surface(self.image)
def update(self):
self.rect.y += self.speedy
if self.rect.top > height + 10 or self.rect.left < -25 or self.rect.right > width + 20:
self.rect.x = random.randrange(width - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedx = random.randrange(2,0)
def render(self, screen):
screen.blit(self.image, (self.x, self.y))
mobYRange = random.randrange(200, 450)
mobs = pygame.sprite.Group()
for i in range(8):
mob = Mob(850,mobYRange)
mobs.add(mob)
mob.render(screen)
You don't have actual random y-axis, since once generated random list is passed to all instances of the Mob, use code below:
mobs = pygame.sprite.Group()
for i in range(8):
mob = Mob(850, random.randrange(200, 450))
mobs.add(mob)
mob.render(screen)
When you choose the y coord you do it like this mobYRange = random.randrange(200, 450) and then you use the SAME coord for all your mobs. You need to move the call of randrange into the for loop where you create your Mobs.
Also I'm not sure how pygame works. But are you supposed to call screen.blit() just once? I would have guessed this is something you call every frame to keep drawing it to the screen.

How to animate scale and rotate in pygame using rotozoom [duplicate]

This question already has answers here:
How to rotate an image around its center while its scale is getting larger(in Pygame)
(2 answers)
Closed 2 years ago.
Okay so Im just trying to get it working with rotations first before scaling then once I nail that the rotozoom should be easy. For the life of me I cant seem to get it working. Heres a simple class that I want the object to rotate over time as well a transform in the x direction. The transform is working fine but i just cant get it to rotate.
class Puff(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
try:
self.imagePuff = pygame.image.load(os.path.join("Images","puff.tga")).convert()
except:
raise UserWarning, "Unable to find Puff image"
self.imagePuff.set_colorkey((0,0,255))
self.image = self.imagePuff
self.rect = self.image.get_rect()
self.x = self.screen.get_width()/3
self.y = self.screen.get_height()/3+10
self.rect.center = (self.x, self.y)
self.lifespan = 60
self.speed = 1
self.count = 0
self.angle = 0
def update(self):
self.calcPos()
self.rect.center = self.x, self.y
self.transform()
if self.count > self.lifespan:
self.kill()
def calcPos(self):
self.x -= 5
self.y = self.y
def transform(self):
self.count += 1.1
self.angle += self.count*25
self.newTrans = pygame.transform.scale(self.copyImage, (400,400))
self.newRect = self.newTrans.get_rect()
self.newRect.center = self.rect.center
This is how I've made it so you can rotate your puff class:
import pygame
class Puff(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
try:
self.imagePuff = pygame.image.load("puff.jpg").convert()
except:
raise UserWarning, "Unable to find Puff image"
self.image = self.imagePuff
self.imagePuff.set_colorkey((0,0,255))
self.rect = self.image.get_rect()
self.x = self.screen.get_width()/3
self.y = self.screen.get_height()/3+10
self.rect.center = (self.x, self.y)
self.lifespan = 60
self.speed = 1
self.count = 0
self.angle = 0
def update(self):
oldCenter = self.rect.center
self.image = pygame.transform.rotate(self.imagePuff, self.angle)
self.rect = self.image.get_rect()
self.rect.center = oldCenter
def calcPos(self):
self.x -= 5
self.y = self.y
def turnLeft(self):
self.angle = (self.angle + 45) % 360
def turnRight(self):
self.angle = (self.angle - 45) % 360
if __name__ == "__main__":
pygame.init()
screen = pygame.display.set_mode((400,300))
clock = pygame.time.Clock()
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
pygame.display.set_caption("Spinning sprite!!!")
ball = Puff(screen)
sprites = pygame.sprite.Group()
sprites.add(ball)
keepGoing = True
while keepGoing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keepGoing = False
ball.turnRight()
sprites.clear(screen, background)
sprites.update()
sprites.draw(screen)
pygame.display.flip()
clock.tick(30)
Essentially the key points are:
self.image = pygame.transform.rotate(self.imagePuff, self.angle)
In the update method, and the two methods for changing the angle:
def turnLeft(self):
self.angle = (self.angle + 45) % 360
def turnRight(self):
self.angle = (self.angle - 45) % 360
In the code above every clock tick the sprite is rotated to the right:
ball.turnRight()
As you omitted your transform method, I had to edit the code to show how to do just rotations.
Hope this helps and if you need any more help please leave a comment.
Edit:
if you want to rotate and move to the left then you only really need to add this:
def update(self):
self.calcPos() # This moves the position - 5 in the x direction
self.rect.center = self.x, self.y
self.rotate() # This calls the bit to change the angle
if self.count > self.lifespan:
self.kill()
oldCenter = self.rect.center
self.image = pygame.transform.rotate(self.imagePuff, self.angle) # This rotates
self.rect = self.image.get_rect()
self.rect.center = oldCenter
def calcPos(self):
self.x -= 5
def rotate(self):
self.angle = (self.angle + 45) % 360
You should check out:
http://www.gamedev.net/topic/444490-pygame-easy-as-py/
If you search for "rotate.py" you'll see the a section of code on rotating sprites
EDIT:
Try changing you transform method to:
def transform(self):
self.count += 1.1
self.angle += (self.count*25) % 360
self.copyImage = pygame.transform.rotate(self.imagePuff, self.angle)
self.newTrans = pygame.transform.scale(self.copyImage, (400,400))
self.image = self.newTrans

Categories