Python cleaning and visual improvement - python

I'm just starting to learn python, specifically pygame, and am trying to make a simple jumping game. I made a basic movement script as a test, but the animations are really choppy. Whenever the block moves, there's an afterimage, and it looks like its just breaking down. Also, if you have any suggestions for cleaning up the script, that'd be great.
import pygame
from pygame.locals import *
SIZE = 800, 600
RED = (255, 0, 0)
GRAY = (150, 150, 150)
x = 50
y = 50
pygame.init()
screen = pygame.display.set_mode(SIZE)
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
pressed = pygame.key.get_pressed()
if pressed[pygame.K_RIGHT]:
x += 3
if pressed[pygame.K_LEFT]:
x -= 3
if pressed[pygame.K_UP]:
y -= 3
if pressed[pygame.K_DOWN]:
y += 3
rect = Rect(x, y, 50, 50)
screen.fill(GRAY)
pygame.draw.rect(screen, RED, rect)
pygame.display.flip()
pygame.quit()

In PyGame, you have to manage FPS in order to keep your game constant. For example, if you have a really fast computer you will have like 200 or 300 FPS and on a little scene like you did, every second your player will move by 200 times the speed, so this is quite fast, otherwise your computer is a really old one, you'll get like 30 FPS, and your player will move by only 30 times your speed every second, and that's obviously way slower.
What I want to explain to you is that FPS are essential so your game can have constant moves and velocity.
So I added just to lines to configure FPS, I set 60 and changed the speed to 10 but you can easily adapt these values for your computer.
import pygame
from pygame.locals import *
SIZE = 800, 600
RED = (255, 0, 0)
GRAY = (150, 150, 150)
x = 50
y = 50
pygame.init()
screen = pygame.display.set_mode(SIZE)
# creating a clock
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
pressed = pygame.key.get_pressed()
if pressed[pygame.K_RIGHT]:
x += 10
if pressed[pygame.K_LEFT]:
x -= 10
if pressed[pygame.K_UP]:
y -= 10
if pressed[pygame.K_DOWN]:
y += 10
rect = Rect(x, y, 50, 50)
screen.fill(GRAY)
pygame.draw.rect(screen, RED, rect)
# setting the fps to 60, depending on your machine, 60 fps is great in my opinion
clock.tick(60)
pygame.display.flip()
pygame.quit()

Related

Text keeps blinking in pygame

so I am making a code where there is a character(A rectangle) and and Balloon(A circle) and the character has to catch the balloons before it hits the ground. Everything worked fine until I tried making the game look a little better and used the blit function to add an image. For some reason my text keeps buffering now.
Code:
import random
import pygame
from pygame.locals import *
pygame.init()
#Variables
white = (255, 255, 255)
blue = (70,130,180)
black = (0,0,0)
red = (255,0,0)
x = 400
y = 450
score = 0
cooly = 100
randomx = random.randint(100,800)
clock = pygame.time.Clock()
#screen stuff
screenwidth = 800
screenheight = 600
screen = pygame.display.set_mode((screenwidth, screenheight))
pygame.display.set_caption("Balloon Game!")
#end of screen stuff
#Initializing font
def show_text(msg, x, y, color,size):
fontobj= pygame.font.SysFont("freesans", size)
msgobj = fontobj.render(msg,False,color)
screen.blit(msgobj,(x, y))
#Game loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
# Draw Character
screen.fill(blue)
character = pygame.draw.rect(screen, red, (x, y, 60, 60))
#End of Drawing Character
#Draw Balloons
balloon = pygame.draw.circle(screen, (black), (randomx, cooly), 30, 30)
cooly = cooly + 2
# Making Arrow Keys
keyPressed = pygame.key.get_pressed()
if keyPressed[pygame.K_LEFT]:
x -= 3
if keyPressed[pygame.K_RIGHT]:
x += 3
#Drawing Cool Stuff
Cloud = pygame.image.load('Cloud.png')
screen.blit(Cloud,(100,75))
pygame.display.update()
#End of making arrow keys
show_text("Score:",130,0,black,50)
show_text(str(score),250,0,black,50)
#Collision
if balloon.colliderect(character):
randomx = random.randint(100,800)
cooly = 100
score = score + 1
#end of collision
#Ending
if cooly >= 600:
screen.fill(blue)
show_text("Game Over!", 200, 250, black, 100)
show_text("Score :", 200, 350, black, 75)
show_text(str(score), 400, 350, black, 75)
#Polishing
if score == score + 5:
cooly += 1
x += 3
pygame.display.update()
clock.tick(250)
The problem is caused by multiple calls to pygame.display.update(). An update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.
Remove all calls to pygame.display.update() from your code, but call it once at the end of the application loop.
Do not create the font object and do not load the images in the application loop. This are very expensive operatios, because the filed have to be read and interpreted:
fontobj= pygame.font.SysFont("freesans", size) #<-- INSERT
def show_text(msg, x, y, color,size):
# fontobj= pygame.font.SysFont("freesans", size) <-- DELET
msgobj = fontobj.render(msg,False,color)
screen.blit(msgobj,(x, y))
Cloud = pygame.image.load('Cloud.png') #<-- INSERT
# [...]
while True:
# [...]
# Cloud = pygame.image.load('Cloud.png') <-- DELETE
screen.blit(Cloud,(100,75))
# pygame.display.update() <-- DELETE
# [...]
pygame.display.update()
clock.tick(250)

