創作者定義的可視組件 link

最複雜也最強大,能夠訂製Ren’Py表現效果的方式,就是使用創作者定義的可視組件。 一個創作者定義的可視組件允許使用任何pygame事件消息。 其可以渲染其他可視組件,並將其他可視組件放置在界面的任何位置。 這可是突破Ren’Py提供的工具限制,適合創建一些2D的迷你遊戲。 (但請參考 sprites 章節內容,描述了生成同樣物體的高階方法。)

創作者定義的可視組件完全使用Python代碼編寫, 我們鼓勵創作者在創建自己的可視組件之前具有一定程度的Python面向對象編程技能。

樣例 link

這是一個創作者定義可視組件的樣例。 這個可視組件能根據子組件中心與滑鼠指針的距離修改子組件的alpha值。

init python:

    import math

    class Appearing(renpy.Displayable):

        def __init__(self, child, opaque_distance, transparent_distance, **kwargs):

            # 向renpy.Displayable構造器傳入額外的特性(property)。
            super(Appearing, self).__init__(**kwargs)

            # 子組件。
            self.child = renpy.displayable(child)

            # 子組件完全不透明和完全透明的距離。
            # 前者必須小於後者。
            self.opaque_distance = opaque_distance
            self.transparent_distance = transparent_distance

            # 子組件的alpha通道值。
            self.alpha = 0.0

            # 子組件的寬度和高度。
            self.width = 0
            self.height = 0

        def render(self, width, height, st, at):

            # 創建一個變換(transform),調整子組件的alpha通道值。
            t = Transform(child=self.child, alpha=self.alpha)

            # 創建一個子組件的渲染器。
            child_render = renpy.render(t, width, height, st, at)

            # 或者子組件尺寸。
            self.width, self.height = child_render.get_size()

            # 創建返回的渲染器。
            render = renpy.Render(self.width, self.height)

            # 以blit方式將子組件的渲染器資訊複製我們的渲染器。
            render.blit(child_render, (0, 0))

            # 返回渲染器。
            return render

        def event(self, ev, x, y, st):

            # 繼續按從可視組件中心到滑鼠指針的距離。
            # 滑鼠指針位置為x和y,表示指針圖案左上角為原點的坐標。
            distance = math.hypot(x - (self.width / 2), y - (self.height / 2))

            # 根據距離,計算alpha值。
            if distance <= self.opaque_distance:
                alpha = 1.0
            elif distance >= self.transparent_distance:
                alpha = 0.0
            else:
                alpha = 1.0 - 1.0 * (distance - self.opaque_distance) / (self.transparent_distance - self.opaque_distance)

            # 如果alpha值發生變化,觸發redraw事件。
            if alpha != self.alpha:
                self.alpha = alpha
                renpy.redraw(self, 0)

            # 將事件傳給各子組件。
            return self.child.event(ev, x, y, st)

        def visit(self):
            return [ self.child ]

使用創作者定義的可視組件時,我們可以創建對應的實例,並將實例添加至界面。

screen alpha_magic:
    add Appearing("logo.png", 100, 200):
        xalign 0.5
        yalign 0.5

label start:
    show screen alpha_magic

    "你能找到logo嗎?"

    return

renpy.Displayable link

創作者定義的可視組件是通過renpy.Displayable類的子類創建的。創作者定義的可視組件必須重寫render方法,也可以重寫其他方法。

一個可視組件對象必須是可以被pickle的,這意味著其不含有不能被pickle的對象特性(reference)。特別需要注意的是,Render對象不能儲存在創作者定義的可視組件中。

由於需要重寫Displayable類的很多方法,我們將這些方法都放在 self 參數中。

class renpy.Displayable link

創作者定義可視組件的基類。

__init__(**properties):

子類可能重寫這個構造器,並添加新的參數。如果的確出現了新參數,需要把所有未知的關鍵字入參都傳入到renpy.Displayable構造器,這樣調用:

