Giter Site home page Giter Site logo

python-aturtle's People

Contributors

tmontes avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

fabricejumel

python-aturtle's Issues

Turtle lines don't follow non-linear forward paths.

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.

Refactor Window vs tkinter dependency

Facts

  • The work in #79 / #80 is decoupling the Window class from its direct tkinter.Canvas dependency -- keeping a tkinter.Canvas-like interface, but decoupled.
  • The Window class is still directly coupled with tk.Tk and tk.TopLevel for OS level window creation.

Idea

  • Decoupling the second point, might facilitate future implementations of non-Tk GUI backends, like Qt, and more (web browser? maybe problematic because current GUI API is synchronous)

New Sprite API: visual depth control

Sprites should support two new methods:

  • to_front(of=None)
  • to_back(of=None)

Behaviour:

  • With no arguments, when of is None, the Sprite will be visually pushed to the frontmost/backmost plane.
  • When of is an instance of Sprite, the Sprite will be visually pushed "one level" in front/behind the passed in Sprite.
  • Otherwise, 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:

  • Useful to ensure lines drawn by turtles are behind the turtle sprite itself.
  • Eventually useful in multi-sprite scenarios, like simple games.

Window test hiding another one

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.

Refactor bitmap shape class?

Facts

  • The current bitmap shape implementation is a single class handling two possible image backends: Tkinter and Pillow.
  • The associated testing machinery is slightly more complex due to that fact, too.

Thought

  • Could breaking the current shape.Bitmap apart into two classes -- one Tkinter-backed, the other PIL-backed -- make life easier?
  • Maybe.

Windows should expose an event handling API

Plan:

  • Simple wrapping of tk.bind for common keyboard/mouse/etc events.
  • Clever handling of direct-key support.

About direct-key support:

  • By default tk keyboard events are fired based on OS level configured key repeat and delay.
  • Thus, holding a key down, triggers multiple key events.
  • This article shows a technique to handle such behaviour and convertit to single "press" and "release" events.

Support different async libraries and frameworks

Facts

  • Current work is bound to Standard Library's asyncio.
  • It depends on asyncio.sleep and on the asyncio.CancelledError exception.
  • WRT asyncio, the syncer module transforms asyncio.sleep to time.sleep.

Idea

  • Supporting other libraries and frameworks would be nice: curio, trio, and Twisted come to mind.
  • Maybe having a decoupling module that would map 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.
  • The syncer module would need minor and trivial changes, it seems.
  • Sleeping is nearly trivial, even in Twisted, that would require a minimal sleep implementation to be provided.
  • Need to confirm task cancellation model under different targets: do they all throw exceptions into the underlying coroutine?

Bitmap sprite rotation around non-anchor fails with Tk 8.4

Reproduction

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

Motive

Guessing that Tk 8.4's Canvas objects to not handle the moveto operation.

Way forward

  • Ignore, given that Tk 8.4 is old.
  • Change rotate implementation to be based on Canvas.move operations.

Support optional caching of rotated shapes to disk

Facts

  • Bitmap shapes support rotation.
  • Rotated variations of the source image are computed.
  • Such computation is not fast, especially when no 3rd-party libraries are installed.
  • They are cached in RAM for the lifetime of the running process.
  • New processes have to recompute everything: potentially slow and wasteful.

Thoughts

  • Adding support for optional caching of such computed images to disk may be valuable for some use cases.

Implementation idea

  • The shape could be given a "cache object factory" callable, defaulting to dict.
  • Such factory would create a mutable mapping object that the 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.

Extra

  • One or more custom mutable mappings and their factories could be included.
  • One such custom mapping could even support having everything bundled with the code itself: no external disk-based dependencies.
  • An alternative, very easy to use API could be made available too:
    • Maybe the above mentioned "cache object factory" would be passed to a cache shape argument.
    • When given a callable, the implementation above would be used.
    • If given a 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. :)

Sprite access to the underlying shape

Possible use case:

  • Change the underlying shape.
  • With vector shapes could allow for shape polygon distortion and fill/line changes.
  • With bitmap shapes could allow for bitmap replacement.

Related to #28?

Shape and Sprite design and API improvements

