首页 > 解决方案 > 有没有办法返回被点击的海龟对象?

问题描述

我正在制作一个配对游戏,其中有几张纸牌倒置,用户必须匹配正确的配对。倒置的牌都是海龟对象。

例如。如果有 8 张面朝下的牌,则有 8 个海龟对象。

我在弄清楚如何选择卡片时遇到了一些麻烦,因为我不知道哪个海龟与用户选择的特定卡片相关联。我确实有一个包含所有海龟的嵌套列表,并且具有相似图像的那些被组合在一起。有没有办法返回用户选择的海龟对象?

标签: pythonpython-3.xreturnturtle-graphicspython-turtle

解决方案


你可以做的是定义一个列表,turned用来存储翻过来的卡片。

下面是一个Card类的例子:

class Card(turtle.Turtle):
    def __init__(self, number):
        super(Card, self).__init__()
        self.number = number
    def click(self, x, y):
        if self in turned:
            self.clear()
            turned.remove(self)
        else:
            self.sety(self.ycor() - self.shapesize()[1] * 7)
            self.write(self.number, align='center', font=('Arial', 20, 'bold'))
            self.sety(self.ycor() + self.shapesize()[1] * 7)
            turned.append(self)

super(Card, self).__init__()会给类一个类所有的Card属性turtle.Turtle。用于self.number = number向类添加类变量Card

click函数中:

        if self in turned:
            self.clear()
            turned.remove(self)

这将允许用户通过将其从turned列表中删除并清除文本来取消选择已选择的卡,并且

        else:
            self.sety(self.ycor() - self.shapesize()[1] * 7)
            self.write(self.number, align='center', font=('Arial', 20, 'bold'))
            self.sety(self.ycor() + self.shapesize()[1] * 7)
            turned.append(self)

将写入文本并将卡片附加到turned列表中。

我还定义了一个Deck类,它将使用Card该类来创建整个卡片网格:

class Deck:
    def __init__(self, rows, cols, width, height, x, y):
        self.cards = []
        for i in range(cols):
            for j in range(rows):
                card = Card(randint(2, 10))
                card.shape("square")
                card.color('black', 'white')
                card.shapesize(height / 20, width / 20)
                card.goto(i * width + x, j * height + y)
                card.onclick(card.click)
                self.cards.append(card)

例子:

import turtle
from random import randint

wn = turtle.Screen()
wn.tracer(0)

turned = []

class Card(turtle.Turtle):
    def __init__(self, number):
        super(Card, self).__init__()
        self.number = number
    def click(self, x, y):
        if self in turned:
            self.clear()
            turned.remove(self)
        else:
            self.sety(self.ycor() - self.shapesize()[1] * 7)
            self.write(self.number, align='center', font=('Arial', 20, 'bold'))
            self.sety(self.ycor() + self.shapesize()[1] * 7)
            turned.append(self)
        print([card.number for card in turned]) # print to display the clicked cards

class Deck:
    def __init__(self, rows, cols, width, height, x, y):
        self.cards = []
        for i in range(cols):
            for j in range(rows):
                card = Card(randint(2, 10))
                card.shape("square")
                card.color('black', 'white')
                card.shapesize(height / 20, width / 20)
                card.goto(i * width + x, j * height + y)
                card.onclick(card.click)
                self.cards.append(card)

deck = Deck(8, 8, 45, 62.5, -165, -210)

wn.update()
wn.mainloop()

输出:

在此处输入图像描述


上面的代码可能看起来更简单,但它使用了一个全局变量,,turned并且数字只会显示半秒钟,而tracerleft on。并且直接点击显示的数字不会改变卡片的状态。

下面的代码纠正了这些缺陷:

您可以做的是将一个类定义为每张卡片,并将一个类定义为一副卡片。在deck类中,定义一个类变量列表,turned用来存放翻过来的卡片。

下面是一个Card类的例子:

class Card(turtle.Turtle):
    def __init__(self, number):
        super(Card, self).__init__()
        self.number = number
        self.penup()

    def write_number(self, pen):
        pen.goto(self.xcor(), self.ycor() - self.shapesize()[1] * 7)
        pen.write(self.number, align='center', font=('Arial', 20, 'bold'))

    def clicked(self, x, y):
        h, w = self.shapesize()[:-1]
        half_width = w * 10
        half_height = h * 10
        return self.xcor() + half_width > x > self.xcor() - half_width and \
               self.ycor() + half_height > y > self.ycor() - half_height

super(Card, self).__init__()会给类一个类所有的Card属性turtle.Turtle。用于self.number = number向类添加类变量Card

正如您可能猜到的那样,该write_number函数将使用单独的海龟对象在当前海龟对象上显示一个数字,以便该数字将显示在卡片的中心。

clicked函数基本上会取两个坐标,并检测坐标是否在当前海龟对象上。我定义一个clicked函数而不是使用内置turtle.onclick方法的原因是因为我希望它返回一个布尔值而不是执行一个函数。

Deck使用Card该类创建整个卡片网格的类。:

class Deck:
    def __init__(self, rows, cols, width, height, x, y):
        self.pen = turtle.Turtle(visible=False)
        self.pen.penup()
        self.pen.speed(0)
        self.cards = []
        self.numbers = []
        self.turned = []
        for i in range(cols):
            for j in range(rows):
                card = Card(randint(2, 10))
                card.shape("square")
                card.color('black', 'white')
                card.shapesize(height / 20, width / 20)
                card.goto(i * width + x, -j * height - y)
                self.cards.append(card)
                
    def click(self, x, y):
        for card in self.cards:
            if card.clicked(x, y):
                if card in self.turned:
                    card.clear()
                    self.turned.remove(card)
                else:
                    self.turned.append(card)
        self.draw()
        print([card.number for card in self.turned])
        
    def draw(self):
        for card in self.turned:
            card.write_number(self.pen)

self.cards列表存储所有Card对象,存储self.turned翻转的卡片。

click函数将使用该类中的clicked函数Card来检测对类变量Card内所有对象的点击。Deckcards

最后,该draw函数将显示turned列表中所有卡片的编号,self.pen使用Deck.

完整的工作代码:

import turtle
from random import randint

wn = turtle.Screen()

class Card(turtle.Turtle):
    def __init__(self, number):
        super(Card, self).__init__()
        self.number = number
        self.penup()

    def write_number(self, pen):
        pen.goto(self.xcor(), self.ycor() - self.shapesize()[1] * 7)
        pen.write(self.number, align='center', font=('Arial', 20, 'bold'))

    def clicked(self, x, y):
        h, w = self.shapesize()[:-1]
        half_width = w * 10
        half_height = h * 10
        return self.xcor() + half_width > x > self.xcor() - half_width and \
               self.ycor() + half_height > y > self.ycor() - half_height
    
class Deck:
    def __init__(self, rows, cols, width, height, x, y):
        self.pen = turtle.Turtle(visible=False)
        self.pen.penup()
        self.pen.speed(0)
        self.cards = []
        self.numbers = []
        self.turned = []
        for i in range(cols):
            for j in range(rows):
                card = Card(randint(2, 10))
                card.shape("square")
                card.color('black', 'white')
                card.shapesize(height / 20, width / 20)
                card.goto(i * width + x, -j * height - y)
                self.cards.append(card)
                
    def click(self, x, y):
        for card in self.cards:
            if card.clicked(x, y):
                if card in self.turned:
                    card.clear()
                    self.turned.remove(card)
                else:
                    self.turned.append(card)
        self.draw()
        print([card.number for card in self.turned])
        
    def draw(self):
        for card in self.turned:
            card.write_number(self.pen)

deck = Deck(8, 8, 45, 62.5, -165, -210)

wn.onscreenclick(deck.click)
wn.mainloop()

推荐阅读