When I run the following code, I get this error
reindeer.moveUp(screen)
File "C:\Users\adity\Desktop\Python\CPT.py", line 38, in moveUp
self.y = self.y - 3
AttributeError: 'pygame.Surface' object has no attribute 'y'
I want to move the rectangle up or down every time the user presses w or s using methods in the reindeer class. Is it because of something wrong with the methods?
Why does the program not know what y is? I assigned it in the list of attributes for the class.
import pygame
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
size = (1000, 800)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
screen.fill(WHITE)
class Reindeer():
def __init__(self):
self.color = (255,0,0)
self.y_move = 3
self.x = 100
self.y = 100
self.width = 100
self.length = 100
def draw(screen, self):
pygame.draw.rect(screen, color, [self.x,self.y,self.width,self.length], 0)
def moveDown(screen, self):
self.y = self.y + 3
pygame.draw.rect(screen, self.color, [self.x,self.y,self.width, self.length], 0)
def moveUp(screen, self):
self.y = self.y - 3
pygame.draw.rect(screen, self.color, [self.x,self.y,self.width,self.length], 0)
reindeer = Reindeer()
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
reindeer.moveDown(screen)
elif event.key == pygame.K_s:
reindeer.moveUp(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
I finally dug down to it, by (sigh) reading the code. You have your method parameters in the wrong order: the first parameter is, by definition, the invoking object. Switch your method signatures:
def moveDown(self, screen):
... and the same for all others.
Related
I'm trying to learn OOP but my pygame window wont update with the background I'm trying to put in. The gameObject class is in another file. Filling it with white color also isn't working and I don't know why. I was able to display a background on another project I did but I cant now and I have no idea what's different. I have compared the code and they seem like they should be doing the same thing.
gameObject.py
import pygame
class GameObject:
def __init__(self, x, y, width, height, image_path):
self.background= pygame.image.load(image_path)
self.background = pygame.transform.scale(self.background, (width, height))
self.x = x
self.y = y
self.width = width
self.height = height
main.py
import pygame
from gameObject import GameObject
pygame.init()
class Player(GameObject):
def __init__(self, x, y, width, height, image_path, speed):
super().__init__(x, y, width, height, image_path)
self.speed = speed
def move(self, direction, max_height):
if (self.y >= max_height - self.height and direction > 0) or (self.y <= 0 and direction < 0):
return
self.y += (direction * self.speed)
class Game:
def __init__(self):
self.width = 800
self.height = 800
self.color = (255, 255, 255)
self.game_window = pygame.display.set_mode((self.width, self.height))
self.clock = pygame.time.Clock()
self.background = GameObject(0, 0, self.width, self.height, 'assets/background.png')
self.player1 = Player(375, 700, 50, 50, 'assets/player.png', 10)
self.level = 1.0
def draw_objects(self):
self.game_window.fill(self.white_color)
self.game_window.blit(self.background.image, (self.background.x, self.background.y))
pygame.display.update()
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
self.draw_objects()
self.clock.tick(60)
game = Game()
game.run_game_loop()
quit()
I have tried basic research on it and looking at other code that uses a custom background with pygame
It is a matter of indentation. self.draw_objects() must be called in the application loop not after the application loop:
class Game:
# [...]
def run_game_loop(self):
gameRunning = True
while gameRunning:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if gameRunning == False:
pygame.quit()
# INDENTATION
#-->|
self.draw_objects()
self.clock.tick(60)
Your loop never actually does anything but clear the event queue looking for pygame.QUIT.
You need to indent the calls to self.draw_objects() and self.clock.tick(60) so they are inside the loop.
This question already has an answer here:
Python only running while loop once
(1 answer)
Closed 2 years ago.
This is my code for my game. I am trying to display a rectangle i can move with wasd or arrow keys. But when I run it the window is just black and that's it. No rectangle.
import pygame
class window:
def __init__(self, height, width):
self.height = height
self.width = width
window.height = 800
window.width = 600
class Player(object):
def __init__(self):
self.rect = pygame.rect.Rect((64, 54, 16, 16))
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_LEFT]:
self.rect.move_ip(-1, 0)
def draw(self, surface):
# Im guessing this is where the problem is
screen.fill(255, 255, 255)
pygame.draw.rect(screen, (0, 0, 128), self.rect)
#making thi window
def makeWindow():
pygame.init()
screen = pygame.display.set_mode((window.height, window.width))
# pygame loop
def loop():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if __name__ == "__main__":
makeWindow()
player = Player()
loop()
To move the player with wasd, you have to evaluate the state of the keys in Player.handle_keys and to change the position of self.rect:
class Player(object):
# [...]
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_a]:
self.rect.move_ip(-1, 0)
if key[pygame.K_d]:
self.rect.move_ip(1, 0)
if key[pygame.K_w]:
self.rect.move_ip(0, -1)
if key[pygame.K_s]:
self.rect.move_ip(0, 1)
The argument to pygame.Surface.fill() has to be a tuple with 3 or 4 arguments:
screen.fill(255, 255, 255)
screen.fill((255, 255, 255))
screen has to be a variable in global namespace. Use the global statement:
def makeWindow():
global screen
pygame.init()
screen = pygame.display.set_mode((window.height, window.width))
In the main main application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
def loop():
running = True
while running:
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# update position of player
player.handle_keys()
# clear display
screen.fill((255, 255, 255))
# draw scene
player.draw(screen)
# update display
pygame.display.flip()
See the complete example code:
import pygame
class window:
def __init__(self, height, width):
self.height = height
self.width = width
window.height = 800
window.width = 600
class Player(object):
def __init__(self):
self.rect = pygame.rect.Rect((64, 54, 16, 16))
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 1
if key[pygame.K_a]:
self.rect.move_ip(-1, 0)
if key[pygame.K_d]:
self.rect.move_ip(1, 0)
if key[pygame.K_w]:
self.rect.move_ip(0, -1)
if key[pygame.K_s]:
self.rect.move_ip(0, 1)
def draw(self, surface):
# Im guessing this is where the problem is
pygame.draw.rect(surface, (0, 0, 128), self.rect)
#making thi window
def makeWindow():
global screen
pygame.init()
screen = pygame.display.set_mode((window.height, window.width))
# pygame loop
def loop():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255))
player.handle_keys()
player.draw(screen)
pygame.display.flip()
if __name__ == "__main__":
makeWindow()
player = Player()
loop()
I am learning pygame by making a simple game.
Here is the code:
Main script:
import pygame
from gracz2 import SpriteGenerator
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
BLUE = ( 0, 0, 255)
pygame.init()
pygame.display.set_caption("Super Gra!")
screen_height = 720
screen_width = 1280
screen = pygame.display.set_mode((screen_width, screen_height))
all_sprites_list = pygame.sprite.Group()
playerSprite = SpriteGenerator(1,150,150)
playerSprite.rect.x = (screen_width/2 - 75)
playerSprite.rect.y = 550
all_sprites_list.add(playerSprite)
clock = pygame.time.Clock()
mainloop = True
playtime = 0
while mainloop:
for event in pygame.event.get():
# User presses QUIT-button.
if event.type == pygame.QUIT:
mainloop = False
elif event.type == pygame.KEYDOWN:
# User presses ESCAPE-Key
if event.key == pygame.K_ESCAPE:
mainloop = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
playerSprite.moveLeft(8)
if keys[pygame.K_RIGHT]:
playerSprite.moveRight(8)
milliseconds = clock.tick(60)
playtime += milliseconds / 1000.0
all_sprites_list.update()
pygame.display.set_caption("Czas gry: " + str(round(playtime,1)) + " sekund")
# Refresh the screen
screen.fill(BLACK)
all_sprites_list.draw(screen)
screen.blit(playerSprite.image, (playerSprite.rect.x,playerSprite.rect.y))
pygame.display.flip()
print(all_sprites_list.sprites())
print(all_sprites_list)
print(playerSprite.rect.x)
print(playerSprite.rect.y)
pygame.quit()
and another file called "gracz2.py":
import pygame
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
class SpriteGenerator(pygame.sprite.Sprite):
#This class represents a player. It derives from the "Sprite" class in Pygame.
def __init__(self, type, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Pass in the color of the player, and its x and y position, width and height.
# Set the background color and set it to be transparent
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
if type == 1:
self.image = pygame.image.load("sprite-ufo.gif").convert_alpha()
elif type == 2:
self.image = pygame.image.load("sprite-bomb.jpg").convert_alpha()
# Fetch the rectangle object that has the dimensions of the image.
self.rect = self.image.get_rect()
def moveRight(self, pixels):
self.rect.x += pixels
def moveLeft(self, pixels):
self.rect.x -= pixels
It could be done in one file but the code is more readable for me this way.
around line 50 i call all_sprites_list.draw(screen)
which to my understanding should blit all the sprites contained in all_sprites_list but it does nothing.
I have to use screen.blit(playerSprite.image, (playerSprite.rect.x,playerSprite.rect.y))
to manually blit the sprite.
As i am going to add generate lots of sprites later i can't blit them all manually.
Why doesn't all_sprites_list.draw(screen) work as intended?
It's probably a stupid mistake in the code but I am trying to find for over an hour now and I am unable to locate it.
Turns out that when i restart my PC the draw() function works fine.
I don't know what caused it first, sorry for asking without following the first rule of IT troubleshooting first (restart and try again)
PS: thank you furas for your answers
I'm starting to work with classes more and I was trying to translate my old classless code to this new format. Before, I defined my lists as global variables and could draw multiple enemies to the screen with no problem. This time, however, something about working with classes causes the enemies to be drawn and instantly disappear from their position.
Some help or workaround would be greatly appreciated. Here's the code:
import pygame
import sys
import random
import math
pygame.init()
class enemies(object):
enemies = []
def __init__(self, enemy_num, diff, enemy_size):
self.enemy_num = enemy_num
self.diff = diff
self.enemy_s = enemy_size
def add_enemies(self):
counter = 0
if len(self.enemies) < self.enemy_num:
for enemy in range(0, self.enemy_num):
if len(self.enemies) < 5:
self.enemies.append([counter * (self.enemy_s * 0.5), 200, (50, 168, 82)])
elif len(self.enemies) > 5 and len(self.enemies) <= 9:
self.enemies.append([counter * (self.enemy_s * 0.5), 250, (168, 160, 50)])
else:
self.enemies.append([counter * (self.enemy_s * 0.5), 300, (50, 52, 168)])
counter += 1
def move(self, surface):
for enemy in self.enemies:
surface.fill((0, 0, 0))
pygame.draw.rect(surface, enemy[2], (enemy[0], enemy[1], self.enemy_s, self.enemy_s))
pygame.display.update()
class ship(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
def draw_all(self, surface, ship_size):
surface.fill((0, 0, 0))
pygame.draw.rect(surface, self.color, (self.x, self.y, ship_size, ship_size))
pygame.display.update()
def move(self):
keys = pygame.key.get_pressed()
for key in keys:
if keys[pygame.K_LEFT]:
self.x -= 0.2
if keys[pygame.K_RIGHT]:
self.x += 0.2
if keys[pygame.K_UP]:
self.y -= 0.2
if keys[pygame.K_DOWN]:
self.y += 0.2
def main():
width = 800
height = 1000
ship_size = 35
difficulty = 0
enemy_number = 12
enemy_size = 35
player = ship(width / 2, height - 100, (255, 0, 0))
aliens = enemies(enemy_number, difficulty, enemy_size)
screen = pygame.display.set_mode((width, height))
enemy_list = 12
run = True
clock = pygame.time.Clock()
aliens.add_enemies()
while run:
player.draw_all(screen, ship_size)
player.move()
aliens.move(screen)
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
main()
You've to do 1 clear display and 1 display update in the main loop of the application.
Remove .fill() respectively .pygame.display.update from the .move() and .draw_all method. Clear the display once, draw all the objects and then update the display:
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
screen.fill((0, 0, 0))
player.draw_all(screen, ship_size)
player.move()
aliens.move(screen)
pygame.display.update()
Note, you didn't see the enemies, because the display is clear before drawing a single enemy in enemies.move() and it is clear again when drawing the ship in ship.draw_all()
I'm just getting started with PyGame. Here, I'm trying to draw a rectangle, but it's not rendering.
Here's the whole program.
import pygame
from pygame.locals import *
import sys
import random
pygame.init()
pygame.display.set_caption("Rafi's Game")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((700, 500))
class Entity():
def __init__(self, x, y):
self.x = x
self.y = y
class Hero(Entity):
def __init__(self):
Entity.__init__
self.x = 0
self.y = 0
def draw(self):
pygame.draw.rect(screen, (255, 0, 0), ((self.x, self.y), (50, 50)), 1)
hero = Hero()
#--------------Main Loop-----------------
while True:
hero.draw()
keysPressed = pygame.key.get_pressed()
if keysPressed[K_a]:
hero.x = hero.x - 3
if keysPressed[K_d]:
hero.x = hero.x + 3
if keysPressed[K_w]:
hero.y = hero.y - 3
if keysPressed[K_s]:
hero.y = hero.y + 3
screen.fill((0, 255, 0))
#Event Procesing
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#Event Processing End
pygame.display.flip()
clock.tick(20)
self.x and self.y are currently 0 and 0.
Note that this is not a finished program, all it should do is draw a red square on a green background that can be controled by the WASD keys.
Let's look at a portion of your main loop:
while True:
hero.draw()
keysPressed = pygame.key.get_pressed()
if keysPressed[K_a]:
hero.x = hero.x - 3
if keysPressed[K_d]:
hero.x = hero.x + 3
if keysPressed[K_w]:
hero.y = hero.y - 3
if keysPressed[K_s]:
hero.y = hero.y + 3
screen.fill((0, 255, 0))
Inside the Hero class's draw function, you are drawing the rect. In the main loop, you are calling hero.draw(), and then after handling your inputs, you are calling screen.fill(). This is drawing over the rect you just drew. Try this:
while True:
screen.fill((0, 255, 0))
hero.draw()
keysPressed = pygame.key.get_pressed()
....
That will color the entire screen green, then draw your rect over the green screen.
This is more of an extended comment and question than an answer.
The following draws a red square. Does it work for you?
import sys
import pygame
pygame.init()
size = 320, 240
black = 0, 0, 0
red = 255, 0, 0
screen = pygame.display.set_mode(size)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(black)
# Either of the following works. Without the fourth argument,
# the rectangle is filled.
pygame.draw.rect(screen, red, (10,10,50,50))
#pygame.draw.rect(screen, red, (10,10,50,50), 1)
pygame.display.flip()
Check these links:
http://www.pygame.org/docs/ref/draw.html#pygame.draw.rect
And here have a some examples:
http://nullege.com/codes/search?cq=pygame.draw.rect
pygame.draw.rect(screen, color, (x,y,width,height), thickness)
pygame.draw.rect(screen, (255, 0, 0), (self.x, self.y, 50, 50), 1)