Как остановить движение кадра при повторном вызове функции? - PullRequest
0 голосов
/ 26 апреля 2019

Для домашней работы я должен нарисовать прямоугольную рамку, а черепаха должна быть точкой и двигаться к случайному месту назначения.

Когда я нажимаю клавишу пробела (которая запускает и останавливает симуляцию), рамканачинает менять положение, подпрыгивая с точкой.Точка также не движется, а только отскакивает в центре.

'' '

import turtle
import random

#used to infect 
class Virus:
    def __init__(self, colour, duration):
        self.colour = colour
        self.duration = duration

## This class represents a person
class Person:
    def __init__(self, world_size):
        self.world_size = world_size
        self.radius = 7
        self.location = turtle.position()
        self.destination = self._get_random_location()

    #random locations are used to assign a destination for the person
    #the possible locations should not be closer than 1 radius to the edge of the world 
    def _get_random_location(self):
        x = random.randint(-349, 349)
        y = random.randint(-249, 249)
        return (x, y)


    #draw a person using a dot.  Use colour if implementing Viruses 
    def draw(self):
        turtle.penup()
        turtle.home()
        turtle.pendown()
        turtle.dot(self.radius*2)


    #returns true if within 1 radius
    def reached_destination(self):
        self.location = turtle.position()
        distX = abs(abs(self.destination[0])-abs(self.location[0]))
        distY = abs(abs(self.destination[1])- abs(self.location[1]))
        if distX and distY < self.radius:
            return True
        else:
            pass



    #Updates the person each hour.
    #- moves each person by calling the move method
    #- if the destination is reached then set a new destination
    #- progress any illness
    def update(self):
        self.move()
        if self.reached_destination():
            self._get_random_location()

        else:
            self.move()

    #moves person towards the destination
    def move(self):
        turtle.setheading(turtle.towards(self.destination))
        turtle.forward(self.radius/2)


class World:
    def __init__(self, width, height, n):
        self.size = (width, height)
        self.hours = 0
        self.people = []
        self.add_person()


    #add a person to the list
    def add_person(self):
        person = Person(1)
        self.people.append(person)

    #simulate one hour in the world.
    #- increase hours passed.
    #- update all people
    #- update all infection transmissions
    def simulate(self):
        self.hours += 1
        for item in self.people:
            item.update()

    #Draw the world.  Perform the following tasks:
    #   - clear the current screen
    #   - draw all the people
    #   - draw the box that frames the world
    #   - write the number of hours and number of people infected at the top of the frame
    def draw(self):
        turtle.clear()
        turtle.hideturtle()
        turtle.penup()
        turtle.right(180)
        turtle.forward(250)
        turtle.right(90)
        turtle.forward(350)
        turtle.left(180)
        turtle.pendown()
        turtle.forward(700)
        turtle.left(90)
        turtle.forward(500)
        turtle.left(90)
        turtle.forward(700)
        turtle.left(90)
        turtle.forward(500)
        turtle.right(180)
        turtle.forward(500)
        turtle.write(f'Hours: {self.hours}', False, 'left')
        turtle.update()
        for item in self.people:
            item.draw()



#---------------------------------------------------------
#Should not need to alter any of the code below this line
#---------------------------------------------------------
class GraphicalWorld:
    """ Handles the user interface for the simulation

    space - starts and stops the simulation
    'z' - resets the application to the initial state
    'x' - infects a random person
    'c' - cures all the people
    """
    def __init__(self):
        self.WIDTH = 800
        self.HEIGHT = 600
        self.TITLE = 'COMPSCI 130 Project One'
        self.MARGIN = 50 #gap around each side
        self.PEOPLE = 200 #number of people in the simulation
        self.framework = AnimationFramework(self.WIDTH, self.HEIGHT, self.TITLE)

        self.framework.add_key_action(self.setup, 'z') 
        self.framework.add_key_action(self.infect, 'x')
        self.framework.add_key_action(self.cure, 'c')
        self.framework.add_key_action(self.toggle_simulation, ' ') 
        self.framework.add_tick_action(self.next_turn)

        self.world = None

    def setup(self):
        """ Reset the simulation to the initial state """
        print('resetting the world')        
        self.framework.stop_simulation()
        self.world = World(self.WIDTH - self.MARGIN * 2, self.HEIGHT - self.MARGIN * 2, self.PEOPLE)
        self.world.draw()

    def infect(self):
        """ Infect a person, and update the drawing """
        print('infecting a person')
        self.world.infect_person()
        self.world.draw()

    def cure(self):
        """ Remove infections from all the people """
        print('cured all people')
        self.world.cure_all()
        self.world.draw()

    def toggle_simulation(self):
        """ Starts and stops the simulation """
        if self.framework.simulation_is_running():
            self.framework.stop_simulation()
        else:
            self.framework.start_simulation()           

    def next_turn(self):
        """ Perform the tasks needed for the next animation cycle """
        self.world.simulate()
        self.world.draw()

