How to draw a 1/4 of a circle in Pygame? - python

I'm using Python 3.7.4 and Pygame 1.9.6. I know about the pygame.draw.arc and pygame.draw.circle. I want to draw a quarter circle like here:
It's the quarter circle of the soccer field.
My attempts:
pygame.draw.arc(screen, (255, 255, 255), (75, 25, 50, 50), 90, 120, 5)
pygame.draw.arc(screen, (255, 255, 255), (75, 25, 50, 50), 80, 100, 5)
Changing the starting angle and ending angle doesn't change a thing it seems.
So it must be the coordinates of drawing the boundaries.
When I change the 75 in this(75, 25, 50, 50) it just makes the circle go to the right more. If the change the 25 in (75, 25, 50, 50) it makes it go up or down more. If I change the first 50 in (75, 25, 50, 50) it makes it wider width bigger or smaller depending on changing the numbers. If I change the second 50 in (75, 25, 50, 50) it makes the height bigger or smaller.
I've just tried decimals in the angles, because the coordinates have to be integers. When I do pygame.draw.arc(screen, (255, 255, 255), (75, 25, 100, 50), 95.5, 100.5, 5) look at the decimals.
I get:
So maybe the key it changing the starting and ending angles I'll keep updating what I find.
I found the right one with help from #bashBedlam in the comments:
pygame.draw.arc(screen, (255, 255, 255), (60, 13, 50, 50), 17, 13, 5)
I changed the coordinates but keep the same starting and ending angle.
Which is pretty much perfect though I do hate the little black dots though.
The screen is 600 x 600
I can't get to right angle or the circle itself. I'm not aloud to use decimals. Only allows integers. So I don't know how to properly make a quarter circle. I appreciate the advice and thanks.
I just wanted to say for people helping me I've created my own soccer field. I drew all the lines out, but then I just turned it into a png so it wouldn't lag me out of loading all 27 lines with the background constantly. Here is the finished result with everyone's help:

The issue with your code is that pygame.draw.arc takes angles in radians as stated in the documentation. Also angles between 90 and 120 would not draw and arc like you need, 90 to -90 will.
import pygame
import math
pygame.init()
d = pygame.display.set_mode((1200, 600))
while True:
pygame.event.get()
d.fill((255, 255, 255))
pygame.draw.arc(d, (0, 0, 0), [900, 300, 100, 100], math.radians(90), math.radians(-90), 5)
pygame.draw.arc(d, (0, 0, 0), [300, 300, 100, 100], math.radians(-90), math.radians(90), 5)
pygame.display.update()
Edit:
So i was looking online for ways for pygame.draw.arc to draw arc without dots without using floating point numbers, but couldn't any, so i wrote this function for you. If you consider this function as not being a part of the code you wrote (like pygame.draw.arc) then technically, you are not using decimal because the decimal is only used inside of the function(finessed the system :)). Here's the function:
def drawArc(display, startAngle, endAngle, distance, pos, color, thickness=1):
if startAngle > endAngle:
theta = endAngle
bigger = startAngle
else:
theta = startAngle
bigger = endAngle
while theta < bigger:
for t in range(thickness):
x = round((cos(radians(theta)) * (distance-t)) + pos[0])
y = round((-sin(radians(theta)) * (distance-t)) + pos[1])
display.set_at((x, y), color)
theta += 0.01
Think of this function like a compass, it draws an arc in-between the angle you specify (in degrees). Argument pos being the centre of the compass and distance being the distance of the arc from the centre. So now just draw the quarter circles in 4 different corners.
import pygame
from math import radians, sin, cos
pygame.init()
d = pygame.display.set_mode((1200, 600))
def drawArc(display, startAngle, endAngle, distance, pos, color, thickness=1):
if startAngle > endAngle:
theta = endAngle
bigger = startAngle
else:
theta = startAngle
bigger = endAngle
while theta < bigger:
for t in range(thickness):
x = round((cos(radians(theta)) * (distance-t)) + pos[0])
y = round((-sin(radians(theta)) * (distance-t)) + pos[1])
display.set_at((x, y), color)
theta += 0.01
while True:
pygame.event.get()
d.fill((255, 255, 255))
drawArc(d, -90, 0, 100, [0, 0], (0, 0, 0), thickness=5)
drawArc(d, 180, 270, 100, [1200, 0], (0, 0, 0), thickness=5)
drawArc(d, 0, 90, 100, [0, 600], (0, 0, 0), thickness=5)
drawArc(d, 180, 90, 100, [1200, 600], (0, 0, 0), thickness=5)
pygame.display.update()
Btw, using this function hinders performance, so i strongly recommend using pygame.draw.arc with floating point numbers if possible.

