python won't recognize rect as an attribute - python

I am currently in the process of making a 2D platformer game with procedurally generated levels in pygame, however I am getting the following error messages, which are preventing me from continuing:
Traceback (most recent call last):
File "C:\Users\Win10\Desktop\SCV v3.2.py", line 63, in <module>
main() #calls the main function
File "C:\Users\Win10\Desktop\SCV v3.2.py", line 36, in main
block_object = block_class(0, 5)
File "C:\Users\Win10\Desktop\SCV v3.2.py", line 29, in __init__
self.image.Rect = (32, 32) #block is 32*32 pixels large
AttributeError: 'pygame.Surface' object has no attribute 'Rect'
My first thought was that I had just made some of the classes and functions in the wrong order, however that didn't seem to help, I then tried renaming some of the variables, as well as making sure that I had correctly named all of my variables after this fact. I then went to youtube to see if anyone else was having a similar problem and I found that this works in python 3.4 as I had seen a very similar class work, however I have a feeling that this would only create more problems for the rest of the code as I have only used versions of python from 3.6 to the present.
Here is the code that is having the problem:
import pygame #imports pygame
import time #imports the timer so I can use the tick function to make game 60 fps
import sys #imports system
from pygame import * #imports all pygame files
win_height = 500 #height of the window is 500 pixles
win_width = 500 #width of the window is 500 pixels
red = (255, 0, 0) #makes red a preset colour using rgb
green = (0, 255, 0) #makes green a preset colour using rgb
display = (win_height, win_width) #creates the windown as 500*500 pixels
depth = 32 #prevents infinate recursion
timer = pygame.time.Clock() #creates a timer
flags = 0 #I don't really know what this does, however I have seen in many places it being used, therefore I assumed that it was important
screen = pygame.display.set_mode(display, depth, flags) #loads up a pygame window
class entity(pygame.sprite.Sprite): #makes player a sprite
def __init__(self):
pygame.sprite.Sprite.__init__(self) #sets sprite to initiate
class block_class(entity):
def __init__(self, x, y):
self.image = Surface((32, 32))
self.image.rect = (32, 32) #block is 32*32 pixels large
self.image.fill(Color ("#FF0400")) #block is red
self.image.convert()
self.rect = Rect(x, y, 32, 32)
def main(): #main game function
block_object = block_class(0, 5)
player_object = player_class(0,0)
while 1: #updates the screen so you can see changes like movement
timer.tick(60)
player_object.update()
screen.fill(red) #makes the screen red(will probably be temporary)
pygame.display.update()
class player_class(entity): #defines the player class
def __init__(self, x, y): #x is the players x coordinate, y is player y coordinate
self.xvel = 0 #how fast the player is moving to the left and right
self.yvel = 0 #how fast the player is moving up and down
self.image = Surface((32, 32))
self.image.rect = (32, 32) #player is 32*32 pixels large
self.image.fill(Color ("#00FF33")) #player is green
self.image.convert()
self.rect = Rect(x, y, 32, 32)
def update():
pass
main() #calls the main function

self.image = Surface((32, 32))
You set surface width and height there. There is no rect attr in Surface.
Surface doc

Related

Surface display able to properly represent opacity, but any other surface cannot

