tmontes / python-aturtle Goto Github PK
View Code? Open in Web Editor NEWWIP: Python AsyncIO-ready Turtle Graphics
License: MIT License
WIP: Python AsyncIO-ready Turtle Graphics
License: MIT License
After #57, the turtle line drawing code needs to be updated.
As of now, a single line segment is created and the end point is progressively updated to track the turtle's movement. To draw potentially non-linear paths, multiple line segments need to be created instead.
Window
class from its direct tkinter.Canvas
dependency -- keeping a tkinter.Canvas
-like interface, but decoupled.Window
class is still directly coupled with tk.Tk
and tk.TopLevel
for OS level window creation.Maybe.
Useful examples available at https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-python-with-github-actions.
Sprites should support two new methods:
to_front(of=None)
to_back(of=None)
Behaviour:
of is None
, the Sprite will be visually pushed to the frontmost/backmost plane.of
is an instance of Sprite
, the Sprite will be visually pushed "one level" in front/behind the passed in Sprite.of
is assumed to be a canvas item id and the Sprite will be visually pushed "one level" in front/behind the given canvas item.May need future improvements but:
The test_unbind_default_works_with_no_bindings
test is defined twice in tests/test_window.py
. Thus, the first defined test is never run.
Let's fix this.
shape.Bitmap
apart into two classes -- one Tkinter-backed, the other PIL-backed -- make life easier?Plan:
tk.bind
for common keyboard/mouse/etc events.About direct-key support:
asyncio
.asyncio.sleep
and on the asyncio.CancelledError
exception.asyncio
, the syncer
module transforms asyncio.sleep
to time.sleep
.sleep
and task cancellation to the various candidates above could work. Such mapping could be done automatically by trying to import them (and prioritising if more than one is found), falling back to asyncio
. Manual selection should be possible.syncer
module would need minor and trivial changes, it seems.sleep
implementation to be provided.Motivations:
(the title says it all)
Python linked against Tk 8.4
import aturtle
w = aturtle.Window()
s = aturtle.create_sprite(w.canvas, 'sprite.png')
s.rotate(90, around=(-50, 50))
Leads to the following traceback:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/tmontes/Work/python-aturtle/src/aturtle/sprites/bitmap.py", line 43, in rotate
self._canvas.moveto(
File "/Users/tmontes/usr/local/python-3.8.1/lib/python3.8/tkinter/__init__.py", line 2924, in moveto
self.tk.call(self._w, 'moveto', tagOrId, x, y)
_tkinter.TclError: bad option "moveto": must be addtag, bbox, bind, canvasx, canvasy, cget, configure, coords, create, dchars, delete, dtag, find, focus, gettags, icursor, index, insert, itemcget, itemconfigure, lower, move, postscript, raise, scale, scan, select, type, xview, or yview
Guessing that Tk 8.4's Canvas
objects to not handle the moveto
operation.
rotate
implementation to be based on Canvas.move
operations.dict
.shape.Base
class would use.This could be enough, I suppose. With this, simple disk-based caching could be achieved by passing one of the classes in the shelve
Standard Library, for example.
cache
shape argument.str
of path.Path
it could take that as the file to be used for caching, taking care of the dirty work of setting and wiring it up. :)With #57, sprite forward movements optionally track concurrent angle changes, depending on a track_angle
argument value.
Turtle forward movements should support that argument too.
Modules are called fake_*
, why should their internal objects be called Fake*
?
(inline with the name simplifications in #89)
Title says it all.
Possible use case:
Related to #28?
What things are:
Let's improve the consistency across shapes/sprites and vector/bitmap classes:
Bitmap
image. Such access returns a usable "payload" that Sprites "put" on the canvas.Bitmap
) or ii) computed on demand and cached.Bitmap
rotations to also be i) pre-computed or ii) computed on demand and cached.anchor
argument instead of cx
, cy
.More:
sprite
package to sprites
, for consistency with shapes
.str
assume it's an image filename, when given bytes
assume it's image data, if it's a list assume a list of points, otherwise, assume a vector shape.VectorShape
in a shape.vector
module? Mutatis mutants for other vector/bitmap and shape/sprite combinations. :-)As of the WIP in #56, turtles have both forward/backward methods while sprites only have forward. Let's make this consistent, shall we?
The following code results in the sprite being displayed center and bottom, instead of fully centered on the Window Canvas.
import aturtle
w = aturtle.Window(width=640, x=780)
s = aturtle.create_sprite(w.canvas, aturtle.shapes.vector.Star())
Moving / resizing the window leads to it finally ending up centered. Something related to canvas centering and window sizing is going on. Should be a simple fix, hopefully! :)
Pillow
is installed.The "filled" corners are non-transparent black.
The "filled" corners should be transparent. If not possible, those corners should be filled with a user selectable color.
I'm positive we can make it simpler... Can we?
Thoughts:
VectorShape
class with the following initialiser arguments:
points
: iterable of (x, y) tuples.anchor
: (x, y) tuple.RegularPolygon
class with the following initialiser arguments:
sides
: how many sides the polygon will have.radius
or side_length
: defining the polygon "size".angle
: used to create squares with sides parallel to the axes or, say, at 45 degrees.anchor
: (x, y) tuple.Star
class with the following initialiser arguments:
points
: how many points the start will have.radius
: the outer radius of the star.inner_radius
: the inner radius of the star.angle
: rotate the star points.anchor
: (x, y) tuple.Maybe more, later. :-)
Turtle
class, probably wrapping a sprite, maybe mimicking a lot of its behaviour, with the added option of "drawing lines" as it moves.Turtle
API will have the following operations: forward
, left
, right
, up
, and down
.Sprite
class: not only do they make sense there (all movement code under the same class), but also they might actually be useful to someone wanting to use "turtle-like" movements with Sprites.PS: None of this is true when the optional Pillow 3rd party library is installed.
tkinter
API.bind_direct_key
is the exception.bind_key
taking a "single letter" key argument:
on_press=True
, on_release=False
arguments.direct
boolean flag for the current bind_direct_key
behaviour.Thoughts:
move
, move_to
, rotate
, and rotate_to
.PS: Famous last words: how hard can this be?! :-)
There are typos in the async_move
and async_move_to
method implementations.
The lines that currently read...
speed = self._r_speed if speed is None else speed
...must be replaced with:
speed = self._m_speed if speed is None else speed
*_forward
method moves the sprite a certain distance in the direction it is facing.async_forward
does not track the angle that a concurrent async_rotate
progressively changes.async_forward
should be "clever" enough to track concurrent rotations.Implementation idea:
base.Sprite.rotate
implementation updates self._anchor
and self._angle
.vector.Sprite.rotate
and bitmap.Sprite.rotate
implementations build on top of it.self._id
and self._update
.base.Sprite.rotate
also do the "canvas item move"?vector
and bitmap
implementations such that they would only need to update the shape?With #34 nearly completed, it has come to my mind that synchronous animation could also be supported -- pretty much like the Standard Library's turtle
module supports.
Instead of copying+pasting the nearly ready a_move
, a_move_to
, a_rotate
, and a_rotate_to
methods to their sync counterparts we might be able to automatically generate them. Here's how:
await asyncio.sleep
expressions with time.sleep
equivalents.Will I regret this? :-)
Scenario:
Observed result:
Possible fix:
int
with round
in the shape's __getitem__
step calculation.As of now, per tkinter.Canvas
' coordinate system, larger y values go towards the bottom of the screen. Humans, however, tend to work more naturally with the reverse, having larger y values at the top. Moreover, the turtle
module in Python's Standard Library also makes larger y values towards the top. Let's fix this shall we?
Two immediate approaches come to mind:
Nicely designed: implement a Canvas
class, wrapping a tkinter.Canvas
(or inheriting), with an equivalent API, where the y values are negated. This should be enough, given that y == 0 is at the vertical center of the visible canvas.
Hardcoded: reverse all (most?) y coordinate values in the existing code base (Shapes at least, maybe Sprites, Turtles probably not).
The benefit of the first is that it simplifies future changes and capabilities (arbitrary transformations of the coordinate system, including scaling/rotation/etc) and also serves as a template for implementing non-Tk backed canvas objects. The penalty is indirection and, eventually performance.
The benefit of the second boils down to performance and, eventually, it might be simpler to implement. Not sure.
Will sleep over this and decide later. :-)
Title says it all.
Such that the following program skeleton would work, even when turtles and events and animation is included.
import asyncio
import aturtle
w = aturtle.Window()
asyncio.run(w.mainloop())
PS: Maybe we could add the synchronous counterpart with the help of syncer
. In that case, the above code would probably call w.async_mainloop()
while the sync version would be called with w.sync_mainloop()
.
aturtle.create_sprite
helper function is expected to be a canvas.w = aturtle.Window(...)
s = turtle.create_sprite(w.canvas, ...)
Let's allow the helper function to take either a canvas or a window, with a duck-typing approach:
.canvas
attribute. If so, uses that.This should allow for a cleaner, more direct:
w = aturtle.Window(...)
s = aturtle.create_sprite(w, ...)
Let's publish this, as is, shall we?
Specifically:
Thoughts:
Thoughts:
Discovered while implementing sync animation.
import aturtle, easing_functions
w = aturtle.Window(height=800, x=800, y=50)
sh = aturtle.shapes.vector.Star(radius=24)
s = aturtle.create_sprite(w.canvas, sh, update=True)
s.sync_rotate(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<generated>", line 28, in sync_rotate
ZeroDivisionError: division by zero
About Turtle objects:
Other aspects to be defined.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.