Python Pygame Basic Program - python

I have been trying to learn pygame the last day or so, and tried to write a basic program that just has a small image of a leaf falling from the top of the screen.
Nothing appears when I run it, and I imagine I'm missing something obvious with how I'm doing this. (I can tell this is a very inefficient way of doing this as well, so tips would be appreciated!)
Here's the code:
import pygame
from pygame.locals import *
import random
pygame.init()
class Leaf:
def __init__(self):
self.leafimage = pygame.image.load('fallingleaf.jpg').convert()
self.leafrect = self.leafimage.get_rect()
xpos = random.randint(0, 640)
self.leafrect.midtop = (xpos, 0)
def move(self):
self.leafrect = self.leafrect.move([0, 1])
def main():
width= 640
heigth = 480
dimensions = (width, heigth)
screen = pygame.display.set_mode(dimensions)
pygame.display.set_caption('Some Epic Pygame Stuff')
clock = pygame.time.Clock()
leaves = []
for i in range(5):
leaves.append(Leaf())
running = 1
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = 0
for i in leaves:
i.move()
screen.blit(i.leafimage, i.leafrect)
screen.fill((255, 255, 255))
pygame.display.flip()
if __name__ == '__main__': main()

You probably don't want this sequence:
for i in leaves:
i.move()
screen.blit(i.leafimage, i.leafrect)
screen.fill((255, 255, 255))
pygame.display.flip()
You draw the leaves, and then fill the entire screen with white, and then show the screen.
fill the screen, then draw the leaves, then flip()

Related

How to draw a square wherever you click in the pygame window

