首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QPolygon元素的纹理化

QPolygon元素的纹理化
EN

Stack Overflow用户
提问于 2022-07-13 20:09:10
回答 1查看 47关注 0票数 0

我目前正在使用Python开发一个基于十六进制的2D棋盘游戏。我没有使用PyGame,我用更难的方法来练习。图形目前是使用PyQt5创建的。使用QPolygonF和QGraphicsPolygonItem创建六边形块,并使用QPixmap和QGraphicsPixmapItem添加来自图像文件的图像。“移动相机”仅仅是通过调整所有位置计算的起始点来完成的。

问题是,我想要一些纹理的瓷砖从现成的图像文件。这样,板子看起来比纯色漂亮多了。我可以绘制准备好的六边形图像文件并放置它们,但这看起来很好,只有当图像已经是六边形,并且图像是仔细地缩放和放置。如果我以后改变主意,例如,我想从六边形变成正方形或透视六边形或其他形状,所有的工作都白费了。因此,将纹理设置为形状会更好--这将是更通用的。

我发现可以使用QBrush ()将纹理设置为setTexture()。起初,这听起来是个完美的解决方案,只是不,它不是。由于某种原因,这种纹理缺乏一个更好的术语,是全球性的。

此外,纹理不会“粘”在瓷砖上,因为“照相机”(实际上是瓷砖)被移动

我首先尝试通过测试像素映射的滚动()做什么来解决这个问题。我不知道在地狱的九圈里发生了什么。此外,它显然是沉重的计算机,帧速率的程序严重中断。

我需要建议,因为我不知道该怎么做,谷歌教授也没有多大帮助。

绝对最好的解决方案是,添加几行代码就可以生成裁剪到QPolygon描述的区域的图像。我也可以使用一个全局纹理,只要我可以移动它与瓷砖,以“粘贴”纹理。由于我进入这个项目的时间还早,如果认为有必要改变库或其他类似的东西,那么它也是一个合理的工作量。

以下是相关代码:

代码语言:javascript
复制
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.Qt import QPixmap
from PyQt5.QtGui import QBrush
import math

def main():
    global app
    app = QApplication(sys.argv)
    
    window = Window()
    
    sys.exit(app.exec_())


class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setCentralWidget(QtWidgets.QWidget())
        self.horizontal = QtWidgets.QHBoxLayout()
        self.centralWidget().setLayout(self.horizontal)
        
        self.x0 = 30
        self.y0 = 30
        self.scale = 1.0
        self.board = Board(8,8)
    
        self.scene = QtWidgets.QGraphicsScene()
        self.initWindow()
        self.update()
        
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(int(1000 / 60)) # Milliseconds
    
    
    "Initialize the window"
    def initWindow(self):
        self.setGeometry(300,200,800,800)
        self.show()

        self.scene.setSceneRect(0, 0, 700, 700)

        self.view = QtWidgets.QGraphicsView(self.scene, self)
        self.view.adjustSize()
        self.view.show()
        self.horizontal.addWidget(self.view)
    
    
    def update(self):
        self.scene.clear() # The window is wiped clean before adding updated graphics
    
        r = self.scale * 50
        h = r * math.sin(math.pi/3)
        midpointX = 0
        midpointY = 0
    
        for x in range(self.board.width):
            for y in range(self.board.height):                
                qt_polygon = QtGui.QPolygonF()
                
                if y % 2 == 0:
                    midpointX = ( self.x0 + h*2*x )
                else:
                    midpointX = ( self.x0 + h + h*2*x )
                midpointY = ( self.y0 + 1.5*r*y )
                
                qt_polygon.append(QtCore.QPointF( midpointX, midpointY - r ))
                qt_polygon.append(QtCore.QPointF( midpointX + h, midpointY - 0.5*r ))
                qt_polygon.append(QtCore.QPointF( midpointX + h, midpointY + 0.5*r ))
                qt_polygon.append(QtCore.QPointF( midpointX, midpointY + r ))
                qt_polygon.append(QtCore.QPointF( midpointX - h, midpointY + 0.5*r ))
                qt_polygon.append(QtCore.QPointF( midpointX - h, midpointY - 0.5*r ))
                
                polygon = QtWidgets.QGraphicsPolygonItem(qt_polygon)
                
                path = <insert path>
                pixmap = QPixmap(path)
                
                brush = QBrush()
                brush.setTexture(pixmap)
                polygon.setBrush(brush)
                
                self.scene.addItem(polygon)
    
    "Keyboard commands"
    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_A:
            self.x0 -= 5
        if event.key() == QtCore.Qt.Key_D:
            self.x0 += 5
        if event.key() == QtCore.Qt.Key_W:
            self.y0 -= 5
        if event.key() == QtCore.Qt.Key_S:
            self.y0 += 5
    
class Tile():
    def __init__(self):
        ""

class Board():
    def __init__(self, width, height):
        self.height = height
        self.width = width
        
        self.tiles = [None] * self.width
        for x in range(self.width):
            self.tiles[x] = [None] * self.height
            for y in range(self.height):
                self.tiles[x][y] = Tile()


main()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-14 19:19:11

笔刷总是相对于图形项的位置。

由于一个新的图形项总是位于(0, 0)坐标,所以您将始终得到相同的画笔,因为您正在创建的多边形的点总是相对于0。

相反,您应该做的是始终创建相同的多边形,然后在适当的坐标下移动它。

代码语言:javascript
复制
    def update(self):
        self.scene.clear()
    
        r = self.scale * 50
        h = r * math.sin(math.pi/3)
    
        hexagon = QtGui.QPolygonF([
            QtCore.QPointF(h, 0), 
            QtCore.QPointF(h * 2, 25), 
            QtCore.QPointF(h * 2, 75), 
            QtCore.QPointF(h, 100), 
            QtCore.QPointF(0, 75), 
            QtCore.QPointF(0, 25), 
        ])
        for x in range(self.board.width):
            for y in range(self.board.height):                
                midpointX = 2 * h * x
                if y & 1:
                    midpointX += h
                midpointY = 1.5 * r * y

                polygon = QtWidgets.QGraphicsPolygonItem(hexagon)
                polygon.setPos(midpointX, midpointY)

                path = '/tmp/spacebg.jpg'
                pixmap = QPixmap(path)

                brush = QBrush()
                brush.setTexture(pixmap)
                polygon.setBrush(brush)
                
                self.scene.addItem(polygon)

一个非常重要的注意事项:虽然图形视图框架非常快,但是持续地清除场景并重新创建它通常并不是非常有效;相反,要找到方法重用现有的项并最终更新它们。

如果您只想在按下键时移动项目,那么不断地重建整个场景是没有意义的,而且完全没有必要,而不是完全浪费资源。相反,创建一个实际移动这些项的函数,然后只在适当的键按下时才调用它。还请注意,如果您实际上只想滚动场景的视图,则应该使用视图的setSceneRect(),或者最终使用滚动条(假设场景足够大)。

最后,请注意,update()是任何QWidget的一个现有函数,它不仅非常重要,而且也是一个插槽,因此,除非您真正知道要做什么,否则不应该覆盖它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72972062

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档