I want to access my player position, I tried following Moving a Sprite Class from outside of the original Class in pygame but then I got "AttributeError: 'GroupSingle' object has no attribute 'rect'" as my error. I need to access player position inside my obstacle class.
This is my code:
import pygame
import os
import random
from sys import exit
pygame.init()
os.system("cls")
WIDTH = 288
HEIGHT = 512
FPS = 60
JUMP_POWER = 60
GRAVITY = 0.15
GAME_ACTIVE = 1
OBSTACLE_INTERVAL = 1000
AWAY_FROM_BIRD = 100
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("assets/images/player/bird.png").convert_alpha()
self.rect = self.image.get_rect(center = (WIDTH/4, HEIGHT/2))
self.gravity_store = 0
self.jump_sfx = pygame.mixer.Sound("assets/audio/jump.wav")
self.jump_sfx.set_volume(0.1)
def player_input(self):
for event in event_list:
if event.type == pygame.KEYDOWN:
if self.rect.bottom <= 0:
pass
else:
if event.key == pygame.K_SPACE:
self.gravity_store = 0
self.rect.y -= JUMP_POWER
self.jump_sfx.play()
def gravity(self):
self.gravity_store += GRAVITY
self.rect.y += self.gravity_store
print(int(self.gravity_store), int(clock.get_fps()))
def collision(self):
if self.rect.colliderect(ground_rect):
GAME_ACTIVE = 0
def update(self):
self.player_input()
self.gravity()
self.collision()
class Obstacles(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("assets/images/obstacles/pipe-green.png")
def obstacle_spawn(self):
#I want to access player position here
print(player.rect.x)
self.rect = self.image.get_rect(midleft = (0, 0))
def update(self):
self.obstacle_spawn()
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Mama Bird")
clock = pygame.time.Clock()
background_surf = pygame.image.load("assets/images/background/background-day.png")
ground_surf = pygame.image.load("assets/images/background/base.png")
ground_rect = ground_surf.get_rect(topleft = (0, HEIGHT-112))
player = pygame.sprite.GroupSingle()
player.add(Player())
obstacle = pygame.sprite.Group()
obstacle.add(Obstacles())
OBSTACLESPAWN = pygame.USEREVENT + 1
pygame.time.set_timer(OBSTACLESPAWN, OBSTACLE_INTERVAL)
while True:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
pygame.quit()
exit()
SCREEN.blit(background_surf, (0,0))
player.draw(SCREEN)
player.update()
for event in event_list:
if event.type == OBSTACLESPAWN and GAME_ACTIVE == 1:
obstacle.update()
obstacle.draw(SCREEN)
SCREEN.blit(ground_surf, ground_rect)
pygame.display.update()
clock.tick(FPS)
I tried to see if it would access the player position using "print(player.rect.x)". And got this error:
Traceback (most recent call last):
File "c:\Users\46722\Documents\Programmering\Python\yesman\Pygame\Mama Bird\main.py", line 98, in <module>
obstacle.update()
File "C:\Users\46722\AppData\Local\Programs\Python\Python310\lib\site-packages\pygame\sprite.py", line 539, in update
sprite.update(*args, **kwargs)
File "c:\Users\46722\Documents\Programmering\Python\yesman\Pygame\Mama Bird\main.py", line 65, in update
self.obstacle_spawn()
File "c:\Users\46722\Documents\Programmering\Python\yesman\Pygame\Mama Bird\main.py", line 61, in obstacle_spawn
print(player.rect.x)
AttributeError: 'GroupSingle' object has no attribute 'rect'
PS C:\Users\46722\Documents\Programmering\Python\yesman\Pygame\Mama Bird>
player is an instance of pygame.sprite.Group():
player = pygame.sprite.GroupSingle()
player.add(Player())
Use the sprite property to access the pygame.sprite.Sprite in a pygame.sprite.GroupSingle:
print(player.rect.x)
print(player.sprite.rect.x)
Related
This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
How to get keyboard input in pygame?
(11 answers)
Closed 3 months ago.
I am new to Pygame and am facing issues getting the event handler to register my keystrokes to move my player when I call that class under the event handler in the main loop
I run this code and the level and player render correctly but not able to move my player. I've looked at various other answers such as adding pygame.event.pump() but this doesn't work and shouldn't be needed as it should be handled by the main event handler
import pygame, sys
# Settings
size = width, height = (800, 800)
FPS = 60
road_w = width//1.6
roadmark_w = width//80
right_lane = width/2 + road_w/4
left_lane = width/2 - road_w/4
speed = 5
player_start = right_lane, height*0.8
enemy_start = left_lane, height*0.2
# Create Player Class
class Player(pygame.sprite.Sprite):
def __init__(self,pos,groups):
super().__init__(groups)
self.image = pygame.image.load("car.png").convert_alpha()
self.rect = self.image.get_rect(center = pos)
self.direction = pygame.math.Vector2(0,0)
self.speed = 5
def input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
self.direction.y = -1
elif keys[pygame.K_DOWN]:
self.direction.y = 1
else:
self.direction.y = 0
if keys[pygame.K_RIGHT]:
self.direction.x = 1
print(self.direction.x)
elif keys[pygame.K_LEFT]:
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)
#Create Level Class
class Level:
def __init__(self):
# get display surface
self.display_surface = pygame.display.get_surface()
#Sprite group set up
self.player_sprite = pygame.sprite.Group()
def create_map(self):
pygame.draw.rect(self.display_surface,(50, 50, 50),\
(width/2-road_w/2, 0, road_w, height))
pygame.draw.rect(self.display_surface,(255, 240, 60),\
(width/2 - roadmark_w/2, 0, roadmark_w, height))
pygame.draw.rect(self.display_surface,(255, 255, 255),\
(width/2 - road_w/2 + roadmark_w*2, 0, roadmark_w, height))
pygame.draw.rect(self.display_surface,(255, 255, 255),\
(width/2 + road_w/2 - roadmark_w*3, 0, roadmark_w, height))
def run(self):
# Update and draw level
self.create_map()
self.player = Player(player_start,[self.player_sprite])
self.player_sprite.draw(self.display_surface)
self.player_sprite.update
# Create Game Class
class Game:
def __init__(self):
# Setup
pygame.init()
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Car Game')
self.clock = pygame.time.Clock()
self.level = Level()
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.screen.fill((60,220,0))
self.level.run()
pygame.display.update()
self.clock.tick(FPS)
# Run Game
if __name__ == '__main__':
game = Game()
game.run()
Car.png
from numpy import place
import pygame, sys ,random as ran
start = True
class Player(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__()
self.attack_animation = False
self.sprites_1 = []
self.sprites_1.append(pygame.image.load('crossHair.png'))
self.sprites_1.append(pygame.image.load('crossHair_2.png'))
self.sprites_1.append(pygame.image.load('crossHair_3.png'))
self.sprites_1.append(pygame.image.load('crossHair_4.png'))
self.sprites_1.append(pygame.image.load('crossHair_5.png'))
self.sprites_1.append(pygame.image.load('FIRE.png'))
self.current_sprite = 0
self.image = self.sprites_1[self.current_sprite]
self.image.set_colorkey('white')
for items in self.sprites_1:
items.set_colorkey('white')
self.rect = self.image.get_rect()
self.rect.topleft = [pos_x,pos_y]
def attack(self):
self.attack_animation = True
self.image.set_colorkey('white')
def update(self,speed):
self.image.set_colorkey('white')
if self.attack_animation == True:
self.current_sprite += speed
if int(self.current_sprite) >= len(self.sprites_1):
self.current_sprite = 0
self.attack_animation = False
print('shot')
self.image = self.sprites_1[int(self.current_sprite)]
# self.image = self.sprites_1[int(self.current_sprite)]
mouse = pygame.mouse.get_pos()
self.rect = mouse
class enemy(pygame.sprite.Sprite):
def __init__(self, pos_x, pos_y):
super().__init__()
self.image = pygame.image.load('sp_1.png')
self.rect = self.image.get_rect()
self.rect.center = [pos_x, pos_y]
self.image.set_colorkey((255,255,255))
# General setup
pygame.init()
pygame.mouse.set_visible(0)
clock = pygame.time.Clock()
# Game Screen
screen_width = 400
screen_height = 400
mouse = pygame.mouse.get_pos()
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption("Sprite Animation")
# Creating the sprites and groups
moving_sprites = pygame.sprite.Group()
crosshair = Player(mouse[0],mouse[1])
enemy_x = ran.randint(18,387)
enemy_y = ran.randint(18,387)
print(enemy_x,enemy_y)
enemy_ = enemy(enemy_x,enemy_y)
moving_sprites.add(enemy_,crosshair)
while True:
# Player.set_pos(*pygame.mouse.get_pos())
globals()['mouse'] = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]:
crosshair.attack()
enemy.checkCollision(enemy,crosshair,enemy_)
# enemy.attack()
# pygame.sprite.spritecollide(Player,enemy,True)
screen.fill((120,220,150))
#this is causing the problem
get_hit = pygame.sprite.spritecollide(Player,enemy,True)
# Drawing
screen.set_colorkey('white')
moving_sprites.draw(screen)
moving_sprites.update(0.08)
pygame.display.flip()
clock.tick(120)
the movement i check for sprite collision it gives me error sayin' :
File "c:\Users\pc\VS_PYTHON_PY\pyGame.py", line 82, in
get_hit = pygame.sprite.spritecollide(Player,enemy,True)
File "C:\python-py\lib\site-packages\pygame\sprite.py", line 1682, in spritecollide
default_sprite_collide_func = sprite.rect.colliderect
AttributeError: type object 'Player' has no attribute 'rect'
why is that happening can you solve this pls
The arguments of pygame.sprite.spritecollide must be instance objects of Sprite and Group classes. Player and enemy are a classes, however crosshair and enemy_ are objects. Create a Group for the enemies and detect the collisions between the crosshair and the Group of enemies:
crosshair = Player(mouse[0],mouse[1])
enemyGroup = pygame.sprite.Group()
enemy_ = enemy(enemy_x,enemy_y)
enemyGroup.add(enemy_)
while True:
# [...]
get_hit = pygame.sprite.spritecollide(crosshair, enemyGroup, True)
See also How do you program collision in classes? and How do I detect collision in pygame?.
Also see Style Guide for Python Code: Class names should normally use the CapWords convention. The name of the class should be Enemy instead of enemy.
This question already has answers here:
Created multiple instances of the same image using a loop, can I move each instance of the image independently?
(1 answer)
Why do group lists in pygame have to have "update" functions, and not any other?
(1 answer)
Closed 2 years ago.
I am new to Python and got stuck with some Pygame code (see below traceback and complete code). I don't understand why the bullet object has no rect attribute when I iterate over the items stored in self.bullets. Any help or pointers would be hugely appreciated. Thanks!
Traceback
Traceback (most recent call last):
File "/Users/svengerlach/PycharmProjects/AlienInvasion/practice_12_6.py", line 82, in <module>
game.game_loop()
File "/Users/svengerlach/PycharmProjects/AlienInvasion/practice_12_6.py", line 22, in game_loop
self._bullet_update()
File "/Users/svengerlach/PycharmProjects/AlienInvasion/practice_12_6.py", line 54, in _bullet_update
if bullet.rect.left > self.screen_rect.right:
AttributeError: 'Bullet' object has no attribute 'rect'
Complete Code
import pygame
import sys
class Game:
def __init__(self):
[...]
self.bullets = pygame.sprite.Group()
def game_loop(self):
while True:
self._check_user_inputs()
self._ship_update()
self._bullet_update()
self._screen_update()
def _check_user_inputs(self):
for event in pygame.event.get():
elif event.type == pygame.KEYDOWN:
[...]
elif event.key == pygame.K_SPACE:
new_bullet = Bullet(self)
self.bullets.add(new_bullet)
elif event.type == pygame.KEYUP:
[...]
def _ship_update(self):
[...]
def _bullet_update(self):
self.bullets.update()
for bullet in self.bullets.copy():
if bullet.rect.left > self.screen_rect.right:
self.bullets.remove(bullet)
def _screen_update(self):
[...]
for bullet in self.bullets.sprites():
bullet.draw_bullet()
pygame.display.flip()
class Bullet(pygame.sprite.Sprite):
def __init__(self, ai_game):
super().__init__()
self.screen = ai_game.screen
self.ship_rect = ai_game.ship_rect
self.bullet_rect = pygame.Rect(0, 0, 15, 3)
self.bullet_rect.midleft = self.ship_rect.midright
def update(self):
self.bullet_rect.x += 5
def draw_bullet(self):
pygame.draw.rect(self.screen, (60, 60, 60), self.bullet_rect)
if __name__ == '__main__':
game = Game()
game.game_loop()
bullet has no attribute rect, but it has an attribute bullet_rect. I recommend to rename bullet_rect to rect. This way you can use pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect for the position.
Furthermore use pygame.sprite.Sprite.kill():
The Sprite is removed from all the Groups that contain it. [...]
Example:
class Bullet(pygame.sprite.Sprite):
def __init__(self, ai_game):
super().__init__()
self.image = pygame.Surface((15, 3))
self.image.fill((60, 60, 60))
self.rect = self.image.get_rect(midleft = ai_game.ship_rect.midright)
def update(self):
self.rect.x += 5
class Game:
def __init__(self):
# [...]
self.bullets = pygame.sprite.Group()
def game_loop(self):
while True:
self._check_user_inputs()
self._ship_update()
self._bullet_update()
self._screen_update()
def _check_user_inputs(self):
for event in pygame.event.get():
elif event.type == pygame.KEYDOWN:
# [...]
elif event.key == pygame.K_SPACE:
self.bullets.add(Bullet(self))
elif event.type == pygame.KEYUP:
# [...]
def _bullet_update(self):
self.bullets.update()
for bullet in self.bullets:
if bullet.rect.left > self.screen_rect.right:
bullet.kill()
def _screen_update(self):
# [...]
self.bullets.draw(ai_game.screen)
pygame.display.flip()
Here is my code so far.
import pygame
import os
import sys
#start pygame
pygame.init()
#start the game and create the backround
window_width = 1920
window_height = 1010
size = (window_width, window_height)
screen = pygame.display.set_mode(size)
#put the name of the game here
pygame.display.set_caption('Le Epic Game')
#create the player
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('C:\\Users\\Dev\\Documents\\Pythontextgame\\Sprites\\temporaryplayer.jpg').convert()
self.image.set_colorkey((255, 255, 255))
self.rect = self.image.get_rect()
self.rect.centerx = window_width / 2
self.rect.bottom - window_height / 2
self.speedx = 0
def moveRight(self, pixels):
self.rect.x += pixels
def moveLeft(self, pixels):
self.rect.x -= pixels
def update(self):
self.rect.x += self.speedx
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
#game loop
FPS = 60
clock = pygame.time.Clock()
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type==pygame.KEYDOWN:
if event.key==pygame.K_ESCAPE:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
Player.moveLeft(5, 5)
if keys[pygame.K_d]:
Player.moveRight(5, 5)
all_sprites.update()
background_image = pygame.image.load('C:\\Users\\Dev\\Documents\\Pythontextgame\\backrounds\\Start.jpg').convert()
screen.blit(background_image, [0, 0])
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
But when I run this program and then press the a or d button I get this.
Traceback (most recent call last):
File "C:\Users\Dev\Documents\Pythontextgame\start.py", line 63, in <module>
Player.moveRight(5, 5)
File "C:\Users\Dev\Documents\Pythontextgame\start.py", line 31, in moveRight
self.Rect.x += pixels AttributeError: 'int' object has no attribute 'Rect'
I've tried looking up info about this, but none of it has been helpful so far. I'm also wondering why it hasn't done this before, as those aren't the only times I used self.rect. All help would be appreciated.
Player is the class. You have to call the moveLeft respectively moveRight method of the object player (e.g.: player.moveLeft(5)). player is a instance of Player:
(See Method Objects respectively Instance Objects)
running = True
while running:
# [...]
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
player.moveLeft(5)
if keys[pygame.K_d]:
player.moveRight(5)
I am trying to learn pygame by replicating and examining this: https://www.wikihow.com/Program-a-Game-in-Python-with-Pygame#Adding_a_Player_Object_sub
however when I run either the original version(step 4) as seen above or my code
it brings me a black screen and this error:
Traceback (most recent call last):
File "C:/Users/Mohamed/Desktop/mopy/pys/first pycharm.py", line 77, in <module>
game().gameloo()
File "C:/Users/Mohamed/Desktop/mopy/pys/first pycharm.py", line 60, in gameloo
self.handle()
File "C:/Users/Mohamed/Desktop/mopy/pys/first pycharm.py", line 74, in handle
for event in pygame.event.get():
pygame.error: video system not initialized
here is my code:
import pygame
from pygame.locals import *
pygame.init()
resolution = (400, 350)
white = (250, 250, 250)
black = (0, 0, 0)
red = (250, 0, 0)
green = (0, 250, 0)
screen = pygame.display.set_mode(resolution)
class Ball:
def __init__(self, xPos=resolution[0] / 2, yPos=resolution[1] / 2, xVel=1, yVel=1, rad=15):
self.x = xPos
self.y = yPos
self.dx = xVel
self.dy = yVel
self.radius = rad
self.type = "ball"
def draw(self, surface):
pygame.draw.circle(surface, black, (int(self.x), int(self.y)), self.radius)
def update(self):
self.x += self.dx
self.y += self.dy
if (self.x <= 0 or self.x >= resolution[0]):
self.dx *= -1
if (self.y <= 0 or self.y >= resolution[1]):
self.dy *= -1
class player:
def __init__(self, rad=20):
self.x = 0
self.y = 0
self.radius = rad
def draw(self, surface):
pygame.draw.circle(surface, red, (self.x, self.y))
ball = Ball()
class game():
def __init__(self):
self.screen = pygame.display.set_mode(resolution)
self.clock = pygame.time.Clock()
self.gameobjct = []
self.gameobjct.append(Ball())
self.gameobjct.append(Ball(100))
def handle(self):
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
def gameloo(self):
self.handle()
for gameobj in self.gameobjct:
gameobj.update()
screen.fill(green)
for gameobj in self.gameobjct:
gameobj.draw(self.screen)
pygame.display.flip()
self.clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
game().gameloo()
You've initialized the window twice pygame.display.set_mode(). Remove the global window initialization, but keep and use the window set to the .screen attribute of the class game.
The method handle should only do the event loop, but the method gameloo should contain the main loop. Inside the main loop the events have to be handled by self.handle():
screen = pygame.display.set_mode(resolution)
class game():
def __init__(self):
self.screen = pygame.display.set_mode(resolution)
self.clock = pygame.time.Clock()
self.gameobjct = []
self.gameobjct.append(Ball())
self.gameobjct.append(Ball(100))
def handle(self):
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
def gameloo(self):
while True:
self.handle()
for gameobj in self.gameobjct:
gameobj.update()
self.screen.fill(green)
for gameobj in self.gameobjct:
gameobj.draw(self.screen)
pygame.display.flip()
self.clock.tick(60)
game().gameloo()