使用 Pyglet 如何将多个视图(例如翻译)应用于多个组?

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

我知道这个问题没有说太多,所以我只是尝试解释我的问题。

我正在 Pyglet 中开发一个项目,这是一个 2D 自上而下的游戏,标签代表网格上的图块(标签的原因是模拟 ASCII 图形,并且比手工制作艺术更容易)。我已经设置了所有批次和组,甚至还有相机,我正在寻找的是对我的一些代码的优化。

我认为,与其在屏幕外放置大量代表整个地图的精灵,不如重复使用预先存在的精灵来使游戏运行得更快,为此,我将图块分成了组,这些组将成为最初持有他们的主要团体。

基本上,我有一个

MapGroup
实例(父组),其中包含 36 个
MapGrid
实例(子组),每个
MapGrid
包含 1024 个
RenderTile
实例(图块)。

我最初所做的是,每当需要新的

MapGrid
时,假设相机向右移动到一些空白区域,
MapGroup
就会查看相反方向最远的每个网格并设置这些
MapGrid 
的内部坐标值覆盖了该空白区域,使其看起来像是出现了一个新网格,但它只是一个在屏幕外重复使用的网格。

主要问题是实际的

RenderTile
,这是我主要尝试解决的问题,到目前为止,移动它们的最佳方法是迭代移动的每个
RenderTile
中的每个
MapGrid
并以这种方式设置位置。它比渲染一个全新的
MapGrid
要好,我什至安排每个动作与上次相比有 1 毫秒的延迟,使其根本不会滞后太多,但它仍然不是很好,我觉得应该有更好的。

我的主要优化尝试是尝试将

MapGroup
具有的相同翻译应用到每个
MapGrid
上,但由于某种原因,
set_state
似乎只在第一个
MapGrid
上运行,所以从那里我尝试使
MapGrid
set_state
迭代每个
MapGrid
并使用迭代中的值,但这也不起作用。我什至尝试使
MapGroup
不是一个 pyglet 组,而只是管理组的东西,但这也存在
MapGrid
仍然只运行第一个实例的问题。如果有一种方法可以将这些
set_state
调用分开,以便它确实为每个单独的
MapGrid
进行设置和取消设置,那就太好了,否则我不知道该去哪里。

这是我正在使用的代码,其中包含关于什么作用的额外注释:

from pyglet.text import Label
from pyglet.graphics import Group
from pyglet.clock import schedule_once
from pyglet.math import clamp,Vec2,Vec3
from pyglet.gl import glEnable,glDisable,glScissor
from random import randint

