Sprites not appearing correctly onscreen - pygame - python

I'm in a game programming class and I'm supposed to make a game where there are sprites falling down from the top of the screen that you catch or avoid. Right now I'm working on making the objects fall and they were working at first but then I screwed something up because now they appear patchily/randomly disappear while falling down the screen. I've tried changing various things in the code to fix the problem but I've been stuck for a while.
I'm pretty certain that I messed something up either blitting the coal/candy to the screen or adding new ones to fall once others disappear, but I included a large portion of my code just in case something there is messing it up. I'll highlight the likely messed up sections below.
Oh, I also always really appreciate comments on how to make code more concise/efficient, but the teacher expects the code to be similar to how he taught us, so if you do have a specific fix, if it could keep the code similar to how it is right now I'd really appreciate it!
Thank you so much!
#Setting up time/timer
time = 6000
TICKTOCK = 0
pygame.time.set_timer (TICKTOCK+1, 10)
#Class for candy
class Candy:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH - 150)
self.y = random.randint(-1000, 0)
self.image_Candy = pygame.image.load('konpeito.png')
self.height = self.image_Candy.get_height()
self.width = self.image_Candy.get_width()
def collide (self, sprite):
selfRect = pygame.Rect(self.x, self.y, self.width, self.height)
spriteRect = pygame.Rect(sprite.x, sprite.y, sprite.width, sprite.height)
if selfRect.colliderect(spriteRect):
return True
else:
return False
#class for coal
class Coal:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH - 150)
self.y = random.randint(-1000, SCREEN_HEIGHT)
self.image_Coal = pygame.image.load('coal.png')
self.width = self.image_Coal.get_width()
self.height = self.image_Coal.get_height()
def collide (self, sprite):
selfRect = pygame.Rect(self.x, self.y, self.width, self.height)
spriteRect = pygame.Rect(sprite.x, sprite.y, sprite.width, sprite.height)
if selfRect.colliderect(spriteRect):
return True
else:
return False
#class for sootsprite (collects candy and coal)
class Sootsprite:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH)
self.y = random.randint(0, SCREEN_HEIGHT)
self.image_bowl = pygame.image.load('sootsprite.png')
self.height = self.image_bowl.get_height()
self.width = self.image_bowl.get_width()
clock = pygame.time.Clock()
fps = 10
#Creating candies and rocks
bowl = []
for i in range (15):
candyInstance = Candy()
bowl.append(candyInstance)
rocks = []
for i in range (8):
coalInstance = Coal()
rocks.append(coalInstance)
catch = Sootsprite()
playground.fill(cyan)
Game_Over = False
while not Game_Over:
font = pygame.font.SysFont(None, 30)
endfont = pygame.font.SysFont(None, 100)
text = font.render('Points: ' + str(total) + '/15', True, black)
playground.blit(text, (0,0))
timer = font.render('Time remaining: ' + str(time), True, black)
playground.blit(timer, (0, 40))
end = endfont.render("GAME OVER." + str(total) + " POINTS EARNED", True, black)
This is where I blitted things onscreen and potentially screwed up:
playground.blit(catch.image_bowl, (catch.x, catch.y))
playground.blit(candyInstance.image_Candy, (candyInstance.x, candyInstance.y))
playground.blit(coalInstance.image_Coal, (coalInstance.x, coalInstance.y))
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game_Over = True
if event.type == TICKTOCK+1:
time -=1
#ends game when time is over
if time < 0:
playground.blit(end, (300, 400))
#moving sootsprite with mouse
if event.type == MOUSEMOTION:
(catch.x, catch.y) = pygame.mouse.get_pos()
#making candy fall
for candyInstance in bowl:
if candyInstance.x <= 0:
candyInstance.x += 0
elif candyInstance.x >= 0 :
candyInstance.x -=0
if candyInstance.y <= (SCREEN_HEIGHT+150):
candyInstance.y += 20
elif candyInstance.y > (SCREEN_HEIGHT + 150) :
candyInstance.y = -100
this is where I'm removing things and adding new ones and might've messed up:
#removing candy when collected
for candyInstance in bowl:
if candyInstance.collide(catch):
bowl.remove(candyInstance)
total += 1
candyInstance = Candy()
bowl.append(candyInstance)
#making coal fall
for coalInstance in rocks:
if coalInstance.x <= 0:
coalInstance.x += 0
elif coalInstance.x >= 0 :
coalInstance.x -=0
if coalInstance.y <= (SCREEN_HEIGHT + 200):
coalInstance.y += 20
elif coalInstance.y > (SCREEN_HEIGHT + 200) :
coalInstance.y = -100
this is also a place where I removed objects and added new ones:
#removing coal when collected
for coalInstance in rocks:
if coalInstance.collide(catch):
rocks.remove(coalInstance)
total -= 1
coalInstance = Coal()
rocks.append(coalInstance)
pygame.display.flip()
playground.fill(cyan)
clock.tick (fps)
pygame.quit()

