使用跟踪器(0)和更新后理解Python海龟刷新的问题

问题描述 投票:0回答:1

最近,我一直在尝试用Python创建一个假的3D引擎。我说假是因为它并不是真正创建“Z”轴,而是刷新并重新创建用户应该在每一帧中看到的内容。为此,我使用了一种相对基本的光线投射技术(我从播放器发送多条光线,每次发送新光线时,我都会稍微倾斜它们的方向。每次光线接触墙壁时,都会计算它行进的距离及其光线数字(例如,如果第 45 条光线与墙壁碰撞,则其数字将为 45)被添加到列表中。所有这些对用户来说都是不可见的。但是,使用此信息,可以绘制多条垂直线不同的尺寸取决于墙的距离,或者光线传播的距离,以重现透视。问题是,为了完成所有这些,我每次都使用turtle.tracer(0)和turtle.update()当用户按下一个键来移动时,这样我就可以在每次角色应该移动时刷新屏幕。问题是,由于某种原因,每次玩家移动时,屏幕不仅需要一点时间来刷新但在显示新图像之前也会变成黑色(背景颜色),就好像我在turtle.tracer(0)之外使用turtle.clear(),但我没有这样做。 这是我的代码。我并不是真的希望有人会读它,因为它有 250 行代码,但我确实指定了它。

import turtle
import random
import tkinter
xScreenSize = 1225
yScreenSize = 720
turtle.screensize(xScreenSize, yScreenSize)

def _3DTracer(height, RapportDistance, list,AngleTot2D, NbRay):
    """
    Entrees : height -> float , RapoortDistance -> float, list -> list, AngleTot2D -> int, NbRay -> int
    The list contains 4 elements : the current angle, the number of the ray, legth of the ray divided by the max one,
    the difference of brightness this ray has
    """
    #turtle.tracer(0)
    turtle.clear()
    turtle.pu()
    turtle.bgcolor(0,0,0)
    lenList = len(list)
    turtle.pensize(xScreenSize//AngleTot2D)
    WallYCenter = 0
    for f in range(lenList):
        colDif = 250 - list[f][3]
        if colDif > 255:
            colDif = 255
        print(colDif)
        turtle.color(0,0,colDif)
        currentX = list[f][1]/NbRay*xScreenSize - xScreenSize/2
        turtle.pu()
        turtle.goto(currentX, WallYCenter)
        turtle.left(-turtle.heading() - 90) # -> Sets dir to up
        WallHeight = yScreenSize - yScreenSize*list[f][2]
        turtle.forward(WallHeight/2)
        turtle.left(180)
        turtle.pd()
        turtle.forward(WallHeight)
    turtle.pensize(1)
    #turtle.update()
    return 'ok'

def Update3DScreen(NbAngle, NbTot):
    """
    Call: Update3DScreen(NbAngle,NbTot, OriginalAngle)
    Entrees : NbTot -> int
            OriginalAngle, NbAngle -> float
    Return: /
    Everytime this fonction is called, rays a created from the player's position and these rays keep moving strait
    until they collide a wall (using the CheckInsideColliders() fonction)or reach their max range. Then, the direction turns by
    NbAngle et it keeps going "NbTot" times. Everytime a wall is hit by a ray, it is added to the list
    """
    print('NbTot',NbTot)
    AngleEntreChaqueRayon = NbAngle/NbTot
    listOfCollisionsFoundInRay = []
    turtle.pd()
    turtle.tracer(0)
    turtle.goto(currentPos)
    turtle.left(-turtle.heading() + currentPlayerAngle)
    for i in range (NbTot):
        ColorDifference = 0
        hi = 'hi'
        shouldWrite = True
        FreeToMove = True
        count = 0
        tailleMaxLigne = 450
        while FreeToMove:
            turtle.forward(5)
            NotTouchedWall = CheckInsideColliders(FreeToMove, turtle.pos())
            if not NotTouchedWall:
                turtle.left(180)
                newCount =0
                while not NotTouchedWall:
                    turtle.forward(1)
                    NotTouchedWall = CheckInsideColliders(FreeToMove, turtle.pos())
                    newCount += 1
                turtle.left(180)
                listOfCollisionsFoundInRay.append([i * AngleEntreChaqueRayon, i,(count+5-newCount)/tailleMaxLigne, ColorDifference])
                FreeToMove = False
            else:
                newCount = 0
            if count >= tailleMaxLigne:
                FreeToMove = False
                shouldWrite = False
            count += 5 - newCount
            ColorDifference = count*255//tailleMaxLigne - 20

        turtle.goto(currentPos)
        turtle.left(AngleEntreChaqueRayon)
    if len(listOfCollisionsFoundInRay) != 0:
        _3DTracer(0.5, count/tailleMaxLigne, listOfCollisionsFoundInRay, NbAngle, NbTot)
    print(listOfCollisionsFoundInRay)
    turtle.update()
    turtle.left(-turtle.heading())

def CheckInsideColliders(Ok, Pos):
    """
    Call : CheckInsideColliders(bool, Tuple)
    Entrees : Ok -> bool
    Returns : Ok -> bool
    Verifies if the point Pos is situed in a collision zone, inside a wall. If it is, ok takes False,
    otherwise it takes True
    """
    LenColl = len(colliders)
    for hi in range(LenColl):
        if hi != 0 and hi%2 == 1:
            if PreviousPoints[0] > colliders[hi][0]: #le x du nv point est plus petit que celui d avant
                if PreviousPoints[1] > colliders[hi][1]:
                    if Pos[0] > PreviousPoints[0] or Pos[0] < colliders[hi][0] \
                            or Pos[1] > PreviousPoints[1] or Pos[1] < colliders[hi][1]:
                        Ok = True
                    else:
                        return False
                else:
                    # x current > previous but y current < previous
                    if Pos[0] > PreviousPoints[0] or Pos[0] < colliders[hi][0] or Pos[1] < \
                            PreviousPoints[1] or Pos[1] > colliders[hi][1]:
                        Ok = True
                    else:
                        return False
            else: # previous point x < current collider
                if PreviousPoints[1] > colliders[hi][1]:
                    if Pos[0] < PreviousPoints[0] or Pos[0] > colliders[hi][0] \
                        or Pos[1] > PreviousPoints[1] or Pos[1] < colliders[hi][1]:
                        Ok = True
                    else:
                        return False
                else : #previous point x < current collider and previous point y < current collider
                    if Pos[0] < PreviousPoints[0] or Pos[0] > colliders[hi][0] \
                        or Pos[1] < PreviousPoints[1] or Pos[1] > colliders[hi][1]:
                        Ok = True
                    else :
                        return False
        PreviousPoints = colliders[hi]
    return Ok
def up():
  """
  Is called every time the right arrow is pressed. It changes the player's position and then calls Update3DScreen
  to update the 3D perspective
  """
  turtle.tracer(0)
  turtle.goto(currentPos)
  turtle.left(-turtle.heading() + currentPlayerAngle)
  turtle.forward(7)
  globals()['currentPos'] = turtle.pos()
  turtle.clear()
  Update3DScreen(40,80)
  turtle.update()

def down():
  """
  Is called every time the right arrow is pressed. It changes the player's position and then calls Update3DScreen
  to update the 3D perspective
  """
  turtle.tracer(0)
  turtle.goto(currentPos)
  turtle.left(-turtle.heading() + currentPlayerAngle)
  turtle.forward(-7)
  globals()['currentPos'] = turtle.pos()
  turtle.clear()
  Update3DScreen(40,80)
  turtle.update()

def left():
  """
  Is called every time the right arrow is pressed. It changes the camera's direction and then calls Update3DScreen
  to update the 3D perspective
  """
  turtle.tracer(0)
  turtle.goto(currentPos)
  globals()['currentPlayerAngle'] -= 5
  turtle.clear()
  Update3DScreen(40,80)
  turtle.update()

def right():
    """
    Is called every time the right arrow is pressed. It changes the camera's direction and then calls Update3DScreen
    to update the 3D perspective
    """
    #globals()['currentPos'] = (currentPos[0] + 4, currentPos[1]) #globals()[variable] permet de changer une variable
    # globale dans une fonction
    turtle.tracer(0)
    turtle.goto(currentPos)
    globals()['currentPlayerAngle'] += 5
    turtle.clear()
    Update3DScreen(40, 80)
    #turtle.update()

def playerPos():
  """
  When the map is created, it creates a random position for the player to go to that is outside wall collisions. After that,
  it checks for key arrow presses and keeps track of the player's position
  """
  global currentPos
  basePosOk = False
  while not basePosOk:
      currentPos = [random.randint(- xScreenSize//2, xScreenSize//2),
                    random.randint(-yScreenSize//2, yScreenSize//2)]
      basePosOk = CheckInsideColliders(basePosOk, currentPos)
  print("currentPos : ", currentPos)
  turtle.pu()
  turtle.goto(currentPos)
  turtle.pd()
  global currentPlayerAngle
  currentPlayerAngle = 0
  turtle.dot(8)
  global currentPlayerOrientation
  currentPlayerOrientation = 0
  turtle.listen()
  turtle.pu()
  turtle.onkey(up, 'Up')
  turtle.onkey(down, 'Down')
  turtle.onkey(left, 'Left')
  turtle.onkey(right, 'Right')

def echap():
  """
  Fonctionnement : permet de continuer le programme donné dans cette fonction après avoir appuyé sur la touche "Echap"
  Allows the program to keep going when the used finished creating the 2D map by pressing the "escape" arrow. It then makes
  appear the 2D map that was just created and calls the playerPos() fonction.
  """
  print("\n")
  turtle.clear()
  lenColl = len(colliders)
  turtle.tracer(0)
  for i in range(lenColl):
    if i != 0 and i % 2 == 1:
      turtle.pu()
      turtle.goto(previousX, previousY)
      turtle.pd()
      turtle.goto(colliders[i][0], previousY)
      turtle.goto(colliders[i][0], colliders[i][1])
      turtle.goto(previousX, colliders[i][1])
      turtle.goto(previousX, previousY)
      turtle.pu()
    previousX = colliders[i][0]
    previousY = colliders[i][1]
    print(previousX, previousY)
  turtle.update()
  playerPos()

def get_mouse_click_coor(x, y):
  """
    :param x: float
    :param y: float
    Allows the user to create his own map by pressing anywhere on the screen. To keep track of where he pressed, turtle
    places dots on those locations
  """
  colliders.append([x, y])
  turtle.tracer(0)
  turtle.pu()
  turtle.goto(x,y)
  turtle.pd()
  turtle.dot(5)
  turtle.pu()
  turtle.update()
  print(x, y)

help(turtle.pos)
help(turtle.pensize)
turtle.colormode(255)
turtle.listen()  # fait en sorte que turtle vérifie tt le tps que certaines touches aient étées pressées
count = 0
colliders = []
turtle.onscreenclick(get_mouse_click_coor)
turtle.onkey(echap, "Escape")  # si l'utilisateur presse la touche "Echap", la fonction echap se lance
turtle.mainloop()
print(colliders)

为了找出问题所在,我删除了代码中的每个跟踪器(0)和更新(),但不知何故,海龟没有为任何东西设置动画。它只是表现得好像turtle.tracer(0) 和turtle.update() 函数仍然存在。

python optimization refresh python-turtle
1个回答
0
投票

我已经检查了您的代码,并尝试在其他调整中解决您的

tracer()
问题。看看它现在的表现是否更接近您的期望:

from turtle import Screen, Turtle
from random import randint

xScreenSize = 1225
yScreenSize = 720

def _3DTracer(height, RapportDistance, ray_list, AngleTot2D, NbRay):
    """
    Entrees : height -> float, RapoortDistance -> float, ray_list -> list, AngleTot2D -> int, NbRay -> int
    The ray_list contains 4 elements : the current angle, the number of the ray, length of the ray divided by the max one,
    the difference of brightness this ray has
    """

    # screen.bgcolor('black')

    turtle.clear()
    turtle.penup()

    lenList = len(ray_list)
    turtle.pensize(xScreenSize // AngleTot2D)
    WallYCenter = 0

    for f in range(lenList):
        colDif = 250 - ray_list[f][3]
        if colDif > 255:
            colDif = 255

        turtle.color(0, 0, colDif)
        currentX = ray_list[f][1] / NbRay * xScreenSize - xScreenSize/2
        turtle.penup()
        turtle.goto(currentX, WallYCenter)
        turtle.left(-turtle.heading() - 90)  # -> Sets direction to up
        WallHeight = yScreenSize - yScreenSize * ray_list[f][2]
        turtle.forward(WallHeight/2)
        turtle.left(180)
        turtle.pendown()
        turtle.forward(WallHeight)

    turtle.pensize(1)
    screen.update()

def Update3DScreen(NbAngle, NbTot):
    """
    Call: Update3DScreen(NbAngle, NbTot)
    Entrees:
        NbAngle -> float
        NbTot -> int
    Return: /
    Every time this function is called, rays are created from the player's position and these rays keep moving straight
    until they collide with a wall (using the CheckInsideColliders() function) or reach their maximum range. Then, the
    direction turns by NbAngle and it keeps going "NbTot" times. Every time a wall is hit by a ray, it is added to a list
    """

    AngleEntreChaqueRayon = NbAngle / NbTot
    listOfCollisionsFoundInRay = []

    turtle.pendown()
    turtle.goto(currentPos)
    turtle.left(currentPlayerAngle - turtle.heading())

    for i in range(NbTot):
        ColorDifference = 0
        # shouldWrite = True
        FreeToMove = True
        my_count = 0
        tailleMaxLigne = 450

        while FreeToMove:
            turtle.forward(5)
            NotTouchedWall = CheckInsideColliders(FreeToMove, turtle.position())
            if not NotTouchedWall:
                turtle.left(180)
                newCount = 0

                while not NotTouchedWall:
                    turtle.forward(1)
                    NotTouchedWall = CheckInsideColliders(FreeToMove, turtle.position())
                    newCount += 1

                turtle.left(180)
                listOfCollisionsFoundInRay.append((i * AngleEntreChaqueRayon, i, (my_count+5 - newCount) / tailleMaxLigne, ColorDifference))
                FreeToMove = False
            else:
                newCount = 0
            if my_count >= tailleMaxLigne:
                FreeToMove = False
                # shouldWrite = False
            my_count += 5 - newCount
            ColorDifference = my_count*255 // tailleMaxLigne-20

        turtle.goto(currentPos)
        turtle.left(AngleEntreChaqueRayon)

    if len(listOfCollisionsFoundInRay) != 0:
        _3DTracer(0.5, count/tailleMaxLigne, listOfCollisionsFoundInRay, NbAngle, NbTot)

    screen.update()
    turtle.left(-turtle.heading())

def CheckInsideColliders(Ok, Pos):
    """
    Call : CheckInsideColliders(bool, Tuple)
    Entrees : Ok -> bool
    Returns : Ok -> bool
    Verifies if the point Pos is situated in a collision zone, inside a wall. If it is, Ok goes False,
    otherwise it goes True
    """

    for i, collider in enumerate(colliders):
        if i != 0 and i%2 == 1:
            if PreviousPoints[0] > collider[0]:  # le x du nv point est plus petit que celui d avant
                if PreviousPoints[1] > collider[1]:
                    if Pos[0] > PreviousPoints[0] or Pos[0] < collider[0] or Pos[1] > PreviousPoints[1] or Pos[1] < collider[1]:
                        Ok = True
                    else:
                        return False
                else:
                    # x current > previous but y current < previous
                    if Pos[0] > PreviousPoints[0] or Pos[0] < collider[0] or Pos[1] < PreviousPoints[1] or Pos[1] > collider[1]:
                        Ok = True
                    else:
                        return False
            else:  # previous point x < current collider
                if PreviousPoints[1] > collider[1]:
                    if Pos[0] < PreviousPoints[0] or Pos[0] > collider[0] or Pos[1] > PreviousPoints[1] or Pos[1] < collider[1]:
                        Ok = True
                    else:
                        return False
                else:  # previous point x < current collider and previous point y < current collider
                    if Pos[0] < PreviousPoints[0] or Pos[0] > collider[0] or Pos[1] < PreviousPoints[1] or Pos[1] > collider[1]:
                        Ok = True
                    else:
                        return False

        PreviousPoints = collider

    return Ok

def up():
    """
    Is called every time the right arrow is pressed. It changes the player's
    position and then calls Update3DScreen to update the 3D perspective
    """

    global currentPos

    turtle.goto(currentPos)
    turtle.left(currentPlayerAngle - turtle.heading())
    turtle.forward(7)
    currentPos = turtle.position()
    turtle.clear()
    Update3DScreen(40, 80)
    screen.update()

def down():
    """
    Is called every time the right arrow is pressed. It changes the player's
    position and then calls Update3DScreen to update the 3D perspective
    """
    global currentPos

    turtle.goto(currentPos)
    turtle.left(currentPlayerAngle - turtle.heading())
    turtle.forward(-7)
    currentPos = turtle.position()

    turtle.clear()
    Update3DScreen(40, 80)
    screen.update()

def left():
    """
    Is called every time the right arrow is pressed. It changes the camera's
    direction and then calls Update3DScreen to update the 3D perspective
    """
    global currentPlayerAngle

    turtle.goto(currentPos)
    currentPlayerAngle -= 5
    turtle.clear()
    Update3DScreen(40, 80)
    screen.update()

def right():
    """
    Is called every time the right arrow is pressed. It changes the camera's
    direction and then calls Update3DScreen to update the 3D perspective
    """

    global currentPlayerAngle

    turtle.goto(currentPos)
    currentPlayerAngle += 5
    turtle.clear()
    Update3DScreen(40, 80)
    screen.update()

def playerPos():
    """
    When the map is created, it creates a random position for the player to
    go to that is outside wall collisions. After that,
    """

    global currentPos, currentPlayerAngle, currentPlayerOrientation

    basePosOk = False

    while not basePosOk:
        currentPos = randint(-xScreenSize//2, xScreenSize//2), randint(-yScreenSize//2, yScreenSize//2)
        basePosOk = CheckInsideColliders(basePosOk, currentPos)

    turtle.penup()
    turtle.goto(currentPos)
    turtle.pendown()

    currentPlayerAngle = 0
    turtle.dot(8)
    currentPlayerOrientation = 0
    turtle.penup()

    screen.update()

def echap():
    """
    Fonctionnement : permet de continuer le programme donné dans cette fonction après avoir appuyé sur la touche "Echap"
    Allows the program to keep going when the user finished creating the 2D map by pressing the "escape" arrow. It then
    makes the 2D map appear that was just created and calls the playerPos() function.
    """
    turtle.clear()

    for i, collider in enumerate(colliders):
        if i != 0 and i % 2 == 1:
            turtle.penup()
            turtle.goto(previousX, previousY)
            turtle.pendown()

            turtle.goto(collider[0], previousY)
            turtle.goto(collider)
            turtle.goto(previousX, collider[1])
            turtle.goto(previousX, previousY)
            turtle.penup()

        previousX, previousY = collider

    screen.update()
    playerPos()

def get_mouse_click_coor(x, y):
    """
    :param x: float
    :param y: float

    Allows the user to create his own map by pressing anywhere on the screen. To keep
    track of where he pressed, turtle places dots on those locations
    """

    colliders.append((x, y))

    turtle.penup()
    turtle.goto(x, y)
    turtle.dot(5)
    screen.update()

screen = Screen()
screen.setup(xScreenSize, yScreenSize)
screen.tracer(False)
screen.colormode(255)

turtle = Turtle()

count = 0
colliders = []

currentPos = None
currentPlayerAngle = None
currentPlayerOrientation = None

screen.onkey(up, 'Up')
screen.onkey(down, 'Down')
screen.onkey(left, 'Left')
screen.onkey(right, 'Right')
screen.onkey(echap, "Escape")  # si l'utilisateur presse la touche "Echap", la fonction echap se lance
screen.listen()  # fait en sorte que turtle vérifie tt le tps que certaines touches aient étées pressées

screen.onclick(get_mouse_click_coor)

screen.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.