Объекты вне видимой области в Pyglet - PullRequest
0 голосов
/ 24 января 2020

Я прикрепил изображение, вы можете видеть, что верхние прямоугольники не видны, и есть несколько других прямоугольников, нарисованных за пределами самых верхних прямоугольников. Размеры прямоугольников уже масштабированы Мне нужно нарисовать несколько прямоугольников, и я использую Pyglet. За границами окна нарисовано несколько прямоугольников. Как я могу сделать эти прямоугольники видимыми или как прокрутить область рендеринга?

Вот пример кода.

textureSize = [(100,500), (200, 1200), (300, 2000), (400, 2500)] window1 = pyglet.window.Window(1800, 1000) for (width, height) in textureSize: prewidth = width + 5<br> pyglet.graphics.draw_indexed( 4, pyglet.gl.GL_TRIANGLES, [0, 1, 2, 0, 2, 3], ('v2f', (prewidth, 0, width, 0, width, height,prewidth,height)), ('c3B', (255,255,255, 255,255,255, 255,255,255, 255,255,255)) )

1 Ответ

0 голосов
/ 27 января 2020

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

Если вы хотите, чтобы ваши объекты были на экране, по крайней мере, некоторые их вершины должны находиться в пределах диапазона окна. Здесь есть три подхода:

  1. Изменение размера окна
  2. Масштабирование вершин
  3. Реализация прокрутки

" Прокрутка область рендеринга"не совсем так, как все работает на базовом уровне. Ваши вершины не относятся к реальному пространству: их координаты относительно окна . Концепция пространства визуализации - это абстракция, позволяющая сделать вещи более интуитивно понятными. Ваше окно не является порталом в какое-то альтернативное измерение, это фундаментальное пространство, где существуют объекты на самом низком уровне. Если координаты объекта находятся вне координат окна, объект не рисуется.

Если вы хотите, чтобы ваши вершины были видны, они должны находиться внутри окна. Первый вариант - увеличить окно.

Размер окна

Если вы хотите отобразить большую область, чем значение по умолчанию для pyglet (то есть 640 на 480), вы можете установить размер окна в один из следующих способов:

  1. Инициализировать окно с правильными размерами:

window = pyglet.window.Window(1280, 720).

Установите правильные размеры в другом месте программы:

window.set_size(1280, 720) или window.width = 1280 и window.height = 720.

Позволяет пользователю изменять размер окна при инициализации:

window = pyglet.window.Window(resizable = True).

И для максимального пространства рендеринга установите полноэкранное окно:

window = pyglet.window.Window(fullscreen = True), которое также можно переключать:

window.set_fullscreen(True) и window.set_fullscreen(False).

См. Также Руководство и Документация обо всем, что вы можете сделать с окном.

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

Масштабирование

Возможно, вы довольны размером окна, но все еще не можете видеть все объекты в вашем мире. Если ваш мир больше, чем ваш идеальный размер окна, может быть целесообразно применить некоторое масштабирование и сопоставить ваши координаты мира с координатами окна.

Для масштабирования относительно координат начала координат (0., 0.) в двух измерениях, процедура относительно проста: умножить все координаты на размер окна и разделить на размер мира. Возможно, вы захотите рассчитать соотношение window_size / world_size раньше времени, а не каждый раз, когда вы хотите визуализировать.

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

    #Say our world is defined by the range of textureSize rectangles
    widths, heights = zip(*textureSize)
    world_width  = max(widths)  - min(widths) + 5
    world_height = max(heights) - 0
    #if your world has different dimensions, use those

    #then this is our scale factor
    scale_factor = min(window.width/world_width, window.height/world_height, 1.)

    #keeping it up to date with our window
    @window.event
    def on_resize(width, height)
        scale_factor = min(width/world_width, height/world_height, 1.)

    #your code, now using scaled coordinates (and a few code readability changes)
    for (width, height) in textureSize:
        #working in world coordinates
        prewidth = width + 5          

        #scale coordinates from world to window
        width    *= scale_factor
        height   *= scale_factor
        prewidth *= scale_factor

        #draw in window coordinates
        pyglet.graphics.draw_indexed(
            4,
            pyglet.gl.GL_TRIANGLES,
            [0, 1, 2, 0, 2, 3],
            ('v2f', (prewidth, 0, width, 0,    width, height, prewidth, height)),
            ('c3B', (255,255,255, 255,255,255, 255,255,255,   255,255,255     ))
        )

Этот шаблон работает, когда источник вашей мировой системы координат равен (0., 0.). Я настоятельно рекомендую работать в такой системе координат, если вы собираетесь использовать отдельную систему координат. Убедитесь, что scale_factor доступен во всех позициях в коде, которые должны что-то нарисовать, или создайте объект pyglet (например, pyglet.graphics.vertex_list_indexed() или pyglet.graphics.Batch().add_indexed()), который будет нарисован позже. Если вы хотите что-то нарисовать или создать объект-пиглет, который что-то нарисовал aws, вам нужно будет указать масштабированные координаты, поэтому вам потребуется доступ к этому коэффициенту масштабирования.

