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)
I am working on a "3D" cube in Python with Turtle. I am trying to find a way so I can make a cursor lock, or just so when you hold right click you can look at the cube from different angles. Since I do not know how to do this, I have a rotating function.
My current code:
import turtle
VERTEXES = [(-1, -1, -1), ( 1, -1, -1), ( 1, 1, -1), (-1, 1, -1),
(-1, -1, 1), ( 1, -1, 1), ( 1, 1, 1), (-1, 1, 1)]
TRIANGLES = [
(0, 1, 2), (2, 3, 0),
(0, 4, 5), (5, 1, 0),
(0, 4, 3), (4, 7, 3),
(5, 4, 7), (7, 6, 5),
(7, 6, 3), (6, 2, 3),
(5, 1, 2), (2, 6, 5)
]
FOV = 400
# Create turtle,
pointer = turtle.Turtle()
# Turn off move time, makes drawing instant,
turtle.tracer(0, 0)
pointer.up()
def rotate(x, y, r):
s, c = sin(r), cos(r)
return x * c - y * s, x * s + y * c
counter = 0
while True:
# Clear screen,
pointer.clear()
# Draw,
for triangle in TRIANGLES:
points = []
for vertex in triangle:
# Get the X, Y, Z coords out of the vertex iterator,
x, y, z = VERTEXES[vertex]
# Rotate,
x, z = rotate(x, z, counter)
y, z = rotate(y, z, counter)
x, y = rotate(x, y, counter)
# Perspective formula,
z += 5
f = FOV / z
sx, sy = x * f, y * f
# Add point,
points.append((sx, sy))
# Draw triangle,
pointer.goto(points[0][0], points[0][1])
pointer.down()
pointer.goto(points[1][0], points[1][1])
pointer.goto(points[2][0], points[2][1])
pointer.goto(points[0][0], points[0][1])
pointer.up()
# Update,
turtle.update()
counter += 0.01
First off I just wanna say that Turtle does not have a lot of support for mouse events and other fun things that other frameworks have.
Because of turtles lack of support for mouse up events when it is triggered via screen events this will allow you to right click and not hold it down and it will continue to get the delta of your mouse movements before setting the mouse back to the original position. Once you done dragging the mouse just right click again and it will release the mouse.
The delta will be low, usually between 1-3. If this is to low then add in a time.sleep(1/60). This will lock the fps to 60 frames and will allow the mouse to move more before being locked back to its original position.
I also want to show off this question cause it seems like it has a way of adding in on mouse up and move events to turtle but ill let you look at it to decide if you want to go that route.
Find the cursor's current position in Python turtle
Good luck.
from ctypes import windll, Structure, c_long, byref
from turtle import Turtle, Screen, update
is_dragging = False
start_mouse_pos = (0, 0)
class POINT(Structure):
_fields_ = [("x", c_long), ("y", c_long)]
x: int
y: int
def getMousePosition():
pt = POINT()
windll.user32.GetCursorPos(byref(pt))
return (pt.x, pt.y)
def setMousePosition(pos: tuple):
windll.user32.SetCursorPos(int(pos[0]), int(pos[1]))
def onScreenClick(x, y):
global is_dragging, start_mouse_pos
is_dragging = not is_dragging
start_mouse_pos = getMousePosition()
turtle = Turtle()
screen = Screen()
screen.onscreenclick(onScreenClick, 3)
while True:
if is_dragging:
pos = getMousePosition()
delta_pos = (start_mouse_pos[0] - pos[0], start_mouse_pos[1] - pos[1])
# Do something with how much the mouse has moved then set the mouse position back
setMousePosition(start_mouse_pos)
update()
You should be able to do this with an ondrag() event handler. Below is a rework of your code to remove the automatic movement and substitute the ability to manually move the cube by clicking on the the red corner and moving the mouse while continuing to hold the button down (dragging):
from math import sin, cos, atan2 as atan
from turtle import Screen, Turtle
VERTEXES = [
(-1, -1, -1), (1, -1, -1), (1, 1, -1), (-1, 1, -1),
(-1, -1, 1), (1, -1, 1), (1, 1, 1), (-1, 1, 1)
]
TRIANGLES = [
(0, 1, 2),
(2, 3, 0),
(0, 4, 5),
(5, 1, 0),
(0, 4, 3),
(4, 7, 3),
(5, 4, 7),
(7, 6, 5),
(7, 6, 3),
(6, 2, 3),
(5, 1, 2),
(2, 6, 5)
]
FOV = 400
def rotate(x, y, r):
s, c = sin(r), cos(r)
return x * c - y * s, x * s + y * c
orientation = 0 # radians
def draw():
global orientation
turtle.clear()
for triangle in TRIANGLES:
for flag, vertex in enumerate(triangle):
# Get the X, Y, Z coords out of the vertex iterator
x, y, z = VERTEXES[vertex]
# Rotate
x, z = rotate(x, z, orientation)
y, z = rotate(y, z, orientation)
x, y = rotate(x, y, orientation)
# Perspective formula
z += 5
f = FOV / z
s = x * f, y * f
# Draw line
turtle.setposition(s)
turtle.pendown()
if not flag:
start = s
turtle.setposition(start)
turtle.penup()
screen.update()
def orient(x, y):
global orientation
turtle.ondrag(None) # disable handler inside handler
orientation = atan(y, x)
draw()
turtle.ondrag(orient) # reenable handler
# Turn off move time, makes drawing instant,
screen = Screen()
screen.tracer(False)
# Create turtle,
turtle = Turtle('circle')
turtle.fillcolor('red')
turtle.shapesize(0.5)
turtle.penup()
draw()
turtle.ondrag(orient)
screen.mainloop()
The mouse position to cube position mapping clearly isn't optimal, but should be enough to convince you it is possible and provide a starting point.
I'm attempting to create a Rubik's Cube in Python, i have gotten as far as visually representing the cube. Struggling a bit with how to implement rotation.
I guess i'm asking for feedback as to how to go about doing this. I thought at first of, rotating each cubes set of vertices's, without much luck.
I basically want to select a slice from an array of cube objects (of varying size), perform a rotation and a translation on each object.
import pygame
import random
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
vertices = (
(1, -1, -1),
(1, 1, -1),
(-1, 1, -1),
(-1, -1, -1),
(1, -1, 1),
(1, 1, 1),
(-1, -1, 1),
(-1, 1, 1)
)
edges = (
(0,1),
(0,3),
(0,4),
(2,1),
(2,3),
(2,7),
(6,3),
(6,4),
(6,7),
(5,1),
(5,4),
(5,7)
)
surfaces = (
(0,1,2,3),
(3,2,7,6),
(6,7,5,4),
(4,5,1,0),
(1,5,7,2),
(4,0,3,6)
)
colors = (
(1,0,0), #Red
(0,1,0), #Green
(1,0.5,0), #Orange
(1,1,0), #Yellow
(1,1,1), #White
(0,0,1), #Blue
)
class Cube():
'''set the vertices edges and surfaces(colored) for a Cube'''
def __init__(self):
'''initiate the display to show the cube'''
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
glEnable(GL_DEPTH_TEST)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
glTranslatef(1,1, -40)
def setVertices(self, xmove, ymove, zmove):
'''set predefined vertices'''
xValueChange = xmove
yValueChange = ymove
zValueChange = zmove
newVertices = []
for vert in vertices:
newVert = []
newX = vert[0] + xValueChange
newY = vert[1] + yValueChange
newZ = vert[2] + zValueChange
newVert.append(newX)
newVert.append(newY)
newVert.append(newZ)
newVertices.append(newVert)
return newVertices
def CreateCube(self, vertices):
'''create with OpenGL'''
glBegin(GL_QUADS)
x = 0
for surface in surfaces:
glColor3fv(colors[x])
x+=1
for vertex in surface:
glVertex3fv(vertices[vertex])
glEnd()
class EntireCube():
def __init__(self,typeOfCube):
self.typeOfCube = typeOfCube
self.NewCube = Cube()
def createEntireCube(self):
'''for each dimension x,y,z make a dictionary containing the vertices to be displayed'''
self.cubeDict = {}
count = 0
for x in range(self.typeOfCube):
for y in range(self.typeOfCube):
for z in range(self.typeOfCube):
self.cubeDict[count] = self.NewCube.setVertices(x*2.1,y*2.1,z*2.1)
count += 1
def mainloop(self):
'''key events, creates the matrix of cubes'''
rotateUpKey, rotateDownKey, rotateLeftKey, rotateRightKey = False, False, False, False
rotationalSensitivity = 2
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == KEYDOWN:
if event.key == K_UP:
rotateUpKey = True
if event.key == K_DOWN:
rotateDownKey = True
if event.key == K_LEFT:
rotateLeftKey = True
if event.key == K_RIGHT:
rotateRightKey = True
if event.type == KEYUP:
if event.key == K_UP:
rotateUpKey = False
if event.key == K_DOWN:
rotateDownKey = False
if event.key == K_LEFT:
rotateLeftKey = False
if event.key == K_RIGHT:
rotateRightKey = False
if rotateUpKey:
glRotatef(rotationalSensitivity,-rotationalSensitivity,0,0)
if rotateDownKey:
glRotatef(rotationalSensitivity,rotationalSensitivity,0,0)
if rotateLeftKey:
glRotatef(rotationalSensitivity,0,-rotationalSensitivity,0)
if rotateRightKey:
glRotatef(rotationalSensitivity,0,rotationalSensitivity,0)
#eventually implement keysbindings to call function to rotate a slice of the matrix created
# x = glGetDoublev(GL_MODELVIEW_MATRIX)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
for eachCube in self.cubeDict:
self.NewCube.CreateCube(self.cubeDict[eachCube])
# glPushMatrix()
# glRotatef(1,3,1,1)
# glPopMatrix()
pygame.display.flip()
pygame.time.wait(10)
def main():
NewEntireCube = EntireCube(3) #create a 3x3x3 cube
NewEntireCube.createEntireCube()
NewEntireCube.mainloop()
if __name__ == '__main__':
main()
pygame.quit()
quit()
I'm hoping someone who knows much more about this can give me some guidance as to how to proceed.
A rubik's cube can be organized by an 3 dimensional array of 3x3x3 cubes. It seems to be easy to rotate a slice of the cube, but note if on slice is rotated the positions of the cube change and have to be reorganized. Not only the position changes, also the orientation of the (rotated) single cubes changes.
First of all remove the PyGame and OpenGL initialization form the constructor of the class Cube. That is the wrong place for this. In the following will generate 27 objects of type Cube.
Each cube has to know where it is initially located (self.init_i) and where it is current located after some rotations (self.current_i). This information is encoded in a list with 3 elements, one for each axis. The values are indices of cube in the NxNxN rubik's cube in range [0, N[.
The orientation of a single cube is encoded in 3 dimensional Rotation matrix (self.rot). The rotation matrix has to be initialized by the identity matrix.
class Cube():
def __init__(self, id, N, scale):
self.N = N
self.scale = scale
self.init_i = [*id]
self.current_i = [*id]
self.rot = [[1 if i==j else 0 for i in range(3)] for j in range(3)]
Create a list of the 27 cubes
cr = range(3)
self.cubes = [Cube((x, y, z), 3, scale) for x in cr for y in cr for z in cr]
If a slice of the rubik's cube is rotated, then it has to be checked which of the single cubes is affected. This can be done by checking if the slice matches the entry of the rotation axis of the current position.
def isAffected(self, axis, slice, dir):
return self.current_i[axis] == slice
To rotate a cube, the position and the orientation has to be rotated by 90° around an axis. A 3 dimension rotation matrix consists of 3 direction vectors. A d dimensional vector can be rotated by swapping the coordinates of the vector and inverting the x coordinate of the result for a right rotation and inverting the y coordinate of the result for a left rotation:
rotate right: (x, y) -> (-y, x)
rotate left: (x, y) -> (y, -x)
Since all the vectors of the rotation matrix are in an axis aligned plane this algorithm can be used to change the orientation and the position of the cube. axis the rotation axis (x=0, y=1, z=2) and dir is the rotation direction (1 is right and -1 left)
To rotate the axis vector, 2 components of the vector have to be swapped and one of them inverted.
e.g rotate left around the Y-axis:
(x, y, z) -> (z, y, -x)
When the position is rotated, then the indices have to be swapped. Inverting an index means to map the index i to the index N-1-i:
e.g rotate left around the Y-axis:
(ix, iy, iz) -> (iz, iy, N-1-ix)
Rotation of a single cube:
i, j = (axis+1) % 3, (axis+2) % 3
for k in range(3):
self.rot[k][i], self.rot[k][j] = -self.rot[k][j]*dir, self.rot[k][i]*dir
self.current_i[i], self.current_i[j] = (
self.current_i[j] if dir < 0 else self.N - 1 - self.current_i[j],
self.current_i[i] if dir > 0 else self.N - 1 - self.current_i[i] )
When the cube has to be drawn, then the current position of the cube (self.current_i) and the orientation self.rot can be used to set up 4x4 transformation matrix:
def transformMat(self):
scaleA = [[s*self.scale for s in a] for a in self.rot]
scaleT = [(p-(self.N-1)/2)*2.1*self.scale for p in self.current_i]
return [
*scaleA[0], 0,
*scaleA[1], 0,
*scaleA[2], 0,
*scaleT, 1]
With glPushMatrix respectively glPushMatrix. By glMultMatrix a matrix can be multiplied to the current matrix.
The following function draws a single cube. The parameters angle, axis, slice, dir and it can even apply an animation to the cube, by setting animate=True and setting parameters angle, axis, slice, dir:
def draw(self, col, surf, vert, animate, angle, axis, slice, dir):
glPushMatrix()
if animate and self.isAffected(axis, slice, dir):
glRotatef( angle*dir, *[1 if i==axis else 0 for i in range(3)] )
glMultMatrixf( self.transformMat() )
glBegin(GL_QUADS)
for i in range(len(surf)):
glColor3fv(colors[i])
for j in surf[i]:
glVertex3fv(vertices[j])
glEnd()
glPopMatrix()
To draw the cubes, it is sufficient to call the method draw in a loop:
for cube in self.cubes:
cube.draw(colors, surfaces, vertices, animate, animate_ang, *action)
The implementation of the class Cube works for any NxNxN Rubik's cube.
See the example program for a 3x3x3 cube. The slices of the cube are rotated to the right by the keys 1 to 9 and to the left by the keys F1 to F9:
Of course the code uses the Legacy OpenGL in regard to your original code. But the method Cube.transformMat sets a general 4x4 model matrix for a single partial cube. Thus it is possible to port this code to modern OpenGL with ease.
import pygame
import random
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
vertices = (
( 1, -1, -1), ( 1, 1, -1), (-1, 1, -1), (-1, -1, -1),
( 1, -1, 1), ( 1, 1, 1), (-1, -1, 1), (-1, 1, 1)
)
edges = ((0,1),(0,3),(0,4),(2,1),(2,3),(2,7),(6,3),(6,4),(6,7),(5,1),(5,4),(5,7))
surfaces = ((0, 1, 2, 3), (3, 2, 7, 6), (6, 7, 5, 4), (4, 5, 1, 0), (1, 5, 7, 2), (4, 0, 3, 6))
colors = ((1, 0, 0), (0, 1, 0), (1, 0.5, 0), (1, 1, 0), (1, 1, 1), (0, 0, 1))
class Cube():
def __init__(self, id, N, scale):
self.N = N
self.scale = scale
self.init_i = [*id]
self.current_i = [*id]
self.rot = [[1 if i==j else 0 for i in range(3)] for j in range(3)]
def isAffected(self, axis, slice, dir):
return self.current_i[axis] == slice
def update(self, axis, slice, dir):
if not self.isAffected(axis, slice, dir):
return
i, j = (axis+1) % 3, (axis+2) % 3
for k in range(3):
self.rot[k][i], self.rot[k][j] = -self.rot[k][j]*dir, self.rot[k][i]*dir
self.current_i[i], self.current_i[j] = (
self.current_i[j] if dir < 0 else self.N - 1 - self.current_i[j],
self.current_i[i] if dir > 0 else self.N - 1 - self.current_i[i] )
def transformMat(self):
scaleA = [[s*self.scale for s in a] for a in self.rot]
scaleT = [(p-(self.N-1)/2)*2.1*self.scale for p in self.current_i]
return [*scaleA[0], 0, *scaleA[1], 0, *scaleA[2], 0, *scaleT, 1]
def draw(self, col, surf, vert, animate, angle, axis, slice, dir):
glPushMatrix()
if animate and self.isAffected(axis, slice, dir):
glRotatef( angle*dir, *[1 if i==axis else 0 for i in range(3)] )
glMultMatrixf( self.transformMat() )
glBegin(GL_QUADS)
for i in range(len(surf)):
glColor3fv(colors[i])
for j in surf[i]:
glVertex3fv(vertices[j])
glEnd()
glPopMatrix()
class EntireCube():
def __init__(self, N, scale):
self.N = N
cr = range(self.N)
self.cubes = [Cube((x, y, z), self.N, scale) for x in cr for y in cr for z in cr]
def mainloop(self):
rot_cube_map = { K_UP: (-1, 0), K_DOWN: (1, 0), K_LEFT: (0, -1), K_RIGHT: (0, 1)}
rot_slice_map = {
K_1: (0, 0, 1), K_2: (0, 1, 1), K_3: (0, 2, 1), K_4: (1, 0, 1), K_5: (1, 1, 1),
K_6: (1, 2, 1), K_7: (2, 0, 1), K_8: (2, 1, 1), K_9: (2, 2, 1),
K_F1: (0, 0, -1), K_F2: (0, 1, -1), K_F3: (0, 2, -1), K_F4: (1, 0, -1), K_F5: (1, 1, -1),
K_F6: (1, 2, -1), K_F7: (2, 0, -1), K_F8: (2, 1, -1), K_F9: (2, 2, -1),
}
ang_x, ang_y, rot_cube = 0, 0, (0, 0)
animate, animate_ang, animate_speed = False, 0, 5
action = (0, 0, 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == KEYDOWN:
if event.key in rot_cube_map:
rot_cube = rot_cube_map[event.key]
if not animate and event.key in rot_slice_map:
animate, action = True, rot_slice_map[event.key]
if event.type == KEYUP:
if event.key in rot_cube_map:
rot_cube = (0, 0)
ang_x += rot_cube[0]*2
ang_y += rot_cube[1]*2
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glTranslatef(0, 0, -40)
glRotatef(ang_y, 0, 1, 0)
glRotatef(ang_x, 1, 0, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
if animate:
if animate_ang >= 90:
for cube in self.cubes:
cube.update(*action)
animate, animate_ang = False, 0
for cube in self.cubes:
cube.draw(colors, surfaces, vertices, animate, animate_ang, *action)
if animate:
animate_ang += animate_speed
pygame.display.flip()
pygame.time.wait(10)
def main():
pygame.init()
display = (800,600)
pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
glEnable(GL_DEPTH_TEST)
glMatrixMode(GL_PROJECTION)
gluPerspective(45, (display[0]/display[1]), 0.1, 50.0)
NewEntireCube = EntireCube(3, 1.5)
NewEntireCube.mainloop()
if __name__ == '__main__':
main()
pygame.quit()
quit()
I'm new to Python and have a question. I want to move the turtle to a specific start location, and from there draw a shape. The shape has pre-determined coordinates, so I need to connect the points to make the shape.
I have to make 2 functions such that the following code calls those 2 functions and draws three shapes:
def testPolyLines():
# First square
squareShape = [(50, 0), (50, 50), (0, 50), (0, 0)]
drawPolyLine((200, 200), squareShape)
# Second square
drawPolyLine((-200, 200), squareShape, lineColour="green")
biggerSquareShape = generateSquarePoints(100)
# A triangle
triangleShape = [(200, 0), (100, 100), (0, 0)]
drawPolyLine((100, -100), triangleShape, fillColour="green")
def main():
testPolyLines()
main()
I made the first function to generate points for a square of any size:
def generateSquarePoints(i):
squareShape = [(i, 0), (i, i), (0, i), (0, 0)]
But I get stuck when it comes to actually drawing the shape. I can make the turtle go to the start position, but I don't know how to make it go through a list of points and connect them to form a shape. This is what I have:
def drawPolyLine(start, squareShape, lineColour="black", fillColour = "white"):
pencolor(lineColour)
fillcolor(fillColour)
penup()
goto(start)
pendown()
begin_fill()
goto(squareShape)
end_fill()
This is obviously not right...the part I'm confused about is how to tell the turtle to go to the list of points, and connect them along the way to form the shape. My program now only goes to the start positions but doesn't draw the shape.
I would really appreciate any help or advice! Thanks in advance.
Issues with your code: you can't just goto() the points, you need to adjust them to the starting position, treating the x & y in the point as more of a delta-x, delta-y; generateSquarePoints() needs to return its list of points, not assign it; obviously a for loop is needed as others have mentioned; you need to explicitly draw back to the starting point to close the shape.
Try the following rework of your code to see if it does what you want:
import turtle
def generateSquarePoints(i):
""" generate points for a square of any size """
return [(i, 0), (i, i), (0, i), (0, 0)]
def drawPolyLine(start, points, lineColour="black", fillColour="white"):
""" draw shapes using a list of coordinates """
turtle.pencolor(lineColour)
turtle.fillcolor(fillColour)
turtle.penup()
turtle.goto(start) # make the turtle go to the start position
turtle.pendown()
turtle.begin_fill()
x, y = start
for point in points: # go through a list of (relative) points
dx, dy = point
turtle.goto(x + dx, y + dy)
turtle.goto(start) # connect them to start to form a closed shape
turtle.end_fill()
turtle.penup()
if __name__ == "__main__":
def testPolyLines():
""" test shapes shape drawing functions """
# First square
squareShape = [(50, 0), (50, 50), (0, 50), (0, 0)]
drawPolyLine((200, 200), squareShape)
# Second square
biggerSquareShape = generateSquarePoints(100)
drawPolyLine((-200, 200), biggerSquareShape, lineColour="green")
# A triangle
triangleShape = [(200, 0), (100, 100), (0, 0)]
drawPolyLine((100, -100), triangleShape, fillColour="green")
def main():
testPolyLines()
turtle.done()
main()