5

First off, i have searched online and this website for solutions and the ones i have tried are not working so i decided to post my individual question and code. This program was created using Python 3.2.2 and the corresponding compatible version of pygame. I also realize a more efficient method would be to use sprites, sprite groups and 'dirty rect' updating but i unable to convert the program and so i will continue without the added benefits of such functions.

Problem: Smudge trails where the 'asteroids' are moving are left behind.
Hypothesis: Background is blitted onto the screen however the asteroids are blitted onto the Background.

Please Reply - btw i'm a highschooler from AUS :D

import pygame
import random
import math
pygame.init()

height = 550
width = 750
screen = pygame.display.set_mode((width, height))
background = pygame.image.load("Planet.jpg")
Clock = pygame.time.Clock()


class asteroid(pygame.sprite.Sprite):
    def __init__(self, x, y, size):
        pygame.sprite.Sprite.__init__(self)
        self.x = x
        self.y = y
        self.size = 15
        self.speed = 0.0
        self.angle = 0
        self.colour = (171, 130, 255)
        self.thickness = 0

def display(self):
     pygame.draw.circle(background, self.colour, (int(self.x),int(self.y)), self.size, self.thickness)

     pygame.draw.circle(background, (255, 255, 255), (int(self.x),int(self.y)), self.size, 1)

def move(self):
    self.x += math.sin(self.angle) * self.speed
    self.y -= math.cos(self.angle) * self.speed

def boundaries(self):
    if self.x > width - self.size:
        self.x = 0 + self.size
    elif self.x < self.size:
        self.x = width - self.size
    if self.y > height - self.size:
        self.y = 0 + self.size
    elif self.y <self.size:
        self.y = height - self.size




num_target = 5
my_particles = []
num_particles = len(my_particles)
while num_particles < 5:
    for n in range(num_target):
        size = 20
        x = random.randint(size, height - size)
        y = random.randint(size, width - size)
        target = asteroid(x, y, size)
        target.speed = random.uniform(1.0, 1.0)
        target.angle = random.uniform(0, math.pi*2)
        my_particles.append(target)
        num_particles = num_particles + 1


def main():
    pygame.display.set_caption("Anyu's Game")
    screen.blit(background, (0,0))
    pygame.display.update()
    score = (pygame.time.get_ticks()/1000)
    print (score)


while True:
    pygame.display.update()
    screen.blit(background, (0,0))
    MouseP = pygame.mouse.get_pos()
    frames = Clock.get_fps
    pygame.mouse.set_visible
    score = (pygame.time.get_ticks()/1000)
    print (score)
    print (MouseP)
    for target in my_particles:
        target.move()
        target.boundaries()
        target.display()
        pygame.display.update()


    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            pygame.quit();

if __name__=='__main__':
    main()
AnjewGS
  • 61
  • 3

2 Answers2

4

Basically, you are right! The circles are drawn directly onto the background, and everytime new circles are drawn, the old circles remain. Resulting in the smudges/trails.

You can just change background to screen in your draw method. This will fix it.

But it is really worth using the Sprite classes as intended. I've made a few changes to your code to switch it over for you. With these changes it runs without trails :)

Here are the changes and explainations:

Add this near the top:

#Create a new `pygame.Surface`, and draw a circle on it, then set transparency:
circle = pygame.Surface((30,30))
circle = circle.convert()
pygame.draw.circle(circle, (171, 130, 255), (int(15),int(15)), 15, 0)
circle.set_colorkey(circle.get_at((0, 0)), pygame.RLEACCEL)

Add this to the asteroid, __init__ method:

#Sets the asteroid image, and then the asteroids co-ords (these are in `rect`)
        self.image = circle
        self.rect = self.image.get_rect()

Add this to the end of def move(self):

        self.rect[0] = self.x
        self.rect[1] = self.y

change:

my_particles = []

to:

#This is a special pygame container class, it has a draw() method that tracks changed areas of the screen.
my_particles = pygame.sprite.RenderUpdates()

change:

my_particles.append(target)

to:

my_particles.add(target)

change:

while True:
    pygame.display.update()
    screen.blit(background, (0,0))
    MouseP = pygame.mouse.get_pos()
    frames = Clock.get_fps
    pygame.mouse.set_visible
    score = (pygame.time.get_ticks()/1000)
    print (score)
    print (MouseP)
    for target in my_particles:
        target.move()
        target.boundaries()
        target.display()
        pygame.display.update()

to:

#initial screen draw:
screen.blit(background, (0,0))
pygame.display.update()
while True:
    #remove previous drawn sprites and replaces with background:
    my_particles.clear(screen, background)
    MouseP = pygame.mouse.get_pos()
    frames = Clock.get_fps
    pygame.mouse.set_visible
    score = (pygame.time.get_ticks()/1000)
    print (score)
    print (MouseP)
    for target in my_particles:
        target.move()
        target.boundaries()
    #draws changed sprites to the screen:
    pygame.display.update(my_particles.draw(screen))

Remove the display method as it is no longer needed.

This will also run a lot faster than the your earlier code, as the time taken to draw something is proportional to the size of the drawing area, and previously it was drawing the whole background everytime - now it only draws the sprites and changes to the background!

Hope this helps :)

fraxel
  • 34,470
  • 11
  • 98
  • 102
  • Thank you so much, you are a lifesaver. Such detailed answers i never expected such a nice community. Also where is the sprite group you have placed in the code, i'm not sure whether it is "my_particles.add(target)" or "my_particles = pygame.sprite.RenderUpdates()". I need to figure it out so i can move onto collisions. @fraxel – AnjewGS May 05 '12 at 14:17
  • 1
    @AnjewGS - thanks :) . If I understand your question correctly,.. I changed your list: `my_particles` into a pygame class: `pygame.sprite.RenderUpdates()` which is effectively a set of sprites that we may need to redraw every iteration. The line `my_particles.add(target)` adds your asteroids into this set (as it starts out empty, `add`, is a bit like `append` but for sets - if you don't know what sets are you should check them out..). – fraxel May 05 '12 at 14:31
  • ok cool, thanks again. I can use this "pygame.sprite.groupcollide "right? – AnjewGS May 05 '12 at 14:48
  • 1
    @AnjewGS - Best way is to try it out! `groupcollide` is to see which members of two groups are colliding. Here we only have one group (currently), so you can use `spritecollide`, for each asteroid.. ie. put it in you `for` loop at the very end, but you have to first do: `my_particles.remove(target)`, then, `pygame.sprite.spritecollide(target,my_particles,True)` then `my_particles.add(target)`. Because otherwise it will report collisions between each asteroid and itself... try printing the output of these things, and get a feel for what is going on.. – fraxel May 05 '12 at 15:03
0

This already has an answer but this can be useful instead of other methods. Make sure when you blit the images onto the screen, flip the display after blitting everything. I would consider making a draw() function Like this:

def draw(self):

    # Blit images
    self.screen.blit(image)

    # Flip display
    pygame.display.flip()

This will flip the display every frame and then draw the next frame without a trail.

Also quick notes, remember to do image = pygame.image.load(image).convert or .convert_alpha() else after adding more images the game will slow down. Also, if you do import pygame as pg you don't have to type out pygame each time, instead you can just type pg.

Kai
  • 115
  • 1
  • 2
  • 7