如何在Python中慢慢画一条线 [英] How to slowly draw a line in Python

查看:122
本文介绍了如何在Python中慢慢画一条线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在python中慢慢画一条线,这样肉眼就可以看到绘制的行为。



我试图通过将其放在一个循环中来制作它并每次都增加距离,但是我从来没有成功。事情是什么都不会出现3秒钟,然后整个行将出现,这与我想要完成的相反。 pygame.display.delay()函数也没有成功。唯一可行的方法是将clock.tick设置为一些令人讨厌的值,例如 clock.tick(300000),但这只会使整个程序真正滞后。 / p>

  def draw_red_line(i):
y = 0
而y< 300:
pygame.draw.line(screen,RED,(i * 100 + 50,0),(i * 100 + 50,y))
y + = 0.01


解决方案

在这种情况下使用睡眠不是一个好主意,因为它会减慢睡眠速度。整个线程(这是单线程模型中的整个程序)。



最好保留有关该行的某种状态信息,并基于实时计时(例如:经过的毫秒数)以秒为单位逐行处理行的增长。



这意味着该行需要分成几段,而最小的行段是单个像素。使用


I want to slowly draw a line in python so the act of drawing is actually visible to the naked eye.

I tried making it by putting it in a loop and increasing the distance each time but i never had any success with it. The thing is nothing would appear for 3 sec and then the whole line would appear which is the opposite of what i want to accomplish. I didn't have success with a pygame.display.delay() function either. The only thing that kind of worked is having clock.tick set to some abysmal values such as clock.tick(300000) but this would just make the entire program really laggy.

def draw_red_line(i):
    y = 0
    while y < 300:
        pygame.draw.line(screen, RED, (i*100+50, 0), (i*100+50, y))
        y+=0.01

解决方案

Using a sleep is not a good idea in this sort of situation, since it slows the whole thread (which is the entire program in a single-thread model).

It's better to keep some kind of state information about the line, and based on real-time timings (e.g.: elapsed milliseconds) progress the "growth" of the line, second by second.

This means the line needs to be broken into segments, and the smallest line segment is a single pixel. Using the Midpoint Line Algorithm, is an efficient way to determine all the pixels that lay on a line. Once all the "line parts" have been determined, it's possible to simply update the end-point of the line based on the elapsed time.

Here's some code I wrote earlier that, given a pair of points, returns a list of pixels.

midpoint.py:

def __plotLineLow( x0,y0, x1,y1 ):
    points = []
    dx = x1 - x0
    dy = y1 - y0
    yi = 1
    if dy < 0:
        yi = -1
        dy = -dy
    D = 2*dy - dx
    y = y0

    for x in range( x0, x1 ):
        points.append( (x,y) )
        if D > 0:
           y = y + yi
           D = D - 2*dx
        D = D + 2*dy
    return points

def __plotLineHigh( x0,y0, x1,y1 ):
    points = []
    dx = x1 - x0
    dy = y1 - y0
    xi = 1
    if dx < 0:
        xi = -1
        dx = -dx
    D = 2*dx - dy
    x = x0

    for y in range( y0, y1 ):
        points.append( (x,y) )
        if D > 0:
            x = x + xi
            D = D - 2*dy
        D = D + 2*dx
    return points

def linePoints( pointA, pointB ):
    """ Generate a list of integer points on the line pointA -> pointB """
    x0, y0 = pointA
    x1, y1 = pointB
    points = []
    if ( abs(y1 - y0) < abs(x1 - x0) ):
        if ( x0 > x1 ):
            points += __plotLineLow( x1, y1, x0, y0 )
        else:
            points += __plotLineLow( x0, y0, x1, y1 )
    else:
        if ( y0 > y1 ):
            points += __plotLineHigh( x1, y1, x0, y0 )
        else:
            points += __plotLineHigh( x0, y0, x1, y1 )

    return points


if __name__ == "__main__":
    #midPoint( (597, 337), (553, 337) )
    print( str( linePoints( (135, 295), (135, 304) ) ) )

And some demonstration code which implements a SlowLine class.

import pygame
import random
import time
import sys

from midpoint import linePoints  # Midpoint line algorithm

# Window size
WINDOW_WIDTH      = 400
WINDOW_HEIGHT     = 400

SKY_BLUE = ( 30,  30,  30)
SKY_RED  = (200, 212,  14)

# Global millisecond count since start
NOW_MS = 0

class SlowLine():
    def __init__( self, pixels_per_second, x0,y0, x1,y1, colour=SKY_RED ):
        self.points       = linePoints( ( x0, y0 ), ( x1, y1 ) )
        self.pixel_count  = len( self.points )
        self.speed        = pixels_per_second
        self.start_point  = self.points[0]     # start with a single-pixel line
        self.end_point    = self.points[0]
        self.pixel_cursor = 0                  # The current end-pixel
        self.last_update  = 0                  # Last time we updated
        self.colour       = colour
        self.fully_drawn  = False

    def update(self):
        global NOW_MS

        if ( self.fully_drawn == True ):
            # nothing to do
            pass
        else:
            # How many milliseconds since the last update() call?
            if ( self.last_update == 0 ):
                self.last_update = NOW_MS
                time_delta = 0
            else:
                time_delta = NOW_MS - self.last_update
                self.last_udpate = NOW_MS

            # New pixels to add => speed * time
            new_pixel_count = time_delta * self.speed / 1000   # this may loose precision with very small speeds

            if ( new_pixel_count + self.pixel_cursor > self.pixel_count ):
                # We're out of pixels
                self.end_point  = self.points[-1]   
                self.full_drawn = True
            else:
                # Grow the line by <new_pixel_count> pixels
                self.pixel_cursor += new_pixel_count
                self.end_point     = self.points[ int( self.pixel_cursor ) ]

    def draw( self, screen ):
        pygame.draw.line( screen, self.colour, self.start_point, self.end_point )




### MAIN
pygame.init()
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
WINDOW  = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Slow Line Movement")


# Create some random lines
lines = []
for i in range( 20 ):
    rand_speed = random.randint( 1, 50 )
    rand_x0    = random.randint( 0, WINDOW_WIDTH )
    rand_y0    = random.randint( 0, WINDOW_HEIGHT )
    rand_x1    = random.randint( 0, WINDOW_WIDTH )
    rand_y1    = random.randint( 0, WINDOW_HEIGHT )
    lines.append( SlowLine( rand_speed, rand_x0, rand_y0, rand_x1, rand_y1 ) )


# Main event loop
clock = pygame.time.Clock()
done = False
while not done:
    NOW_MS = pygame.time.get_ticks()

    # Update the line lengths
    for l in lines:
        l.update()

    # Handle user-input
    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True

    # Movement keys
    keys = pygame.key.get_pressed()
    if ( keys[pygame.K_UP] ):
        print("up")
    elif ( keys[pygame.K_DOWN] ):
        print("down")
    elif ( keys[pygame.K_LEFT] ):
        print("left")
    elif ( keys[pygame.K_RIGHT] ):
        print("right")
    elif ( keys[pygame.K_q] and ( keys[pygame.K_RCTRL] or keys[pygame.K_LCTRL] ) ):
        print("^Q")
        done = True

    # Update the window, but not more than 60fps
    WINDOW.fill( SKY_BLUE )
    for l in lines:
        l.draw( WINDOW )

    pygame.display.flip()

    # Clamp FPS
    clock.tick_busy_loop(60)

pygame.quit()

In this animation the progress is a bit jerky, but that's the animation, not the demo.

这篇关于如何在Python中慢慢画一条线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