I am trying to make a tic-tac-toe game with pygame. An important thing I want is being able to make my images (eg. X and O) slightly translucent for when my user is only hovering over a grid tile. I also use opacity to visually show whose turn it is.
This is what I have tried:
x_tile = pygame.image.load('x_tile').convert()
x_tile.set_alpha(100)
This works fine when I'm blitting x_tile directly onto the display like this:
# This is for simplicity's sake. The actual blit process is all being done in an infinite loop
screen = pygame.display.set_mode((300, 300))
screen.blit(x_file, x_file.get_rect())
But my game is using another image that represents the grid, and that is what I'm blitting onto. So I'm blitting this board onto the display, then blitting the actual X and O tiles on the board.
screen = pygame.display.set_mode((300, 300))
screen.blit(board, board_rect)
board.blit(x_tile, x_tile.get_rect(center=grid[0].center)) # I have a list of Rects that make a grid on the board image. grid[0] is the top left
When I do it that way, x_tile.set_alpha(100) seems to have no effect and I don't know what to do.
Edit: I am using pygame 2.0.1. I'm on Windows 10.
Here is the entire code
import os
import pygame
from pygame.locals import *
# Game constants
WIN_SIZE = WIN_WIDTH, WIN_HEIGHT = 800, 600
BLACK = 0, 0, 0
WHITE = 255, 255, 255
RED = 255, 0, 0
BLUE = 0, 0, 255
# Game functions
class NoneSound:
"""dummy class for when pygame.mixer did not init
and there is no sound available"""
def play(self): pass
def load_sound(file):
"""loads a sound file, prepares it for play"""
if not pygame.mixer:
return NoneSound()
music_to_load = os.path.join('sounds', file)
try:
sound = pygame.mixer.Sound(music_to_load)
except pygame.error as message:
print('Cannot load following sound:', music_to_load)
raise SystemExit(message)
return sound
def load_image(file, colorkey=None, size=None):
"""loads image into game"""
image_to_load = os.path.join('images', file)
try:
image = pygame.image.load(image_to_load).convert()
except pygame.error as message:
print('Cannot load following image:', image_to_load)
raise SystemExit(message)
if colorkey is not None:
if colorkey == -1:
colorkey = image.get_at((0, 0))
image.set_colorkey(colorkey, RLEACCEL)
if size is not None:
image = pygame.transform.scale(image, size)
return image
# Game class
class TTTVisual:
"""Controls game visuals"""
def __init__(self, win: pygame.Surface):
self.win = win
# Load in game images
self.board = load_image('board.png', size=(600, 450), colorkey=WHITE)
self.x_tile = load_image('X_tile.png', size=(100, 100), colorkey=BLACK)
self.o_tile = load_image('O_tile.png', size=(100, 100), colorkey=BLACK)
# Translucent for disabled looking tile
self.x_tile_trans = self.x_tile.copy()
self.o_tile_trans = self.o_tile.copy()
self.x_tile_trans.set_alpha(100)
self.o_tile_trans.set_alpha(100)
# Used to let user know whose turn it is
self.x_turn = pygame.transform.scale(self.x_tile, (50, 50))
self.o_turn = pygame.transform.scale(self.o_tile, (50, 50))
self.x_turn_trans = pygame.transform.scale(self.x_tile_trans, (50, 50))
self.o_turn_trans = pygame.transform.scale(self.o_tile_trans, (50, 50))
self.get_rects()
self.grid = self.setup_grid()
def get_rects(self):
"""Creates coords for some visual game assets"""
self.board_rect = self.board.get_rect(
center=self.win.get_rect().center)
self.x_turn_rect = self.x_turn.get_rect(top=10, left=10)
self.o_turn_rect = self.o_turn.get_rect(top=10, left=WIN_WIDTH-60)
def setup_grid(self):
grid = []
left = 0
top = 150
row = 0
for i in range(9):
if (i != 0) and (i % 3 == 0):
row += 1
left = 0
grid.append(pygame.Rect(left, row*top, 200, 150))
left += 200
return grid
def update_turn_status(self):
"""Updates the X and O tiles on the top left and right to
let user know whose turn it is"""
self.win.blits((
(self.x_turn_trans, self.x_turn_rect),
(self.o_turn, self.o_turn_rect)
))
def update_grid(self):
"""Updates board"""
self.win.blit(self.board, self.board_rect)
# Here is where you could change board to win and see that the tile changes in opacity
self.board.blit(self.x_tile_trans, self.x_tile_trans.get_rect(center=self.grid[0].center))
def update(self):
self.win.fill(WHITE)
self.update_turn_status()
self.update_grid()
pygame.display.flip()
def main():
pygame.init()
win = pygame.display.set_mode(WIN_SIZE)
tttvisual = TTTVisual(win)
tttfunc = TTTFunc(tttvisual)
clock = pygame.time.Clock()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
running = False
tttvisual.update()
pygame.quit()
if __name__ == "__main__":
main()
The issue is caused by the line:
self.board.blit(self.x_tile_trans, self.x_tile_trans.get_rect(center=self.grid[0].center))
You don't blit the image on the display Surface, but on the self.board Surface. When a Surface is blit, it is blended with the target. When you draw on a Surface, it changes permanently. Since you do that over and over again, in every frame, the source Surface appears to by opaque. When you decrease the alpha value (e.g. self.x_tile_trans.set_alpha(5)), a fade in effect will appear.
Never draw on an image Surface. Always draw on the display Surface. Cleat the display at begin of a frame. Draw the entire scene in each frame and update the display once at the end of the frame.
class TTTVisual:
# [...]
def update_grid(self):
"""Updates board"""
self.win.blit(self.board, self.board_rect)
# Here is where you could change board to win and see that the tile changes in opacity
x, y = self.grid[0].center
x += self.board_rect.x
y += self.board_rect.y
self.win.blit(self.x_tile_trans, self.x_tile_trans.get_rect(center=(x, y)))
The typical PyGame 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()

