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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.