【问题标题】:Python Turtle color change蟒龟变色
【发布时间】:2016-10-20 17:27:37
【问题描述】:

我目前正在玩蟒蛇龟模块,我试图制作一个不透明的方形网格,比如 30x30,它可以根据某些属性改变颜色(不管是什么属性)我的问题是,是否有任何改变形状在画布上绘制后的颜色?

我尝试将所有正方形添加到一个数组中,包括图章和多边形,但是一旦它们被绘制出来,似乎就不可能改变它们的颜色。

我知道邮票不起作用,因为它就像海龟所在位置的足迹,但是有没有任何方法可以使用多边形或其他我不知道的方法来实现这一点?

我没有添加任何 sn-ps 代码,因为它是一个非常基本的问题,可以用于很多事情。

【问题讨论】:

  • 不,一旦被海龟绘制,就无法改变形状的颜色。你必须重新绘制它。您可以使用支持这种东西的不同 GUI 框架,例如 Tkinter

标签: python turtle-graphics


【解决方案1】:

是的,你可以做到。解决这个问题以及许多复杂的海龟问题的关键是使用印章。它们是单独或集体可移动的。由于它们采用海龟本身的形状,因此它们可以是图像或任意大小或颜色的任意多边形:

from turtle import Turtle, Screen
from random import randrange, choice
from collections import namedtuple
from math import ceil

GRID = 15  # GRID by GRID of squares
SIZE = 30  # each square is SIZE by SIZE

INCREASE = 1.5  # how much to lighten the square's color
WHITE = [255, 255, 255]  # color at which we stop changing square
DELAY = 100  # time between calls to change() in milliseconds
DARK = 32 # range (ceil(INCREASE) .. DARK - 1) of dark colors

def change():
    block = choice(blocks)
    blocks.remove(block)

    color = [min(int(primary * INCREASE), WHITE[i]) for i, primary in enumerate(block.color)]  # lighten color

    turtle.color(color)
    turtle.setposition(block.position)
    turtle.clearstamp(block.stamp)

    stamp = turtle.stamp()

    if color != WHITE:
        blocks.append(Block(block.position, color, stamp))  # not white yet so keep changing this block

    if blocks:  # stop all changes if/when all blocks turn white
        screen.ontimer(change, DELAY)

HALF_SIZE = SIZE // 2

screen = Screen()
screen.colormode(WHITE[0])
screen.register_shape("block", ((HALF_SIZE, -HALF_SIZE), (HALF_SIZE, HALF_SIZE), (-HALF_SIZE, HALF_SIZE), (-HALF_SIZE, -HALF_SIZE)))
screen.tracer(GRID ** 2)  # ala @PyNuts

turtle = Turtle(shape="block", visible=False)
turtle.speed("fastest")
turtle.up()

Block = namedtuple('Block', ['position', 'color', 'stamp'])

blocks = list()

HALF_GRID = GRID // 2

for x in range(-HALF_GRID, HALF_GRID):
    for y in range(-HALF_GRID, HALF_GRID):
        turtle.goto(x * SIZE, y * SIZE)
        color = [randrange(ceil(INCREASE), DARK) for primary in WHITE]
        turtle.color(color)
        blocks.append(Block(turtle.position(), color, turtle.stamp()))

screen.ontimer(change, DELAY)

screen.exitonclick()

【讨论】:

  • 谢谢,明天我会查看该代码 :) 我正在尝试通过将它们添加到数组中然后使用 clearstamp() 删除它们来尝试标记,但似乎可以让它做我想做的事跨度>
  • 'couldnt' 我的意思是说,我运行了你的代码,它工作得很好,所以我想用它来满足我的需要,再次感谢
  • 顺便说一句,如果您删除 turtle.speed(''fastest'') 并使用,turtle.tracer(1000) 它会停止删除和重新标记之间的闪烁,并且在更改颜色时更快
  • @PyNuts,谢谢。我已经将tracer()update() 一起使用,但不是在这种模式下。它很好地使视觉效果更流畅,并稍微减少癫痫发作......
  • @Alan,也许吧。 stamp() 返回的 id 是一个 tkinter 画布对象 id,因此可以在 tkinter 级别编写一个例程,返回给定 x、y 坐标处所有海龟标记 id 的列表。将此作为一个 SO 问题连同上下文一起提出来,让我们看看...
【解决方案2】:

Turtle 的想法是,图像一旦绘制,就会变成像素,提交到画布上——即使 Turtle 命令本身是“矢量”命令,当人们谈论“矢量”与“光栅”图形时。