You blit only one candy. Use for loop to blit all candies.
for candyInstance in bowl:
playground.blit(candyInstance.image_Candy, (candyInstance.x, candyInstance.y))
You have the same problem with rocks
for coalInstance in rocks:
playground.blit(coalInstance.image_Coal, (coalInstance.x, coalInstance.y))

Related

Conway's Game of Life Gliders break after a few generations

So I tried creating Conway's game of life in python with pygame. I made this without watching any tutorials, which is probably why it is so broken. It seems to be working fine, but when I creates a glider it seems to just break after a few generations. I looked at some other posts about my problem and added their solutions but that didn't make it work either. I know this is a lot to ask for, but can someone at least identify the problem.
Here is my code. I expected the glider to function as do they are supposed to, but it ended up just breaking in a few generations
Code:
main.py:
from utils import *
from grid import Grid
running = True
t = Grid(30)
while running:
pygame.display.set_caption(f'Conways Game of Life <Gen {t.generations}>')
clock.tick(200)
screen.fill(background_colour)
if not t.started:
t.EditMode()
else:
t.Update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()`
grid.py:
import cell
from utils import *
class Grid:
def __init__(self, size):
self.cells = []
self.cellSize = size
self.generations = 0
self.tick = 1
self.started = False
self.GenerateGrid()
def GenerateGrid(self):
x, y = 0, 0
while y < screen.get_height():
while x < screen.get_width():
c = cell.Cell(self, (x,y), self.cellSize)
self.cells.append(c)
x+=self.cellSize
x = 0
y+=self.cellSize
def EditMode(self):
self.Draw()
if self.started:
return
for cell in self.cells:
if pygame.mouse.get_pressed()[0]:
if cell.rect.collidepoint(pygame.mouse.get_pos()):
cell.state = 1
if pygame.mouse.get_pressed()[2]:
if cell.rect.collidepoint(pygame.mouse.get_pos()):
cell.state = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_RETURN]:
self.started = True
def Draw(self):
for cell in self.cells:
cell.Draw()
def Update(self):
self.Draw()
self.tick -= 0.05
if self.tick < 0:
for cell in self.cells:
cell.UpdateState()
for cell in self.cells:
cell.state = cell.nextState
self.tick = 1
self.generations+=1
cell.py
from utils import *
class Cell:
def __init__(self, grid, position:tuple, size):
self.grid = grid
self.size = size
self.position = pygame.Vector2(position[0], position[1])
self.rect = pygame.Rect(self.position.x, self.position.y, self.size, self.size)
self.state = 0
self.nextState = self.state
def Draw(self):
pygame.draw.rect(screen, (0,0,0), self.rect)
if self.state == 0:
pygame.draw.rect(screen, (23,23,23), (self.position.x+4, self.position.y+4, self.size-4, self.size-4))
else:
pygame.draw.rect(screen, (255,255,255), (self.position.x+4, self.position.y+4, self.size-4, self.size-4))
def UpdateState(self):
rect = pygame.Rect(self.position.x-self.size, self.position.y-self.size, self.size*3, self.size*3)
pygame.draw.rect(screen, (0,0,0), rect)
targetCells = []
for c in self.grid.cells:
if rect.colliderect(c.rect):
targetCells.append(c)
livingAmt = 0
for c in targetCells:
if c.rect.x == self.rect.x and c.rect.y == self.rect.y:
continue
if c.state == 1:
livingAmt+=1
if self.state == 1:
if livingAmt > 3 or livingAmt <2:
self.nextState = 0
if self.state ==0:
if livingAmt == 3:
self.nextState =1
utils.py
import pygame
background_colour = (23, 23, 23)
screen = pygame.display.set_mode((900, 900))
clock = pygame.time.Clock()
running = True
Your function UpdateState both counts a cell's neighbors and updates the cell's state. Since you call that function in a loop, both are done together, which does not work, as explained here. You must split the "count" phase from the "update state" phase.

How to create multiple objects of a class with unique name values gathered from a list in a csv file

I'm new to programming and I'm struggling to figure out how to get this to work. I'm trying to build a simple game called "Pet pandemic" and you basically just press start and the "pets" marked by different colored dots roam around on a grid in the window. Some of the pets spawn in with the "virus". While roaming the pets will see if they are within a certain distance from one another and if so they will transmit the virus to the other who doesn't have it already, in turn updating the status of that pet to have the "virus" and there dot image will update to be red. The game will run until every "pet" has the "virus". I'm struggling to implement a way to spawn the "pets" with unique names like "Alex" or "Doug". I would like to use a list of names I have that's in a .csv file for this.
Thank you for your time.
Here are the files:
https://drive.google.com/drive/folders/1tjEY6Eo1nKKtEr0st1CUFkcnBvvbiMn1?usp=sharing
import pygame
import random
import math
import time
# Window settings
WIDTH = 960
HEIGHT = 660
TITLE = "PET PANDEMIC"
FPS = 60
#create window
pygame.init()
screen = pygame.display.set_mode([WIDTH, HEIGHT])
pygame.display.set_caption(TITLE)
clock = pygame.time.Clock()
#Game Stages
START = 0
PLAYING = 1
END = 2
#Define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
BLUE = (132, 201, 217)
# Load fonts
title_font = default_font = pygame.font.Font("fonts/recharge bd.ttf", 60)
default_font = pygame.font.Font(None, 55)
# Load images
has_v_img = pygame.image.load("red_dot.png").convert_alpha()
no_v_img = pygame.image.load("grey_dot.png").convert_alpha()
no_v_mask_img = pygame.image.load("black_dot.png").convert_alpha()
#Game classes
class Pet(pygame.sprite.Sprite):
def __init__(self, name, x, y):
super().__init__()
self.wearing_mask = random.randint(0, 1) # 0 = no, 1 = yes.
self.has_virus = random.randint(0, 6) # 6 = Virus
if self.has_virus == 6:
self.image = has_v_img
elif self.wearing_mask != 1 and self.has_virus != 6:
self.image = no_v_mask_img
else:
self.image = no_v_img
self.rect = self.image.get_rect()
self.rect.center = x, y
self.name = name
self.dir = random.randint(0, 3)
self.is_alive = True
self.print_name()
def print_name(self):
amnt_w_virus = 0
if self.has_virus == 6:
print("Spawned {} ".format(self.name) + "With The Virus!")
amnt_w_virus += 1
else:
print("Spawned {}.".format(self.name))
return amnt_w_virus
def check_distance(self, other):
distance = math.sqrt(((self.x - other.x) ** 2) + ((self.y - other.y) ** 2))
if distance < 6 and self.has_virus == 6:
other.has_virus = 6
print(self.name + " Was In Range Of " + other.name + " And Gave Them The Virus.")
amnt_w_virus += 1
else:
return amnt_w_virus
def roam(self):
while game_running:
if self.is_alive == True:
time.sleep(1.5)
self.dir = random.randint(0, 3)
self.move()
def move(self):
if self.dir == 0:
self.rect.y += 1
elif self.dir == 1:
self.rect.x += 1
elif self.dir == 2:
self.rect.y -= 1
elif self.dir == 3:
self.rect.x -= 1
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.top > HEIGHT:
self.rect.top = HEIGHT
elif self.rect.right > WIDTH:
self.rect.right = WIDTH
print(self.name + " Moved Forward In Direction " + str(self.dir) + " (" + str(self.x) + "," + str(self.y) + ").")
class Players(pygame.sprite.Group):
def __init__(self, *sprites):
super().__init__(*sprites)
def update(self, *args):
super().update(*args)
self.check_distance()
self.roam()
# Setup
def new_game():
global players
#Random Spawn Location Inside Window
start_x = random.randint(0,WIDTH)
start_y = random.randint(0,HEIGHT)
#Open List Of Names To Use For The Pets
f = open("names.csv", "r")
reader = csv.reader(f)
name = []
for row in reader:
name.append(row)
pet = {}
#Here Im trying to spawn the pets and assign them unique names from the list but this code is all messed up
for item in name:
name = '{}'.format(item)
pet[name] = pet.get(name, Pet(name=name))
pets = Pet([name], start_x, start_y)
#making players = a sprite group of all the pets
players = Players(pets)
#trying to calculate the number of pets without the virus
players.amount_alive = len(players) - amnt_w_virus
print(players.amnt_alive)
#grid overlay
def draw_grid(width, height, scale):
for x in range(0, WIDTH, scale):
pygame.draw.line(screen, WHITE, [x, 0], [x, HEIGHT], 1)
for y in range(0, HEIGHT, scale):
pygame.draw.line(screen, WHITE, [0, y], [WIDTH, y], 1)
def display_stats():
infected_text = default_font.render("Infected: " + str(amnt_w_virus), True, WHITE)
rect = infected_text.get_rect()
rect.top = 20
rect.left = 20
screen.blit(infected_text, rect)
non_infected_text = default_font.render("Non-Infected: " + str(players.amount_alive), True, WHITE)
rect = non_infected_text.get_rect()
rect.top = 20
rect.right = WIDTH - 20
screen.blit(non_infected_text, rect)
time_text = default_font.render("Time: " + str(time.time), True, WHITE)
rect = time_text.get_rect()
rect.bottom = HEIGHT - 20
rect.left = 20
screen.blit(time_text, rect)
def start_screen():
screen.fill(BLACK)
title_text = title_font.render(TITLE, True, WHITE)
rect = title_text.get_rect()
rect.centerx = WIDTH // 2
rect.bottom = HEIGHT // 2 - 15
screen.blit(title_text, rect)
sub_text = default_font.render("Press Any Key To Start The Spread", True, WHITE)
rect = sub_text.get_rect()
rect.centerx = WIDTH // 2
rect.top = HEIGHT // 2 + 15
screen.blit(sub_text, rect)
def end_screen():
end_text = default_font.render("GAME OVER, EVERYONE IS INFECTED.", True, WHITE)
rect = end_text.get_rect()
rect.centerx = WIDTH // 2
rect.centery = HEIGHT // 2
screen.blit(end_text, rect)
# Game loop
new_game()
stage = START
running = True
while running:
# Input handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if stage == START:
stage = PLAYING
elif stage == END:
if event.key == pygame.K_r:
new_game()
stage = START
# Game logic
if stage != START:
players.update()
if len(players) == 0:
stage = END
# Drawing Code
screen.fill(BLUE)
draw_grid(960, 660, 20)
players.draw(screen)
display_stats()
pygame.display.flip()
if stage == START:
start_screen()
elif stage == END:
end_screen()
# Update screen
pygame.display.update()
# Limit refresh rate of game loop
clock.tick(FPS)
# Close window and quit
pygame.quit() ```
You are overwriting the object called name:
for item in name:
name = '{}'.format(item) ### BAD BAD BAD BAD BAD
pet[name] = pet.get(name, Pet(name=name))
pets = Pet([name], start_x, start_y)
#making players = a sprite group of all the pets
players = Players(pets)
If you actually wanted to do that then you need to preserve the items in name by converting it to a list.
for item in list(name):
name = '{}'.format(item)
pet[name] = pet.get(name, Pet(name=name))
pets = Pet([name], start_x, start_y)
#making players = a sprite group of all the pets
players = Players(pets)
I'm sure that you didn't actually want to do that though so just use a different variable name (e.g. _name).
for item in name:
_name = '{}'.format(item)
pet[_name] = pet.get(_name, Pet(name=_name))
pets = Pet([_name], start_x, start_y)
#making players = a sprite group of all the pets
players = Players(pets)