Related

Setting colors on a trimesh union mesh according to the original component meshes

I'm working with the trimesh Python library, and I couldn't wrap my head around working with colors from reading the docs (a Spartan API reference) and examples. I'm not even sure if I'm setting the face colors right, if I can modify mesh.visual.face_colors directly or if I should make a ColorVisuals-type object.
But the main question is, can I set the color of different faces of a mesh approximately (I know there can be nasty edge cases) according to it being "overlapping" to faces in the original meshes I had before?
from shapely import Polygon
import trimesh
pts = ((100, 100), (400, 100), (400, 400), (100, 400))
hole = ((150, 150), (350, 150), (350, 350), (150, 350))
p = Polygon(pts, [hole])
mesh = trimesh.creation.extrude_polygon(p, 100)
other = mesh.copy()
other.apply_translation((150, 50, 50))
mesh = mesh.union(other)
# Silly idea (most faces wouldn't be the same) and it doesn't work, I get an error.
# other_v_set = set(other.vertices)
# colors = [([255, 0, 0] if set(mesh.vertices[v] for v in f).issubset(other_v_set)
# else [0, 255, 0]) for f in mesh.faces]
# mesh.visual = trimesh.visual.ColorVisuals(mesh, colors)
mesh.show()

How to make a L-shaped body in pymunk?

I am new to pymunk and I want to make a L-shaped body like this.
I read that it is possible to have two shapes attached to same body but the best I got is this.
The code I used is this:
import pymunk
import pygame
import pymunk.pygame_util
pygame.init()
size = 640, 240
screen = pygame.display.set_mode(size)
draw_options = pymunk.pygame_util.DrawOptions(screen)
space = pymunk.Space()
space.gravity = 0, 90
b0 = space.static_body
segment = pymunk.Segment(b0, (0, 200), (640, 200), 4)
segment.elasticity = 1
body = pymunk.Body(mass=1, moment=10)
body.position = 300, 50
box = pymunk.Poly.create_box(body, (100, 50))
box.elasticity = 0.9
box.friction = 0.8
box2 = pymunk.Poly.create_box(body, (50, 100))
space.add(body, box, box2, segment)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(color="GRAY")
space.debug_draw(draw_options)
pygame.display.update()
space.step(0.01)
pygame.quit()
Is there any way to do make a L-shaped body?
Thanks in advance!
The problem is that both Poly shapes that are created with the shorthand create_box method are created with their center at the position of the body they are attached to. So the two boxes are positioned on top of each other.
To fix this you need to use the more generic Poly constructor. In this way you can pick the positions as you want.
If I just take your picture and write up the coordinates times 10, it would be something like this:
box = pymunk.Poly(body, [(0, 0), (60, 0), (60, 30), (0, 30)])
box.elasticity = 0.9
box.friction = 0.8
box2 = pymunk.Poly(body, [(0, 30), (30, 30), (30, 60), (0, 60)])
box2.elasticity = 0.9
box2.friction = 0.8
However, note that the coordinates are relative to the body they are attached to, and the center of gravity is where the body is positioned. That means that the resulting L shape will behave as if its a hollow shape with a super heavy stone in one corner.
If this is not what you want to can adjust the coordinates, for example like this (I just subtracted 30 from each one. This can probably be tweaked even more depending on what your goal is):
box = pymunk.Poly(body, [(-30, -30), (30, -30), (30, 0), (-30, 0)])
box.elasticity = 0.9
box.friction = 0.8
box2 = pymunk.Poly(body, [(-30, 0), (0, 0), (0, 30), (-30, 30)])
box2.elasticity = 0.9
box2.friction = 0.8
This is the easiest to understand way (at least I think so), but there are two other options available. You can instead give a translate pymunk.Transform as an option to the Poly constructor, with the downside that it is less obvious what the result will be. Or you can move the center of gravity on the body with the center_of_gravity property, with the downside that when you look at the position of the body it will still be at the "corner" of the shape.
Try this
https://pymunk-tutorial.readthedocs.io/en/latest/shape/shape.html#l-shaped-segment
body = pymunk.Body(mass=1, moment=1000)
body.position = (100, 200)
s1 = pymunk.Segment(body, (0, 0), (50, 0), 8)
s1.density = 1
s1.elasticity = 0.999
space.add(body, s1)

