When I left click, a line should show from the origin, and if left clicked with two seconds, white circles should appear. After two seconds, another line is drawn and then after two seconds the previous line should disappear. Right now, when I click, a line shows from the origin and then when I click again, two lines show.
from pygame import *
import random
init()
size = width, height = 700, 700
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
color = RED
mx = 0
my = 0
cx = 0
cy = 0
def drawScene(screen, button):
if button == 1:
draw.circle(screen, RED, (mx,my), 5)
draw.line(screen, color, (mx,my),(lx,ly), 2)
cx = lx
cy = ly
draw.circle(screen, RED, (mx,my), 5)
display.flip()
if button == 3:
draw.line(screen, color, (mx,my),(lx,ly), 2)
draw.circle(screen, color, (lx,ly), 5)
display.flip()
running = True
myClock = time.Clock()
# Game Loop
while running:
lx = mx
ly = my
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN:
mx,my = evnt.pos
button = evnt.button
if time.get_ticks() <= 2000 and time.get_ticks() > 0 :
draw.circle(screen, WHITE, (mx,my), 5)
else:
draw.line(screen, WHITE, (cx,cy),(lx,ly), 2)
if button == 3:
if color == RED:
color = BLUE
elif color == BLUE:
color = GREEN
elif color == GREEN:
color = RED
drawScene(screen, button)
myClock.tick(60)
quit()
Lets start with setting up a basic window first
from pygame import *
import random
init()
size = width, height = 700, 700
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
color = RED
running = True
myClock = time.Clock()
def drawScene():
screen.fill(BLACK)
display.update() #update is the same as flip()
# Game Loop
while running:
myClock.tick(60)
drawScene()
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running = False
After helping someone else with this problem (the question i linked), i found that using lists would be the best idea
So lets create a list for the points where the circles go and lines connect to
points = [] #put this before the drawScene function so it can reference it
Now, when the user clicks, we want to add the point to the list and draw it on the screen
def drawScene():
screen.fill(BLACK)
for point in points:
draw.circle(screen,color,point,5)
display.update() #update is the same as flip()
if evnt.type == MOUSEBUTTONDOWN:
points.append(evnt.pos)
now we can create points on the screen by clicking. Lets create the lines
We want to start at the origin so add the origin to the list at the start
points = [(0,0)]
Now we want to loop through every point and draw a circle and a line in between. so change the loop to
for i in range(1,len(points)): #loop through all but the first point as you dont want circle at origin
draw.circle(screen,WHITE,points[i],5)
draw.line(screen,color,points[i - 1],points[i])
Now we can draw lines and circles. But we only want to draw the circles if we clicked within 2 seconds, so lets create a timer, we will make one for each line so lets make a list as each line disappears after 2 seconds aswell
timers = []
Once we click, we want to start the timer, we can do that with
if evnt.type == MOUSEBUTTONDOWN:
points.append(evnt.pos)
timers.append(time.get_ticks())
this gets the current time in milliseconds we want to know once its been 2 seconds so if we get the current time and minus the start time, we get the difference so
for i in range(len(timers)-1,-1,-1):
if time.get_ticks() - timers[i] > 2000: #if been 2 seconds
del timers[i] #delete the timer
del points[i + 1] #delete the point for the line
this gets pretty close after 2 seconds the new line moves to the origin, to fix this, we need to delete the origin point
del points[i]
but now after the lines disappear, it starts at the last place clicked instead of the origin. so lets check if there is no lines, make sure the origin is the first point
if len(points) == 1:
points[0] = (0,0)
Awesome, the last thing is the circles appearing within the 2 seconds, which also means more than 1 line so
if points[0] != (0,0) or len(points) > 2:
draw.circle(screen,WHITE,points[i],5)
Here is the full code:
from pygame import *
import random
init()
size = width, height = 700, 700
screen = display.set_mode(size)
button = 0
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
WHITE = (255, 255, 255)
color = RED
running = True
myClock = time.Clock()
points = [(0,0)]
timers = []
def drawScene():
screen.fill(BLACK)
for i in range(1,len(points)): #loop through all but the first point as you dont want circle at origin
if points[0] != (0,0) or len(points) > 2:
draw.circle(screen,WHITE,points[i],5)
draw.line(screen,color,points[i - 1],points[i])
for i in range(len(timers)-1,-1,-1):
if time.get_ticks() - timers[i] > 2000: #if been 2 seconds
del timers[i] #delete the timer
del points[i] #delete the point for the line
if len(points) == 1:
points[0] = (0,0)
display.update() #update is the same as flip()
# Game Loop
while running:
myClock.tick(60)
drawScene()
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN:
points.append(evnt.pos)
timers.append(time.get_ticks())
Related
I need some help creating a video renderer in Pygame. It has a 48x36 display and has 3 colours. Black, white and grey. The data that goes into the project is in the form of a .txt file and each frame of the video in a line(as an example my video uses 6567 frames so there are 6567 lines in the text file). To render the frames I am using the rectangle function.
pygame.draw.rect(canvas, rect_color, pygame.Rect(30,30,60,60))
(By the way in the .txt file 0=black, 1=white and 2=grey)
After finally making a window pop up it stayed a rather boring black color...
After finally making a window pop up it stayed a rather boring black color...
If you could give any help it would be greatly needed!
(The code is messy i know)
import time
from datetime import datetime
import pygame
file= open(r"C:\Users\User\Downloads\video Data.txt","r")
lines = file.readlines()
current_l = 1
start_time = time.perf_counter()
pygame.init()
surface = pygame.display.set_mode((480,360))
color = (150,75,75)
def start_vid():
current_l = 1
for frame in range(1, 6572):
xpos = 0
ypos = 0
now = datetime.now()
count = 0
seconds = now.second
frame_data = lines[current_l]
current = frame_data[count]
for y in range(0, 36):
for x in range(0, 48):
if current == '0':
pygame.draw.rect(surface, (0, 0, 255),[xpos, xpos+10, ypos, ypos+10], 0)
elif current == '1':
pygame.draw.rect(surface, (255, 255, 255),[xpos, ypos, xpos, ypos], 0)
else:
pygame.draw.rect(surface, (130, 130, 130),[xpos, ypos, xpos, ypos], 0)
#print(current)
#pygame.display.update()
xpos = xpos + 10
current = frame_data[count]
count = count + 1
timer = round(abs((start_time - time.perf_counter())), 1)
current_l = seconds*30
current_l = int(timer*30)
ypos = ypos + -10
print(current_l)
pygame.display.update()
start_vid()
The reason why you can't see anything is because in Pygame, the origin (0, 0) of the screen is in the top left. The right side of the screen is where the x increases, and the bottom is where the y increases. So, the line:
ypos = ypos + -10
draws everything "above" the screen, hence invisible. You need to remove the - sign.
I also saw a couple of things in your code that could be improved, such as:
The fact that you never close the data file. To do that automatically, you could use the with statement:
with open('video.txt') as file:
lines = file.readlines()
# the file is closed
This will allow other applications to access the file.
You are drawing empty rects
You are using the pygame.draw.rect method incorrectly. You should use rect objects like such:
rect = pygame.Rect(x, y, width, height)
pygame.draw.rect(surface, color, rect)
You don't need the time and datetime modules, Pygame handles time like this. For example:
framerate = 30
start = pygame.time.get_ticks()
... # main loop
current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
And, most importantly
In Pygame, you need a main loop with events handling:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
...
pygame.quit()
quit()
A correct implementation of your code could look like this:
import pygame
with open('video.txt') as file:
lines = file.readlines()
pygame.init()
surface = pygame.display.set_mode((480,360))
framerate = 30
start = pygame.time.get_ticks()
run = True
while run:
# get pygame events
for event in pygame.event.get():
if event.type == pygame.QUIT: # user closes the window
run = False
current_frame = int((pygame.time.get_ticks()-start) / 1000 * framerate)
if current_frame < len(lines): # is the video still running?
count = 0
for y in range(36):
for x in range(48):
current_pixel = lines[current_frame][count] # current pixel data
if current_pixel == '0':
color = (0, 0, 0)
elif current_pixel == '1':
color = (127, 127, 127)
else:
color = (255, 255, 255)
pygame.draw.rect(surface, color, pygame.Rect(x*10, y*10, 10, 10))
count += 1 # next pixel
pygame.display.flip()
# user closed the window
pygame.quit()
quit()
(In this example, you can reduce the amount of resources used since you know the framerate of the video using pygame.time.Clock)
I'm following the programarcadegames website to try and move an object along with mouse movement. When I run the program, the coordinates of the moving mouse print out as it goes which is good, but the issue is that the item itself is constantly stuck in its starting position. I've tried making changes and running them to see what went wrong but the same thing keeps happening. Here is my code so far:
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GRAY = (128, 128, 128)
pygame.init()
star_list = []
for i in range(50):
x = random.randrange(0, 700)
y = random.randrange(0, 700)
star_list.append([x, y])
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Space Game")
# Loop until the user clicks the close button.
done = False
# Draw spaceship
def draw_spaceship(screen, x ,y):
#body
pygame.draw.rect(screen, GRAY, [350,375,20,40], 0)
#wing1 pygame.draw.polygon(screen, BLUE, [[350,375], [330,375], [350,400]], 0)
pygame.draw.polygon(screen, GRAY, [[390,375], [365,375], [365,400]], 0)
#wing2
pygame.draw.polygon(screen, GRAY, [[350,375], [330,375], [350,400]], 0)
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Game logic
# Mouse movement
pos = pygame.mouse.get_pos()
print (pos)
x=pos[0]
y=pos[1]
# Background
screen.fill(BLACK)
# Process each star in the list
for i in range(len(star_list)):
pygame.draw.circle(screen, WHITE, star_list[i], 2)
star_list[i][1] += 1
if star_list[i][1] > 700:
y = random.randrange(-50, -10)
star_list[i][1] = y
x = random.randrange(0, 700)
star_list[i][0] = x
#call draw_spaceship
draw_spaceship(screen, 0, 0)
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
Your draw_spaceship function draws the ship at a constant position. Draw the ship relative to the x and y coordiante:
def draw_spaceship(screen, x, y):
#body
pygame.draw.rect(screen, GRAY, [x-10, y-20, 20, 40], 0)
#wing1
pygame.draw.polygon(screen, GRAY, [[x+30,y-20], [x+10,y-20], [x+10,y+5]], 0)
#wing2
pygame.draw.polygon(screen, GRAY, [[x-10,y-20], [x-30,y-20], [x-10,y+5]], 0)
Call draw_spaceship with the current mouse position, instead of (0, 0):
while not done:
# [...]
#draw_spaceship(screen, 0, 0)
draw_spaceship(screen, pos[0], pos[1])
draw_spaceship is drawing your ship at a constant position, (0,0). You should change the call for that to something more like
draw_spaceship(screen, pos[0], pos[1])
Edit: It looks like your draw_spaceship() function has hardcoded values for where to draw the spaceship, without even using the x and y arguments given.
I am creating a randomly generated map in with PyGame. However, I've run into an issue, where, if the user scrolls away from the top-left corner of the map and changes the PyGame surface that's displayed, an issue happens.
The problem is, PyGame still starts them on the upper-left of the surface, and will then allow them to scroll off the edges of the surface because the list that keeps track of that, camera_pos, now has incorrect values.
All of the surfaces are the same dimensions and I want to make it so the user is in the same position when they change the displayed surface. However, I'm not sure how to set the position of the user's view when pygame switches surfaces.
How can I switch the position of the user's view back to what it used to be when the surface is switched?
I have made a MCV Example below I hope will help. Instead of displaying maps, it just draws a border around a solid color. I apologize for how long it is. I'm not sure how to make it much shorter.
In this example, scrolling is done with the arrow keys. You can press r, g, or b on the keyboard to display the different colored surfaces.
import pygame
import numpy as np
import sys
def scroll_y(display_surface, offset):
"""
Handles vertical scrolling.
:param display_surface: A pyGame surface object.
:param offset: The speed of the scroll
"""
width, height = display_surface.get_size()
map_copy = display_surface.copy()
display_surface.blit(map_copy, (0, offset))
# handle scrolling down
if offset < 0:
display_surface.blit(map_copy,
(0, height + offset),
(0, 0, width, -offset))
# handle scrolling up
else:
display_surface.blit(map_copy,
(0, 0),
(0, height - offset, width, offset))
def scroll_x(display_surface, offset):
"""
Handles horizontal scrolling.
:param display_surface: A pyGame surface object.
:param offset: The speed of the scroll
"""
width, height = display_surface.get_size()
map_copy = display_surface.copy()
display_surface.blit(map_copy, (offset, 0))
# handle scrolling right
if offset < 0:
display_surface.blit(map_copy,
(width + offset, 0),
(0, 0, -offset, height))
# handle scrolling left
else:
display_surface.blit(map_copy,
(0, 0),
(width - offset, 0, offset, height))
def main():
"""
This function displays the three surfaces.
Press r to show the red surface (which is displayed by default).
Press g to show the green surface.
Press b to show the blue surface.
"""
pygame.init()
window = pygame.display.set_mode((1600, 900))
red_surface = pygame.Surface([3200, 1800]).convert(window)
green_surface = pygame.Surface([3200, 1800]).convert(window)
blue_surface = pygame.Surface([3200, 1800]).convert(window)
red_surface.fill((255, 145, 145))
green_surface.fill((145, 255, 145))
blue_surface.fill((145, 145, 255))
# draw thick black lines on surface borders
pygame.draw.rect(red_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
pygame.draw.rect(green_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
pygame.draw.rect(blue_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
display_surface = red_surface.copy()
camera_pos = np.array([0, 0])
while True: # <-- the pyGame loop
event = pygame.event.poll()
pressed = pygame.key.get_pressed()
# handle closing the window
if event.type == pygame.QUIT:
break
window.blit(display_surface, (0, 0))
# handle switching display modes
if pressed[pygame.K_g]:
display_surface = green_surface
elif pressed[pygame.K_b]:
display_surface = blue_surface
elif pressed[pygame.K_r]:
display_surface = red_surface
# handle scrolling, make sure you can't scroll past the borders
if pressed[pygame.K_UP] and camera_pos[1] > 0:
scroll_y(display_surface, 5)
camera_pos[1] -= 5
elif pressed[pygame.K_DOWN] and camera_pos[1] < (1800 / 2):
scroll_y(display_surface, -5)
camera_pos[1] += 5
elif pressed[pygame.K_LEFT] and camera_pos[0] > 0:
scroll_x(display_surface, 5)
camera_pos[0] -= 5
elif pressed[pygame.K_RIGHT] and camera_pos[0] < (3200 / 2):
scroll_x(display_surface, -5)
camera_pos[0] += 5
# updates what the window displays
pygame.display.update()
pygame.quit()
sys.exit(0)
if __name__ == "__main__":
# runs the pyGame loop
main()
Here's what I think is a fairly elegant solution that doesn't require the two scrolling functions, scroll_x() and scroll_y() you have. Because it was so fast not using them, the main loop was detecting the same scrolling key as being pressed multiple times — necessitating the addition of a pygame.time.Clock to slow the frame-rate down to something reasonable.
Instead of scrolling the display surfaces themselves via those scrolling functions, as your code was doing, this version just updates the current "camera" position, then blits the corresponding region of the current display_surface to the window whenever it's modified. The camera's position is constrained by making sure its x and y components stay within some boundary limit constants — MINX,MINY and MAXX,MAXY — which get computed based the values of some other previously defined constants.
The use of symbolic constants rather than hardcoding literal values multiple places in the code is considered a very good programming practice because it makes changing them easier, since doing so only requires a source code change to be done one place.
import pygame
import sys
def main():
"""
This function displays the three surfaces.
Press r to show the red surface (which is displayed by default).
Press g to show the green surface.
Press b to show the blue surface.
"""
FPS = 60 # Frames per second
SURF_WIDTH, SURF_HEIGHT = 3200, 1800
WIN_WIDTH, WIN_HEIGHT = 1600, 900
DX, DY = 5, 5 # Scroll amounts.
MINX, MAXX = DX, SURF_WIDTH - WIN_WIDTH + DX - 1
MINY, MAXY = DY, SURF_HEIGHT - WIN_HEIGHT + DY - 1
pygame.init()
pygame.font.init()
fonts = pygame.font.get_fonts()
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
red_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
green_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
blue_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
red_surface.fill((255, 145, 145))
green_surface.fill((145, 255, 145))
blue_surface.fill((145, 145, 255))
# Draw thick black lines on surface borders
pygame.draw.rect(red_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
pygame.draw.rect(green_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
pygame.draw.rect(blue_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
# Draw label on each of the surfaces for testing. (ADDED)
font = pygame.font.SysFont(None, 35)
rtext = font.render('red surface', True, (255, 0, 0))
textpos = rtext.get_rect(centerx=300, centery=200) # Reused.
red_surface.blit(rtext, textpos)
rtext = font.render('green surface', True, (0, 192, 0))
green_surface.blit(rtext, textpos)
rtext = font.render('blue surface', True, (0, 0, 255))
blue_surface.blit(rtext, textpos)
display_surface = red_surface
camera_pos = pygame.math.Vector2(0, 0)
update_surface = True
while True: # Game loop
if update_surface:
window.blit(display_surface, (0, 0), (camera_pos[0], camera_pos[1],
WIN_WIDTH, WIN_HEIGHT))
update_surface = False
event = pygame.event.poll()
pressed = pygame.key.get_pressed()
# Close window?
if event.type == pygame.QUIT or pressed[pygame.K_ESCAPE]:
break
# Switch display surface?
if pressed[pygame.K_g]:
display_surface = green_surface
update_surface = True
elif pressed[pygame.K_b]:
display_surface = blue_surface
update_surface = True
elif pressed[pygame.K_r]:
display_surface = red_surface
update_surface = True
# Constrain scrolling to within borders
if pressed[pygame.K_LEFT] and camera_pos[0] >= MINX:
camera_pos[0] -= DX
update_surface = True
elif pressed[pygame.K_RIGHT] and camera_pos[0] <= MAXX:
camera_pos[0] += DX
update_surface = True
elif pressed[pygame.K_UP] and camera_pos[1] >= MINY:
camera_pos[1] -= DY
update_surface = True
elif pressed[pygame.K_DOWN] and camera_pos[1] <= MAXY:
camera_pos[1] += DY
update_surface = True
# updates what the window displays
pygame.display.update()
clock.tick(FPS)
pygame.quit()
sys.exit(0)
if __name__ == "__main__":
main() # runs the pyGame loop
I've added two rectangles, red and green to the top of the following code, and for some reason my code, which otherwise worked, does not now. The grid cells should go RED when clicked, but the clicking is skewed. Can anyone advise on the problem? I have two issues:
An upvote to the first one to spot and point out the error, unless I get it first!
I also want to add text (user 1 and user 2) to the rectangles and make them clickable. On clicking, the user selects a random grid cell (which turns either red or green)
Code as follows:
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
pygame.init()
size = (350, 350)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
done = False
clock = pygame.time.Clock()
width=22
height=22
margin=12
grid=[]
#Loop for each row in the list
for row in range(7):
#for each row, create a list that will represent an entire row
grid.append([])
#loop for each column
for column in range(7):
#add the number zero to the current row
grid[row].append(0)
#set row 1, column 5 to one
#grid[1][3]=1
#print(grid[1][3]) #this is the 2nd row and the 4th element along (0...1 row and 0...1...2....3 Column)
# -------- Main Program Loop -----------
while not done:
#ALL EVENT PROCESSING SHOULD GO BELOW THIS LINE
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#************CODE ADDED HERE**********************
elif event.type == pygame.MOUSEBUTTONDOWN:
#print("user clicked the screen")
pos=pygame.mouse.get_pos()
#x = grid[0]
#y= grid[1]
#print(pos)
#CHANGE THE X and Y screen coordinates as in the comments above to grid coordinates
column=pos[0]//(width+margin+50)
row=pos[1]//(height+margin+60)
#set the location to one (when selected by the mouse)
grid[row][column]=1
#print("User click ", pos, "Grid coordinates:", row+1, column+1)
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(BLACK)
# --- Drawing code should go here
#Drawing the red and Green rectangles
pygame.draw.rect(screen,RED, [0,0,120,50])
pygame.draw.rect(screen,GREEN, [240,0,120,50])
for row in range(7):
#the column number - this refers to the number of columns it will produce. 2, for example, will produce only 2 columns
for column in range(7):
color = WHITE
if grid[row][column] ==1:
color = RED
#****MOVING THE REST OF THE GRID DOWN*****
#the 60 is the margin from the top
#the 50 is the margin from the left
pygame.draw.rect(screen,color,[(margin + width) * column + margin+50, (margin + height) * row + margin+60,width,height])
#*******PRINTING TEXT TO THE SCREEN**********
# Select the font to use, size, bold, italics
#font = pygame.font.SysFont('Calibri', 25, True, False)
#text = font.render("a", True, BLACK)
# Put the image of the text on the screen at 250x250
#screen.blit(text, [25, 25])
# --- This bit updates the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
This is by no means an ideal way to achieve your goal, but I tried to keep the code as consistent with yours as possible. Let me know if you have any questions about how this works. I will do my best to answer quickly.
import pygame
from pygame.locals import *
pygame.init()
# first we define some constants
# doing this will reduce the amount of 'magic' numbers throughout the code
WINWIDTH = 350
WINHEIGHT = 350
WINSIZE = (WINWIDTH, WINHEIGHT)
CELLWIDTH = 22
CELLHEIGHT = 22
CELLSIZE = (CELLWIDTH, CELLHEIGHT)
CELLMARGINX = 12 # number of pixels to the left and right of each cell
CELLMARGINY = 12 # number of pixels to the top and bottom of each cell
SCREENPADX = 60 # number of pixels between the GRID and the left and right of the window
SCREENPADY = 70 # number of pixels between the GRID and the top and bottom of the window
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
DONE = False # is our program finished running?
# information about the two buttons (red and green)
REDBUTTON = (0, 0, 120, 50)
GREENBUTTON = (240, 0, 120, 50)
# create the WINDOW and CLOCK
WINDOW = pygame.display.set_mode(WINSIZE)
pygame.display.set_caption('My Game')
CLOCK = pygame.time.Clock()
CURRENTCOLOR = RED # which color is active
# setting up the GRID
# cells can be accessed by GRID[row][col] ie. GRID[3][4] is the 3rd row and 4th column
# each cell contains [x, y, color]
# where x is the x position on the screen
# y is the y position on the screen
# color is the current color of the cell
GRID = []
for y in range(7):
row = []
for x in range(7):
row.append([x * (CELLWIDTH + CELLMARGINX) + SCREENPADX, y * (CELLHEIGHT + CELLMARGINY) + SCREENPADY, WHITE])
GRID.append(row)
# main loop
while not DONE:
# process all events
for event in pygame.event.get():
if event.type == QUIT: # did the user click the 'x' to close the window
DONE = True
if event.type == MOUSEBUTTONDOWN:
# get the position of the mouse
mpos_x, mpos_y = event.pos
# check if REDBUTTON was clicked
button_x_min, button_y_min, button_width, button_height = REDBUTTON
button_x_max, button_y_max = button_x_min + button_width, button_y_min + button_height
if button_x_min <= mpos_x <= button_x_max and button_y_min <= mpos_y <= button_y_max:
CURRENTCOLOR = RED
# check if GREENBUTTON WAS CLICKED
button_x_min, button_y_min, button_width, button_height = GREENBUTTON
button_x_max, button_y_max = button_x_min + button_width, button_y_min + button_height
if button_x_min <= mpos_x <= button_x_max and button_y_min <= mpos_y <= button_y_max:
CURRENTCOLOR = GREEN
# calculations for clicking cells
mpos_x -= SCREENPADX # mouse position relative to the upper left cell
mpos_y -= SCREENPADY # ^ same
col = mpos_x // (CELLWIDTH + CELLMARGINX) # which cell is the mouse clicking
row = mpos_y // (CELLHEIGHT + CELLMARGINY) # ^ same
# make sure the user clicked on the GRID area
if row >= 0 and col >= 0:
try:
# calculate the boundaries of the cell
cell_x_min, cell_y_min = col * (CELLHEIGHT + CELLMARGINY), row * (CELLWIDTH + CELLMARGINX)
cell_x_max = cell_x_min + CELLWIDTH
cell_y_max = cell_y_min + CELLHEIGHT
# now we will see if the user clicked the cell or the margin
if cell_x_min <= mpos_x <= cell_x_max and cell_y_min <= mpos_y <= cell_y_max:
GRID[row][col][2] = CURRENTCOLOR if event.button == 1 else WHITE
else:
# the user has clicked the margin, so we do nothing
pass
except IndexError: # clicked outside of the GRID
pass # we will do nothing
# logic goes here
# drawing
WINDOW.fill(BLACK)
pygame.draw.rect(WINDOW, RED, REDBUTTON)
pygame.draw.rect(WINDOW, GREEN, GREENBUTTON)
for row in GRID:
for x, y, color in row:
pygame.draw.rect(WINDOW, color, (x, y, CELLWIDTH, CELLHEIGHT))
pygame.display.flip()
CLOCK.tick(60)
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()