Player Randomly Jumps Really High - Pygame Platformer [duplicate] - pygame

I want to make my character jump. In my current attempt, the player moves up as long as I hold down SPACEv and falls down when I release SPACE.
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(135, 220, 30, 30)
vel = 5
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
rect.centerx = (rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
if keys[pygame.K_SPACE]:
rect.y -= 1
elif rect.y < 220:
rect.y += 1
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
pygame.draw.circle(window, (255, 0, 0), rect.center, 15)
pygame.display.flip()
pygame.quit()
exit()
However, I want the character to jump if I hit the SPACE once. I want a smooth jump animation to start when SPACE is pressed once.
How would I go about this step by step?

To make a character jump you have to use the KEYDOWN event, but not pygame.key.get_pressed(). pygame.key.get_pressed () is for continuous movement when a key is held down. The keyboard events are used to trigger a single action or to start an animation such as a jump. See alos How to get keyboard input in pygame?
pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
jump = True
Use pygame.time.Clock ("This method should be called once per frame.") you control the frames per second and thus the game speed and the duration of the jump.
clock = pygame.time.Clock()
while True:
clock.tick(100)
The jumping should be independent of the player's movement or the general flow of control of the game. Therefore, the jump animation in the application loop must be executed in parallel to the running game.
When you throw a ball or something jumps, the object makes a parabolic curve. The object gains height quickly at the beginning, but this slows down until the object begins to fall faster and faster again. The change in height of a jumping object can be described with the following sequence:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
Such a series can be generated with the following algorithm (y is the y coordinate of the object):
jumpMax = 10
if jump:
y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
A more sophisticated approach is to define constants for the gravity and player's acceleration as the player jumps:
acceleration = 10
gravity = 0.5
The acceleration exerted on the player in each frame is the gravity constant, if the player jumps then the acceleration changes to the "jump" acceleration for a single frame:
acc_y = gravity
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if vel_y == 0 and event.key == pygame.K_SPACE:
acc_y = -acceleration
In each frame the vertical velocity is changed depending on the acceleration and the y-coordinate is changed depending on the velocity. When the player touches the ground, the vertical movement will stop:
vel_y += acc_y
y += vel_y
if y > ground_y:
y = ground_y
vel_y = 0
acc_y = 0
See also Jump
Example 1: replit.com/#Rabbid76/PyGame-Jump
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(135, 220, 30, 30)
vel = 5
jump = False
jumpCount = 0
jumpMax = 15
run = True
while run:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if not jump and event.key == pygame.K_SPACE:
jump = True
jumpCount = jumpMax
keys = pygame.key.get_pressed()
rect.centerx = (rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
if jump:
rect.y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
pygame.draw.circle(window, (255, 0, 0), rect.center, 15)
pygame.display.flip()
pygame.quit()
exit()
Example 2: replit.com/#Rabbid76/PyGame-JumpAcceleration
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
player = pygame.sprite.Sprite()
player.image = pygame.Surface((30, 30), pygame.SRCALPHA)
pygame.draw.circle(player.image, (255, 0, 0), (15, 15), 15)
player.rect = player.image.get_rect(center = (150, 235))
all_sprites = pygame.sprite.Group([player])
y, vel_y = player.rect.bottom, 0
vel = 5
ground_y = 250
acceleration = 10
gravity = 0.5
run = True
while run:
clock.tick(100)
acc_y = gravity
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if vel_y == 0 and event.key == pygame.K_SPACE:
acc_y = -acceleration
keys = pygame.key.get_pressed()
player.rect.centerx = (player.rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
vel_y += acc_y
y += vel_y
if y > ground_y:
y = ground_y
vel_y = 0
acc_y = 0
player.rect.bottom = round(y)
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
exit()

Related

Pygame - How to make mouse gesture movement smoother?

I wanted to be able to "scroll" around a pygame window using just mouse gestures, or in this case, "two fingers scrolling" (don't know the right term for this).
I managed to make an example implementation:
import pygame
pygame.init()
size = (width, height) = (800, 600)
screen = pygame.display.set_mode(size)
class SceneElement:
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
class Scene:
def __init__(self):
self.elements = [
SceneElement(150, 150, 200, 200, (55, 55, 10, 0.3)),
SceneElement(250, 300, 200, 200, (155, 200, 10, 0.5)),
]
def render(self, offset):
screen.fill((255, 255, 255))
for element in self.elements:
x = element.x + offset[0]
y = element.y + offset[1]
pygame.draw.rect(screen, element.color, (x, y, element.width, element.height))
scene = Scene()
offset = [0, 0]
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == 1027:
if event.x == 0 and event.y == -1:
print(event.x, event.y)
offset[1] -= 10
elif event.x == -1 and event.y == 0:
offset[0] += 10
print(event.x, event.y)
elif event.x == 1 and event.y == 0:
offset[0] -= 10
print(event.x, event.y)
elif event.x == 0 and event.y == 1:
offset[1] += 10
print(event.x, event.y)
scene.render(offset)
pygame.display.flip()
pygame.quit()
The above works. Here is a gif showing that it works.
Now problem is, I don't think this is how this is supposed to be implemented. I didn't see any example or existing code online that did this.
So while the above works, it doesn't feel "smooth". Trying to move in a circle or diagonally feels very unnatural (as can be seen in the gif near the end). Is there a better way to do the above (moving around using mouse gestures) or is this the right implementation?
Mainly what you have to deal with here is that your diagonal movement is not normalized, to fix this the easiest would be to just use pygame.Vector2 for positions and such, it also has a normalized method that will do the normalizing for you:
scene = Scene()
offset = pygame.Vector2()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEWHEEL:
direction = pygame.Vector2(event.x, event.y).normalize()
offset += direction * 10
scene.render(offset)
pygame.display.flip()
This won't affect functionality of the rest of the code as vectors can be indexed just like lists, however, I'd suggest you use pygame.Vector2 for positions and velocities and accelerations and other physics related things in general as they are faster and far more convenient.
Also use constants instead of some arbitrary integer values for event types and other stuff as it makes reading the code a lot easier.
Thanks to Matiiss's answer, I managed to find a clue on how to do this:
import pygame
pygame.init()
size = (width, height) = (800, 600)
screen = pygame.display.set_mode(size)
class SceneElement:
def __init__(self, x, y, width, height, color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
class Scene:
def __init__(self):
self.elements = [
SceneElement(150, 150, 200, 200, (55, 55, 10, 0.3)),
SceneElement(250, 300, 200, 200, (155, 200, 10, 0.5)),
]
def render(self, offset):
screen.fill((255, 255, 255))
for element in self.elements:
x = element.x + offset[0]
y = element.y + offset[1]
pygame.draw.rect(screen, element.color, (x, y, element.width, element.height))
scene = Scene()
offset = pygame.Vector2()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEWHEEL:
print(event.x, event.y)
if event.x == 0 and event.y == 1:
direction = pygame.Vector2(event.x, event.y).normalize()
offset += direction * 10
elif event.x == 0 and event.y == -1:
direction = pygame.Vector2(event.x, event.y).normalize()
offset += direction * 10
elif event.x == -1 and event.y == 0:
direction = pygame.Vector2(1, event.y).normalize()
offset += direction * 10
elif event.x == 1 and event.y == 0:
direction = pygame.Vector2(-1, event.y).normalize()
offset += direction * 10
scene.render(offset)
pygame.display.flip()
pygame.quit()
This seems to work much more smoothly, but I feel like this could be improved still: https://imgur.com/a/7WNNQIl
EDIT: Based on Matiiss's comment, using their answer and replacing event.x with -event.x seems to work like the above without if/elif:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEWHEEL:
direction = pygame.Vector2(-event.x, event.y).normalize()
offset += direction * 10
scene.render(offset)
pygame.display.flip()

Why is pygame.K_UP and DOWN working but K_w and K_s not? [duplicate]

This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
How to get keyboard input in pygame?
(11 answers)
Closed 11 days ago.
I am learning Pygame and trying to make pong as a first game to learn.
At "Left Paddle Control" the "w" and "s" to move up and down do not work, however, the UP and DOWN arrow keys for the right paddle do work. So I'm confused.
The code is as follows :
import pygame
WIDTH, HEIGHT = 480, 360
screen = pygame.display.set_mode((WIDTH, HEIGHT))
BLACK = (0, 0, 0)
pygame.display.set_caption("Pong")
clock = pygame.time.Clock()
def draw_border():
pygame.draw.rect(screen, (255, 0, 0), [0, 0, 5, HEIGHT])
pygame.draw.rect(screen, (255, 0, 0), [0, 0, WIDTH, 5])
pygame.draw.rect(screen, (255, 0, 0), [WIDTH - 5, 0, 5, HEIGHT])
pygame.draw.rect(screen, (255, 0, 0), [0, HEIGHT - 5, WIDTH, 5])
def left_paddle(screen, y):
pygame.draw.rect(screen, BLACK, [20, y + 20, 8, 60])
def right_paddle(screen, y):
pygame.draw.rect(screen, BLACK, [(WIDTH - 30), y + 20, 8, 60])
ly_speed = 0
ry_speed = 0
ly_coord = 10
ry_coord = 10
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.fill((255, 255, 255))
draw_border()
# ----------- Left Paddle Control ----------------
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
ly_speed = -3
elif event.key == pygame.K_s:
ly_speed = 3
elif event.type == pygame.KEYUP:
if event.key == pygame.K_w or event.key == pygame.K_s:
ly_speed = 0
# ----------- Right Paddle Control ----------------
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
ry_speed = -3
elif event.key == pygame.K_DOWN:
ry_speed = 3
elif event.type == pygame.KEYUP:
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
ry_speed = 0
ly_coord += ly_speed
ry_coord += ry_speed
left_paddle(screen, ly_coord)
right_paddle(screen, ry_coord)
pygame.display.update()
clock.tick(60)
pygame.quit()
I've tried changing the "w" and "s" on the left paddle to UP and DOWN arrows and that works but when I change it back to "w" and "s" it stops. Can you help me out?
import pygame
WIDTH, HEIGHT = 480, 360
screen = pygame.display.set_mode((WIDTH, HEIGHT))
BLACK = (0, 0, 0)
pygame.display.set_caption("Pong")
clock = pygame.time.Clock()
def draw_border():
pygame.draw.rect(screen, (255, 0, 0), [0, 0, 5, HEIGHT])
pygame.draw.rect(screen, (255, 0, 0), [0, 0, WIDTH, 5])
pygame.draw.rect(screen, (255, 0, 0), [WIDTH - 5, 0, 5, HEIGHT])
pygame.draw.rect(screen, (255, 0, 0), [0, HEIGHT - 5, WIDTH, 5])
def left_paddle(screen, y):
pygame.draw.rect(screen, BLACK, [20, y + 20, 8, 60])
def right_paddle(screen, y):
pygame.draw.rect(screen, BLACK, [(WIDTH - 30), y + 20, 8, 60])
pygame.rect.Rect().clamp
ly_speed = 0
ry_speed = 0
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#basicly returns a pygame object that if specific key is pressed returns True
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
ry_speed -= 3
elif keys[pygame.K_DOWN]:
ry_speed += 3
if keys[pygame.K_w]:
ly_speed -= 3
elif keys[pygame.K_s]:
ly_speed += 3
screen.fill((255, 255, 255))
draw_border()
left_paddle(screen, ly_speed)
right_paddle(screen, ry_speed)
pygame.display.update()
clock.tick(60)
pygame.quit()
First of all event.type == pygame.KEYDOWN is not suitable for your code because you need a handler that checks your keyboard events every frame in this case pygame.key.get_pressed() much more efficient. I change some functionality in your code and works well now you need to add collision for your game.I high recommend when you wanna move an object use pygame.rect.Rect and pygame.Surface() objects together to move from one location to another.
for example:
# Set the rectangle size and position
rect_size = (100, 50)
rect_pos = (0, 0)
# Set the rectangle color
rect_color = (255, 0, 0)
# Create the rectangle
rect = pygame.Surface(rect_size)
rect.fill(rect_color)
rect_speed = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Move the rectangle to the right
rect_pos = (rect_pos[0] + rect_speed, rect_pos[1])
screen.fill((255, 255, 255))
# Draw the rectangle
screen.blit(rect, rect_pos)
pygame.display.update()

PYGAME managing different joysticks with different "circuit mappings" [duplicate]

I use python3 and pygame and I have player class, in which I have my controls of the player defined as in the function:
def get_input(self):
#xbox example code, which doesnt work:
buttons=pygame.joystick.Joystick.get_button()
if buttons(button=0):
self.jump()
#more code for xbox controller.
#keyboard, this works perfectly:
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
self.direction.x = 1
elif keys[pygame.K_LEFT]:
self.direction.x = -1
elif keys[pygame.K_d]:
self.direction.x = 1
elif keys[pygame.K_a]:
self.direction.x = -1
else:
self.direction.x = 0
if (keys[pygame.K_LEFT] and keys[pygame.K_RIGHT]):
self.direction.x = 0
if (keys[pygame.K_SPACE] and self.on_ground):
self.jump()
Question how do I add XBOX controls as in example above for the keys? (I wanna use axis for left-right movement and one button for jumping)
This code for reason I don't understand gives me following error:
File [...], line 37, in get_input
buttons=pygame.joystick.Joystick.get_button()
AttributeError: 'builtin_function_or_method' object has no attribute 'get_button'
What's going on here?
You have to create an instance object of a pygame.joystick.Joystick.
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 0, 20, 20)
rect.center = window.get_rect().center
vel = 5
color = (255, 0, 0)
joystick = None
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
print("joystick initialized")
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
if joystick:
button = joystick.get_button(0)
rect.x += round(joystick.get_axis(0) * vel)
rect.y += round(joystick.get_axis(1) * vel)
if joystick.get_button(0):
color = (0, 255, 0)
elif joystick.get_button(1):
color = (255, 0, 0)
elif joystick.get_button(2):
color = (0, 0, 255)
elif joystick.get_button(3):
color = (255, 255, 0)
keys = pygame.key.get_pressed()
rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel
rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel
rect.centerx = rect.centerx % window.get_width()
rect.centery = rect.centery % window.get_height()
window.fill(0)
pygame.draw.rect(window, color, rect)
pygame.display.flip()
pygame.quit()
exit()

Why does my player disappears when pressed jump? All indentations wrong or right? [duplicate]

I want to make my character jump. In my current attempt, the player moves up as long as I hold down SPACEv and falls down when I release SPACE.
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(135, 220, 30, 30)
vel = 5
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
rect.centerx = (rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
if keys[pygame.K_SPACE]:
rect.y -= 1
elif rect.y < 220:
rect.y += 1
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
pygame.draw.circle(window, (255, 0, 0), rect.center, 15)
pygame.display.flip()
pygame.quit()
exit()
However, I want the character to jump if I hit the SPACE once. I want a smooth jump animation to start when SPACE is pressed once.
How would I go about this step by step?
To make a character jump you have to use the KEYDOWN event, but not pygame.key.get_pressed(). pygame.key.get_pressed () is for continuous movement when a key is held down. The keyboard events are used to trigger a single action or to start an animation such as a jump. See alos How to get keyboard input in pygame?
pygame.key.get_pressed() returns a sequence with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
jump = True
Use pygame.time.Clock ("This method should be called once per frame.") you control the frames per second and thus the game speed and the duration of the jump.
clock = pygame.time.Clock()
while True:
clock.tick(100)
The jumping should be independent of the player's movement or the general flow of control of the game. Therefore, the jump animation in the application loop must be executed in parallel to the running game.
When you throw a ball or something jumps, the object makes a parabolic curve. The object gains height quickly at the beginning, but this slows down until the object begins to fall faster and faster again. The change in height of a jumping object can be described with the following sequence:
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
Such a series can be generated with the following algorithm (y is the y coordinate of the object):
jumpMax = 10
if jump:
y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
A more sophisticated approach is to define constants for the gravity and player's acceleration as the player jumps:
acceleration = 10
gravity = 0.5
The acceleration exerted on the player in each frame is the gravity constant, if the player jumps then the acceleration changes to the "jump" acceleration for a single frame:
acc_y = gravity
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if vel_y == 0 and event.key == pygame.K_SPACE:
acc_y = -acceleration
In each frame the vertical velocity is changed depending on the acceleration and the y-coordinate is changed depending on the velocity. When the player touches the ground, the vertical movement will stop:
vel_y += acc_y
y += vel_y
if y > ground_y:
y = ground_y
vel_y = 0
acc_y = 0
See also Jump
Example 1: replit.com/#Rabbid76/PyGame-Jump
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(135, 220, 30, 30)
vel = 5
jump = False
jumpCount = 0
jumpMax = 15
run = True
while run:
clock.tick(50)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if not jump and event.key == pygame.K_SPACE:
jump = True
jumpCount = jumpMax
keys = pygame.key.get_pressed()
rect.centerx = (rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
if jump:
rect.y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
pygame.draw.circle(window, (255, 0, 0), rect.center, 15)
pygame.display.flip()
pygame.quit()
exit()
Example 2: replit.com/#Rabbid76/PyGame-JumpAcceleration
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
player = pygame.sprite.Sprite()
player.image = pygame.Surface((30, 30), pygame.SRCALPHA)
pygame.draw.circle(player.image, (255, 0, 0), (15, 15), 15)
player.rect = player.image.get_rect(center = (150, 235))
all_sprites = pygame.sprite.Group([player])
y, vel_y = player.rect.bottom, 0
vel = 5
ground_y = 250
acceleration = 10
gravity = 0.5
run = True
while run:
clock.tick(100)
acc_y = gravity
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if vel_y == 0 and event.key == pygame.K_SPACE:
acc_y = -acceleration
keys = pygame.key.get_pressed()
player.rect.centerx = (player.rect.centerx + (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel) % 300
vel_y += acc_y
y += vel_y
if y > ground_y:
y = ground_y
vel_y = 0
acc_y = 0
player.rect.bottom = round(y)
window.fill((0, 0, 64))
pygame.draw.rect(window, (64, 64, 64), (0, 250, 300, 100))
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
exit()

Detect mouse click on circle that is on different surface

How can I check if circle on separate surface is clicked?
from pygame.locals import *
import pygame, sys, math
pygame.init()
screen = pygame.display.set_mode((640, 480))
s = pygame.Surface((100, 100))
s.fill((255, 0, 0))
s_rect = s.get_rect(center = (300, 300))
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
x = pygame.mouse.get_pos()[0]
y = pygame.mouse.get_pos()[1]
sqx = (x - 20)**2
sqy = (y - 20)**2
if math.sqrt(sqx + sqy) < 20:
print ('inside')
screen.fill((200, 200, 255))
screen.blit(s, s_rect)
pygame.draw.circle(s, (0, 0, 0), (20, 20), 20) # this doesn't work
pygame.draw.circle(screen, (0, 0, 0), (20, 20), 20) # this works
pygame.display.update()
pygame.quit()
Nothing happens when I run this code. However if I draw the circle on the main screen it works!!!
You have to compute the mouse position relative to the Surface.
You have 2 possibilities. Either subtract the (top left) position of the Surface on the screen from the mouse position:
x = event.pos[0] - s_rect.left
y = event.pos[1] - s_rect.top
Or add the (top left) position of the Surface on the screen to the center point of the circle:
sqx = (x - (s_rect.left + 20))**2
sqy = (y - (s_rect.top + 20))**2
Complete example
from pygame.locals import *
import pygame, math
pygame.init()
screen = pygame.display.set_mode((640, 480))
s = pygame.Surface((100, 100))
s.fill((255, 0, 0))
s_rect = s.get_rect(center = (300, 300))
clicked = False
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
x = event.pos[0]
y = event.pos[1]
sqx = (x - (s_rect.left + 20))**2
sqy = (y - (s_rect.top + 20))**2
if math.sqrt(sqx + sqy) < 20:
clicked = not clicked
print ('inside')
screen.fill((200, 200, 255))
color = (255, 255, 255) if clicked else (0, 0, 0)
pygame.draw.circle(s, color, (20, 20), 20)
screen.blit(s, s_rect)
pygame.display.update()
pygame.quit()