PyGame/Python: Placing a circle onto an ellipse - python

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

Related

Pygame Slider one pixel too short

so I'm trying to make a slider in, pygame, but ran into a rather annoying problem. for some reason my slider is 1 pixel too short of the specified value on the right side.
import pygame
pygame.init()
screen_height = 700
screen_width = 1500
resolution = [screen_width, screen_height]
screen = pygame.display.set_mode(resolution)
rectangle_coordinates = [100, 100]
rectangle_size = [100, 100]
rectangle = pygame.Rect(rectangle_coordinates[0], rectangle_coordinates[1], 100, 100)
click_zone_coordinates = [rectangle_size[0]/2, rectangle_size[1]]
click_zone_size = [screen_width-rectangle_size[0], rectangle_size[1]]
click_zone = pygame.Rect(click_zone_coordinates[0], click_zone_coordinates[1], click_zone_size[0], click_zone_size[1])
# colors
white = [255, 255, 255]
black = [0, 0, 0]
purple = [128, 0, 128]
running = True
while running:
screen.fill(white)
rectangle = pygame.Rect(rectangle_coordinates[0], rectangle_coordinates[1], rectangle_size[0], rectangle_size[1])
def is_over(rect, pos):
return True if rect.collidepoint(pos) else False
pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if pygame.mouse.get_pressed(3)[0]:
if is_over(click_zone, pos):
rectangle_coordinates[0] = pos[0]-rectangle_size[0]/2
pygame.draw.rect(screen, purple, click_zone)
pygame.draw.rect(screen, black, rectangle)
pygame.display.update()
pygame.quit()
also, I'm trying to base the values off the screen dimensions, so it is scale-able.
it would be terrific if someone knew a fix for this.
See pygame.Rect.collidepoint:
Returns true if the given point is inside the rectangle. A point along the right or bottom edge is not considered to be inside the rectangle.
Therefore you need to increase the width of the click_zone by 1:
click_zone = pygame.Rect(
click_zone_coordinates[0], click_zone_coordinates[1],
click_zone_size[0] + 1, click_zone_size[1])
To make the slider depend on the size of the screen, you need to calculate the rectangle click_zone in the application loop depending on the width of the screen:
while running:
click_zone = pygame.Rect(
rectangle_size[0]//2, rectangle_size[1],
screen.get_width() - rectangle_size[0] + 1, rectangle_size[1])
# [...]

Python pygame.mouse.get_pos() coordinates printing in IDE terminal, but object in game window isn't moving when the mouse is moved

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.

what does draw.lines return?

from what I understand draw.lines joins each coordinate that is passed to it, so if we have [A, B, C]
will draw a line from coordinate A to coordinate B and from B to C and if closed is True it draws a line from coordinate A to coordinate C therefore it will always join the first coordinate with the last one its right?
what i don't understand is what the rect variable returns..
I think that every time I add a new coordinate it returns (starting_point, rectangle_size) where starting point is the first coordinate and the rectangle size is calculated by the distance of the first coordinate with the last one then draw the rectangle with draw.rect
but the reasoning I don't think is right because if I add a coordinate of this type to the list the rectangle remains unchanged
CODE:
"""Place a polygone line with the clicks of the mouse."""
import pygame
from pygame.locals import *
RED = (255, 0, 0)
GREEN = (0, 255, 0)
GRAY = (150, 150, 150)
pygame.init()
screen = pygame.display.set_mode((640, 240))
drawing = False
points = []
running = True
while running:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
points.append(event.pos)
drawing = True
elif event.type == MOUSEBUTTONUP:
drawing = False
elif event.type == MOUSEMOTION and drawing:
points[-1] = event.pos
screen.fill(GRAY)
if len(points)>1:
rect = pygame.draw.lines(screen, RED, True, points, 3)
pygame.draw.rect(screen, GREEN, rect, 1)
pygame.display.update()
pygame.quit()
pygame.draw.lines() returns a pygame.Rect object that encloses all the points of the line:
a rect bounding the changed pixels, if nothing is drawn the bounding rect's position will be the position of the first point in the points parameter (float values will be truncated) and its width and height will be 0
The rectangle does not start at any particular point on the line, but is just large enough to enclose all the points along the line.
It returns the same as:
list_x, list_y = zip(*points)
min_x, max_x = min(list_x), max(list_x)
min_y, max_y = min(list_y), max(list_y)
rect = pygame.Rect(min_x, min_y, max_x-min_x, max_y-min_y)
According to the docs:
Returns:
a rect bounding the changed pixels, if nothing is drawn the bounding rect's position will be the position of the first point in the points parameter (float values will be truncated) and its width and height will be 0
this is the reasoning I made:
import pygame
def minore(lista_coordinate, asse):
dimensione = lista_coordinate[0][asse]
for coordinata in lista_coordinate:
if coordinata[asse] < dimensione:
dimensione = coordinata[asse]
return dimensione
def maggiore(lista_coordinate, asse):
dimensione = lista_coordinate[0][asse]
for coordinata in lista_coordinate:
if coordinata[asse] > dimensione:
dimensione = coordinata[asse]
return dimensione
pygame.init()
schermo = pygame.display.set_mode((500, 400))
punti = [(100, 100), (200, 100), (200, 50), (150, 80)]
larghezza_minore = minore(punti, 0)
larghezza_maggiore = maggiore(punti, 0)
larghezza_rettangolo = larghezza_maggiore - larghezza_minore
altezza_minore = minore(punti, 1)
altezza_maggiore = maggiore(punti, 1)
altezza_rettangolo = altezza_maggiore - altezza_minore
dimensioni_rettangolo = (larghezza_rettangolo, altezza_rettangolo)
inizio = (larghezza_minore, altezza_minore)
pygame.draw.lines(schermo, (255, 0, 0), True, punti, 3)
pygame.draw.rect(schermo, (0, 255, 0), (inizio, dimensioni_rettangolo), 1)
pygame.display.update()

inconsistent motion with pygame

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.

Adding gradient to moving objects in pygame

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

Categories

Resources