Но, может быть, то, что вы на самом деле хочу не получить ваши объекты на стати c холсте. Возможно, вы действительно хотите реализовать прокрутку в качестве пользовательской функции.

Прокрутка

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

Вершины относительно окна. Если окно прокручивается вправо, то мы хотим, чтобы наши объекты двигались в кадре справа, двигаясь влево относительно рамки. Чтобы сделать это, мы хотим переместить их вершины влево пропорционально тому, сколько мы прокрутили вправо.

Чтобы начать с этой концепции, давайте сначала подумаем, что произойдет, если мы «прыгнем» вправо , На какое бы расстояние мы ни сместились вправо, на это расстояние мы должны переместить все вершины влево. Итак, давайте создадим функцию перехода (обычно называемую переводом):

    import pyglet

    #use this on all x, y pairs of vertices whenever we:
    #jump the window a distance jump_x to the right
    #and a distance jump_y up
    def translate(x, y, jump_x, jump_y):
        new_x = x - jump_x
        new_y = y - jump_y
        return new_x, new_y

    # E X A M P L E
    #---------------
    #say we want to draw a white triangle  2k pixels offscreen somewhere
    triangle_vertices = [(2000, 2000),(2050, 2100),(2100, 2000)]
    triangle_colors = [(255,255,255)] * 3

    #translate by a jump 2000 pixels right and up
    jump_to = (2000, 2000)
    triangle_vertices = [tuple(jump(*position, *jump_to)) for position in triangle_vertices ]

    #useful function to have
    #flattens 2D lists
    def flatten(input_list):
        return [value for sublist in input_list for value in sublist]

    #now we can draw it
    pyglet.graphics.draw_indexed(
        3, 
        pyglet.gl.GL_TRIANGLES,
        [0, 1, 2],
        ('v2f', tuple(flatten(triangle_locations))),
        ('c3B', tuple(flatten(triangle_colors)))
    )

Теперь, когда мы можем переводить в прыжках, мы можем реализовать это всякий раз, когда просто прыгаем в окно. Но свиток не является внезапным прыжком; это плавное движение. Как нам это сделать?

Для этого нам потребуется оживить наш мир. Основной способ сделать это - добавить функцию анимации в расписание. Мы не можем запустить python в том же потоке, что и pyglet.app.run () после того, как он был вызван, так как он имеет бесконечное значение l oop, пока окно активно. Pyglet позволяет нам устанавливать расписание заранее, и он будет выполнять эти функции в то время, когда мы сообщаем ему об этом. Поэтому мы настроили расписание для анимации прокрутки.

У рассматриваемой функции должен быть доступ как к месту прокрутки, так и к вершинам для обновления. Это проблема, так как pyglet не имеет прямого доступа к нашему пространству имен. Один из элегантных способов сделать это - использовать классы.

Классы позволяют нам хранить переменные и функции в одной структуре данных и предоставлять функциям класса доступ к переменным класса. Поэтому, если мы создадим основной класс, который отслеживает все, что нам нужно знать, а также предоставляет функцию анимации, функция может использовать свой класс для доступа к месту прокрутки и вершинам для их перевода.

    class Scroller
        def __init__(self):
            self.window = pyglet.window.Window()

            #this keeps track of our scrolling
            #we are currently scrolling to the right at a rate of 10 pixels per second
            self.scroll = {
                'currently': True
                'x': 0
                'y': 0
                'vx': 10
                'vy': 0
            }

            #this list is a stand-in for your actual data structure
            #just make sure the animation function can access your vertices
            x1, y1, x2, y2 = 100, 100, 200, 200
            self.vertices = [(x1,y1),(x2,y2)]

            #adding the animation function to the schedule (60 FPS)
            framerate = 60
            timestep = 1 / framerate
            pyglet.clock.schedule_interval(self.scroll_animation, timestep)

            #starting the program
            pyglet.app.run()

        #the translate function we already had
        def translate(self, x, y, jump_x, jump_y):
            return x - jump_x, y - jump_y

        def scroll_animation(self, timestep):
            #using self, we can access what we need
            scroll = self.scroll
            vertices = self.vertices

            #by scaling the scrolling speed with the timestep
            #we are free to choose our framerate independently of our scrollspeed
            if scroll['currently']:
                scroll['x'] += scroll['vx'] * timestep
                scroll['y'] += scroll['vy'] * timestep

            #the location to where we should scroll
            scroll_to = [scroll[k] for k in ('x','y')]

            #translating all vertices by the scrolling
            for index, position in enumerate(vertices):
                self.vertices[index] = translate(*vertex, *scroll_to)

            #drawing the objects
            #(this is pseudocode: use batches)
            self.vertices.drawAll()

    Scroller()

Это скелет прокрутки Вы можете выбрать способ прокрутки (пользовательский ввод? Непрерывное движение?), И вам нужно будет создать разумную структуру данных, чтобы эта работа работала. Но эта основная концепция, переводящая все вершины в противоположном направлении прокрутки, - это то, что вам нужно, чтобы прокрутка работала для вас. Я надеюсь, что это было полезно для вас. Желаем удачи.

...