super(MyDisplayable, self).__init__(**properties)
render(self, width, height, st, at) link

子類必須重新這個方法,並返回一個 renpy.Render 對象。渲染器對象決定了在界面的所有顯示效果。

width, height

這個可視組件的有效區域範圍,單位為像素。

st

一個浮點數,表示顯示時間軸,單位為秒。可視組件在界面上首次顯示的時間點,是顯示時間軸的起始點。

at

一個浮點數,動畫時間軸,單位為秒。帶有同樣標籤(tag)的圖像顯示而不是隱藏的時間點,是動畫時間軸的起始點。(當可視組件不使用標籤顯示,就與顯示顯示時間軸相同。)

可視組件首次顯示時會調用render方法。在 renpy.redraw() 函數調用這個對象時,對象會再次調用render方法。

event(self, ev, x, y, st) link

將一個pygame事件消息傳入創作者定義可視組件就會調用event方法。如果event方法返回一個非None的值,這個也會作為交互動作的結果並返回。

若要忽略沒有返回None的事件,則可以raise renpy.IgnoreEvent

event方法也存在於其他可視組件,允許創作者定義可視組件將事件消息傳給其他可視組件。

ev

一個 event 對象

x, y

事件的x和y坐標值,以可視組件左上角為原點。這些資訊會用在特性(preference)中定位pygame事件對象中的資訊。

st

一個浮點數,顯示時間軸,單位為秒。

每次交互動作的開頭都會生成一個事件消息, renpy.timeout() 函數可以用於觸發另一個事件消息。

per_interact(self) link

每次交互動作的開頭都會調用這個方法。這個函數可以用於觸發一次重新繪製,以及回滾過程中對象需要部分重新繪製的情況。

visit(self) link

如果可視組件有子可視組件,就需要重寫這個方法返回一個子可視組件的列表。這個方法確保那些可視組件的per_interact方法都被調用,並能預載入使用的圖像。

place(self, dest, x, y, width, height, surf, main=True) link

在某個矩形區域中放置一個render對象(必須是該可視組件的render對象)。返回一個(x, y)元組,表示可視組件的坐標。

dest

若不是None,計算出坐標後會將 surf 傳輸(blit)到 dest 上。

x, y, width, height

矩形區域。

surf

對應的render對象。

main

該參數直接傳給Render.blit()的同名入參。

renpy.Render link

創作者定義的可視組件與renpy.Render對象一起運行。 調用某個可視組件的 renpy.render() 函數,可以返回一個Render對象。 一個創作者定義的可視組件應該調用 renpy.Render 的render方法創建一個Render對象。

由於Render對象不能派生子類,我們省略了顯式 self 參數。

class renpy.Render(width, height) link

創建一個新的Render對象。

width, height

Render對象的寬度和高度,單位為像素。

blit(source, pos, main=True) link

在這個Render對象中繪製另一個Render對象。

source

待繪製的Render對象。

pos

繪製的位置。是一個(x, y)元組,表示從目標Render對象左上角為原點的坐標。

main

唯一的關鍵字參數。若為True, source will 會在樣式檢查器中顯示。

place(d, x=0, y=0, width=None, height=None, st=None, at=None, render=None, main=True) link

d 以可視組件形式渲染,使用Ren’Py標準位置算法將其放入由 xywidthheight 定義的矩形中。 返回的(x, y)元組表示可視組件坐標位置。坐標的計算透過調用 Displayable.place() 方法實現。

x, y, width, height

放入的矩形區域。如果 widthheight 為None,就分別使用Render對象的寬或者高。

st, at

傳入Render對象的兩個時間。若為None,預設使用render方法調用這個方法時傳入的時間。

render

若不是None,這項代替 d 成為渲染對象。

main

同 .blit()。

canvas() link

返回一個canvas對象。canvas對象有對應 pygame.draw 函數的方法,第一個參數(surface)省略。