Moving a rectangle with python3 [duplicate]

This question already has answers here:
PyGame rect.move movement not functioning properly
(1 answer)
Why is my pygame application loop not working properly?
(1 answer)
Closed 2 years ago.
I am trying to make a rectangle move in pygame
Here is the code that I am trying to get to work:
currBlock1 = pygame.draw.rect(surface, (0, 255, 255), (340, 50, 60, 30))
currBlock2 = pygame.draw.rect(surface, (0, 255, 255), (310, 80, 60, 30))
currBlock1.move(340, 80)
currBlock2.move(310, 110)
What is wrong here?
pygame.Rect.move doesn't move the rectangle itself. The method returns a new and moved rectangle. You have to use pygame.Rect.move_ip, which operates in place. Further the argument to move/move_ip is an offset rather than a position:
currBlock1.move_ip(0, 30)
currBlock2.move_ip(0, 30)
Actually you recreate the same rectangles in every frame. You need to construct the pygame.Rect() objects before the application loop and you have to move it in the loop:
currBlock1 = pygame.Rect(340, 50, 60, 30)
currBlock2 = pygame.Rect(310, 80, 60, 30)
# application loop
while run:
# [...]
pygame.draw.rect(surface, (0, 255, 255), currBlock1)
pygame.draw.rect(surface, (0, 255, 255), currBlock2)
currBlock1.move_ip(0, 30)
currBlock2.move_ip(0, 30)

Creating an arc between two points pygame

I am trying to create a smooth curve between two straight lines with known gradients, I have found an equation to find theses two point but when i try to find the angle for each of the points the arc doesn't line up.I have done the math and it (should) be right.
def angle(A,B):
o = abs(B[1]-A[1])
a = abs(B[0] - A[0])
angle = math.atan(o/a)
return angle
a1 = angle((250, 175),(75, 300))
a2 = angle((250, 175),(400, 315))
pygame.draw.arc(gameDisplay, WHITE, (0 ,0 ,500,350), (math.pi) + a2,(2*math.pi) - a1)
pygame.draw.line(gameDisplay, BLUE, [400,0], [400, 500], 1)
pygame.draw.line(gameDisplay, BLUE, [0,315], [1000, 315], 1)
pygame.draw.line(gameDisplay, RED, [75,0], [75, 500], 1)
pygame.draw.line(gameDisplay, RED, [0,300], [1000, 300], 1)
This is the basic code for finding the start and stop angle, with (250,175) being the center of the ellipse and (75, 300) and (400, 315) being the two points. The lines are where the arc should start and stop.
You do not draw a perfect circular arc, actually you are drawing an elliptical arc. You've to take into account the rectangular area, which is passed to pygame.draw.arc() ((0, 0, 500, 350)), when the start and end angle for the arc is calculated.
As mention in the comments you've to use math.atan2 rather than math.atan to get angles in the range [-pi, pi]. In pygame, the y axis points downwards, so the y component of the direction vector has to be inverted
def angle(A, B, aspectRatio):
x = B[0] - A[0]
y = B[1] - A[1]
angle = math.atan2(-y, x / aspectRatio)
return angle
a1 = angle((250, 175), (75, 300), 500/350)
a2 = angle((250, 175),(400, 315), 500/350)
pygame.draw.arc(gameDisplay, WHITE, (0, 0, 500, 350), a1, a2)

Python, pygame, how to draw an arc

I'm trying to draw an arc in pygame, the actual size and position of the arc aren't important, at the moment all I get is an elipse.
My code:
import pygame
import sys
pygame.init()
size = width, height = 400, 600
screen = pygame.display.set_mode(size)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill((0,0,0))
pygame.draw.arc(screen, (255, 255, 255), (50, 50, 50, 50), 10, 20, 1)
pygame.display.flip()
Why does this draw a full circle instead of an arc?
From the pygame docs:
The two angle arguments are the initial and final angle in radians, with the zero on the right.
You are starting at 10 radians, and sweeping to 20. I assume you meant to do this in degrees. 10 radians is around 572 degrees.
You have to fix your radian values. Use Pi = 3.14 and then change it
for example :
pygame.draw.arc(screen, (255,255,255), [50,50,50,50], Pi/2, Pi, 2)

Categories