Trouble with rendering background boxes class from a 2d list in pygame

I am trying to make a background of boxes for a simple snake game by iterating through a 2d array and drawing boxes which I've stored as instances of a class BackgroundCube in each part of the array. When I run the program there are no errors, but nothing shows up on the pygame screen.
I've printed the length of each sublist which shows a length of 20, my desired grid size. I've also just printed the entire array which shows what I believe to be instances of the class, something like this: <main.BackgroundCube object at 0x11186e090> would be one entry in the list. So I believe the problem lies in how I'm drawing the rectangles.
python
WIDTH = 400
HEIGHT = 420
screen = pygame.display.set_mode((WIDTH, HEIGHT))
class BackgroundCube:
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
def draw(self, screen):
pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height), 2)
def redrawGameWindow():
for x in range(20):
for y in range(20):
cube2 = background_cube_list[x][y]
cube2.draw(screen)
run = True
background_cube_list = [[0 for x in range(int(WIDTH/20))] for x in range(int((HEIGHT-20)/20))]
while run:
for cube in range(int(WIDTH / 20)):
for cube1 in range(int((HEIGHT - 20) / 20)):
background_cube_list[cube][cube1] = BackgroundCube(cube * 20, cube1 * 20, 20, 20, (144, 144, 144))
clock.tick(30)
redrawGameWindow()
Again, no errors, just a blank white window. Thank you.
You forgot to add
pygame.display.update()
in your main loop. Add it just after redrawGameWindow().
You also need to define clock, which I guess is clock = pygame.time.Clock(). Add it before the main loop.

How to create a sprite from an image

I have two files of code, one with the sprite classing and one. with the main background for my (basic) pygame. I am aiming to load in a png image to use in my background.
class sprite code:
class GRASS (pygame.sprite.Sprite):
def _init_(self):
super()._init_()
self.image = pygame.image.load("grass").convert()
self = self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
main code:
from GRASS import GRASS
pygame.init()
screen = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
FPS = 60
screen.fill(WHITE)
pygame.draw.rect(screen, SKY_BLUE, [0, 0, 20000, 400],0)
pygame.draw.rect(screen, GREEN, [0, 400, 20000, 200],0)
cloud()
grassblock1 = GRASS
grassblock1.x = 10
grassblock1.y = 50
I am aiming for it to show up on the screen in the designated space but it doesn't show up at all. I am not sure if all the code I am using is needed either.
First, Rename the grass file to grass.png.
Then, add the extension .png to the image grass in
self.image = pygame.image.load("grass").convert()