You probably know what I want to do from the title but here's a simple example:
#User clicks somewhere in the pygame window
pos = cursorPosition()
#Function/Class that creates a square where the user clicked.
I have tried this:
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
create.cube()
screen.fill((0, 255, 0))
pygame.display.flip()
pygame.quit()
sys.exit()
But it just gives me a Blue screen and when I click anywhere it doesn't do anything, so if you can help me it would be much appreciated. Thanks!
EDIT: I've managed to do it but now I face another problem:
The square would appear only if I hold down the mouse button.
This is the code
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
screen.fill((0, 255, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
create.cube()
pygame.display.flip()
pygame.quit()
sys.exit()
It's great to see that you are making a good effort to solve the by yourself, and that you are editing the question with the work you've done so far!
What I added to the code basically allows the user to change where the cube is being drawn. If you would like to draw multiple cubes, with their positions based on the mouse clicks from the user, edit your question to add those details, and leave a comment below.
First, I wrote a new class called Cube, which essentially has the same code as Create. I won't go into it in detail, but generally in object-oriented programming, objects are nouns, and their methods are actions. Your class is the opposite, which isn't how object-oriented code is generally written.
I added the update() method which simply updates some of the object's fields with the position of the mouse. Your original code was defining class fields or static variables. I won't go into to too much detail here, but if we were to make 100 instances of cube, we would want to have the positions for all the cubes, right? In cases like these, you are operating on the objects, not the class.
Then, there is one variable which gets set to true after the first mouse click, and, as a result, the cube starts being drawn to the screen.
Here is the fixed code:
import pygame
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
def draw(self):
pygame.draw.rect(screen, (255, 0, 0), self.square)
cube = Cube()
drawing_cube = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
cube.update()
drawing_cube = True
screen.fill((0, 255, 0))
if drawing_cube:
cube.draw()
pygame.display.flip()
pygame.quit()
quit()
I hope this answer helped you, and if you have any further questions, please feel free to leave a comment below!
I have also come across this problem and after a lot of messing around and frustration came up with the following:
import sys
import pygame
import time
pygame.init()
white = (255, 255, 255)
red = (255, 0, 0)
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("OwO")
mouse_cords = []
clicked = False
def draw(cord_list, zero):
''' This is what will draw on the screen when the mouse clicks using recursion'''
pygame.draw.circle(screen, red, cord_list[zero], 100, 1)
zero += 1
if len(cord_list) > zero:
draw(cord_list, zero)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(white)
if pygame.mouse.get_pressed()[0]:
mouse_cords.append(pygame.mouse.get_pos())
clicked = True
if clicked == True:
draw(mouse_cords, 0)
pygame.display.flip()
clock.tick(60)
pygame.quit()
As you can tell I used recursion to solve this problem. Sorry it's circles not boxes but Im sure you can figure out how to change that.
I am a beginner developer and my method is probably not the most efficient, however it does work. I know that I am writing 2 years late, but I am writing this incase anyone has the same question as I did which is to create multiple rectangles, squares or circles with a mousebutton press or in general any event.
I implemented a class to create a Cube object just like Michael O'Dwyer wrote in his explanation, and while his solution works to create one cube at a time, I needed to create multiple for myself.
In addition to his solution, I just created a list "cubeList" and with each mousebutton event I created a new cube object and appended it to that cubeList. Then, I used a for loop in order to iterate through each cube object in the cubeList and used the draw method. This way, I am able to have multiple cubes drawn at the same time, and I am sure there might be a more efficient or better method to do this, but this worked for me.
import pygame
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
Square1 = pygame.Rect(30,30,60,60)
Square2 = pygame.Rect(90,30,60,60)
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx - 25, self.cy - 25, 50, 50)
def draw(self):
pygame.draw.rect(WIN, GREEN, self.square)
def main():
cubeCount = 0
run = True
cubeList = []
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Ending")
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
cube = Cube()
cubeList.append(cube)
cube.update()
clock.tick(60)
WIN.fill((BLUE))
pygame.draw.rect(WIN,RED, Square1)
pygame.draw.rect(WIN, GREEN, Square2)
for x in cubeList:
x.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()

Python 3.5.2 Pygame : Box reveal animation

I wanted to write a program that, when the user clicks anywhere on the surface of the box, it reveals another smaller box hidden behind it . The code is quite far from being finished at the moment .
Currently i wanted to do an animation that strats when the user clicks anywhere on the screen and stops when the box that covers the small box is gone.
Here is my code :
import random, pygame, sys
from pygame.locals import *
pygame.init()
done = False
clock = pygame.time.Clock()
white = (255,255,255) # COLLORS
black = (0,0,0)
red = (255,0,0)
green = (0,100,0)
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
REVEALSPEED = 8
def draw_icon(x,y):
icon = pygame.Rect(x+10,y+10,20,20)
pygame.draw.rect(game_display,red,icon)
def draw_cover(x,y,coverage):
pygame.draw.rect(game_display,white,(x,y,40,40))
draw_icon(x,y)
if coverage > 0:
pygame.draw.rect(game_display, green, (x, y, coverage, 40))
pygame.display.update()
clock.tick(10)
def revealBoxesAnimation(x,y): # Do the "box reveal" animation.
for coverage in range(40, (-REVEALSPEED) - 1, -REVEALSPEED):
draw_cover(x, y, coverage)
def game_loop():
done = False
mouseClicked = False
while done != True:
x = (display_width - 40) / 2
y = (display_height - 40) / 2
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
done = True
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
mousex, mousey = pygame.mouse.get_pos()
if mousex != None and mousey != None :
if mouseClicked == True :
revealBoxesAnimation(x, y)
game_display.fill(white)
pygame.display.update()
clock.tick(60)
game_loop()
In the draw_cover function I said that the program should only draw the big box if the value of 'coverage' is greater than zero.
In the revealBoxesAnimation function, I use the range function to lower the value of coverage from 40 all the way to 0 by 8 at a time (40, 32, 24, 16, 8, 0, -8). Still, when the value of coverage hits zero, the animation does not stop. It goes on in an infinite loop.
How so ?
While there was already a fix suggested in another answer, I recommend to rewrite your code entirely.
Note how all the logic is encapsulated in the Box class (especially the update method), instead of 3 different functions; and now we only have a single, non-blocking main loop.
We have a single class for both, the non-shrinking and the shrinking box, but we could also just create another class for the thing that should not shrink and skip the shrinking argument.
So basically, if the box shrinks, we shrink the rect, create a new Surface with the smaller size, and use that for drawing.
When a mouse click occurs, we just need to create two Box instances, one not shrinking, and a bigger one shrinking.
Here's a full, running example:
import random, pygame, sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
colors = pygame.color.THECOLORS
class Box(pygame.sprite.Sprite):
def __init__(self, group, center, size, color, shrinking=False):
pygame.sprite.Sprite.__init__(self, group)
self.image = pygame.surface.Surface((size, size))
self.image.fill(color)
self.shrinking = shrinking
self.rect = self.image.get_rect(center=center)
def update(self):
if self.shrinking:
self.rect.inflate_ip(-1, 0)
new = pygame.surface.Surface((self.rect.w, self.rect.h))
new.blit(self.image, (0, 0))
self.image = new
if self.rect.width <= 0:
self.kill()
sprites = pygame.sprite.OrderedUpdates()
def game_loop():
while True:
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
return
elif event.type == MOUSEBUTTONUP:
Box(sprites, event.pos, 20, colors['red'])
Box(sprites, event.pos, 40, colors['green'], True)
sprites.update()
game_display.fill(colors['white'])
sprites.draw(game_display)
pygame.display.update()
clock.tick(60)
game_loop()
The problem is simply that after setting mouseClicked to True, you never have a way to make it false again. The simplest fix in my opinion would be to replace
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
with
mouseClicked = pygame.mouse.get_pressed()[0]
(Outside of the event for loop, as you only need to do so once per a frame.)

How to queue multiple pygame scripts in a module?

Does anyone know if there is a way to make pygame scripts run one after another?
This is my module below, I would like to know if I could get them to deploy at certain intervals, that is, I would like 'A_long_time_ago' to run, last for 5 seconds then close and immediately load 'sounds' and 'logo', then 3 seconds later for them to close, transitioning into 'Title_Crawl'.
The Module
from A_long_time_ago import *
from sounds import *
from logo import *
from Title_Crawl import *
A_long_time_ago
import pygame
import time
pygame.init()
screen = pygame.display.set_mode((1376, 760))
clock = pygame.time.Clock()
done = False
font = pygame.font.SysFont("franklingothicbook", 40)
text = font.render("A long time ago in a galaxy far, far away....", True, (75, 213, 238))
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
done = True
screen.fill((0, 0, 0))
screen.blit(text,
(700 - text.get_width() // 2, 380 - text.get_height() // 2))
pygame.display.flip()
clock.tick(60)
sounds
import pygame
pygame.mixer.init()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
pygame.mixer.music.load('The_Theme.wav')
pygame.mixer.music.play()
logo
import pygame
import os
_image_library = {}
def get_image(path):
global _image_library
image = _image_library.get(path)
if image == None:
canonicalized_path = path.replace('/', os.sep).replace('\\', os.sep)
image = pygame.image.load(canonicalized_path)
_image_library[path] = image
return image
pygame.init()
screen = pygame.display.set_mode((1000, 800))
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill((0, 0, 0))
screen.blit(get_image('sw.png'), (10, 10))
pygame.display.flip()
clock.tick(60)
Title_Crawl
#!/usr/bin/python
import pygame
from pygame.locals import *
pygame.init()
pygame.display.set_caption('Title Crawl')
screen = pygame.display.set_mode((1000, 800))
screen_r = screen.get_rect()
font = pygame.font.SysFont("franklingothicdemibold", 40)
clock = pygame.time.Clock()
def main():
crawl = ["Star Wars - The Wilds"," ","It is a dark time for the Galaxy. The evil Dark","Lord, Vitiate is rising to power. Alone, a single", "spec is on a trip, a trip that will ultimately", "rectify the wrongs of the galaxy. The keepers ", "of peace are dying out and the DARK SIDE is", "lurking, a conniving force determined to", "become the omniarch."]
texts = []
# we render the text once, since it's easier to work with surfaces
# also, font rendering is a performance killer
for i, line in enumerate(crawl):
s = font.render(line, 1, (229, 177, 58))
# we also create a Rect for each Surface.
# whenever you use rects with surfaces, it may be a good idea to use sprites instead
# we give each rect the correct starting position
r = s.get_rect(centerx=screen_r.centerx, y=screen_r.bottom + i * 45)
texts.append((r, s))
while True:
for e in pygame.event.get():
if e.type == QUIT or e.type == KEYDOWN and e.key == pygame.K_ESCAPE:
return
screen.fill((0, 0, 0))
for r, s in texts:
# now we just move each rect by one pixel each frame
r.move_ip(0, -1)
# and drawing is as simple as this
screen.blit(s, r)
# if all rects have left the screen, we exit
if not screen_r.collidelistall([r for (r, _) in texts]):
return
# only call this once so the screen does not flicker
pygame.display.flip()
# cap framerate at 60 FPS
clock.tick(60)
if __name__ == '__main__':
main()
The best way to do this would be to make them into classes and give them a run method, and then instantiate each one on a timer and call its run method to do what it needs to do.

Rainbow screen in python

As a project, I'm trying to make a screen that will flash random colors every tenth of a second or so.
Here's the code I have so far:
import pygame, random
from threading import Timer
background_colour = (random.randint(0,255),random.randint(0,255),random.randint(0,255))
(width, height) = (300, 200)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Rainbow!!!')
screen.fill(background_colour)
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
It opens a screen with a random background. But I've tried lots of methods for my next step. A little help?
Before running this make note that it contains rapid flashing colours
You need to change the variable background_colour every tenth of a second
a simple program that achieves the desired result:
import pygame
import random
window_x = 300
window_y = 200
def get_rand_colour():
colour_r = random.randint(0,255)
colour_g = random.randint(0,255)
colour_b = random.randint(0,255)
return (colour_r,colour_g,colour_b)
screen = pygame.display.set_mode((window_x,window_y))
pygame.display.set_caption("Rainbow!")
clock = pygame.time.Clock()
done = False
counter = 0
colour = get_rand_colour()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
counter += 1
if counter > 3:
colour = get_rand_colour()
counter = 0
screen.fill(colour)
pygame.display.flip()
clock.tick(30)
pygame.quit()
Hope this helps :)

How to clear up screen in pygame? [duplicate]

This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
My friends and I are making a quiz game in PyGame and would like to know how, when the user presses a button, he can go to next question (without leaving the previous text behind).
First of all I would suggest that you go to the PyGame documentation and read up a little about PyGame. (Link)
However to save you time what you have to do is before you draw your new set of shapes/writings on the screen you have to use the function screen.fill(#Your chosen colour). That is the function in PyGame that gets rid of the old screen and allows you to draw new items on to a clear screen without the pervious drawings left on there.
Example:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
red = (255, 0, 0)
class Pane(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Hello!', True, black), (200, 100))
pygame.display.update()
def addText2(self):
self.screen.blit(self.font.render('Hello!', True, red), (200, 100))
pygame.display.update()
def functionApp(self):
if __name__ == '__main__':
self.addRect()
self.addText()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.screen.fill(white)
self.addRect()
self.addText2() #i made it so it only changes colour once.
display = Pane()
display.functionApp()
In your game loop, before drawing the new frame, fill the frame with the background color.
Example:
ball = pygame.Rect(0,0,10,10)
while True:
mainSurface.fill((0,0,0))
pygame.draw.circle(display,(255,255,255),ball.center,5)
ball.move_ip(1,1)
pygame.display.update()
The key point is the mainSurface.fill which will clear the previous frame.

Categories