In the previous tutorial we created a blank white screen; now we want to display some graphics on it. In this tutorial, we will:
- Draw a circle in our window
- Define a Particle class
- Create and display a Particle object
This program builds on the code from the previous tutorial. The line numbers show where code should be added assuming the program is written exactly like the program written in the previous tutorial (including blank lines). In this tutorial and all the following tutorials, the final code is available by clicking the Code on Github link at the start of the article.
Drawing with Pygame
In Pygame there are various functions for drawing simple shapes. We will display our particles as circles so use the `pygame.draw.circle()` function. This function takes several parameters:
- A surface where the circle will be drawn (here it's our screen)
- A colour
- An (x, y) coordinate
- A radius
- A thickness (optional)
For example:
pygame.draw.circle(screen, (0,0,255), (150, 50), 15, 1)
This draws a blue ((0,0,255) is blue in RGB notation) circle centred at (150, 50), with radius 15 and thickness of 1 pixel. Note that this function must be called after the screen.fill(background_colour) command and before the flip() command. If you run the program now you should see something like this (I also changed the title of window, but it's not important).
If you’re not familiar with how computer displays work, you might have expected the circle to be near the bottom of the screen, since the particle's y-coordinate is 50 and the screen is 200 units high. However, on a computer display, the origin (0, 0) is in the top, left of the screen, with the x-axis increasing from left-to-right and the y-axis increasing from top-to-bottom; the circle is therefore centred 50 pixels down from the top of the screen.
The Particle object
In our final simulation we will want several particles, each of which will have the same type of attributes. Thus it makes sense to define a Particle class. When we create each Particle object with the `__init__` function (note the double underscores which indicates a built-in method), we will give it an x,y coordinate and a size. The colour and line thickness will be given default values. We'll add more attributes as we go along.
class Particle:
def __init__(self, (x, y), size):
self.x = x
self.y = y
self.size = size
self.colour = (0, 0, 255)
self.thickness = 1
Next we add a `display()` method to our Particle object that will draw it (as a circle) on the screen.
def display(self):
pygame.draw.circle(screen, self.colour, (self.x, self.y), self.size, self.thickness)
Now we can remove the `pygame.draw.circle()` call and replace it by code that creates a particle object (defining its x, y coordinates and size) then calling its `display()` method. If you're not familiar with object-oriented programming, this may seem more long winded, but it will make building on our program a lot easier later on.
my_first_particle = Particle((150, 50), 15)
my_first_particle.display()
If you run the program now, it should look exactly the same as before. However, in the next tutorial I'll show you how the code now can be easily changed to display many more circles. I'll also introduce the random module which is very handy when creating simulations.
Comments (31)
Mayec Rancel on 13 Nov 2010, 2:46 p.m.
I spotted a typo. In code line 21:
my_first_particles = Particle((150, 50), 15)
The variable name should be "my_first_particle" (without the final 's'), to match the call in the next line.
Just wanted to let you know, so that these excellent tutorials of yours are no less than perfect. ;)
Peter on 13 Nov 2010, 4:14 p.m.
Thanks, I've changed it.
Every time I re-read what I've written I spot a couple of typos (it's because I keep changing my mind about things - that and I'm careless). It really helps if other people look out for them too.
David on 13 Nov 2010, 4:14 p.m.
So far this tutorial has been a new experience for me.
However, I was stuck on this tutorial for at least one hour, as I was presented with an error message telling me "this constructor takes no arguments". After some research on the internet, I found out that there were two underscores on both sides of "init", not just one!
Maybe I'm a lone fool, but you could possibly update this content and briefly note how it is two underscores at each side, to allow for other users to overcome this problem.
As I say, apart from this(even though it was my own fault), so far so good!
Thanks.
Peter on 6 Jan 2011, 5:08 a.m.
Sorry about that David. I know how frustrating it can be to spend hours with an error only to find its a minor typographical issue. In my defence, the double underscore is a requirement of Python and not a Pygame thing, which is the focus of this tutorial. But I'll add a note to make it clear for everyone.
Thanks for your feedback.
Anonymous on 27 Jul 2011, 4:21 p.m.
Hi, Love this tutorial, but i'm stuck with this problem
when I run the code upto this point I get a syntax error at "(" which I have highlighted ,
Can you help me out with this. I'm using python 3.1 and compatiable pygame version.
class Particle:
def __init__(self, (x, y), size):
Peter on 27 Jul 2011, 7:36 p.m.
It seems that tuple parameter unpacking doesn't work in Python3. Try:
class Particle:
def __init__(self, position, size):
self.x, self.y = position
faizan on 11 May 2012, 8:30 a.m.
Hii
when I run your code I dont get any errors but the screen is first white then turns black and then stays white for ever. why is it getting that black in white any idea ??
Peter on 11 May 2012, 12:57 p.m.
Hi Faizan. I'm not sure what's happening when you run the program. Is the code exactly the same as I've written here? You could try moving the lines:
screen.fill(background_colour)
my_first_particle.display()
and
pygame.display.flip()
into the while loop so they are called every iteration, which would be a more normal way to do things.
jeff on 1 Jun 2012, 6:44 a.m.
This tutorial finally gave me a good grasp on the importance and efficiency of classes. Thanks so much!
Anonymous on 11 Dec 2012, 4:57 p.m.
Hi, I tried what you suggested and it says:
particle_01 = Particle(150, 50, 15)
TypeError: __init__() takes exactly 3 positional arguments (4 given)
Help?
Peter on 11 Dec 2012, 5:35 p.m.
Sorry I should have said, you still create the particle with the same call, i.e:
particle_01 = Particle((150, 50), 15)
I think that should work, but I don't have Python 3 to test it. If it doesn't then create the particle as you are now change the Particle class to:
class Particle:
def __init__(self, x, y, size):
self.x = x
self.y = y
Anonymous on 13 May 2013, 11:04 p.m.
this bit doesn't work in Python 3.1.1
class Particle:
def __init__(self, x, y, size):
self.x = x
self.y = y
Help!
Peter on 17 May 2013, 11 a.m.
You might need to change the first line to,
class Particle(object):
Anonymous on 23 Jun 2013, 1:20 p.m.
This is what I did to get the code to work for Python3.3:
class Particle:
def __init__(self, position, size):
self.x = position[0]
self.y = position[1]
self.size = size
self.colour = (0, 0, 255)
self.thickness = 1
Montoya on 15 Feb 2014, 2:13 p.m.
pygame.draw.circle(screen, self.colour, (self.x, self.y), self.size, self.thickness)
self.colour should be self.color
Anonymous on 20 Oct 2014, 1:30 a.m.
I tried running the program but I keep getting an attributeerror " 'particle' object has no attribute 'display' "
How can I fix this?
Peter on 27 Nov 2014, 9:03 p.m.
I suspect you need to fix the indentation of the display method so it is inside the Particle class.
Anonymous on 30 Oct 2015, 2:32 p.m.
NameError: global name 'x' is not defined
Gabriel Ligeiro on 9 May 2017, 3:53 a.m.
class Particle:
def __init__(self, position, size):
self.x = position[0]
self.y = position[1]
self.size = size
self.colour = (0, 0, 255)
self.thickness = 1
def display(self):
pygame.draw.circle(screen, self.colour, (self.x, self.y), self.size, self.thickness)
works for me in python3!
Anonymous on 17 Nov 2017, 1:12 a.m.
this is fantastic stuff -- I haven't looked at a ton of this yet but I love the merger of early-skills tutorial with super cutting edge physics stuff...
John Deighan on 26 May 2019, 8:53 p.m.
Coming from a Perl background, where each class definition goes in a separate file, I created my Particle class in a separate file. The problem I ran into was that the display() method knows nothing about the variable screen. I would advise passing screen into the display() method. Alternatively, you could include it in the constructor, but then each particle would be tied to a single Surface (which is a type in pygame, but you can have many Surfaces in your game). There are technical reasons to do that anyway ('encapsulation'), even if your code is all in one file.
joe on 7 Oct 2019, 11:33 p.m.
show whole code please
Peter on 9 Oct 2019, 10:21 p.m.
You can get the whole code by following the link to Github.
Qx7 Developers on 8 Feb 2020, 6:57 p.m.
I come from a low level assembly (x86, atmel, ST, 6502 chips) and i never got into graphics or game programming, and i have to say that tuples can be kind of tricky. I had to access each position[0]&[1] as opposed to unpacking the x,y tuple. Im kind of embarrassed to say i was stumped for a good hour. That's the best part of what we do... ;slogging through the version hell and realizing it was something so stupid. I wish there would be one language that does not change ever. I'm so tired of instruction sets, opcodes etc... I am really enjoying your stuff. I dont know if you mentioned what version you are running. it can lead to newbies getting mad and blaming you. I totally get it and love your effort! I know i am many years ahead writing... That damn tuple was driving me nuts. I dont like to run to stack overflow or quora because that will multiply the insanity. What i learned today is that, simplicity is key and from now on we should all explicitly be more verbose about versioning. (position[0],position[1]) that was my problem. and ive been programming chips for 10 years! Thanks for your content.
Kamalesh on 15 May 2020, 2:37 p.m.
( red , green ,blue )
Adam Wheeler on 28 Jul 2020, 1:34 p.m.
For anyone struggling, this is the full code that works on Python 3.8.3 in 3 parts
Part one
import pygame
pygame.init()
#setting up the screen.
(Width, Height) = (600,400)
background_colour = (173,216,230)
screen = pygame.display.set_mode((Width,Height))
Adam Wheeler on 28 Jul 2020, 1:34 p.m.
Part two
#making a class for the circles
class Particle:
def __init__(self, position, size):
self.x = position[0]
self.y = position[1]
self.size = size
self.colour = (0, 0, 255)
self.thickness = 1
#window properties.
pygame.display.set_caption("Tutorial 1")
screen.fill(background_colour)
def display(self):
pygame.draw.circle(screen, self.colour, (self.x, self.y), self.size, self.thickness)
Adam Wheeler on 28 Jul 2020, 1:35 p.m.
Part 3
#testing the function
my = Particle((150, 50), 15)
display(my)
pygame.display.flip()
#close the game when you press the quit.
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
Caleb on 5 Aug 2020, 5:04 a.m.
Thanks Adam for the update so many years later! Def helped me out
👀 on 17 Oct 2020, 11:24 a.m.
Hey Guys, I found an issue witn the code above.
1. There was no particle display at all.
I found out that you need to run pygame.display.update() after a draw statement - just put this into "display(self)" and youre good!
Oh and if you're trying to draw a rectange, use that code to define it:
into init:
self.rect = ((self.x, self.y), (self.size, self.size))
into display:
pygame.draw.rect(self.screen, self.colour, self.rect)
Have a good one!
Joseph on 23 Oct 2020, 11:05 a.m.
Hi guys, despite my best efforts I'm not able to get this running in Python 3.7. The problem is the "tuple issue", however even the fixes of previous contrinbutors don't seem to work.
It would be fantastic if someone has an idea...
----------------
class Particle:
def __init__(self, position, radius, color):
self.x = position[0],
self.y = position[1],
self.radius = radius,
self.color = color,
self.thickness = 0
def display(self):
pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, self.thickness) ||||| HERE IS THE PROBLEM: "TypeError: an integer is required (got type tuple)"
Particle1 = Particle((200, 200), 15, BLACK)
Particle1.display()