When I am trying to pass an image through pygame, it keeps saying 'pygame.Surface' has no attribute

I have tried everything I can think of to fix this, but I can't seem to find it. I know it is probably a simple fix, but I cannot find what is making this happen. This is the first part of my code :
import pygame, sys, time
from pygame.locals import *
pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
MOVERATE = 5
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 0)
FPS = 40
clock = pygame.time.Clock()
x = 200
y = 150
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super(player, self).__init__()
temp_image = pygame.image.load("stand_down.png").convert_alpha()
self.image_down = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standleft.png").convert_alpha()
self.image_left = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standright.png").convert_alpha()
self.image_right = pygame.transform.scale(temp_image, (100, 200))
self.image = self.image_down
# keep position and size in pygame.Rect()
# to use it in collision checking
self.rect = self.image.get_rect(x=x, y=y)
def draw(self, x, y):
screen.blit(self.image, self.rect)
def handle_event(self):#, event)
self.image = self.image_down.get_rect()
self.image = pygame.Surface((x, y))
key = pygame.key.get_pressed()
if key[K_LEFT]:
self.rect.x -= 50
self.image = self.image_left
if key[K_RIGHT]:
self.rect.x += 50
self.image = self.image_right
class room1():
#bedroom
def __init__(self):
self.x, self.y = 16, WINDOWHEIGHT/2
self.speed = 3
def draw(self):
background = pygame.image.load("bedroom.jpg").convert()
background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
screen.blit(background, (0, 0))
And this is my main function :
def main():
while True:
for event in pygame.event.get():
player.handle_event.get(event)
player.handle_event(screen)
room1.draw(screen)
player.draw(screen, x, y)
pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
main()
I keep getting the same error :
File "C:\Python32\Project3\proj3pt2.py", line 220, in handle_event
self.image = self.image_down.get_rect()
AttributeError: 'pygame.Surface' object has no attribute 'image_down'
I know it's probably an easy fix, but I don't know where to look for it, and how I messed up. If someone could explain that, it would be much appreciated!
When you have an instance and call one of its methods, the instance gets automatically passed as the first argument, self. So if you have a class MyClass and an instance my_instance and you call its handle_event method, it's the same as calling MyClass.handle_event(my_instance).
In your program you never create an instance of the player class and so you're passing the screen as the self argument directly to the class (the screen is actually a pygame.Surface). That means the self in the handle_event method actually refers to the screen surface and since surfaces don't have an image_down attribute, Python raises an error when the self.image_down.get_rect() part is reached.
To fix this problem, you have to create an instance (also called object) of the player class and must not pass an argument to handle_event (unless you add more parameters to the method):
player_instance = player(x_position, y_position)
Then use the instance inside of the while and event loops:
while True:
player_instance.handle_event()
You also have to create an instance of the room1 class instead of using the class directly.
Here's a complete example with some comments about other problems:
import pygame
pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
FPS = 40
clock = pygame.time.Clock()
# Load images once globally and reuse them in the program.
background = pygame.image.load("bedroom.jpg").convert()
background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
temp_image = pygame.image.load("stand_down.png").convert_alpha()
image_down = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standleft.png").convert_alpha()
image_left = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standright.png").convert_alpha()
image_right = pygame.transform.scale(temp_image, (100, 200))
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
super(player, self).__init__()
self.image_down = image_down
self.image_left = image_left
self.image_right = image_right
self.image = self.image_down
# keep position and size in pygame.Rect()
# to use it in collision checking
self.rect = self.image.get_rect(x=x, y=y)
# You don't have to pass x and y, since you already
# use the `self.rect` as the blit position.
def draw(self, screen):
screen.blit(self.image, self.rect)
def handle_event(self):
# These two lines don't make sense.
#self.image = self.image_down.get_rect()
#self.image = pygame.Surface((x, y))
# I guess you want to switch back to image_down.
self.image = self.image_down
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
self.rect.x -= 5
self.image = self.image_left
if key[pygame.K_RIGHT]:
self.rect.x += 5
self.image = self.image_right
class room1():
def __init__(self):
self.x, self.y = 16, WINDOWHEIGHT/2
# Reference to the background image.
self.background = background
def draw(self, screen): # Pass the screen.
screen.blit(self.background, (0, 0))
def main():
# Create player and room instances.
player_instance = player(200, 150)
room1_instance = room1()
while True:
for event in pygame.event.get():
# Users can press the "X" button to quit.
if event.type == pygame.QUIT:
return
player_instance.handle_event()
room1_instance.draw(screen)
player_instance.draw(screen)
# You don't need both update and flip.
# pygame.display.update()
pygame.display.flip()
clock.tick(FPS)
main()
pygame.quit()
Side note: PEP 8 recommends uppercase names for classes, so Player instead of player. Then you could call the instance player.
I suspect you do somewhere something like this
player = player.transform.scale(player.image)
player is Sprite but scale returns Surface - so you replace Sprite with Surface and later you have problems.
(BTW: I saw the same problem in some question few days ago)
If you have to rescale image then do it in __init__ as you already do with some images.
In real game you should create images with correct sizes using any Image Editor so you don't have to use scale()
BTW: in handle_event you do
self.image = self.image_down.get_rect()
self.image = pygame.Surface((x, y))
You assign Rect to Surface (self.image) and later you assing new empty Surface with size x, y. Surface doesn't keep positon, it uses only width, height.
You have self.rect to keep positiona and you already change it with
self.rect.x -= 50
and
self.rect.x += 50
BTW: use UpperCaseNames for classes to make code more readable
class Player(...)
class Room1(...)
Event Stackoverflow knows this rule and it uses light blue color for classes to make code more readable.
More: PEP 8 -- Style Guide for Python Code
BTW: in room1.draw() you read and rescale image again and again - it can slow down program. Do it in room.__init__

