I'm trying to use pygame to make a few balls (circles). The code runs but the circles do not show up. I'm wondering if there is an error somewhere in the ball class or it's in the game function class.
This is the code for the balls class:
import pygame
from pygame.sprite import Sprite
import random
class Ball(Sprite):
def __init__(self, bg_settings, screen, user):
super(Ball,self).__init__()
self.screen = screen
self.bg_settings = bg_settings
self.image = pygame.Surface((bg_settings.ball_radius*2,bg_settings.ball_radius*2))
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.velocityx = random.randint(-1 * bg_settings.ball_speed, bg_settings.ball_speed)
self.velocityy= random.randint(-1 * bg_settings.ball_speed, bg_settings.ball_speed)
self.rect.centerx = random.randint(0,bg_settings.screen_width)
self.rect.centery = random.randint(0,bg_settings.screen_height)
while (self.rect.centerx in range(user.rect.left - 30, user.rect.right + 30) and
self.rect.centery in range(0, user.rect.top + 30)):
self.rect.centerx = random.randint(0,bg_settings.screen_width)
self.rect.centery = random.randint(0,bg_settings.screen_height)
self.speed = bg_settings.ball_speed
self.color = bg_settings.ball_color
self.radius = bg_settings.ball_radius
def draw_ball(self):
pygame.draw.circle(self.image, self.color, (self.rect.centerx,self.rect.centery), self.radius)
def update_ball(self):
if not (self.rect.right < self.screen_rect.right or self.rect.left == self.screen_rect.left):
self.rect.centerx += self.velocityx
if not (self.rect.top == self.screen_rect.top or self.rect.bottom == self.screen_rect.bottom):
self.rect.centery += self.velocityy
Here is relevant code for games functions class (I think just the update screen and creating the balls parts ??):
def update_screen(ai_settings, screen, user, balls, gem):
screen.fill(ai_settings.bg_color)
user.blitme()
for ball in balls.sprites():
ball.draw_ball()
gem.blitme()
pygame.display.flip()
def set_balls(balls, bg_settings, screen, user):
for ball_number in range(bg_settings.num_balls):
new_ball = Ball(bg_settings, screen, user)
balls.add(new_ball)
def update_balls(balls, bg_settings):
balls.update()
for ball in balls.copy():
if ball.rect.left == 0 or ball.rect.right == bg_settings.screen_width:
ball.velocityx = ball.velocityx * -1
elif ball.rect.top == 0 or ball.rect.bottom == bg_settings.screen_height:
ball.velocityy = ball.velocityy * -1
Main loop:
while True:
gf.check_events(user)
gf.update_user(user)
gf.update_screen(bg_settings, screen, user, balls, gem)
gf.update_balls(balls, bg_settings)
Any help is appreciated!
You must use pygame.display.update() at the end of your main event loop to update your screen. After doing this, the window would be updated to reflect the latest state and the circles would appear.
If performance is not an issue, you may want to use pygame.display.flip() instead of pygame.display.update() as I heard that it sometimes has problems with edited zone borders.
The main difference between these two functions is that pygame.display.flip() changes the whole screen while pygame.display.update() only changes parts that it detects changed, so that's why it may have problems
Related
Im making a custom tile system for my game. Its my first time and didnt expect to go that far without a tutorial. So i did my best and made something that works when i render in a tile with the blit method but when i use pygame.sprite.Sprite sprites it doesnt work. I need it to be with pygame's sprite system because it makes it easier doing other stuff and im positive its a rookie mistake i just cant find it.
Code:
# Importing libraries
try:
import pygame
from pygame.locals import *
from time import *
from os import *
from random import *
import sys
print("All Libraries imported successfully \n")
except :
print("Error while importing modules and libraries")
sys.exit()
# Creating Screen
screen_width = 640
screen_height = 640
tile_size = int(screen_width / 10)
screen_res = (screen_width, screen_height)
clock = pygame.time.Clock()
running_fps = 144
screen = pygame.display.set_mode(screen_res)
pygame.display.set_caption(f"GTA Circuit Hack FPS:{running_fps}, {screen_width} x {screen_height}, Tile Size: {tile_size}")
# Loading images
# Background image:
backgroundImg = pygame.image.load("Background.png")
backgroundImg = pygame.transform.scale(backgroundImg, screen_res)
# Not walkable tile image:
noWalkTileImg = pygame.image.load("unwalkTile.png")
noWalkTileImg = pygame.transform.scale(noWalkTileImg, (tile_size, tile_size))
# making tiles
tiles = []
tile_y = 0
tile_x = 0
for i in range(10):
if i > 0:
tile_y += tile_size
for i in range(10):
if i > 0:
tile_x += tile_size
tiles.append((tile_x, tile_y))
tile_x = 0
tile_x = 0
tile_y = 0
# creating object classes
class BadTile (pygame.sprite.Sprite):
def __init__(self, tile):
pygame.sprite.Sprite.__init__(self)
self.image = noWalkTileImg
self.tile = tile
self.rect = self.image.get_rect()
self.x = self.tile[0]
self.y = self.tile[1]
def update(self):
self.x = self.tile[0]
self.y = self.tile[1]
# creating objects
tile1 = BadTile(tiles[99])
game_tiles = pygame.sprite.Group()
game_tiles.add(tile1)
run = True
while run:
clock.tick(running_fps)
screen.blit(backgroundImg, (0,0))
# rendering
game_tiles.update()
game_tiles.draw(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
print ("Exited with no errors")
sys.exit()
Images:
pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.
The latter delegates to the update method of the contained pygame.sprite.Sprites — you have to implement the method. See pygame.sprite.Group.update():
Calls the update() method on all Sprites in the Group. [...]
The former uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects — you have to ensure that the pygame.sprite.Sprites have the required attributes. See 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. [...]
So you need to set self.rect.x and self.rect.y. Instead of self.x and self.y. You don't need self.x and self.y at all:
class BadTile (pygame.sprite.Sprite):
def __init__(self, tile):
pygame.sprite.Sprite.__init__(self)
self.image = noWalkTileImg
self.tile = tile
self.rect = self.image.get_rect()
self.rect.x = self.tile[0]
self.rect.y = self.tile[1]
def update(self):
self.rect.x = self.tile[0]
self.rect.y = self.tile[1]
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.
This question already has answers here:
How do I create animated sprites using Sprite Sheets in Pygame?
(1 answer)
Invalid destination position for blit error, not seeing how
(1 answer)
Closed 2 years ago.
Alright, so I got some extremely simple code going on here, any comments/suggestions are recommended. Keep in mind, SIMPLE, in other words short and concise. thnx.
My problem is loading an image from a png file. So for example i got a couple of images in the file, and i want only one row to be loaded when the user presses for example, the right arrow key. Basically i have 4 rows, 2 or 3 columns 4 rows for each arrow key respectively
#
import pygame, time, random
pygame.init()
HEIGHT = 700
WIDTH = 1350
GRIDSIZE = HEIGHT/28
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
RED = (255, 0, 0)
screen=pygame.display.set_mode((WIDTH,HEIGHT))
font = pygame.font.SysFont("arial", 36)
shift = 10
#---------------------------------------#
# classes #
#---------------------------------------#
class Sprite(pygame.sprite.Sprite):
""" (fileName)
Visible game object.
Inherits Sprite to use its Rect property.
"""
def __init__(self, picture=None):
pygame.sprite.Sprite.__init__(self)
self.x = 0
self.y = 0
self.visible = False
self.image = self.blend_image(picture)
self.rect = self.image.get_rect()
self.width, self.height = self.rect.width, self.rect.height
self.update()
def spawn(self, x, y):
""" Assign coordinates to the object and make it visible.
"""
self.x, self.y = x,y
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
self.visible = True
def draw(self, surface):
surface.blit(self.image, self.rect)
def update(self):
# after moving a sprite, the rect attribute must be updated
self.rect = self.image.get_rect()
self.rect = pygame.Rect(self.x,self.y,self.rect.width,self.rect.height)
def moveLeft(self):
self.x -= shift
self.update()
def moveRight(self):
self.x += shift
self.update()
def moveUp(self):
self.y -= shift
self.update()
def moveDown(self):
self.y += shift
self.update()
def blend_image(self, file_name):
""" Remove background colour of an image.
Need to use it when a picture is stored in BMP or JPG format, with opaque background.
"""
image_surface = pygame.image.load(file_name)
image_surface = image_surface.convert()
colorkey = image_surface.get_at((0,0))
image_surface.set_colorkey(colorkey)
return image_surface
#---------------------------------------#
# functions #
#---------------------------------------#
def redraw_screen():
screen.fill(BLACK)
world.draw(screen)
if player.visible:
player.draw(screen)
pygame.display.update()
#---------------------------------------#
# main program #
#---------------------------------------#
world = Sprite("town.png")
world.spawn(0,0)
player = Sprite("player.png")
player.spawn(100,400)
LEFT_BORDER = 0
RIGHT_BORDER = WIDTH-1100
TOP_BORDER = 0
BOTTOM_BORDER = HEIGHT-480
#---------------------------------------#
clock = pygame.time.Clock()
FPS = 10
inPlay = True
while inPlay:
clock.tick(FPS)
# keyboard handler
pygame.event.get()
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
inPlay = False
# world moves opposite to the arrow
if keys[pygame.K_LEFT] and world.x < LEFT_BORDER:
world.moveRight()
if keys[pygame.K_RIGHT] and world.x > RIGHT_BORDER:
world.moveLeft()
if keys[pygame.K_UP] and world.y < TOP_BORDER:
world.moveDown()
if keys[pygame.K_DOWN] and world.y > -BOTTOM_BORDER:
world.moveUp()
redraw_screen()
#---------------------------------------#
pygame.quit()
Right, so this is using python 2.7 btw. Any help is appreciated thnx again.
And also, there are some things that are added that have no use, but thats for later code, and vice-versa. Some tweaks i could do, like naming, that will come later.
If the player presses right, i have an image of a guy facing right.
Left, up, and down same concept.
if he holds the button, the guy "runs"
Now i hav normal position, and running position.
4 rows, 2 columns in a png file, how to load 1 row for respective key?
I've been banging my head against this for a while. I am trying to make a game with PyGame and I got up to the collision segment and have been stuck for a while and have checked a few threads.
This is the code I have (removed other methods and conditional statements in between, but left the relevant parts). I am a little confused by the error because I do a self.imageRect = self.image.get_rect() in both classes init, yet I have this error. The error was specifically:
"AttributeError: 'Pebble' object has no attribute 'rect'" when the program attempts to carry out the collision detection part in the dog class. What have I been doing wrong?
import random
import pygame, sys
pygame.init()
clock = pygame.time.Clock() # fps clock
screenSize = WIDTH, HEIGHT = [800, 600]
screen = pygame.display.set_mode(screenSize)
background = pygame.Surface(screen.get_size())
bgColorRGB = [153, 204, 255]
background.fill(bgColorRGB)
pebbleGroup = pygame.sprite.Group()
pebbleSingle = pygame.sprite.GroupSingle()
dogSingle = pygame.sprite.GroupSingle()
#----------------------------------------------------------------------
class Dog(pygame.sprite.Sprite):
def __init__(self, path, speed):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
self.image = pygame.image.load(path) # load sprite from path/file loc.
self.imageRect = self.image.get_rect() # get bounds of image
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.speed = speed
# sets location of the image, gets the start location of object
# sets the start location as the image's left and top location
def setLocation(self, location):
self.imageRect.left, self.imageRect.top = location
def checkCollision(self, pebble, dogGroup):
if pygame.sprite.spritecollide(pebble, dogGroup, False):
print "collided"
#---------------------------------------------------------------------
class Pebble(pygame.sprite.Sprite):
def __init__(self, path, speed, location):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(path)
self.imageRect = self.image.get_rect()
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.imageRect.left, self.imageRect.top = location
self.speed = speed # initialize speed
self.isDragged = False
#----------------------------------------------------------------------
def startGame():
pebblePaths = ['images/pebble/pebble1.jpg', 'images/pebble/pebble2.jpg']
for i in range(3):
pebblePath = pebblePaths[random.randrange(0, len(pebblePaths))]
pebbleSpeed = [random.randrange(1, 7), 0]
pebbleLocation = [0, random.randrange(20, HEIGHT - 75)]
pebble = Pebble(pebblePath, pebbleSpeed, pebbleLocation)
pebbleGroup.add(pebble)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for pebble in pebbleGroup:
dog.checkCollision(pebble, dogSingle)
pygame.display.flip()
clock.tick(30) # wait a little before starting again
startGame()
It's expecting Sprite.rect, so change from
self.imageRect = self.image.get_rect()
#to
self.rect = self.image.get_rect()
Note
self.imageWidth = self.image.get_width()
self.imageHeight = self.image.get_height()
self.imageRect.left, self.imageRect.top = location
These are not necessary, since rect's have many properties, like self.rect.width or self.rect.topleft = location . Another useful one is centerx.
full list at: pygame Rect docs
I am just starting out learning pygame and livewires, and I'm trying to make a single-player pong game, where you just hit the ball, and it bounces around until it passes your paddle (located on the left side of the screen and controlled by the mouse), which makes you lose. I have the basic code, but the ball doesn't stay on the screen, it just flickers and doesn't remain constant. Also, the paddle does not move with the mouse. I'm sure I'm missing something simple, but I just can't figure it out. Help please! Here's what I have:
from livewires import games
import random
games.init(screen_width=640, screen_height=480, fps=50)
class Paddle(games.Sprite):
image=games.load_image("paddle.bmp")
def __init__(self, x=10):
super(Paddle, self).__init__(image=Paddle.image,
y=games.mouse.y,
left=10)
self.score=games.Text(value=0, size=25, top=5, right=games.screen.width - 10)
games.screen.add(self.score)
def update(self):
self.y=games.mouse.y
if self.top<0:
self.top=0
if self.bottom>games.screen.height:
self.bottom=games.screen.height
self.check_collide()
def check_collide(self):
for ball in self.overlapping_sprites:
self.score.value+=1
ball.handle_collide()
class Ball(games.Sprite):
image=games.load_image("ball.bmp")
speed=5
def __init__(self, x=90, y=90):
super(Ball, self).__init__(image=Ball.image,
x=x, y=y,
dx=Ball.speed, dy=Ball.speed)
def update(self):
if self.right>games.screen.width:
self.dx=-self.dx
if self.bottom>games.screen.height or self.top<0:
self.dy=-self.dy
if self.left<0:
self.end_game()
self.destroy()
def handle_collide(self):
self.dx=-self.dx
def end_game(self):
end_message=games.Message(value="Game Over",
size=90,
x=games.screen.width/2,
y=games.screen.height/2,
lifetime=250,
after_death=games.screen.quit)
games.screen.add(end_message)
def main():
background_image=games.load_image("background.bmp", transparent=False)
games.screen.background=background_image
paddle_image=games.load_image("paddle.bmp")
the_paddle=games.Sprite(image=paddle_image,
x=10,
y=games.mouse.y)
games.screen.add(the_paddle)
ball_image=games.load_image("ball.bmp")
the_ball=games.Sprite(image=ball_image,
x=630,
y=200,
dx=2,
dy=2)
games.screen.add(the_ball)
games.mouse.is_visible=False
games.screen.event_grab=True
games.screen.mainloop()
main()
I can't help you because you did not post the complete code here. At least, I do not see where you're updating the positions of the sprites (self.x += self.dx somewhere?) and updating the draw to screen. You're also not utilising your classes in the main() function.
That said, I'm seeing
def __init__(self, x=10):
and inside the constructor you never used the x variable. That worries me, too.
Consider using the Paddle and Ball class as a Sprite, like the following:
if __name__ == '__main__':
background_image = games.load_image("background.bmp", transparent=False)
games.screen.background = background_image
the_paddle = Puddle()
games.screen.add(the_paddle)
the_ball = Ball()
games.screen.add(the_ball)
games.mouse.is_visible = False
games.screen.event_grab = True
games.screen.mainloop()
Note I've taken the liberty to make your code read more Pythonic. I have never used livewires, however, so my code may not function. But it should point you to the right direction. Good luck!
Why are you using livewires? You can use only pygame for a pong game.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480)) # window size
pygame.display.set_caption("Simple pong") # window title
# this is a rect that contains the ball
# at the beginning it is set in the center of the screen
ball_rect = pygame.Rect((312, 232), (16, 16))
# speed of the ball (x, y)
ball_speed = [4, 4]
# this contains your paddle
# vertically centered on the left side
paddle_rect = pygame.Rect((8, 200), (8, 80))
# 1 point if you hit the ball
# -5 point if you miss the ball
score = 0
# load the font for displaying the score
font = pygame.font.Font(None, 30)
# mainloop
while True:
# event handler
for event in pygame.event.get():
# quit event => close the game
if event.type == pygame.QUIT:
exit(0)
# control the paddle with the mouse
elif event.type == pygame.MOUSEMOTION:
paddle_rect.centery = event.pos[1]
# correct paddle position if it's going out of window
if paddle_rect.top < 0:
paddle_rect.top = 0
elif paddle_rect.bottom >= 480:
paddle_rect.bottom = 480
# this test if up or down keys are pressed
# if yes move the paddle
if pygame.key.get_pressed()[pygame.K_UP] and paddle_rect.top > 0:
paddle_rect.top -= 5
elif pygame.key.get_pressed()[pygame.K_DOWN] and paddle_rect.bottom < 480:
paddle_rect.top += 5
# update ball position
# this move the ball
ball_rect.left += ball_speed[0]
ball_rect.top += ball_speed[1]
# these two if block control if the ball is going out on the screen
# if it's going it reverse speed to simulate a bounce
if ball_rect.top <= 0 or ball_rect.bottom >= 480:
ball_speed[1] = -ball_speed[1]
if ball_rect.right >= 640:
ball_speed[0] = -ball_speed[0]
# this control if the ball touched the left side
elif ball_rect.left <= 0:
score -= 5
# reset the ball to the center
ball_rect = pygame.Rect((312, 232), (16, 16))
# test if the ball is hit by the paddle
# if yes reverse speed and add a point
if paddle_rect.colliderect(ball_rect):
ball_speed[0] = -ball_speed[0]
score += 1
# clear screen
screen.fill((255, 255, 255))
# draw the ball, the paddle and the score
pygame.draw.rect(screen, (0, 0, 0), paddle_rect) # paddle
pygame.draw.circle(screen, (0, 0, 0), ball_rect.center, ball_rect.width/2) # ball
score_text = font.render(str(score), True, (0, 0, 0))
screen.blit(score_text, (320-font.size(str(score))[0]/2, 5)) # score
# update screen and wait 20 milliseconds
pygame.display.flip()
pygame.time.delay(20)