What things are:

  • #16 Images should be named shapes of which there are, at least, two kinds: vector and bitmap.
  • Sprites are Images on a Canvas:
    • They support placement and rotation.
    • Will support async-based animation and, who knows, collision detection? :)

Let's improve the consistency across shapes/sprites and vector/bitmap classes:

  • Rotation is currently implemented in the sprite for vector based sprites but in the underlying image, for bitmap based sprites. Here's an idea:
    • #18 All images (to be named shapes) will be used via an index, much like the current Bitmap image. Such access returns a usable "payload" that Sprites "put" on the canvas.
    • #20 Move rotation code to the vector shapes.
    • #20 Allow "rotated payloads" to be i) pre-computed (as in current Bitmap) or ii) computed on demand and cached.
    • #18 Along those lines, let's allow Bitmap rotations to also be i) pre-computed or ii) computed on demand and cached.
  • #19 Visual information should belong to the shape as identified in #10. Sprites use that for rendering. Refactor vector sprites/images with regards to this.
  • #17 Bitmap images should use anchor argument instead of cx, cy.
  • #18 The previous points induce the creation of an image (Shape!) base class.

More:

  • #21 Review anchor consistency all around. Sometimes (x, y) tuple, others two separate values.
  • #32 Review Sprite API:
    • Want to have read or write access to underlying shape? Maybe not for now. Later may be interesting for "character" animations. But later. Deferred to #33.
    • #22 Rename the sprite package to sprites, for consistency with shapes.
    • #24 Improve the sprite creation function in the package. Idea: when given an 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.
  • #23 DRY up the names: why have VectorShape in a shape.vector module? Mutatis mutants for other vector/bitmap and shape/sprite combinations. :-)
  • #30 User facing angles should be in degrees (instead of radians) which are more intuitive to most, especially beginners.
  • #30 review the shapes API.

Sprite not visually centred

Issue

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! :)

PIL rotated bitmap shapes have black background

Reproduction

  • Ensure Pillow is installed.
  • Create a bitmap shape with no transparency.
  • Create a bitmap sprite with that shape.
  • Rotate the sprite 45 degrees.

The "filled" corners are non-transparent black.

Desired result

The "filled" corners should be transparent. If not possible, those corners should be filled with a user selectable color.

Support more vector image types

Thoughts:

  • Create a base VectorShape class with the following initialiser arguments:
    • points: iterable of (x, y) tuples.
    • anchor: (x, y) tuple.
  • Create a RegularPolygon class with the following initialiser arguments:
    • sides: how many sides the polygon will have.
    • One of 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.
  • Create a 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. :-)

Sprites should support 'forward' movement.

Thoughts

  • Sprites will be the basic building block of turtles.
  • At some point we will have a Turtle class, probably wrapping a sprite, maybe mimicking a lot of its behaviour, with the added option of "drawing lines" as it moves.
  • A minimal Turtle API will have the following operations: forward, left, right, up, and down.
  • The movement related ones might as well be implemented in the 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.

Improve tkinter-based rotated image quality

Facts

  • Current implementation is simple, naive, and slow.
  • Results are low-quality for two reasons:
    • No interpolation is in place.
    • Alpha control is all or nothing with current Tk version (will improve with TIP 166).
  • In particular, from initial experiments, there is a huge quality different between the unrotated image and its rotated variations.

Thoughts

  • Let's optionally support at least linear interpolation.
  • It will be even slower, but image quality should be better.

PS: None of this is true when the optional Pillow 3rd party library is installed.

Review the window event binding API

Facts

  • Currently mostly directly mapped to tkinter API.
  • The bind_direct_key is the exception.
  • Makes adapting to different backends non-trivial, probably.

Idea

  • Simplify the API.
  • Create a bind_key taking a "single letter" key argument:
    • Optional on_press=True, on_release=False arguments.
    • Optional direct boolean flag for the current bind_direct_key behaviour.
    • Will need to support non-letter keys, somehow (cursor keys, space, functions keys, backspace, etc).
    • Should support modifiers: shift, control, alt, command, meta, windows, etc.
  • Create a a few mouse input focused methods: clicks, movement, scroll?
  • Maybe a few Window related events: focus/unfocus/move/resize/minimize/restore/hide?