how to make collision in flappybird?

Ok, so I need to make a collision between the two pillars to the bird player. Sorry if the code is complicated, I am new to programming.
In the code, there are two pillars that move left and repeat.
I did xpos2, ypos2, xpos, ypos because there are 2 pillars at one moment.
The gap between them is 670 because the picture of the pillars is very big,
so I drew them very high or low - you can't see all the pillar.
What I need to make a collision between each pillar (top or bottom) to the bird.
I tried with colliderect and another pygame func without success.
Thank you.
code
import pygame
import random
size = [900, 504]
wait = pygame.time.Clock()
red = (255, 0, 0)
pygame.init()
class game:
def __init__(self):
self.screen = pygame.display.set_mode((size[0], size[1]))
pygame.display.set_caption("Flappy Bird #yuv")
self.background = pygame.image.load(r"d:\Users\Student\Desktop\background.png").convert()
self.top_pillar = pygame.image.load(r"d:\Users\Student\Desktop\top.png").convert()
self.bottom_pillar = pygame.image.load(r"d:\Users\Student\Desktop\bottom.png").convert()
self.done = False
self.xpos = 400 # XPOS OF THE PILLARS
self.xpos2 = 800 #
self.ypos_top = random.randint(-400, -200) # ypos of the pillar - top
self.ypos_bottom = self.ypos_top + 670 # ypos of the pillar - bottom
self.ypos2_top = random.randint(-400, -200) # ypos of the pillar - bottom
self.ypos2_bottom = self.ypos2_top + 670 # ypos of the pillar - bottom
self.score = 0
def pillars(self):
for i in range(5):
self.xpos -= 1
self.xpos2 -= 1
if self.xpos <= 0:
self.xpos = 800
self.ypos_top = random.randint(-400, -200) # ypos of the pillar - top
self.ypos_bottom = self.ypos_top + 670 # ypos of the pillar - bottom
if self.xpos2 <= 0:
self.xpos2 = 800
self.ypos2_top = random.randint(-400, -200) # ypos of the pillar - bottom
self.ypos2_bottom = self.ypos2_top + 670 # ypos of the pillar - bottom
# def collide(self):
## how the hell i do it ! ? ?! ?! ?! ?!
def scoregame(self):
if bird().x > self.xpos or bird().x > self.xpos2:
self.score += 1
myfont = pygame.font.SysFont('Comic Sans MS', 30)
textsurface = myfont.render('score : ' + str(int(self.score / 39)), True, red)
self.screen.blit(textsurface, (0, 0))
def gameover(self):
font = pygame.font.SysFont(None, 55)
text = font.render("Game Over!", False, red)
self.screen.blit(text, [100, 250])
self.done = True
class bird:
def __init__(self):
self.x = 200
self.y = 350
self.bird = pygame.image.load(r"d:\Users\Student\Desktop\player.png").convert_alpha()
def move_bird(self):
wait.tick(20)
for i in range(3):
self.y += 2
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
for i in range(50):
self.y -= 1
def check_obstacle(self):
if self.y > 478 or self.y < -10: # check if the player touch the top or the bottom of the screen
print('3')
Game.gameover()
Game = game()
birdfunc = bird()
while Game.done == False:
Game.screen.blit(Game.background, (0, 0))
Game.screen.blit(birdfunc.bird, (birdfunc.x, birdfunc.y))
birdfunc.move_bird()
birdfunc.check_obstacle()
Game.screen.blit(Game.top_pillar, (
Game.xpos, Game.ypos_bottom)) # ypos -500 is the start of the top between -400 to -200 XXXXX gap- 200
Game.screen.blit(Game.bottom_pillar, (Game.xpos, Game.ypos_top)) # ypos 500 is the start of the bottom
Game.screen.blit(Game.top_pillar, (Game.xpos2, Game.ypos2_bottom)) # ypos -500 is the start of the top between -400 to -200 XXXXX gap- 200
Game.screen.blit(Game.bottom_pillar, (Game.xpos2, Game.ypos2_top)) # ypos 500 is the start of the bottom
Game.scoregame()
Game.pillars()
pygame.display.flip()
while Game.done == True:
Game.screen.blit(Game.background, (0, 0))
Game.gameover()
You're already pretty close... I see that you've got code for collisions with the top and bottom of the screen already written. You don't need a library to do simple collision handling between objects either, in this case you can probably write your own algorithm.
def check_obstacle(self):
if self.y > 478 or self.y < -10: # check if the player touch the top or the bottom of the screen
print('3')
Game.gameover()
How might you modify this to make the bird collide with pillars?
Here's my initial thought: The pillar edges could be simplified to different values of self.y, so if the bird is outside the range of valid y values in-between the pillars when the pillar goes by (do you have a pillar.x?), it should call Game.gameover(). Drawing a picture and labeling it with coordinates on paper might help you work out the math.