Ren’Py中沒有實現圓弧和橢圓的函數。

canvas對象也有一個get_surface()方法,能返回使用canvas的paygame Surface對象。

get_size() link

R返回一個(width, height)元組,表示Render對象的尺寸。

subsurface(rect) link

返回一個Render對象,原Render對象的剪裁。

rect

一個 (x, y, width, height) 元組。

zoom(xzoom, yzoom) link

設置該可視組件子組件在水平和垂直方向上的縮放(zoom)等級。只有子組件會被縮放——寬度、高度和blit坐標都不會縮放。

下列屬性和方法只在啟用基於模型的渲染器後才能使用:

mesh link

This field enables model-based rendering for this Render. If true: 該欄位對此Render對象啟用基於模型的渲染器。

若為True:

  • 此可視組件的所有子組件都會渲染為紋理(texture)。

  • 此可視組件關聯的第一個子組件的尺寸作為網格(mesh)的尺寸。

  • 使用此Render對象創建網格、著色器、uniform變數和GL屬性。

創建的網格模型將在單次繪製操作中完成。

add_shader(shader) link

該方法使此Render對象或其子對象使用名為 shader 的著色器進行繪製。 著色器名應是一個字串。如果著色器名以“-”開頭,表示不使用此著色器。

add_uniform(name, value) link

此Render對象或其子對象繪製時,將名為 name 的uniform變數賦值為 value

add_property(name, value) link

此Render對象或其子對象繪製時,將名為 name 的GL屬性變數賦值為 value

功能函數和類 link

這些函數管理渲染過程。

renpy.displayable(d, scope=None) link

這個函數使用入參 dd 可能是一個可視組件對象或字串。如果是一個字串,使用常用的規則將其轉換為一個可視組件。

renpy.end_interaction(value) link

value 不是None,立刻結束當前交互動作,並讓交互動作返回 value 。若 value 是None,不做任何事。

在創作者定義的可視組件內部的渲染器和事件消息處理方法中可以調用這個函數。

renpy.is_pixel_opaque(d, width, height, st, at, x, y) link

判斷使用 renpy.render(d, width, height, st, at) 渲染出的可視組件在(x, y)位置的像素是否不透明。

renpy.load_image(im) link

使用圖像快取載入圖像操作器(manipulator) im ,返回一個紋理(texture)。

renpy.load_rgba(data, size) link

bytes 形式載入,以 size 作為尺寸載入圖像數據,然後以紋理對象形式返回。

data

該入參應該是一個bytes對象,按照RGBA8888的格式順序保存圖像數據。

renpy.load_surface(im) link

使用圖像快取載入圖像控制器(manipulator) m ,返回一個pygame Surface對象。

renpy.map_event(ev, keysym) link

如果pygame事件 ev 匹配 keysym 就返回True。

keysym

下列情況之一:

  • config.keymap() 中配置的按鍵綁定名稱。

  • 訂製化快捷鍵 章節中描述的keysym對象。

  • 包含一個或多個keysym的列表。

renpy.render(d, width, height, st, at) link

渲染一個可視組件,並返回一個renpy.Render對象。

d

待渲染的可視組件。

width, height

可視組件渲染區域的寬度和高度。

st, at

顯示和動畫時間軸。

這個對象返回的渲染器可以快取,一旦恢復一次後就不該再修改渲染器。

renpy.timeout(seconds) link

經過 seconds 秒後生成一個事件消息。這個函數確保了創作者定義可視組件的事件處理方法被調用到。

renpy.redraw(d, when) link

經過 when 秒之後重新繪製可視組件 d 。 有時候可視組件的重繪間隔可能比設置的短(比如子組件重繪後),那時將省略重繪。

exception renpy.IgnoreEvent link

異常處理,可以讓Ren’Py忽略異常事件。在事件方法中的使用:

raise renpy.IgnoreEvent()