'Player' has no attribute 'draw' - python

Trying to make my own game in pygame, and I have encountered an error, that I just cant seem to get around. I incorporated a class into the program, called Player. This class is supposed to hold information regarding the player, (image, input, etc). However when I try to call the class and draw it onto the screen. I get the error, ''Player has no attribute 'draw'''. Without using a class I can just blit it onto the screen, now something is different.
import pygame
from sys import exit
pygame.init()
#player info
x = 450
y = 840
vel = 5
#window info
screen_w = 800
screen_h = 600
# player movement etc
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
player_surf = pygame.image.load('game graphics/player_stand.png').convert_alpha()
#scaled player image
player_surf = pygame.transform.scale(player_surf,(500,500))
self.player_rect = player_surf.get_rect(midbottom = (x,y))
def player_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d] and self.rect.bottomright <= screen_h or self.rect.bottomleft >=screen_w:
x += vel
elif keys[pygame.K_a] and self.rect.bottomright <= screen_h or self.rect.bottomleft >=screen_w:
x -= vel
def update(self):
self.player_input()
# def draw(self):
# pass
#window stuff
screen = pygame.display.set_mode((screen_w,screen_h))
pygame.display.set_caption('Cave In')
#clock
clock = pygame.time.Clock()
#background
cave_surf = pygame.image.load('game graphics/background.png').convert()
cave_surf = pygame.transform.scale(cave_surf, (screen_w,screen_h)).convert()
#game
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((0,0,0))
screen.blit(cave_surf,(0,0))
#here is the problem :/
Player.draw(screen)
Player.update()
pygame.display.update()
My question is, using the Player class, how do I get it to appear on the screen?
Thanks.
EDIT ---------------------->
After watching youtube videos, looking a other programs, and experimenting. I still can not get the character on screen. I have updated my code, and I now have a different error message at the moment. Here is the updated program.
import pygame, random
from sys import exit
pygame.init()
#player info
x = 450
y = 840
vel = 5
health = 5
#window info
screen_w = 800
screen_h = 600
# player movement etc
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.player_surf = pygame.image.load('game graphics/player_stand.png').convert_alpha()
#scaled player image
self.player_surf = pygame.transform.scale(self.player_surf,(500,500))
self.rect = self.player_surf.get_rect(midbottom = (x,y))
self.x_speed = vel
self.health = health
self.direction = 1 #1 = right 0 = left
def player_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
x += vel
elif keys[pygame.K_a]:
x -= vel
def update(self):
self.player_input()
# drawing the player on screen?
def draw_hero(self,screen,hero):
current_hero_sprite =
pygame.transform.flip(current_hero_sprite, True, False)
screen.blit(current_hero_sprite,hero.rect)
pygame.display.update(screen)
#window stuff
screen = pygame.display.set_mode((screen_w,screen_h))
pygame.display.set_caption('Cave In')
pygame.display.set_icon(pygame.image.load('game
graphics/player_stand.png'))
#clock
clock = pygame.time.Clock()
#background
cave_surf = pygame.image.load('game
graphics/background.png').convert()
cave_surf = pygame.transform.scale(cave_surf,
(screen_w,screen_h)).convert()
#game loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill((0,0,0))
screen.blit(cave_surf,(0,0))
screen.blit(Player)
Player.update()
pygame.display.update()
My current error message is, ''line 75 TypeError: argument 1 must be pygame.Surface, not type'' There is similar problems on the on stack overflow/Quora etc. However none seem to really solve the problem?
Probably just a noob mistake.

SOLVED -->
screen.blit(player.player_surf,player.rect)
Thats it...

A class is a template to create (instantiate) an object. First instantiate a new Player object, then you can call methods on it.
# At the beginning, instantiate the player object as defined in the class.
player = Player()
#...
player.draw(screen)
player.update()

Related

OOP Pygame player_x variable changing but no changes happen in display

Hi am pretty new to programming in general so this might be a pretty dumb problem. Am currently trying to learn more about OOP by making a game.
while the value of player_x is changing for some reasons its not moving as I expected.
main.py
import pygame, settings, obstacles, npc, player
from utils import *
pygame.init()
window = pygame.display.set_mode((settings.WIDTH, settings.HEIGHT))
FPS = pygame.time.Clock()
player = player.Player(window)
Loop
run = True
while run:
FPS.tick(settings.FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
settings.PLAYER_X -= 5
print(settings.PLAYER_X)
pygame.display.update()
player.py
import pygame, settings
pygame.init()
class Player():
def __init__(self, window) -> None:
pygame.draw.rect(window, settings.OLIVE, (settings.PLAYER_X, settings.PLAYER_Y, settings.PLAYER_WIDTH, settings.PLAYER_HEIGHT)) # (x, y, width, height)
def player_control(self):
pass
settings.py
WIDTH = 1440
HEIGHT = 720
FPS = 60
PLAYER_X = 100
PLAYER_Y = 200
PLAYER_WIDTH = 50
PLAYER_HEIGHT = 50
OLIVE = (136, 196, 23)
To move your player, you need to:
Render your player in every while-loop
Render your player with the updated PLAYER_X
And to achieve it, you need a few modification in your code:
Create a function to render in your player.py and call it in the loop instead of render a player in __init__, which will only be called once.
Reference settings.PLAYER_X only once in the __init__ in player.py and update the variable of the player object when key are pressed.
At the end of every loop, render the player object.
player.py
import pygame, settings
pygame.init()
class Player():
def __init__(self, window) -> None:
self.window = window
self.color = settings.OLIVE
self.X = settings.PLAYER_X
self.Y = settings.PLAYER_Y
self.W = settings.PLAYER_WIDTH
self.H = settings.PLAYER_HEIGHT
self.render()
def render(self):
pygame.draw.rect(self.window, self.color, (self.X, self.Y, self.W, self.H))
def player_control(self):
pass
main.py
import pygame, settings, player
pygame.init()
window = pygame.display.set_mode((settings.WIDTH, settings.HEIGHT))
FPS = pygame.time.Clock()
player = player.Player(window)
run = True
while run:
FPS.tick(settings.FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
player.X -= 5
print(player.X)
window.fill((0, 0, 0))
player.render()
pygame.display.update()

How to draw an object to the screen when receiving input from within a class [duplicate]

This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 8 months ago.
So I'm working on a simple game in pygame and I have a file named players.py that contains a Player class and a PlayerAttack class because I want to have the projectiles be their own object. Here is some code from my players.py
import pygame
import gametools
class PlayerAttack(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.bullet_img = gametools.smoothscale2x(pygame.image.load('sprites/player/player-bullet.png')).convert_alpha()
self.image = self.bullet_img
self.rect = self.image.get_rect(center = (400, 300))
class Player(pygame.sprite.Sprite):
'''The Main player class'''
def __init__(self):
super().__init__()
self.player_image_center = gametools.smoothscale2x(pygame.image.load('sprites/player/player.png')).convert_alpha()
self.player_image_left = gametools.smoothscale2x(pygame.image.load('sprites/player/player-left.png')).convert_alpha()
self.player_image_right = gametools.smoothscale2x(pygame.image.load('sprites/player/player-right.png')).convert_alpha()
self.player_image = [self.player_image_left, self.player_image_center, self.player_image_right]
self.player_index = 1
self.image = self.player_image[self.player_index]
self.rect = self.image.get_rect(center = (400, 500))
self.vector = pygame.math.Vector2()
self.velocity = 5
self.bullet = pygame.sprite.Group()
self.bullet.add(PlayerAttack())
def player_input(self):
keys = pygame.key.get_pressed()
# player movement
if keys[pygame.K_UP]:
self.vector.y = -1
elif keys[pygame.K_DOWN]:
self.vector.y = 1
else:
self.vector.y = 0
if keys[pygame.K_LEFT]:
self.vector.x = -1
elif keys[pygame.K_RIGHT]:
self.vector.x = 1
else:
self.vector.x = 0
# attacks
if keys[pygame.K_x]:
return self.bullet.draw(screen)
def move(self, velocity):
if self.vector.magnitude() != 0:
self.vector = self.vector.normalize()
self.rect.center += self.vector * velocity
def update(self):
self.player_input()
self.animation_state()
self.move(self.velocity)
If you look in the __init__() method in the Player class you will see that I define self.bullet as an object belonging to the PlayerAttack class. Now if you look inside the player_input() method in the Player class you see that it draws it to the screen surface defined in main.py
import pygame
import gametools
import players
from sys import exit
# initilaization
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Bullet hell')
clock = pygame.time.Clock()
# Player
player = pygame.sprite.GroupSingle()
player.add(players.Player())
x = pygame.sprite.GroupSingle()
# Background
back_surf = pygame.image.load('sprites/backgrounds/background.png').convert()
# main game loop
while True:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
# display background
screen.blit(back_surf, (0, 0))
player.draw(screen)
player.update()
pygame.display.update()
clock.tick(60)
This produces an error because screen is defined in main.py and not in the Player class. So my question is how can I draw an object to the screen when receiving input from within the class. Or is there a better way to go about this?

Can't move character in pygame

I am trying to move my character (a spaceship) in pygame but what I have done so far has not worked. Everything runs and it displays the character but it does not move when I press the keys.
class Player:
vel = 10
x = width/2-PLAYER.get_width()/2
y = 450
def __init__(self, width, height):
self.width = width
self.height = height
def draw_player(self, win):
win.blit(PLAYER, (self.x, self.y))
def main():
running = True
clock = pygame.time.Clock()
fps = 30
while running:
bg = Background(0, 0)
bg.draw_background()
sc = Score(f"Score: {score}", WHITE)
sc.draw_score()
player = Player(50, 50)
player.draw_player(win)
pygame.display.set_caption("Space Invaders Game")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
player.x += 1
if keys[pygame.K_LEFT]:
player.x -= 1
pygame.display.flip()
clock.tick(fps)
if __name__ == "__main__":
main()
When you create an instance of a class, the constructor is executed and the object attributes are initialized. Hence, you continuously create a new player in his starting position. You are drawing the player at the same position over and over again. Actually the player is moving, but you never see the movement because a new player is immediately created at the starting position to replace the first player.
You must create the instance object of the Player class before the application loop instead of in the application loop:
def main():
player = Player(50, 50) # <--- ADD
running = True
clock = pygame.time.Clock()
fps = 30
while running:
bg = Background(0, 0)
bg.draw_background()
sc = Score(f"Score: {score}", WHITE)
sc.draw_score()
# player = Player(50, 50) <--- REMOVE
player.draw_player(win)
pygame.display.set_caption("Space Invaders Game")
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
player.x += 1
if keys[pygame.K_LEFT]:
player.x -= 1
pygame.display.flip()
clock.tick(fps)

How to spawn multiple enemies in pygame

So im trying to make a game where the character should dodge enemies which are randomly spawned from above. The problem is, I dont know how to make the Random values different without instanciating another class, which I dont want to do. Also, with Screen.fill(), the enemies wont show up since they're being overlapped by the colour every frame, and if I dont use Screen.fill(), my character would leave a trail everytime it moves. Any Suggestions?
import random
pygame.init()
Running = True
Screen = pygame.display.set_mode((800, 600))
player_img = pygame.image.load('/Users/kevinhadinata/Downloads/ufo.png')
player_updated = pygame.transform.scale(player_img,(60,60))
enemy_list = []
enemy_img = pygame.image.load('/Users/kevinhadinata/Downloads/alien.png')
SPAWNENEMY = pygame.USEREVENT
pygame.time.set_timer(SPAWNENEMY,1000)
class Player:
def __init__(self):
self.ypos = 540
self.xpos = 325
self.height = 60
self.width = 60
self.playerUpdated = player_updated
def create_player(self):
Playerss = pygame.Rect(self.xpos,self.ypos,self.height,self.width)
pygame.draw.ellipse(Screen, (0, 0, 0), Playerss)
Screen.blit(player_updated, (Playerss.x, Playerss.y))
sizee = random.randint(10,40)
randomX = random.randint(0,700)
class Enemy:
def __init__(self):
self.xval = random.randint(0,700)
self.size = random.randint(10,40)
def create_enemy(self):
Enemy = pygame.Rect(self.xval, 0, self.size,self.size)
#enemy_updated = pygame.transform.scale(enemy_img,(self.size,self.size))
enemy_list.append(Enemy)
pygame.draw.ellipse(Screen,(255,255,0),Enemy)
Player = Player()
Enemys = Enemy()
while Running:
Screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Player.xpos -= 20
if event.key == pygame.K_RIGHT:
Player.xpos += 20
if event.type == SPAWNENEMY:
Enemys.create_enemy()
Player.create_player()
pygame.display.update()
It's a good idea to not instantiate a new enemy, because just recycling it back to the top of the screen is enough. This amounts to simply changing the size & x,y.
Some of your code is occluding the Enemy class name with an Enemy variable name. I've changed this variable name to new_enemy.
class Enemy:
def __init__(self):
self.recycle() # set the position & size initially
def recycle( self ):
# start or re-start an enemy position
self.size = random.randint(10,40)
self.xval = random.randint(0,700)
self.yval = -self.size # off the screen-top
self.rect = pygame.Rect( self.xval, self.yval, self.size, self.size )
def draw( self, screen ):
pygame.draw.ellipse( screen, (255,255,0), self.rect )
def create_enemy(self):
global enemy_list
new_enemy = Enemy() # create a new Enemy
enemy_list.append( new_enemy ) # add it to the list
Then in your main loop, you can recycle() any Enemy that goes off-screen.
[...] # in main loop
# draw all the enemies, and re-position any enemies that moved off the screen
for enemy in enemy_list:
enemy.draw( screen )
if ( enemy.ypos > 600 ): # TODO - don't use a fixed size
enemy.recycle() # move back to top
The drawing an spawning code was mixed-up, I have re-arranged this into a separate .draw() function. Using this solves the problem with clearing the screen too. Each frame, the code clears the screen, then repaints all the items.
You need to create a list of enemies and iterate the list in the main loop to draw each enemy. Use randint to randomly place the enemies.
Try this code:
import random, pygame
pygame.init()
Running = True
Screen = pygame.display.set_mode((800, 600))
player_img = pygame.image.load('/Users/kevinhadinata/Downloads/ufo.png')
player_updated = pygame.transform.scale(player_img,(60,60))
enemy_list = []
enemy_img = pygame.image.load('/Users/kevinhadinata/Downloads/alien.png')
SPAWNENEMY = pygame.USEREVENT
pygame.time.set_timer(SPAWNENEMY,1000)
class Player:
def __init__(self):
self.ypos = 540
self.xpos = 325
self.height = 60
self.width = 60
self.playerUpdated = player_updated
def create_player(self):
self.Playerss = pygame.Rect(self.xpos,self.ypos,self.height,self.width)
pygame.draw.ellipse(Screen, (0, 0, 0), self.Playerss)
Screen.blit(player_updated, (self.Playerss.x, self.Playerss.y))
def draw(self): # draw player
Screen.blit(player_updated, (self.xpos,self.ypos))
sizee = random.randint(10,40)
randomX = random.randint(0,700)
class Enemys:
def __init__(self):
#self.xval = random.randint(0,700)
self.size = random.randint(10,40)
def create_enemy(self):
Enemy = pygame.Rect(random.randint(100,700), 0, self.size,self.size)
#enemy_updated = pygame.transform.scale(enemy_img,(self.size,self.size))
enemy_list.append(Enemy)
pygame.draw.ellipse(Screen,(255,255,0),Enemy)
def draw(self): # draw all enemies
for e in enemy_list:
pygame.draw.ellipse(Screen,(255,255,0),e)
Player = Player() # player object
Enemys = Enemys() # collection of enemies
Player.create_player()
while Running:
Screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
Player.xpos -= 20
if event.key == pygame.K_RIGHT:
Player.xpos += 20
if event.type == SPAWNENEMY:
Enemys.create_enemy()
Player.draw() # draw player
Enemys.draw() # draw all enemies
pygame.display.update()

Pygame: Adding a background

I'm making a project for my senior year. Its a game where i can move a user. I would like to add a background that goes behind all the pictures i've blitted. I've searched everywhere but i can't seem to find the solution. Could anybody help?
import pygame
import os
class Player(object):
def __init__(self):
self.image = pygame.image.load("player1.png")
self.image2 = pygame.transform.flip(self.image, True, False)
self.coffee=pygame.image.load("coffee.png")
self.computer=pygame.image.load("computer.png")
self.flipped = False
self.x = 0
self.y = 0
def handle_keys(self):
""" Movement keys """
key = pygame.key.get_pressed()
dist = 5
if key[pygame.K_DOWN]:
self.y += dist
elif key[pygame.K_UP]:
self.y -= dist
if key[pygame.K_RIGHT]:
self.x += dist
self.flipped = False
elif key[pygame.K_LEFT]:
self.x -= dist
self.flipped = True
def draw(self, surface):
if self.flipped:
image = self.image2
else:
image = self.image
surface.blit(image, (self.x, self.y))
surface.blit(self.coffee, (700,500))
surface.blit(self.computer,(0,500))
pygame.init()
screen = pygame.display.set_mode((810, 610)) #creates the screen
player = Player()
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # quit the screen
running = False
player.handle_keys() # movement keys
screen.fill((255,255,255)) # fill the screen with white
player.draw(screen) # draw the player to the screen
pygame.display.update() # update the screen
clock.tick(60) # Limits Frames Per Second to 60 or less
A background image is no different from any other image. Just .blit it first.

Categories

Resources