How do i fix the error "TypeError: argument 1 must be pygame.Surface, not list" when making a simple flappy bird game?

Im following a tutorial on youtube for making a flappy bird game with python and pygame. I have done what he's done so far but when i try to run the code i get an error:
TypeError: argument 1 must be pygame.Surface, not list
I really don't know what could be causing the issue.
I have tried googling and found some threads with potenial answers to my question, but because I dont have much experience in python and pygame it's hard for me to understand what other peoples code have in common with mine to fix the problem.
Here is my code:
import pygame
import neat
import time
import random
import os
WIN_WIDTH= 600
WIN_HEIGHT= 800
BIRD_IMGS = [pygame.transform.scale2x(pygame.image.load("imgs/bird1.png")), pygame.transform.scale2x(pygame.image.load("imgs/bird2.png")), pygame.transform.scale2x(pygame.image.load(("imgs/bird3.png")))]
PIPE_IMG = [pygame.transform.scale2x(pygame.image.load("imgs/pipe.png"))]
BASE_IMG = [pygame.transform.scale2x(pygame.image.load("imgs/base.png"))]
BG_IMG = [pygame.transform.scale2x(pygame.image.load("imgs/bg.png"))]
class Bird:
IMGS = BIRD_IMGS
MAX_ROTATION = 25
ROT_VEL = 20
ANIMATION_TIME = 5
def __init__(self,x,y):
self.x=x
self.y=y
self.tilt = 0
self.tick_count = 0
self.velocity = 0
self.height = self.y
self.img_count=0
self.img=self.IMGS[0]
def jump(self):
self.vel=-10.5
self.tick_count = 0
self.height = self.y
def move(self):
self.tick_count +=1
d = self.vel*self.tick_count + 1.5*self.tick_count**2
if d >= 16:
d = 16
if d < 0:
d -= 2
self.y=self.y+d
if d < 0 or self.y < self.height + 50:
if self.tilt < sel.MAX_ROTATION:
self.tilt=self.MAX_ROTATION
else:
if self.tilt>-90:
self.tilt-=self.ROT_VEL
def draw(self,win):
self.img_count+=1
if self.img_count<self.ANIMATION_TIME:
self.img=self.IMGS[0]
elif self.img_count<self.ANIMATION_TIME*2:
self.img=self.IMGS[1]
elif self.img_count<self.ANIMATION_TIME*3:
self.img=self.IMGS[2]
elif self.img_count<self.ANIMATION_TIME*4:
self.img=self.IMGS[1]
elif self.img_count==self.ANIMATION_TIME*4+1:
self.img=self.IMGS[0]
self.img_count=0
if self.tilt <= -80:
self.img=self.IMGS[1]
self.img_count=self.ANIMATION_TIME*2
rotated_image = pygame.transform.rotate(self.img, self.tilt)
new_rect = rotated_image.get_rect(center=self.img.get_rect(topleft=(self.x, self.y)).center)
win.blit(rotated_image, new_rect.topleft)
def get_mask(self):
return pygame.mask.from_surface(self.img)
((((THIS IS WHERE I GET MY ERROR CODE))))))
def draw_window(win, bird):
HERE--> win.blit(BG_IMG, (0,0))
bird.draw(win)
pygame.display.update()
((((ABOVE HERE IS WHERE I GET MY ERROR CODE))))))
def main():
bird=Bird(200,200)
win=pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
run=True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
draw_window(win,bird)
pygame.quit()
quit()
main()
The error is caused, because in
win.blit(BG_IMG, (0,0))
BG_IMG is a list with a single element:
BG_IMG = [pygame.transform.scale2x(pygame.image.load("imgs/bg.png"))]
Get the 1st element of the list to solve the issue (BG_IMG[0]):
win.blit(BG_IMG[0], (0,0))
Of course you can make BG_IMG a single surface rather than a list of surfaces instead:
BG_IMG = pygame.transform.scale2x(pygame.image.load("imgs/bg.png"))
Further self.vel = 0 is missing in the constructor of the class Bird:
class Bird:
# [...]
def __init__(self,x,y):
self.vel = 0
# [...]