这意味着 Turtle 绘图上下文无法知道“自己”已绘制的内容 - 您无法引用已绘制的形状或多边形并更改其属性。 (更新:但对于邮票 - Turtle 对象确实记录了有关这些的信息 - 感谢@cdlane)

在这种情况下,您必须做的是在您的代码数据上注释您想要进一步修改的任何形状 - 当您需要时,它们会以某种方式重绘它们它。换句话说:您为矢量图形模型开发代码 - 这允许您这样做。

但是,您应该注意,Turtle 在其上运行的 tkinter Canvas widget(至少,我相信)本身就是一个矢量模型 - 所以它可能更适合您的想法。不过,它的文档和工作方式可能很难掌握。

所以,回到“拥有自己的矢量图形实现”,您可以利用 Python 面向对象和数据模型来构建“history-turtle”——它可以在同一位置记录日志并重播命令块上下文(但允许不同的颜色、宽度等...设置)。

做起来比说的有点小技巧,但是,这里有一个示例:

from turtle import Turtle

"""
Python Turtle with logging and replay capabilities

Author: João S. O. Bueno <gwidion@gmail.com>
License: LGPL 3.0+

This implements HistoryTurtle - a subclass of
Python's turtle.Turtle wich features a simple
command history and   new `replay` and `log`
methods -
`turtle.replay(<start>, <end>)` will reissue
the commands logged in those positions of the history,
but with the current Pen settings.

The optional kwarg `position_independent` can be passed
as `True` to `replay` so that the turtle's position
and heading are not restored to the ones recorded
along with the command.

https://gist.github.com/jsbueno/cb413e985747392c460f39cc138436bc

"""


class Command:
    __slots__ = ( "method_name", "args", "kwargs", "pos", "heading")

    def __init__(self, method_name, args=(),
                 kwargs=None, pos=None, heading=None):
        self.method_name = method_name
        self.args = args
        self.kwargs = kwargs or {}
        self.pos = pos
        self.heading = heading

    def __repr__(self):
        return "<{0}> - {1}".format(self.pos, self.method_name)


class Instrumented:
    def __init__(self, turtle, method):
        self.turtle = turtle
        self.method = method

    def __call__(self, *args, **kwargs):
        command = Command(self.method.__name__, args, kwargs,
                          self.pos(), self.heading())
        result = self.method(*args, **kwargs)
        if (self.method.__name__ not in self.turtle.methods_to_skip or
                not kwargs.pop('skip_self', True)):
            self.turtle.history.append(command)
        return result

    def pos(self):
        return self.turtle._execute(Command('pos'), True)

    def heading(self):
        return self.turtle._execute(Command('heading'), True)


class HistoryTurtle(Turtle):

    methods_to_skip = ('replay', '_execute', 'log')

    def __init__(self, *args, **kw):
        self._inited = False
        super().__init__(*args, **kw)
        self.history = []
        self._replaying = [False]
        self._inited = True

    def __getattribute__(self, attr):
        result = super().__getattribute__(attr)
        if (not callable(result) or
                attr.startswith('_') or
                not self._inited or
                self._replaying[-1]):
            return result
        return Instrumented(self, result)

    def replay(self, start, end=None, *,
               position_independent=False,
               skip_self=True,
               restore=True
               ):
        results = []

        self._replaying.append(True)
        if restore:
            pos, heading, state = self.pos(), self.heading(), self.pen()['pendown']
        for command in self.history[start:end]:
            results.append(
                self._execute(command, position_independent))
        if restore:
            self.setpos(pos)
            self.setheading(heading)
            (self.pendown() if state else self.penup())
        self._replaying.pop()
        return results

    def log(self, start=0, end=None):
        for i, command in enumerate(self.history[start:end], start):
            print(i, command)

    def _execute(self, command, position_independent):
        """ Execute a method without triggering the log
        """
        # Warning: not thread-safe:
        self._replaying.append(True)
        method = getattr(self, command.method_name)
        if not position_independent:
            state = self.pen()['pendown']
            self.setpos(command.pos)
            self.setheading(command.heading)
            (self.pendown() if state else self.penup())
        result = method(*command.args, **command.kwargs)
        self._replaying.pop()
        return result

【讨论】:

  • 感谢您的努力,但出于某种原因,无论我多么努力理解,“课程”对我来说似乎都是胡言乱语,哈哈,似乎无法理解它们,即使我做了很短的时间时间我很快忘记了如何在不使用 python 的一周或两周内实现它们
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-08
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-24
  • 1970-01-01
相关资源
最近更新 更多