class RenderTile(Label): # Main Tile
    def __init__(self,internalCoords,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.internalCoords = internalCoords

        self.x = internalCoords[0] * 16 + self.group.gridCoord[0] * 512
        self.y = internalCoords[1] * 16 + self.group.gridCoord[1] * 512
        #Initial values, fine on its own, but idealy the self.group.gridCoord[0] * 512 can be removed as set_state would handle the relative position


    def rePos(self,dt,newPos): #Simply called by MapGrid's update
        self.position = newPos



class MapGrid(Group): # Child Group
    def __init__(self,gridCoord,win,batchPass,order=0,parent=None):
        super().__init__(order,parent)
        self.gridCoord = gridCoord
        self._window = win
        # pyglet window, passed from parent

        self.internalTiles = {} 
        # Dict that holds each Tile, their keys are their coordinates in the grid

        gridTestColor = (randint(0,255),randint(0,255),randint(0,255),255) 
        # Random color for whole grid, mostly for distinction

        internalXSet = 0
        while internalXSet < 32:
            internalYSet = 0
            while internalYSet < 1:
                self.internalTiles[(internalXSet,internalYSet)] = RenderTile(internalCoords=(internalXSet,internalYSet),text="##",font_name="dayton",font_size=8,color=gridTestColor,batch=batchPass,group=self)
                internalYSet += 1
            internalXSet += 1
        # While loops that add each RenderTile to the grid, currently makes the grid 32x1 for testing purposes, it will be 32x32 by the end

        self.testInternalGrid = RenderTile(internalCoords=(16,16),text=str(self.gridCoord),font_name="dayton",font_size=24,color=(255,255,255,255),batch=batchPass,group=self,anchor_x="center",anchor_y="center")
        # Debug item, simply shows the grids position at its center

    def update(self):
        eventIterations = 0
        for tile in self.internalTiles:
            schedule_once(self.internalTiles[tile].rePos,eventIterations,(tile[0] * 16 + self.gridCoord[0] * 512,tile[1] * 16 + self.gridCoord[1] * 512,0))
            eventIterations += 0.001
        self.testInternalGrid.position = (256 + self.gridCoord[0] * 512,256 + self.gridCoord[1] * 512,0)
        self.testInternalGrid.text = str(self.gridCoord)
        # Updates the grids position, this is the unideal solution that I want to replace


    # def set_state(self):
    #     for grid in self.parent.internalGrids:
    #         self.parent.internalGrids[grid]._window.view = self.parent.internalGrids[grid]._window.view.translate(Vec3(-grid[0]*10, -grid[1]*10, 0))
    #         print(grid)

    # def unset_state(self):
    #     for grid in self.parent.internalGrids:
    #         self.parent.internalGrids[grid]._window.view = self.parent.internalGrids[grid]._window.view.translate(Vec3(grid[0]*10, grid[1]*10, 0))

    # This set_state was what I was messing with, if there is some way to make this work as intended that would be absolutley amazing



class MapGroup(Group):
    def __init__(self,win,map,batchPass,x=-1040,y=-540,z=1.0,order=0,parent=None):
        super().__init__(order,parent)
        self._window = win
        # pyglet window

        self.mapData = map
        # currently unused, will hold the data for the map, like what a tile should look like and what not

        self.x = x
        self.y = y
        self._z = z
        # Probaly should have just called this zoom instead of z, but it doesn't break anything yet, so its fine

        self.internalGrids = {}
        # Dict that holds each Grid, their keys are their coordinates in the map

        self.memoryPos = 0

        internalXSet = -3
        while internalXSet < 3:
            internalYSet = -3
            while internalYSet < 3:
                self.internalGrids[(internalXSet,internalYSet)] = MapGrid((internalXSet,internalYSet),win,batchPass,parent=self)
                internalYSet += 1
            internalXSet += 1
        # While loops that add each MapGrid to the MapGroup


    @property
    def position(self):
        return Vec2(self.x,self.y)

    @position.setter
    def position(self,new_pos):
        self.x,self.y = new_pos
        self.update()

    @property
    def z(self):
        return self._z

    @z.setter
    def z(self,new_z):
        self._z = clamp(round(new_z,1),0.5,2)

    def update(self):
        # All the following is frankly a pain to explain, but this is the code that looks for the furthest opposite grid and tells it to move
        XGridOffset = (self.position[0]+1040)/128-self.memoryPos*2
        XGridCheck = abs(XGridOffset)
        self.memoryPos += int(XGridOffset)
        while 1 <= XGridCheck:
            xCheckList = [grid[0] for grid in self.internalGrids]
            xMin = min(xCheckList)
            xMax = max(xCheckList)
            if 0 < XGridOffset:
                xChangeList = [grid for grid in self.internalGrids if self.internalGrids[grid].gridCoord[0] == xMin]
                for grid in xChangeList:
                    shiftingGrid = self.internalGrids.pop(grid,None)
                    newCoord = (xMax+1,shiftingGrid.gridCoord[1])
                    shiftingGrid.gridCoord = newCoord
                    self.internalGrids[newCoord] = shiftingGrid
                    shiftingGrid.update()
            elif 0 > XGridOffset:
                xChangeList = [grid for grid in self.internalGrids if self.internalGrids[grid].gridCoord[0] == xMax]
                for grid in xChangeList:
                    shiftingGrid = self.internalGrids.pop(grid,None)
                    newCoord = (xMin-1,shiftingGrid.gridCoord[1])
                    shiftingGrid.gridCoord = newCoord
                    self.internalGrids[newCoord] = shiftingGrid
                    shiftingGrid.update()
            else:
                xChangeList = [grid for grid in self.internalGrids if self.internalGrids[grid].gridCoord[0] == xMin]
                for grid in xChangeList:
                    shiftingGrid = self.internalGrids.pop(grid,None)
                    newCoord = (xMax+1,shiftingGrid.gridCoord[1])
                    shiftingGrid.gridCoord = newCoord
                    self.internalGrids[newCoord] = shiftingGrid
                    shiftingGrid.update()
            XGridCheck -= 1

    # Main set_state
    def set_state(self):
        glScissor(400, 0, 1280, 1080)
        # Basically the space the map takes up, assuming a 1920x1080 display
        glEnable(3089) #GL_SCISSOR_TEST = 3089
        # Didn't feel like importing from pyglet.gl.gl, so I just put its number in instead

        map_matrix = self._window.view.translate(Vec3(-self.x, -self.y, 0))
        map_matrix = map_matrix.scale(Vec3(self.z, self.z, 1))

        self._window.view = map_matrix

    def unset_state(self):
        glDisable(3089) #GL_SCISSOR_TEST = 3089

        map_matrix = self._window.view.scale(Vec3(1/self.z, 1/self.z, 1))
        map_matrix = map_matrix.translate(Vec3(self.x, self.y, 0))

        self._window.view = map_matrix

除了渲染之外,以下是使代码正常运行所需的最低要求:

import pyglet
from render import MapGroup,MapGrid,RenderTile
# render.py is the name of the file holding the other code

config = Config(double_buffer=True)
display = pyglet.canvas.get_display()
screens = display.get_screens()

window = pyglet.window.Window(1920,1080,fullscreen=True,vsync=True,screen=screens[2])
# Change screen as needed, its just what I have it set to

main_batch = pyglet.graphics.Batch()
map_group = MapGroup(window,{},main_batch)
# Main batch and group

fps_display = pyglet.window.FPSDisplay(window=window,color=(0,255,0,255))

#gui_group = pyglet.graphics.Group(order=2)
#holdThingTest = pyglet.shapes.Rectangle(0,0,400,1080,color=(75,75,75,255),batch=main_batch,group=gui_group)
#holdThingTest2 = pyglet.shapes.Rectangle(1680,0,240,1080,color=(75,75,75,255),batch=main_batch,group=gui_group)
#Bad naming I know, but its just simple boxes to help show where the map should be, uncomment if wanted

@window.event
def on_mouse_drag(x,y,dx,dy,buttons,modifiers):
    if buttons & pyglet.window.mouse.MIDDLE:
        map_group.position = (map_group.x - dx,map_group.y - dy)
# Event for camera movement, just hold and drag middle mouse

@window.event
def on_mouse_scroll(x,y,scroll_x,scroll_y):
    map_group.z += scroll_y/10
# Event for zooming, just scroll your mouse wheel

@window.event
def on_draw():
    window.clear()

    main_batch.draw()
    fps_display.draw()
# Event for drawing, kind of a well duh

if __name__ == "__main__":
    pyglet.app.run(1/60)
# Thing that runs the code, not much else to say

我知道我应该只显示必要的内容,爬过别人的 170 行奇怪的代码会有点痛苦,但据我所知,任何事情都可能是问题,所以我宁愿它可用,以防万一只是忽略了修复所有问题的一行更改。

python pyglet
1个回答
0
投票

好吧,经过一番折腾后,我发现只需将每个

MapGrid
设置为唯一的顺序即可修复它,所以固定的更改就是这样:

        orderSet = 0
        internalXSet = -3
        while internalXSet < 3:
            internalYSet = -3
            while internalYSet < 3:
                self.internalGrids[(internalXSet,internalYSet)] = MapGrid((internalXSet,internalYSet),win,batchPass,order=orderSet,parent=self)
                orderSet += 1
                internalYSet += 1
            internalXSet += 1

我唯一要注意的是,每个

MapGrid
的顺序需要是唯一的,将它们全部设置为1或2,它们似乎会再次导致相同的错误。

© www.soinside.com 2019 - 2024. All rights reserved.