Implement async sprite animation

Thoughts:

  • Should support, at least, async versions of the currently existing move, move_to, rotate, and rotate_to.
  • Animation speed, frames-per-second, and easing should be supported too.

Add support for multi-shape sprites

Facts

  • There are currently two types of supported sprites: bitmap and vector based.
  • Both backed by a single shape object.
  • Bitmap shapes represent a single "image".
  • Vector shapes represent a single closed polygon.

Idea

  • Could we have a multi-shape backed sprite?
  • It would allow for visually rich, multi-color vector based characters.
  • It could support (no idea how!) animation by moving/rotating the individual shapes relatively to themselves or the sprite's anchor point.
  • Feels interesting, fun, and powerful.

PS: Famous last words: how hard can this be?! :-)

Sprite movement does not respect m_speed.

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

Sprite forward should optionally support varying angle

Current Status

  • The Sprite *_forward method moves the sprite a certain distance in the direction it is facing.
  • A running async_forward does not track the angle that a concurrent async_rotate progressively changes.

Wanted

  • By default, async_forward should be "clever" enough to track concurrent rotations.
  • Optionally it should be possible to say "disregard concurrent rotations and consider only the initial angle".

Refactor Sprite.rotate?

Issue

  • The current base.Sprite.rotate implementation updates self._anchor and self._angle.
  • Then, the vector.Sprite.rotate and bitmap.Sprite.rotate implementations build on top of it.
  • They're somewhat inconsistent.
  • They need to access a few super-class private attributes like self._id and self._update.

Wondering

  • Could the base.Sprite.rotate also do the "canvas item move"?
  • Would that allow us to simplify the vector and bitmap implementations such that they would only need to update the shape?

Support synchronous sprite animation

Thought

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.

Crazy Idea

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:

  • Generate an ASTs from the existing async methods.
  • Replace await asyncio.sleep expressions with time.sleep equivalents.
  • Maybe to some other simple replacements.
  • Compile updated AST.
  • Create a new method with that generated code.

Will I regret this? :-)

Add support for sprite self-animation

Idea

  • If sprites are to be used as "characters", it could be interesting to support self-animation.
  • Could a bitmap based sprite keep playing a "move of bitmaps"?
    • How could such a "movie" be changed? (walking character vs running character)
  • Could a vector base sprite keep playing a "movie of polygons" or a "vertex tweak loop"?

Improve bitmap shape rotation

Scenario:

  • Bitmap shape with 360 shape rotations.
  • Rotating 90 degrees multiple times.

Observed result:

  • Floating point error accumulation may lead to a final angle of 89.99999999 at some point.
  • Current code grabs the shape rotated at 89 degrees resulting in a non-perfect visual.

Possible fix:

  • Replace int with round in the shape's __getitem__ step calculation.

Coordinate system: larger y values should be at the top.

Issue

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?

Implementation thoughts

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. :-)

Add a "mainloop" coroutine (and function) to Windows

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().

Window creation should support negative x/y

Issue

  • Setting a Window's x and y attributes moves it on the display.
  • Setting them to negative values, places the window from-right/top.
  • However, creating a window with negative x or y attributes does not work.

Simplify the create_sprite function usage

Facts

  • The first argument of the aturtle.create_sprite helper function is expected to be a canvas.
  • This leads to code like:
w = aturtle.Window(...)
s = turtle.create_sprite(w.canvas, ...)

Thought

Let's allow the helper function to take either a canvas or a window, with a duck-typing approach:

  • Checks if the first argument has a .canvas attribute. If so, uses that.
  • Otherwise, assume it is a canvas and go from there, as per the status quo.

This should allow for a cleaner, more direct:

w = aturtle.Window(...)
s = aturtle.create_sprite(w, ...)

Small sprite rotation raises ZeroDivisionError

Context

Discovered while implementing sync animation.

Reproduction

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

Let there be turtles

About Turtle objects:

  • Wrap a sprite.
  • Have the following attributes:
    • Draws lines as it moves: yes/no.
    • Line colour and width.
  • Will have the following methods:
    • forward, left, right, up, and down.
    • Movement ones should have sync and async variations.

Other aspects to be defined.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.