How can I stop a character in pygame from leaving the edge of the screen?

I have created a small program in pygame where the player controls a blue square moving around the screen, but I want to stop the player from moving past the edge of the screen. Here is the code I have so far, how can I do this?
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
done = False
x = 30
y = 30
clock = pygame.time.Clock()
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_SPACE:
is_blue = not is_blue
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]: y -= 5
if pressed[pygame.K_DOWN]: y += 5
if pressed[pygame.K_LEFT]: x -= 5
if pressed[pygame.K_RIGHT]: x += 5
screen.fill((0, 0, 0))
color = (0, 128, 255)
pygame.draw.rect(screen, color, pygame.Rect(x, y, 60, 60))
pygame.display.flip()
clock.tick(60)
pygame.Rects have a clamp (and clamp_ip) method which you can use to limit the movement area. So create a rect with the size of the screen (called screen_rect here) and a rect for the player (player_rect) and call the clamp_ip method after each movement to keep it inside of the screen area.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
BG_COLOR = pg.Color(30, 30, 50)
def main():
clock = pg.time.Clock()
image = pg.Surface((50, 30))
image.fill(pg.Color('dodgerblue'))
pg.draw.rect(image, pg.Color(40, 220, 190), (0, 0, 49, 29), 2)
player_rect = image.get_rect(topleft=(200, 200))
# This pygame.Rect has the dimensions of the screen and
# is used to clamp the player_rect to this area.
screen_rect = screen.get_rect()
speed = 5
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
pressed = pg.key.get_pressed()
if pressed[pg.K_UP]:
player_rect.y -= speed
if pressed[pg.K_DOWN]:
player_rect.y += speed
if pressed[pg.K_LEFT]:
player_rect.x -= speed
if pressed[pg.K_RIGHT]:
player_rect.x += speed
# Clamp the rect to the dimensions of the screen_rect.
player_rect.clamp_ip(screen_rect)
screen.fill(BG_COLOR)
screen.blit(image, player_rect)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()
This should work
if pressed[pygame.K_UP] and y > 0: y -= 5
if pressed[pygame.K_DOWN] and y < 600 - 60: y += 5
if pressed[pygame.K_LEFT] and x > 0: x -= 5
if pressed[pygame.K_RIGHT] and x < 800 - 60: x += 5
Where 600 and 800 is the screen size and 60 the size of your rectangle
Something like:
if pressed[pygame.K_UP]:
if not (y > maxwidth or y < 0):
y += 5
And so on for the others. the maxwidth looks like 600 in your code but I'd put it at the top of your code so you dont keep having to change it in different places.
What you are trying to do is called edge detection, as in detect if you are at an edge, in this case you want the edges to be the screen's edges. what you should do, is check if your x or y are at an edge, if so don't go any further.
if pressed[pygame.K_UP]:
if 0 < y-5 < 600: #0 and 600 being the edges of your screen, you can use a variable to change it dynamically later one
y -= 5
Note this will only detect if the top left's square is going out of bounds, since x and y is the top and left coords for the rectangle, meaning the bottom right of the square will be able to still go out of bounds,
If you want to check the whole square, you will have to make adjustment calculations in the if statement, or base your x and y on the center (which you will still have to modify the if statement to something like below. (note I'm altering based on your current code for x and y being top left.
if pressed[pygame.K_UP]:
if (0 < y-5 < 600) or (0< y+60-5 <600) #0 and 600 being the edges of your screen, you can use a variable to change it dynamically later one
y -= 5
This checks the other side of the square. Note for x you will check for the horizontal limits which in this case is 800. Also we are checking including the -5 because we want to see where we are going, not where we are at.

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.)

Python pygame balls moving

I am writing a simple "game" and I have three questions for you:
How can I make all the balls moving independetly?
When I drag a ball with a mouse and click on the screen, how can i make the ball stay there. I want to draw it on that specific coordinate where the mouse key was pressed. It has to stay there all the time.
If a small ball touches the large one it shoud become a large one and dissapear after 10 seconds.
I have no idea how to do this. Can you please help me.
My code:
import pygame
import sys
from pygame.locals import *
import random
pygame.init()
width = 800
height = 600
fps = 25
clock = pygame.time.Clock()
black = (0, 0, 0)
white = (255, 255, 255)
display_window = pygame.display.set_mode((width, height))
pygame.display.set_caption('Bouncy')
game_over = False
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
x_cor = random.randint(15, width - 15)
y_cor = random.randint(15, height - 15)
x_change = random.randint(3, 7)
y_change = random.randint(3, 7)
coordinates = []
for i in range(10):
x = random.randint(0, width)
y = random.randint(0, height)
coordinates.append([x, y])
while not game_over:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == pygame.mouse.get_pressed():
pass
x_cor += x_change
y_cor += y_change
display_window.fill(white)
mouse_x, mouse_y = pygame.mouse.get_pos()
for coordinate in coordinates:
pygame.draw.circle(display_window, (r, g, b), (coordinate[0], coordinate[1]), 15, 0)
pygame.draw.circle(display_window, black, (mouse_x, mouse_y), 25, 0)
pygame.draw.circle(display_window, (r, g, b), (x_cor, y_cor), 15, 0)
if x_cor > (width - 15) or x_cor < 15:
x_change = x_change * -1
if y_cor > (height - 15)or y_cor < 15:
y_change = y_change * -1
clock.tick(fps)
pygame.display.update()
First and foremost, do the research required before you post here (see the help documents on the intro tour). There are many tutorials on the Internet, and many answered questions in SO (StackOverflow) that deal with moving objects. To get you started in general:
You move the balls independently by keeping a separate set of coordinates for each ball. On each iteration of the game clock, you have to reiterate the new coordinates of each ball.
To make a ball stay in one place, simply do not change its coordinates.
To change the size of a ball, draw it with a larger radius. This means that you also have to remember the radius of each ball. To give it a 10-second lifetime, keep a "lifespan" for each ball; decrement it on each tick of the game clock.
Bascially, you need a Ball object (make a class Ball); instantiate a new object for each ball you need. Write methods to change the position, size, and life span of each ball.

How to make the object move during a while infinite loop?

I've been trying to create a game. In the game there is a jet that would fly into the recursive background rectangles. The rectangles are created through an infinite loop so once it enters the loop rest of the functions don't work for example the object. My code is below and the problem arises in the main loop. I want the object to move with the recursive rectangles but it freezes when the rectangles start being drawn in the loop. PS help to fix this as I've tried almost every code sample out there to fix it. Thank you
EDIT: the main function of the game is to make the jet go through what seems like recursive like rectangles (there are two of them and the while loop makes it simultaneously move up and down giving the feeling that the jet is going into the screen.). But since the jet is drawn first, when the program enters the rectangle loop the jet freezes and wont be able to move. I want the jet to move while the background is also moving.
import pygame
import random
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
Blue = (2,55,55)
black=(0,0,0)
end_it=False
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE,
[x, y, width, height],
1)
speed = [10,0]
rect_change_x = 10
rect_change_y = 10
# Is the rectangle wide enough to draw again?
if (width > 25):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
def recursive_draw2(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, Blue,
[x, y, width, height],
1)
speed = [10,0]
rect_change_x = 10
rect_change_y = 10
# Is the rectangle wide enough to draw again?
if (width > 25):
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw2(x, y, width, height)
'''
def timer(self):
screen.fill(black)
myfont=pygame.font.SysFont("Britannic Bold", 40)
label2=myfont.render("Ready?", 1, (255, 0, 0))
screen.blit(label2, (350,250))
self =3
nlist=[]
for i in range (2):
score = myfont.render(str(self),1,(255,0,0))
screen.blit((score), (350,250))
self = self - 1
nlist.append(self)
pygame.display.flip()
'''
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
USEREVENT = 0
pygame.time.set_timer(USEREVENT+1, 10)
milliseconds = 0
seconds = 0
start_it = False
while (end_it==False):
screen.fill(black)
myfont=pygame.font.SysFont("Britannic Bold", 40)
nlabel=myfont.render("Welcome to "+ " Jet shooter ", 1, (255, 0, 0))
label=myfont.render("Click on the mouse to start ", 1, (255, 0, 0))
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
end_it=True
screen.blit(nlabel,(200, 100))
screen.blit(label, (170,300))
pygame.display.flip()
while (start_it==False):
screen.fill(black)
myfont2=pygame.font.SysFont("Britannic Bold", 40)
label2=myfont2.render("Ready?", 1, (255, 0, 0))
screen.blit(label2, (300,250))
pygame.display.flip()
pygame.time.wait(3000)
start_it = True
fall = False
while (fall==False):
nlist = [3,2,1]
for i in (nlist):
screen.fill(black)
n = str(i)
myfont3=pygame.font.SysFont("Britannic Bold", 40)
score = myfont3.render(n,1,(255,0,0))
screen.blit((score), (350,250))
pygame.display.flip()
pygame.time.wait(1000)
screen.fill(black)
myfont4=pygame.font.SysFont("Britannic Bold", 40)
label4=myfont3.render("GOOO!!!", 1, (255, 0, 0))
screen.blit(label4, (300,250))
pygame.display.flip()
pygame.time.wait (1000)
fall = True
b = 0
flip = 1
a = 0
time = 100
x_speed = 0
y_speed = 0
x_coord = 320
y_coord = 400
image = pygame.image.load("spaceship.gif").convert()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# User pressed down on key
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_speed = -10
if event.key == pygame.K_RIGHT:
x_speed = 10
if event.key == pygame.K_UP:
y_speed = -10
if event.key == pygame.K_DOWN:
y_speed = 10
# User let go of key
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_speed = 0
if event.key == pygame.K_RIGHT:
x_speed = 0
if event.key == pygame.K_UP:
y_speed = 0
if event.key == pygame.K_DOWN:
y_speed = 0
x_coord += x_speed
y_coord += y_speed
# Set the screen background
screen.fill(BLACK)
screen.blit(image, [x_coord,y_coord])
pygame.display.flip()
clock.tick(60)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
# Limit to 60 frames per second
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
while a == 0 :
if flip == 1 :
recursive_draw(35,25,625,450)
recursive_draw2(0, 0, 700, 500)
flip = flip + 1
pygame.display.flip()
clock.tick(60)
if flip == 2 :
recursive_draw(0, 0, 700, 500)
recursive_draw2(35, 25, 625, 450)
flip = flip - 1
pygame.display.flip()
clock.tick(60)
pygame.quit()
As #Paul Rooney has stated, you'll want to use threads. Here's how you would
import thread
.
.
.
# Instead of calling the function as you are, run it on a new thread
thread.start_new_thread(drawRectanglesFunction, ())
From what I can tell is that you're drawing things in the incorrect order, and I believe that while loop is not needed. (while a == 0). Another thing is that you're flipping the display too often it is hard to keep track of what gets drawn first, and what gets drawn afterwards. My suggestion would be to quickly rewrite your program so that it looks something similar to this:
flip = 1
while not done:
##Catch and handle events()
screen.fill(BLACK)
if flip == 1 :
recursive_draw(35,25,625,450)
recursive_draw2(0, 0, 700, 500)
flip = flip + 1
elif flip == 2 :
recursive_draw(0, 0, 700, 500)
recursive_draw2(35, 25, 625, 450)
flip = flip - 1
screen.blit(image, [x_coord,y_coord])
pygame.display.flip()
clock.tick(60);
I hope this helps out a little.
(Edit: I did this on my own and got the program to run)

Categories