I am having a problem where i am trying to get a circle to go to the same spot every time i execute the program. But each time I run the code, the dot doesn't always line up. I have a test circle in the same place to compare run to run. The Red circle should cover the white circle perfectly but it changes every time i run the program. I am reseting the kernal as i am using pygame.time.get_ticks() to time everything.
import sys, pygame, math
from pygame.locals import *
# set up a bunch of constants
BLUE = ( 0, 0, 255)
WHITE = (255, 255, 255)
ORANGE = (255, 165, 0)
PINK = (255, 20, 147)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
LIMEGREEN = ( 50, 205, 50)
YELLOW = (255, 255, 0)
PURPLE = (160, 32, 240)
BLACK = ( 0, 0, 0)
#Background Colour
BGCOLOR = BLACK
#Setting Window Size and finding window x and y centre
WINDOWWIDTH = 1918# width of the program's window, in pixels 960x540
WINDOWHEIGHT = 1078# height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
# frames per second to run at
FPS = 60
#intializing Variables
AMPLITUDE = 450
colourArray=[BLUE,WHITE,YELLOW,GREEN,RED,PINK,PURPLE,LIMEGREEN,ORANGE]
i=0
xPos = 0
step = 0
small_step =0
stop_step=step=0
xPos=0
yPos=0
c=RED
timestep=0
# standard pygame setup code
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT),pygame.FULLSCREEN)
pygame.display.set_caption('Task1')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
# main application loop
while True:
# event handling loop for quit events
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
#setup for label and time
tempTime=pygame.time.get_ticks()/1000
time_string=str(tempTime)
instructionsSurf = fontObj.render(time_string, True, WHITE, BGCOLOR)
instructionsRect = instructionsSurf.get_rect()
instructionsRect.left = 10
instructionsRect.bottom = WINDOWHEIGHT - 10
# fill the screen to draw from a blank state
DISPLAYSURF.fill(BGCOLOR)
DISPLAYSURF.blit(instructionsSurf, instructionsRect)
tempTime=pygame.time.get_ticks()/1000
#Color change loop
c=RED
if (0<=(tempTime)<3):
c=RED
if (3<=(tempTime)<5):
c=BLUE
if (5<=(tempTime)<7):
c=GREEN
if (7<=(tempTime)<9):
c=YELLOW
if (9<=(tempTime)<11):
c=WHITE
if (11<=(tempTime)<17):
c=RED
if (17<=(tempTime)<42):
c=RED
if (42<=(tempTime)<46):
c=RED
if (46<=(tempTime)<120):
c=colourArray[i]
#Setting position of x and y coordinates
if (0<=(tempTime)<14):
xPos = 0
yPos = 0
if (14<(tempTime)<17):
small_step += 5.111
xPos = small_step
yPos = 0
if (17<(tempTime)<43):
step += 0.05001
step %= 2 * math.pi
xPos = math.cos(step) * AMPLITUDE
yPos = math.sin(step) * AMPLITUDE
if (43<(tempTime)<46):
stop_step=step
xPos = math.cos(stop_step) * AMPLITUDE
yPos = math.sin(stop_step) * AMPLITUDE
if (46<(tempTime)<120):
step += 0.05001
step %= 2 * math.pi
xPos = math.cos(step) * AMPLITUDE
yPos = math.sin(step) * AMPLITUDE
#test dot
pygame.draw.circle(DISPLAYSURF, WHITE, (WIN_CENTERX+AMPLITUDE, 0+WIN_CENTERY),12,0)
# draw dot1
dot1=pygame.draw.circle(DISPLAYSURF, c, (int(xPos)+ WIN_CENTERX, int(yPos) + WIN_CENTERY), 12,0)
# draw dot2
dot2=pygame.draw.circle(DISPLAYSURF, BLACK, (int(xPos) + WIN_CENTERX, int(yPos) + WIN_CENTERY), 6,0)
#refresh
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
I've only scanned your code but I would guess your inconsistency is due to a high frame rate (60). FPSCLOCK.tick(FPS) will make sure you go up to 60, but does not mean you will go 60 fps. So if your computer can not handle 60 frames per second, it will go below 60 frames.
Cristph Terasa's recommendation of using busy_loop should do the job for ya, but I personally have no experience for it and want to share a method of normalizing game speed across different FPSs.
Rather than reinventing a wheel, here's a link to a question that explains it. I recommend the second answer, written by pmoleri.
In Pygame, normalizing game-speed across different fps values
This solution should help your game run at the same speed no matter the frame rate.
Related
So i am new to python, and im working on a code that draws a spirograph and moves it. When I ran the code, all I got was a black screen with no circles on it. Im sure that im drawing circles and the screen is refreshing because i printed out its coordinates. However, the screen is still black. Any help?
import pygame
import math
import sys
import time
#setting colors
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
ORANGE = (255, 127, 0)
YELLOW = (255, 255, 0)
PURPLE = (160, 32, 240)
#setting what order the colors go in
listCircleColor = (RED, BLUE, GREEN, ORANGE, YELLOW, PURPLE, WHITE)
#how many circles per color
intGroup = 5
#the space between each circle
turnangle = 360/35
#width of screen
width = 600
#height of screen
height = 600
#radius of circles
radius = 100
#making the screen
screen = pygame.display.set_mode((width, height))
#if the code is running, then continue
running = True
##.draw.circle(screen, BLUE, (0, 0), radius, width=2)
circles = []
#draw
alpha = turnangle
for i in range(intGroup):
for cl in listCircleColor:
surfacetemp = pygame.Surface((width, height))
##circlerect = pygame.rect
if alpha > 0 and alpha < 90:
circlerect = pygame.draw.circle(surfacetemp, cl, (300 + radius *
math.cos(math.radians(alpha)), 300 + radius * math.sin(math.radians(alpha))), radius, width=2)
# second quarter of circles
if alpha > 90 and alpha < 180:
circlerect = pygame.draw.circle(surfacetemp, cl, (300 - radius *
math.cos(math.radians(180 - alpha)), 300 + radius * math.sin(math.radians(180 - alpha))), radius, width=2)
# third quarter of circles
if alpha > 180 and alpha < 270:
circlerect = pygame.draw.circle(surfacetemp, cl, (300 - radius *
math.cos(math.radians(270 - alpha)), 300 - radius * math.sin(math.radians(270 - alpha))), radius, width=2)
# last quarter of circles
if alpha > 270 and alpha < 360:
circlerect = pygame.draw.circle(surfacetemp, cl, (300 + radius *
math.cos(math.radians(360 - alpha)), 300 - radius * math.sin(math.radians(360 - alpha))), radius, width=2)
alpha = alpha + turnangle
##circles.append(circlerect)
circles.append(surfacetemp)
#move"
#exit only when user clicks on exit button
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
for crect in circles:
ret = crect.get_rect()
ret.right += 5
ret.left += 5
screen.blit(screen, ret)
##screen.blit(crect,crect)
pygame.time.Clock().tick(20)
pygame.display.update()
##for center, color in circles:
## pygame.draw.circle(screen, color, center, radius, 2)
##pygame.display.flip()
You blit on correct screen but you blit wrong objects.
You should use crect instead of screen as first argument
screen.blit(crect, ret)
but you have
screen.blit(screen, ret)
so you blit black screen on black screen
Surface as default uses 24bit colors R,G,B and it has black background so your code shows only one circle because other circles are behind black backgrounds of other surfaces.
To make transparent background you have to convert surfaces to 32bit colors R,G,B,Alpha
surfacetemp = surfacetemp.convert_alpha()
and fill background with transparent color - last value (alpha) has to be 0, other values don't matter (if you don't need semi-transparent color)
surfacetemp.fill((0,0,0,0))
And now you can see all circles.
There is also other problem.
Surface can keep image but not position. surface.get_rect() gives always only (0, 0, width, height). If you want to animate then you need another list to keep positions - you can use pygame.Rect() for this.
At start I create circles_rect with all get_rect() and later I use this list to change position and blit it.
Animation need also to clear screen in every loop to remove circles in old positions. I use screen.fill((0,0,0)) to draw black background.
If you change rec.right += 5 then you don't have to change rec.left because it is changed automatically (the same with rec.centerx)
Running
rec.right += 5
rec.left += 5
gives the same result as
rec.right += 10
EDIT:
You don't have to make different calculations for different quarters.
import pygame
import math
# setting colors
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
ORANGE = (255, 127, 0)
YELLOW = (255, 255, 0)
PURPLE = (160, 32, 240)
# setting what order the colors go in
listCircleColor = (RED, BLUE, GREEN, ORANGE, YELLOW, PURPLE, WHITE)
# how many circles per color
intGroup = 5
# the space between each circle
turnangle = 360/35
# width of screen
width = 600
# height of screen
height = 600
# radius of circles
radius = 100
# making the screen
screen = pygame.display.set_mode((width, height))
# .draw.circle(screen, BLUE, (0, 0), radius, width=2)
circles = []
circles_rect = []
# draw
alpha = turnangle
for i in range(intGroup):
for cl in listCircleColor:
surfacetemp = pygame.Surface((width, height))
surfacetemp = surfacetemp.convert_alpha()
surfacetemp.fill((0,0,0,0))
x = 300 + radius * math.cos(math.radians(alpha))
y = 300 + radius * math.sin(math.radians(alpha))
circlerect = pygame.draw.circle(surfacetemp, cl, (x, y), radius, width=2)
alpha = alpha + turnangle
circles.append(surfacetemp)
circles_rect.append(surfacetemp.get_rect())
# move
# exit only when user clicks on exit button
# if the code is running, then continue
running = True
clock = pygame.time.Clock()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
#running = False
screen.fill((0,0,0)) # remove previous circles
for crect, ret in zip(circles, circles_rect):
ret.right += 5
#ret.left += 5
screen.blit(crect, ret)
result = clock.tick(25)
fps = clock.get_fps()
text = f'FRAME TIME: {result:.02f} ms | FPS: {fps:.02f}'
pygame.display.set_caption(text)
#print(text)
#pygame.display.update()
pygame.display.flip()
I started today to program a game with pygame. In the background is a kind of grid on which you will play in the future. But I noticed that with a while loop to update the screen, the grid is redrawn every time and that's a waste of resources, because nothing changes there anyway. Now I thought about not updating the grid-screen in the background and creating a new screen to play on, which will be updated. But then I encountered a problem: When pygame starts a new screen, the last one closes.
So is it smart to have the game board redrawn every time or is there another method where you can leave an item in the background without updating it? Thank you very much for any help. Code and (wrong) approaches follow.
main.py
import field, game
import ctypes
# Variables
def main():
width, height = ctypes.windll.user32.GetSystemMetrics(0), ctypes.windll.user32.GetSystemMetrics(1)
width_scale, height_scale = 5 / 10, 9 / 10
black = (0, 0, 0)
white = (255, 255, 255)
background_color = (214, 237, 255)
refresh_rate = 60
field_size = [10, 18]
screen = pg.display.set_mode([int(width * width_scale), int(height * height_scale)], pg.NOFRAME)
while True:
for event in pg.event.get():
if event.type == pg.KEYDOWN:
pass
screen.fill(background_color)
box_size = field.draw_boxes(screen.get_width(), screen.get_height(), field_size, screen)
field.draw_next_hand()
pg.display.flip()
game.main(width, height, box_size, field_size)
if __name__ == '__main__':
main()
pg.quit()
field.py
import pygame as pg
def draw_boxes(w, h, size, screen):
global start_x, box_size, g_screen, grey, s
g_screen = screen
s = size
box_size = int(w / 2 / (size[0]+1))
start_x = int(w / 2 - size[0] / 2 * box_size)
grey = (122, 122, 122)
for column in range(0, size[0], 1):
for row in range(0, size[1], 1):
pg.draw.rect(screen, grey, [start_x + column * box_size, box_size + row * box_size, box_size, box_size], width= 1)
return box_size
def draw_next_hand():
global box_size, start_x, g_screen, grey
next_hand_size = 4
next_hand_distance = 1
for column in range(0, next_hand_size, 1):
for row in range(0, next_hand_size, 1):
pg.draw.rect(g_screen, grey, [start_x - 2*box_size*next_hand_distance - column * box_size, box_size + row * box_size, box_size, box_size], width=1)
pg.draw.rect(g_screen, grey, [start_x + box_size*s[0] + box_size * next_hand_distance + column * box_size, box_size + row * box_size, box_size, box_size], width=1)
game.py
import pygame as pg
from main import main
def main(width, height, box_size, f_size):
# Variables
white = (255, 255, 255)
black = (0, 0, 0)
grey = (122, 122, 122)
refresh_rate = 60
g_screen = pg.display.set_mode([int(f_size[0] * box_size), int(f_size[1] * box_size)], pg.NOFRAME)
while True:
g_screen.fill(white)
pg.display.flip()
pg.time.delay(refresh_rate)
Before I added the new screen I had "pg.time.delay(refresh_rate)" instead of "game.main()", which caused the background to be constantly redrawn, so I tried to draw another screen over it, which of course didn't work^^
I've already found some entries on stack overflow, but they didn't fit my problem, because it was suggested to change the screen with for example main = False and game = True, but this wouldn't prevent the board from being redrawn
There's a few ways to improve the performance concerning the background image.
Draw once - You can store the background image in a surface object so it only needs to be generated once. Pygame will retain the screen when hidden or minimized.
Only redraw the updated section - Set a clipping rectangle on the screen so only certain pixels get refreshed when the background is redrawn
Only redraw when needed - The game loop is required, but you can conditionally re-render the background
Draw efficiently - Slow down the game loop using the pygame.time.Clock().tick() method
Here's a short program that illustrates these points. It just shows the current date\time on a background of circles.
import pygame as pg
import time
from datetime import datetime as dt
from random import randint
WIDTH = 480
HEIGHT = 600
pg.init()
screen = pg.display.set_mode((WIDTH, HEIGHT))
def rnd(rg): # save some typing
return randint(0,rg)
font_name = pg.font.match_font('arial')
def draw_text(surf, text, size, x, y): # draw text on screen in rect
font = pg.font.Font(font_name, size)
text_surface = font.render(text, True, (rnd(255),rnd(255),rnd(255)))
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
def make_bg(): # create background image
surf_bg = pg.Surface((WIDTH, HEIGHT))
surf_bg.fill((0,0,0)) # start with black
for i in range(500): # 500 circles
pg.draw.circle(surf_bg,(rnd(255),rnd(255),rnd(255)), (rnd(WIDTH),rnd(HEIGHT)), 15+rnd(50))
return surf_bg
surf_bg = make_bg() # generate circles once, store surface object
#initial background
screen.blit(surf_bg, screen.get_rect()) # draw background, only needed once in Windows
screen.set_clip((10, HEIGHT/2 - 20, WIDTH-10, HEIGHT/2 + 20)) # set active region on screen
lasttick = pg.time.get_ticks() # milliseconds since init
while True:
pg.time.Clock().tick(5) # run loop 5 times per second
pg.event.get() # required in Windows for OS events
if pg.key.get_pressed()[pg.K_SPACE]: quit() # press space to quit
if (pg.time.get_ticks() - lasttick < 1000): continue # only redraw time each second
lasttick = pg.time.get_ticks()
screen.blit(surf_bg, screen.get_rect()) # background, update clip region only
draw_text(screen, str(dt.now()), 30, WIDTH / 2, HEIGHT / 2 - 10) # draw time
pg.display.flip() # swap screen buffer
I have a program with a player (who is an image) and a rectangle and I want that when the player has a collision with the rectangle, the size of the image increase.
For now, I have this code :
import pygame
from random import randint
WIDTH, HEIGHT = 800, 800
FPS = 60
pygame.init()
win = pygame.display.set_mode((WIDTH, HEIGHT))
fenetre_rect = pygame.Rect(0, 0, WIDTH, HEIGHT)
pygame.display.set_caption("Hagar.io")
clock = pygame.time.Clock()
bg = pygame.image.load("bg.png").convert()
bg_surface = bg.get_rect(center=(WIDTH / 2, HEIGHT / 2))
bg_x = bg_surface.x
bg_y = bg_surface.y
x_max = WIDTH / 2
y_max = HEIGHT / 2
# player
player = pygame.transform.scale(pygame.image.load("player.png").convert_alpha(), (i, i))
player_rect = player.get_rect(center=(x_max, y_max))
# cell
rect_surface = pygame.Rect(300, 500, 20, 20)
# Game loop
running = True
while running:
dt = clock.tick(FPS) / 1000
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if player_rect.colliderect(rect_surface):
print("collide")
bg_surface.x = bg_x
bg_surface.y = bg_y
# draw on screen
win.blit(bg, bg_surface)
pygame.draw.rect(win, (255, 0, 0), rect_surface)
win.blit(player, player_rect)
pygame.display.flip()
pygame.quit()
I have try to add in the "colliderect" condition but it does not work :
player_rect.width += 1
player_rect.height += 1
Thanks for your help !
This line
player = pygame.transform.scale(pygame.image.load("player.png").convert_alpha(), (i, i))
is using the variable i but it is not defined in your code. I'm not sure where it is defined, but it is key to what you want. I will try to answer without this information anyway:
Thing is, enlarging the rect won't do anything, because a rect is just coordinates. You have to scale the actual image, and pygame.transform.scale does exactly that.
You can keep the image in a separate variable player_img:
player_img = pygame.image.load("player.png").convert_alpha()
player = pygame.transform.scale(player_img, (i, i))
Then when you want to scale it differently, just call .scale() again:
double_size_player = pygame.transform.scale(player_img, (i*2, i*2))
That still leaves us to the mistery of your undefined i variable, but I think you get the gist of it. Remeber that you have to extract a new rect from the scaled image because it will be bigger.
I am trying to place multiple circles onto an eclipse and be able to move that circle around the eclipse. From looking into PyGames examples I have seen that you can rotate a line around an eclipse however cannot figure out how to do with with a circle.
This is the error message I recieve upon trying:
Traceback (most recent call last):
File "C:/Python32/Attempts/simple_graphics_demo.py", line 66, in <module>
pygame.draw.circle(screen, BLUE, [x, y], 15, 3)
TypeError: integer argument expected, got float
.
import pygame
import math
# Initialize the game engine
pygame.init()
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
PI = 3.141592653
# Set the height and width of the screen
size = [400, 400]
screen = pygame.display.set_mode(size)
my_clock = pygame.time.Clock()
# Loop until the user clicks the close button.
done = False
angle = 0
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(WHITE)
# Dimensions of radar sweep
# Start with the top left at 20,20
# Width/height of 250
box_dimensions = [20, 20, 250, 250]
# Draw the outline of a circle to 'sweep' the line around
pygame.draw.ellipse(screen, GREEN, box_dimensions, 2)
# Draw a black box around the circle
pygame.draw.rect(screen, BLACK, box_dimensions, 2)
# Calculate the x,y for the end point of our 'sweep' based on
# the current angle
x = 125 * math.sin(angle) + 145
y = 125 * math.cos(angle) + 145
# Draw the line from the center at 145, 145 to the calculated
# end spot
pygame.draw.line(screen, GREEN, [145, 145], [x, y], 2)
# Attempt to draw a circle on the radar
pygame.draw.circle(screen, BLUE, [x, y], 15, 3)
# Increase the angle by 0.03 radians
angle = angle + .03
# If we have done a full sweep, reset the angle to 0
if angle > 2 * PI:
angle = angle - 2 * PI
# Flip the display, wait out the clock tick
pygame.display.flip()
my_clock.tick(60)
# on exit.
pygame.quit()
The math.sin and math.cos functions return floats, and the pos keyword argument to pygame.draw.circle expects integer positions, so you'll want to actually cast your coordinates. You have a few options for doing this:
[int(x), int(y)]
[math.floor(x), math.floor(y)]
[math.ceil(x), math.ceil(y)]
Each comes with slightly different behaviours so you might want to figure out which fits your program best. (specifically: int and floor work differently for negative numbers -- int rounds towards 0 and floor rounds down, as expected)
It is not answer for your main question - because you already got answer.
To put more circles use list with angles and for loop to get angle from list (one-by-one) and draw circle.
import pygame
import math
# === CONSTANTS ===
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
SIZE = (400, 400)
TWO_PI = 2 * math.pi # you don't have to calculate it in loop
# === MAIN ===
# --- init ---
pygame.init()
screen = pygame.display.set_mode(SIZE)
# --- objects ---
angles = [0, 1, math.pi] # angles for many circles
box_dimensions = [20, 20, 250, 250] # create only once
# --- mainloop ---
clock = pygame.time.Clock()
done = False
while not done:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
# --- draws (without updates) ---
screen.fill(WHITE)
pygame.draw.ellipse(screen, GREEN, box_dimensions, 2)
pygame.draw.rect(screen, BLACK, box_dimensions, 2)
# draw many circles
for a in angles:
x = int(125 * math.sin(a)) + 145
y = int(125 * math.cos(a)) + 145
pygame.draw.line(screen, GREEN, [145, 145], [x, y], 2)
pygame.draw.circle(screen, BLUE, [x, y], 15, 3)
pygame.display.flip()
clock.tick(60)
# --- updates (without draws) ---
# new values for many angles
for i, a in enumerate(angles):
a += .03
if a > TWO_PI:
a -= TWO_PI
angles[i] = a
# --- the end ---
pygame.quit()
I want to add gradient to the ball in this program & also possibly the waves drawn to fade into the colour of the background (as if glowing) instead of one colour fills.
I've looked at tons of tutorials however none of them are making much sense to my syntax, the general idea to me is confusing as I have moving objects that draw the space I want to add gradient to quite slowly. Can anyone give an insight into how I can do this?
code:
import sys, pygame, math
from pygame.locals import *
# set up of constants
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
BGCOLOR = WHITE
screen = pygame.display.set_mode()
WINDOWWIDTH = 800 # width of the program's window, in pixels
WINDOWHEIGHT = 800 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
screen = pygame.display.get_surface()
FPS = 160 # frames per second to run at
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
# standard pygame setup code
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.RESIZABLE)
pygame.display.set_caption('Window title')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
# variables that track visibility modes
showSine = True
showSquare = True
pause = False
xPos = 0
step = 0 # the current input f
posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves
yPosSquare = AMPLITUDE # starting position
# main application loop
while True:
# event handling loop for quit events
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
# fill the screen to draw from a blank state
DISPLAYSURF.fill(BGCOLOR)
# sine wave
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
if showSine:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
if showSine:
for x, y in posRecord['sin']:
pygame.draw.circle(DISPLAYSURF, DARKRED, (x,y), 4)
#drawing horizontal lines
# square
posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
if showSquare:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
DISPLAYSURF.blit(squareLabelSurf, squareLabelRect)
# draw the waves from the previously recorded ball positions
if showSquare:
for x, y in posRecord['square']:
pygame.draw.circle(DISPLAYSURF, BLUE, (x, y), 4)
# draw the border
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
if not pause:
xPos += 1
#wave movement
if xPos > WINDOWWIDTH:
#sine
xPos = 0
posRecord['sin'] = []
step = 0
# square
yPosSquare = AMPLITUDE
posRecord['square'] = []
else:
#sine
step += 0.008
#step %= 2 * math.pi
# square
# jump top and bottom every 100 pixels
if xPos % 100 == 0:
yPosSquare *= -1
# add vertical line
for x in range(-AMPLITUDE, AMPLITUDE):
posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))
Use SPACE to change background color.
First line use only transparency - and has no problem with different background color.
Second line changes only circles color - and depends on background color.
Third and fourth line (it is the same line with different starting color) change circles color and transparency - and depends on background color.
Second and last line look good on one color background and need more work to find good-looking fading.
import pygame
pygame.init()
screen = pygame.display.set_mode((600,200))
#--------------------------------------
# circles positions and transparency (x,y, alpha)
circles = []
for x in range(100):
circles.append( [100+x*3, 200, x*2] )
#--------------------------------------
white = True # background color
#--------------------------------------
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_SPACE:
white = not white
#--------------------------------------
if white:
screen.fill((255,255,255))
else:
screen.fill((0,0,0))
#--------------------------------------
# first
circle_img = pygame.Surface((20,20))
pygame.draw.circle(circle_img, (255,0,0), (10,10), 10)
circle_img.set_colorkey(0)
for x in circles:
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],40))
#--------------------------------------
# second
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
screen.blit(circle_img, (x[0],90))
#--------------------------------------
# last
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],140))
#--------------------------------------
pygame.display.flip()
pygame.quit()