trying to use clamp_ip to keep sprites onscreen - pygame

I'm working on a game for class and this is what we've learned to do so far. I'm trying to get the sprites to stay onscreen with clamp_ip, but it keeps giving me an error message that "Butterfly instance has no attribute clamp_ip." Is there a different way I should be keeping the butterflies onscreen?
This first bit is just setting up pygame and the butterfly class (where I included a line to define a rectangle for the butterflies), I've highlighted where I'm guessing the potential errors are below.
This should be ok.
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
playground = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Butterflies')
screenRect = playground.get_rect()
steps = 1
class Butterfly:
def __init__(self):
self.x = random.randint(0, SCREEN_WIDTH)
self.y = random.randint(0, SCREEN_HEIGHT)
self.image_Butterfly = pygame.image.load('butterflya.png')
self.image_ButterflyB = pygame.image.load('butterflyb.png')
self.height = self.image_Butterfly.get_height()
self.width = self.image_Butterfly.get_width()
self.rect = (self.width, self.height)
clock = pygame.time.Clock()
fps = 10
net = []
for i in range (15):
butterflyInstance = Butterfly()
net.append(butterflyInstance)
playground.fill(cyan)
Game_Over = False
while not Game_Over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game_Over = True
This is where I'm guessing I messed up. I tried to use the clamp_ip function at the end of this loop
for butterflyInstance in net:
butterflyInstance.x += random.randint(-10, 10)
butterflyInstance.y += random.randint(-10,10)
if steps % 2 == 0:
playground.blit(butterflyInstance.image_Butterfly, (butterflyInstance.x, butterflyInstance.y))
steps += 1
else:
playground.blit(butterflyInstance.image_ButterflyB, (butterflyInstance.x, butterflyInstance.y))
steps +=1
butterflyInstance.clamp_ip(screenRect)
Thank you so much!
See PyGame doc pygame.Rect()
clamp_ip is pygame.Rect method so you have to use butterflyInstance.rect.clamp_ip()
But you have to use self.rect.x, self.rect.y, self.rect.width, self.rect.height instead of self.x, self.y, self.width, self.height to keep position and size of object.
And use butterflyInstance.rect.x, butterflyInstance.rect.y, butterflyInstance.rect.width, butterflyInstance.rect.height
instead of butterflyInstance.x, butterflyInstance.y, butterflyInstance.width, butterflyInstance.height
PyGame use pygame.Rect in many places - it is usefull. For example: you can use rect.right instead of rect.x + rect.width, or rect.center = screenRect.center to center object on screen.

Categories

Resources