Pygame Slider one pixel too short - python

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])
# [...]

Related

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.

Increase the size of an image during a collision with pygame?

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.

How do I change the color of a single rectangle in a grid?

I've already programmed a grid, but now I want to change the color of a single rectangle in the grid.
x = 5
y = 5
height = 30
width = 50
size = 20
color = (255,255,255)
new_color = (255,255,0)
screen.fill((0,0,0))
def draw_grid():
for y in range(height):
for x in range(width):
rect = pygame.Rect(x * (size + 1),y * (size + 1),size,size)
pygame.draw.rect(screen,color,rect)
x += 20
rects.append((rect,color))
y += 20
rects = []
colored_rects = []
while 1:
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
draw_grid()
if pygame.mouse.get_pressed()[0]:
mouse_pos = pygame.mouse.get_pos()
for i,(rect,color) in enumerate(rects):
if rect.collidepoint(mouse_pos):
rects[i] = (rect,new_color)
colored_rects.append((rect,new_color))
for rect,color in rects:
pygame.draw.rect(screen,color,rect)
for rect,new_color in colored_rects:
pygame.draw.rect(screen,new_color,rect)
pygame.display.flip()
clock.tick()
Now I only want to change one rectangle when I click on it, but later they must change automatically (for example when there are three rectangles touching in the same color, they all must become white). I've updated a little bit, but there are still some problems. For example: You have to click on the rectangle till it changes color, and it takes to much time te change color.
One solution would be to store the rects together with their color in tuples. If the mouse button is pressed, you iterate over the rectangles list, if a rectangle collides with the mouse, you create a tuple with the rect and the new color and replace the tuple at the current index.
import sys
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
height = 30
width = 50
size = 20
color = (255, 255, 255)
new_color = (255, 255, 0)
rectangles = []
for y in range(height):
for x in range(width):
rect = pg.Rect(x * (size+1), y * (size+1), size, size)
# The grid will be a list of (rect, color) tuples.
rectangles.append((rect, color))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if pg.mouse.get_pressed()[0]:
mouse_pos = pg.mouse.get_pos()
# Enumerate creates tuples of a number (the index)
# and the rect-color tuple, so it looks like:
# (0, (<rect(0, 0, 20, 20)>, (255, 255, 255)))
# You can unpack them directly in the head of the loop.
for index, (rect, color) in enumerate(rectangles):
if rect.collidepoint(mouse_pos):
# Create a tuple with the new color and assign it.
rectangles[index] = (rect, new_color)
screen.fill((30, 30, 30))
# Now draw the rects. You can unpack the tuples
# again directly in the head of the for loop.
for rect, color in rectangles:
pg.draw.rect(screen, color, rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

PyGame/Python: Placing a circle onto an ellipse

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

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