## This is the animation framework
## Do not edit this framework
class AnimationFramework:
    """This framework is used to provide support for animation of
       interactive applications using the turtle library.  There is
       no need to edit any of the code in this framework.
    """
    def __init__(self, width, height, title):
        self.width = width
        self.height = height
        self.title = title
        self.simulation_running = False
        self.tick = None #function to call for each animation cycle
        self.delay = 1 #smallest delay is 1 millisecond      
        turtle.title(title) #title for the window
        turtle.setup(width, height) #set window display
        turtle.hideturtle() #prevent turtle appearance
        turtle.tracer(0, 0) #prevent turtle animation
        turtle.listen() #set window focus to the turtle window
        turtle.mode('logo') #set 0 direction as straight up
        turtle.penup() #don't draw anything
        turtle.setundobuffer(None)
        self.__animation_loop()

    def start_simulation(self):
        self.simulation_running = True

    def stop_simulation(self):
        self.simulation_running = False

    def simulation_is_running(self):
        return self.simulation_running

    def add_key_action(self, func, key):
        turtle.onkeypress(func, key)

    def add_tick_action(self, func):
        self.tick = func

    def __animation_loop(self):
        try:
            if self.simulation_running:
                self.tick()
            turtle.ontimer(self.__animation_loop, self.delay)
        except turtle.Terminator:
            pass


gw = GraphicalWorld()
gw.setup()
turtle.mainloop()

' ''

Точка черепахи должна медленно подпрыгивать случайным образомрасположение и рамка должны оставаться неподвижными, когда я нажимаю пробел.И я знаю, что код долго сожалеет об этом.

1 Ответ

0 голосов
/ 26 апреля 2019

рамка начинает менять положение, подпрыгивая точкой. Точка также не двигается, а только подпрыгивает в центре.

Я переработал ваши Person и World классы ниже для решения этих двух проблем. В этой имитационной модели используется одна черепаха, что означает, что мы должны играть по определенным правилам:

  • Каждый Person должен отслеживать свою позицию и курс

  • Только метод draw() должен иметь ручку вниз, все другие методы Person должны иметь ручку вверх, если для вычисления используется черепаха

  • Всякий раз, когда Person использует черепаху, вы не можете предположить, что другая Person просто использовала черепаху, поэтому вы должны установить курс, положение и состояние пера

Измененная часть вашего опубликованного кода:

FONT = ('Arial', 16, 'normal')

# This class represents a person
class Person():
    def __init__(self, world_size):
        self.world_size = world_size
        self.radius = 7
        self.location = turtle.position()
        self.destination = self._get_random_location()

        turtle.penup()
        turtle.setposition(self.location)
        turtle.setheading(turtle.towards(self.destination))
        self.heading = turtle.heading()

    # random locations are used to assign a destination for the person
    # the possible locations should not be closer than 1 radius to the edge of the world
    def _get_random_location(self):
        x = random.randint(self.radius - 349, 349 - self.radius)
        y = random.randint(self.radius - 249, 249 - self.radius)
        return (x, y)

    # draw a person using a dot.  Use colour if implementing Viruses
    def draw(self):
        x, y = self.location

        # use .circle() not .dot() as the latter causes an extra update (flicker)
        turtle.penup()
        turtle.setposition(x, y - self.radius)
        turtle.pendown()
        turtle.begin_fill()
        turtle.circle(self.radius)
        turtle.end_fill()

    # returns true if within 1 radius
    def reached_destination(self):
        distX = abs(self.destination[0] - self.location[0])
        distY = abs(self.destination[1] - self.location[1])
        return distX < self.radius and distY < self.radius

    # Updates the person each hour.
    # - moves each person by calling the move method
    # - if the destination is reached then set a new destination
    # - progress any illness
    def update(self):
        self.move()

        if self.reached_destination():
            self.destination = self._get_random_location()
            turtle.penup()
            turtle.setposition(self.location)
            turtle.setheading(turtle.towards(self.destination))
            self.heading = turtle.heading()

    # moves person towards the destination
    def move(self):
        turtle.penup()
        turtle.setheading(self.heading)
        turtle.setposition(self.location)
        turtle.forward(self.radius / 2)
        self.location = turtle.position()

class World:
    def __init__(self, width, height, n):
        self.size = (width, height)
        self.hours = 0
        self.people = []
        for _ in range(n):
            self.add_person()

    # add a person to the list
    def add_person(self):
        person = Person(1)
        self.people.append(person)

    # simulate one hour in the world.
    # - increase hours passed.
    # - update all people
    # - update all infection transmissions
    def simulate(self):
        self.hours += 1

        for item in self.people:
            item.update()

    # Draw the world.  Perform the following tasks:
    # - clear the current screen
    # - draw all the people
    # - draw the box that frames the world
    # - write the number of hours and number of people infected at the top of the frame
    def draw(self):
        turtle.clear()  # also undoes hideturtle(), etc.
        turtle.hideturtle()
        turtle.setheading(0)

        turtle.penup()
        turtle.setposition(-350, -250)

        turtle.pendown()

        for _ in range(2):
            turtle.forward(500)
            turtle.right(90)
            turtle.forward(700)
            turtle.right(90)

        for item in self.people:
            item.draw()

        turtle.penup()
        turtle.setposition(-350, -250)

        # leave this to the end as .write() forces an extra update (flicker)
        turtle.write(f'Hours: {self.hours}', move=False, align='left', font=FONT)

        turtle.update()

Я также включил некоторые настройки, чтобы уменьшить мерцание. Я уверен, что предстоит еще много работы.

Если бы мы хотели запустить эту симуляцию быстрее, мы бы сделали каждую Person отдельной черепахой (например, с помощью наследования) и использовали бы саму измененную черепаху, поскольку она присутствует на экране, а не ничья Person. И мы бросали отдельных черепах в рамку и текст, чтобы упростить обновления.

enter image description here

...