Im trying to make a rain effect with pygame but it seems as if the background is not cleaning up before updating the sprites.
this is what it looks like when i execute the code..
I wonder if there's a way to fix this problem.
rain.py (main file)
#!/usr/bin/python
VERSION = "0.1"
import os, sys, raindrop
from os import path
try:
import pygame
from pygame.locals import *
except ImportError, err:
print 'Could not load module %s' % (err)
sys.exit(2)
# main variables
WIDTH, HEIGHT, FPS = 300, 300, 30
# initialize game
pygame.init()
screen = pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption("Rain and Rain")
# background
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((40,44,52))
# blitting
screen.blit(background,(0,0))
pygame.display.flip()
# clock for FPS settings
clock = pygame.time.Clock()
def main():
raindrops = pygame.sprite.Group()
# a function to create new drops
def newDrop():
nd = raindrop.Raindrop()
raindrops.add(nd)
# creating 10 rain drops
for x in range(0,9): newDrop()
# variable for main loop
running = True
# event loop
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
raindrops.update()
screen.blit(background,(100,100))
raindrops.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == '__main__': main()
raindrop.py ( class for raindrops )
import pygame
from pygame.locals import *
from os import path
from random import randint
from rain import HEIGHT
img_dir = path.join(path.dirname(__file__), 'img')
class Raindrop(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.width = randint(32, 64)
self.height = self.width + 33
self.image = pygame.image.load(path.join(img_dir, "raindrop.png")).convert_alpha()
self.image = pygame.transform.scale(self.image, (self.width, self.height))
self.speedy = 5 #randint(1, 8)
self.rect = self.image.get_rect()
self.rect.x = randint(0, 290)
self.rect.y = -self.height
def update(self):
self.rect.y += self.speedy
if self.rect.y == HEIGHT:
self.rect.y = -self.height
self.rect.x = randint(0, 290)
This is the line you use to clear the screen:
screen.blit(background, (100, 100))
In other words; you're clearing the screen starting at x=100, y=100. Since pygame coordinates starts from topleft and extends to the right and downwards, you're not clearing the screen left of x=100 and above y=100.
Simple fix is blitting at 0, 0 as you did at the start of the program.
screen.blit(background, (0, 0))
Related
I am new to stackoverflow.
My code has a problem which the screen turns completely black.
The error.
I need the answer quickly so any help will be good.
Heres the code:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screeen.fill(217,217,217)
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)
Any help on what to do???
Thanks.
screeen.fill(217,217,217) should be screen.fill((217,217,217))
The Indentation is not correct. In particular, the scene must be pulled in the application loop and not in the bleed loop:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
# INDENTATION
#<--|
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# INDENTATION
#<------|
screen.fill((217,217,217))
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)
This is an exercise from Crash Course - at this stage I am trying to create a row of raindrops, but I believe in my for loop, something is broken.. I am updating the image's rect position at each iteration and then adding that into sprite Group, why will this not draw() onto the screen?
import sys
import pygame
from raindrops import Raindrop
from pygame.sprite import Group
def let_it_rain():
'''initialize pygame, settings, and screen object'''
pygame.init()
screen_width = 1200
screen_height = 800
bg_color = (144, 177, 226)
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Let It Rain")
raindrop = Raindrop(screen)
raindrops = Group()
#number of drops in a row
spacex = screen_width - (2 * raindrop.rect.width)
raindrop_number_x = int(spacex / (2 * raindrop.rect.width))
#start window for raindrops
while True:
screen.fill(bg_color)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
for raindrop_number in range(raindrop_number_x):
raindrop = Raindrop(screen)
raindrop.rect.x = raindrop.rect.x + 2 * raindrop.rect.x * raindrop_number_x
raindrops.add(raindrop)
raindrops.draw(screen)
pygame.display.flip()
let_it_rain()
and here's my raindrops class in another module
import pygame
from pygame.sprite import Sprite
class Raindrop(Sprite):
def __init__(self, screen):
#load image
super(Raindrop, self).__init__()
self.screen = screen
self.pic = pygame.image.load('rain.png')
self.image = pygame.transform.smoothscale(self.pic,(50,60))
self.rect = self.image.get_rect()
#starting position
self.rect.x = self.rect.width
self.rect.y = self.rect.height
def blit(self):
raindrops.draw(screen)
# self.screen.blit(self.image, self.rect)
Feel like this has something to do with blit vs. draw OR my positions are not updating somehow
In your main loop, when setting the drop rectangles, use the loop variable instead of the drop count:
for raindrop_number in range(raindrop_number_x):
raindrop = Raindrop(screen)
raindrop.rect.x = raindrop.rect.x + 2 * raindrop.rect.x * raindrop_number # use loop variable
raindrops.add(raindrop)
When the game first starts both the player and the enemy appear but when the player moves the enemy disappears.
import pygame
import os
import random
from pygame.locals import * # Constants
import math
import sys
import random
pygame.init()
screen=pygame.display.set_mode((1280,720)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background.fill((255,255,255)) # fill the background white
White = (255,255,255)
screen.blit(background, (0, 0))
class Player(pygame.sprite.Sprite):
def __init__(self):
self.rect = pygame.draw.rect(screen, (0,0,128), (50,560,50,25)) #(colour)(x-position,y-position,width,height)
self.dist = 100
def draw_rect(self,x,y): # This is my code which should make the player move
screen.blit(background, (0, 0)) #If this isn't included then when the rectangle moves it's old positon will still be on the screen
self.rect = self.rect.move(x*self.dist, y*self.dist); pygame.draw.rect(screen, (0, 0, 128), self.rect)
pygame.display.update()
def handle_keys(self): # code to make the character move when the arrow keys are pressed
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.draw_rect(-0.05,0)
elif keys[K_RIGHT]:
self.draw_rect(0.05,0)
elif keys[K_UP]:
self.draw_rect(0,-0.05)
elif keys[K_DOWN]:
self.draw_rect(0,0.05)
elif keys[K_SPACE]:
self.draw_rect(0.4,-0.9)
if self.rect.right > 1280: # These are to stop the player from going out of the boundary
self.rect.right = 1280
if self.rect.left < 0:
self.rect.left = 0
if self.rect.bottom > 720:
self.rect.bottom = 720
if self.rect.top < 0:
self.rect.top = 0
The movement of the player works perfectly fine.
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
x = random.randint(50,450)
self.rect = pygame.draw.rect(screen, (128,0,0), (300,x,50,25))
The enemy just spawns at a random place and should still appear when the player moves around. I tried to do something but it didn't work.
clock = pygame.time.Clock() # A clock to limit the frame rate.
player = Player()
enemy = Enemy()
def main(): #my main loop
running = True
while running:
player.handle_keys()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
clock.tick(60) # Limit the frame rate to 60 FPS.
pygame.display.flip() #updates the whole screen
if __name__ == '__main__': main()
It's because you draw the Rect of the enemy only once: in the __init__ function of Enemy. Also, you do a lot of drawing in different places of the Player class, like clearing the screen. Stop doing that.
You already subclass Sprite, so use this class as intended. Sprites have an image and rect that defines how they look like and where they are, and you add them to a Group that takes care of calling their update function and drawing them to the screen.
Your code should look like this:
import pygame
import random
from pygame.locals import * # Constants
pygame.init()
screen=pygame.display.set_mode((1280,720)) #(length,height)
screen_rect=screen.get_rect()
background = pygame.Surface(screen.get_size())
background.fill((255,255,255)) # fill the background white
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50,25))
self.image.fill((0,0,128))
self.rect = self.image.get_rect(topleft=(50,560))
self.dist = 100
def update(self): # code to make the character move when the arrow keys are pressed
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
self.rect.move_ip(-1,0)
elif keys[K_RIGHT]:
self.rect.move_ip(1,0)
elif keys[K_UP]:
self.rect.move_ip(0,-1)
elif keys[K_DOWN]:
self.rect.move_ip(0,1)
self.rect.clamp_ip(screen_rect)
class Enemy(pygame.sprite.Sprite): # the enemy class which works fine
def __init__(self):
super().__init__()
x = random.randint(50,450)
self.image = pygame.Surface((50,25))
self.image.fill((128,0,0))
self.rect = self.image.get_rect(topleft=(300, x))
clock = pygame.time.Clock() # A clock to limit the frame rate.
player = Player()
enemy = Enemy()
sprites = pygame.sprite.Group(player, enemy)
def main(): #my main loop
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
sprites.update()
screen.blit(background, (0, 0))
sprites.draw(screen)
clock.tick(60) # Limit the frame rate to 60 FPS.
pygame.display.flip() #updates the whole screen
if __name__ == '__main__':
main()
EDIT: I have fixed it, there should be a self infront of the return for invader_position_x
I am making a space invaders game. However I have encountered strange behavior.
When I press the right key on my keyboard, the sprite does not move but after holding it down for a few seconds, it jumps to the right boundary.
The space invader game is using classes and this is the main class:
# IMPORTS
import pygame, sys
from pygame.locals import *
import invader
pygame.init()
###################
#IMAGE SIZE AND FPS
width = 800
height = 600
fps = 30
fpsClock = pygame.time.Clock()
DISPLAY = pygame.display.set_mode((width,height))
#################
#OTHER VARIABLES
pygame.display.set_caption('space invaders!')
white = (225,225,225)# The colour white
invader_sprite = pygame.image.load("cross.png")
invader_lenght = 40
invader_position_x = 400
invader_position_y = 560
right_boundary = width- invader_lenght
keypress = ""
my_invader = invader.Invader(invader_position_x,right_boundary,keypress)# Initialising invader
while True: # main game loop
DISPLAY.fill(white)
DISPLAY.blit(invader_sprite,(invader_position_x,invader_position_y))
keypress = pygame.key.get_pressed()
invader_position_x=my_invader.invader_move(keypress,right_boundary,invader_position_x)
print(invader_position_x)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
fpsClock.tick(fps)
This is my invader class in a seperate file:
import pygame, sys
from pygame.locals import *
pygame.init()
class Invader():
def __init__(self,invader_position_x,right_boundary,keypress):
self.invader_position_x= invader_position_x
self.right_boundary=right_boundary
self.keypress= keypress
def invader_move(self,keypress,right_boundary,invader_position_x):
if self.invader_position_x> right_boundary:#Right boundary
invader_position_x=right_boundary-5
if self.invader_position_x<0:
invader_position_x= 5
if keypress[K_RIGHT]:# right
self.invader_position_x = self.invader_position_x+ 5
elif keypress[K_LEFT]:# left
self.invader_position_x =self.invader_position_x- 5
return invader_position_x
So what is the solution to fixing this weird behaviour?
I think problem is that you have two variables to keep position . But I didn't check this - I changed code to make it better organized and problem disappeared.
#!/usr/bin/env python3
import pygame
# --- constants ---
WIDTH = 800
HEIGHT = 600
FPS = 30
WHITE = (225, 225, 225)
# --- classes ---
class Invader():
def __init__(self, x, y):
self.image = pygame.image.load("cross.png")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def draw(self, screen):
screen.blit(self.image, self.rect)
def update(self, screen_rect, keypress):#EDIT Replaced screen with screem_rect
if keypress[pygame.K_RIGHT]: # right
self.rect.x += 15
elif keypress[pygame.K_LEFT]: # left
self.rect.x -= 15
if self.rect.right > screen_rect.right: # right boundary
self.rect.right = screen_rect.right
if self.rect.left < screen_rect.left:
self.rect.left = screen_rect.left
# --- main ---
# - init -
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen_rect = screen.get_rect()
pygame.display.set_caption('space invaders!')
# - objects -
my_invader = Invader(400, 560)
# - mainloop -
fps_clock = pygame.time.Clock()
while True: # main game loop
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
keypress = pygame.key.get_pressed()
# - updates -
my_invader.update(screen_rect, keypress)
# - draws -
screen.fill(WHITE)
my_invader.draw(screen)
pygame.display.update()
# - FPS -
fps_clock.tick(FPS)
import time
import sys
import pygame
from pygame.locals import *
from pygame.sprite import Sprite, Group
pygame.init()
running = False
screen_width = 1280
screen_height = 720
size = (screen_width, screen_height)
screen = pygame.display.set_mode((size), pygame.FULLSCREEN)
pygame.display.set_caption('Laser Bits')
class world(Sprite):
def __init__(self):
Sprite.__init__(self)
self.image = pygame.image.load('levels/LBMAPPREALPHA1.png')
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = 0
Group.add(self)
group_sprites = pygame.sprite.Group()
while running == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
group_sprites.draw(screen)
pygame.display.update()
I'm a newbie at Python and I'm "trying" to make a game and I need some help, I do not know why my sprite won't show. Thank you for your responses in advanced!
You never create an instance of your world class.
Remove this line:
Group.add(self)
and then create an instance of world and add it to the group_sprites group:
the_world = world()
group_sprites = pygame.sprite.Group(the_world)