making sprites randomly appear

I am trying to have sprites randomly appear on the screen with out using OOP principles
this code is from a ants demo for AI
if randint(1, 10) == 1:
leaf = Leaf(world, leaf_image)
leaf.location = Vector2(randint(0, w), randint(0, h))
world.add_entity(leaf)
world.process(time_passed)
world.render(screen)
pygame.display.update()
Question:
How do I get Sprites on the screen randomly?
I know to blit them
but how without using Object-Oriented
this is the only part my code is missing a way for sprites to randomly appear
this the code to the antstate.py where im getting the code:
http://www.mediafire.com/?5tjswcyl9xt5huj
A sprite is an object. So you need to use some OOP to work with a sprite. Here's an example:
# Sample Python/Pygame Programs
# Simpson College Computer Science
# http://cs.simpson.edu/?q=python_pygame_examples
import pygame
import random
# Define some colors
black = ( 0, 0, 0)
white = ( 255, 255, 255)
# This class represents the ball
# It derives from the "Sprite" class in Pygame
class Block(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.Surface([width, height])
self.image.fill(color)
# Fetch the rectangle object that has the dimensions of the image
# image.
# Update the position of this object by setting the values
# of rect.x and rect.y
self.rect = self.image.get_rect()
# Initialize Pygame
pygame.init()
# Set the height and width of the screen
screen_width=700
screen_height=400
screen=pygame.display.set_mode([screen_width,screen_height])
# This is a list of 'sprites.' Each block in the program is
# added to this list. The list is managed by a class called 'RenderPlain.'
block_list = pygame.sprite.RenderPlain()
for i in range(50):
# This represents a block
block = Block(black, 20, 15)
# Set a random location for the block
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(screen_height)
# Add the block to the list of objects
block_list.add(block)

Categories

Resources