"""
turtler.py
支持旋转角色的海龟模块。
本个模块重定义了原生海龟类的_rotate,__init__和shape方法
使用pillow模块支持图形角色旋转,并且支持直接设定图片为角色的造型。
本模块尚不支持用addshape或register_shape注册造型到型字典!
"""
__author__ = '李兴球'
__blog__ = 'www.lixingqiu.com'
__date__ = '2020/9/7'
__version__ = 0.1
import os
from PIL import Image,ImageTk
from turtle import Tbuffer,_Screen,_CFG,TNavigator,TPen,_TurtleImage,RawTurtle,Turtle,Screen,Shape
Sprite = Turtle
def _place_to_shapes(self,imagefilename):
"""用pillow模块打开图像文件,形成造型,放到造型字典中,返回在造型字典中的key"""
self._imagename = imagefilename # 保留原始图像文件名
self._rawim = Image.open(imagefilename) # 用pillow模块打开这个文件
self._rawim = self._rawim.convert('RGBA')
angle = self.heading()
im = self._rawim.rotate(angle,expand=1)
sp = Shape('image',ImageTk.PhotoImage(im))
shapename = self._imagename + "_" + str(angle)
self.screen.addshape(shapename,sp)
return shapename
RawTurtle._place_to_shapes = _place_to_shapes
def __init__(self, canvas=None,shape=_CFG["shape"],
undobuffersize=_CFG["undobuffersize"],
visible=_CFG["visible"]):
if isinstance(canvas, _Screen):
self.screen = canvas
elif isinstance(canvas, TurtleScreen):
if canvas not in RawTurtle.screens:
RawTurtle.screens.append(canvas)
self.screen = canvas
elif isinstance(canvas, (ScrolledCanvas, Canvas)):
for screen in RawTurtle.screens:
if screen.cv == canvas:
self.screen = screen
break
else:
self.screen = TurtleScreen(canvas)
RawTurtle.screens.append(self.screen)
else:
raise TurtleGraphicsError("bad canvas argument %s" % canvas)
screen = self.screen
TNavigator.__init__(self, screen.mode())
TPen.__init__(self)
screen._turtles.append(self)
self.drawingLineItem = screen._createline()
if os.path.isfile(shape): # 如果是文件
shape = self._place_to_shapes(shape) # 第一次放到造型字典中
else:
self._imagename = None # 图片造型属性
self._rawim = None
self.turtle = _TurtleImage(screen, shape)
self._poly = None
self._creatingPoly = False
self._fillitem = self._fillpath = None
self._shown = visible
self._hidden_from_screen = False
self.currentLineItem = screen._createline()
self.currentLine = [self._position]
self.items = [self.currentLineItem]
self.stampItems = []
self._undobuffersize = undobuffersize
self.undobuffer = Tbuffer(undobuffersize)
self._update()
RawTurtle.__init__ = __init__
def _rotate(self, angle):
"""Turns pen clockwise by angle.
"""
if self.undobuffer:
self.undobuffer.push(("rot", angle, self._degreesPerAU))
angle *= self._degreesPerAU
neworient = self._orient.rotate(angle)
tracing = self.screen._tracing
if tracing == 1 and self._speed > 0:
anglevel = 3.0 * self._speed
steps = 1 + int(abs(angle)/anglevel)
delta = 1.0*angle/steps
for _ in range(steps):
self._orient = self._orient.rotate(delta)
self._update()
self._orient = neworient
angle = self.heading()
shapename = self._imagename + "_" + str(angle)
if shapename not in self.screen.getshapes():
im = self._rawim.rotate(angle,expand=1)
sp = Shape('image',ImageTk.PhotoImage(im))
self.screen.addshape(shapename,sp)
self.shape(shapename)
self._update()
RawTurtle._rotate = _rotate
def _shape(self, name=None):
"""设定海龟的造型,用给定的文件名或造型名称"""
if name is None:
return self.turtle.shapeIndex
if not name in self.screen.getshapes():
shape = name
if os.path.isfile(shape): # 如果是文件
shapename = self._place_to_shapes(shape)
self.turtle._setshape(shapename)
else:
raise TurtleGraphicsError("There is no shape named %s" % name)
else:
self.turtle._setshape(name)
self._update()
RawTurtle.shape = _shape
if __name__ == '__main__':
from time import sleep
images = [f"cats/{i}.png" for i in range(16)]
cat = Sprite()
cat2 = Sprite()
i = 0
while True:
cat.shape(images[i])
cat2.shape(images[i])
i = i + 1
i = i % 16
sleep(0.1)
cat.left(1)
cat2.right(1)