1. 程式人生 > >Python遊戲引擎開發(七):繪製向量圖

Python遊戲引擎開發(七):繪製向量圖

今天來完成繪製向量圖形。

沒有讀過前幾章的同學,請先閱讀前幾章:

Graphics類

首先我們建立Graphics類用於建立向量圖形:

class Graphics(DisplayObject):
    def __init__(self):
        super(Graphics, self).__init__()

        # 儲存所有圖形資料的列表
        self.__drawingList = []
        # 用於儲存當前圖形資料
        self.__currentGraphics = None

由於我們的視窗介面是在不斷清除,然後重繪的,所以加入__drawingList

屬性來儲存所有圖形的資料。而__currentGraphics用於儲存當前圖形資料。

flash中,我們使用beginFill方法來下達開始繪製命令。加入該方法:

def beginFill(self, color = "transparent", alpha = 1):
    if color == "transparent":
        alpha = 0

    self.__currentGraphics = {
        "path" : QtGui.QPainterPath(),
        "lineAlpha" : 255,
        "lineWidth"
: None, "lineColor" : None, "fillColor" : color, "fillAlpha" : 255 * alpha, "joins" : None, "caps" : None, "miterLimit" : None }

開始繪製命令需要如下幾個引數:圖形填充色、填充色透明度。
在上面的程式碼中,我們初始化了__currentGraphics屬性,可以看到,他是一個dict物件,其中的path成員是一個QPainterPath物件,這個物件來自Qt,通過呼叫這個類中的一些方法,可以建立一些圖形,然後呼叫QPainter

drawPath方法就可以把這個物件裡建立的所有圖形畫出來。

新增endFill方法,用於把當前圖形儲存到__drawingList中,儲存到__drawingList後,就可以使其顯示出來:

def endFill(self):
    if not self.__currentGraphics:
        return

    self.__currentGraphics["path"].setFillRule(QtCore.Qt.WindingFill)

    self.__drawingList.append(self.__currentGraphics)

然後是_show方法,在前面的章節中介紹過,每個顯示在介面上的物件都有這個方法,用於顯示自身:

def _show(self, c):
    for item in self.__drawingList:
        if not isinstance(item, dict):
            return

        path = item["path"]

        if not path:
            continue

        lineWidth = item["lineWidth"]
        lineColor = item["lineColor"]
        fillColor = item["fillColor"]
        joins = item["joins"]
        caps = item["caps"]
        miterLimit = item["miterLimit"]
        fillAlpha = item["fillAlpha"]
        lineAlpha = item["lineAlpha"]

        brush = None
        pen = QtGui.QPen()

        c.save()

        if lineWidth:
            pen.setWidth(lineWidth)
        else:
            pen.setWidth(0)

        if lineColor:
            color = getColor(lineColor)

            if isinstance(color, QtGui.QColor):
                if lineAlpha:
                    color.setAlpha(lineAlpha)

                pen.setColor(color)
        else:
            pen.setColor(getColor("transparent"))

        if joins:
            pen.setJoinStyle(joins)

        if caps:
            pen.setCapStyle(caps)

        if miterLimit:
            pen.setMiterLimit(miterLimit)

        if fillColor:
            color = getColor(fillColor)

            if fillAlpha and hasattr(color, "setAlpha"):
                color.setAlpha(fillAlpha)

            brush = QtGui.QBrush(color)

            brush.setStyle(QtCore.Qt.SolidPattern)

            c.setBrush(brush)

        c.setPen(pen)
        c.drawPath(path)

        c.restore()

其中,我們遍歷了__drawingList,從中讀取每個圖形資料,然後根據資料進行一些圖形樣式設定,最後drawPath畫出圖形。

上面的程式碼主要完成了基礎的一些部分,目前我們只有開始繪圖和結束繪圖命令。還差設定樣式以及新增圖形的命令,通過以下程式碼加入:

def lineStyle(self, thickness = 1, color = "black", alpha = 1, joints = None, caps = None, miterLimit = 3):
    if not self.__currentGraphics:
        return

    if color == "transparent":
        alpha = 0

    if joints == JoinStyle.ROUND:
        joints = QtCore.Qt.RoundJoin
    elif joints == JoinStyle.MITER:
        joints = QtCore.Qt.MiterJoin
    elif joints == JoinStyle.BEVEL:
        joints = QtCore.Qt.BevelJoin

    if caps == CapsStyle.NONE:
        caps = QtCore.Qt.FlatCap
    elif caps == CapsStyle.SQUARE:
        caps = QtCore.Qt.SquareCap
    elif caps == CapsStyle.ROUND:
        caps = QtCore.Qt.RoundCap

    self.__currentGraphics["lineWidth"] = thickness
    self.__currentGraphics["lineColor"] = color
    self.__currentGraphics["lineAlpha"] = 255 * alpha
    self.__currentGraphics["joints"] = joints
    self.__currentGraphics["caps"] = caps
    self.__currentGraphics["miterLimit"] = miterLimit

def moveTo(self, x, y):
    if not self.__currentGraphics:
        return

    self.__currentGraphics["path"].moveTo(x, y)

def lineTo(self, x, y):
    if not self.__currentGraphics:
        return

    self.__currentGraphics["path"].lineTo(x, y)

def drawRect(self, x, y, width, height):
    if not self.__currentGraphics:
        return

    self.__currentGraphics["path"].addRect(x, y, width, height)

def drawCircle(self, x, y, radius):
    self.drawEllipse(x - radius, y - radius, radius * 2, radius * 2)

def drawEllipse(self, x, y, width, height):
    if not self.__currentGraphics:
        return

    self.__currentGraphics["path"].addEllipse(x, y, width, height)

有了這些命令,就可以進行繪圖操作了。

Sprite上使用Graphics

Graphics主要是在Sprite上使用,如下程式碼所示:

layer = Sprite()
layer.graphics.beginFill("#FF0000")
layer.graphics.drawRect(0, 0, 200, 200)
layer.graphics.endFill()
addChild(layer)

可見我們需要為Sprite新增一個graphics屬性,用於操作向量圖形,所以在Sprite構造器中加入如下程式碼:

self.graphics = new Graphics()
self.graphics.parent = self

通過上面的這些命令,我們就可以創建出許多不同的向量圖形:

Image 1

繪製向量圖的功能就搞定了~如有不懂之處,歡迎留言。

至此,引擎基本功能就實現了