精靈(sprite) link

為了滿足同時顯示大量圖像的需求,Ren’Py支持精靈(sprite)系統。這個系統允許用戶創建精靈,每個精靈包含一個可視組件。精靈可以擁有自身的界面坐標和垂直順序改變。

如果不在乎系統性能的話,精靈系統的概念類似於 Fixed()Transform() 的結合。 精靈的運行速度比變換(transform)快,但是擴展性比較低。精靈系統最大的性能提升方法是,每一幀中每個可視組件只渲染一次。精靈的限制是只能修改自身的xoffset和yoffset值,而不像變換(transform)有許多特性(property)可以修改。

使用那個精靈系統之前,需要先創建一個SpriteManager對象,然後調用它的create方法創建新的粒子(particle)。根據需要,更新每個精靈的xoffset、yoffset和zorder域,就能讓精靈在界面內移動。透過把 updateevent 入參應用於SpriteManager,創作者能根據時間調整精靈,並對用戶輸入做出響應。

Sprite類 link

class Sprite link

這表示一個被SpriteManager類管理下的精靈(sprite)。其包含的欄位(field)控制精靈在界面的位置。精靈不能直接創建,而是調用 SpriteManager.create()

Sprite對象的欄位(field)如下:

x, y
精靈左上角為原點的x和y軸坐標值,與SpriteManager相關。
zorder
一個整數值,控制SpriteManager中所有精靈疊放順序。這個數值越大,對應精靈距離觀看者(viewer)越近。
events
若為True,事件消息會傳給子組件。若為False,也是預設值,子組件忽略所有事件消息(並屏蔽事件消息以免浪費時間處理)。

Sprite對象含有如下的方法:

destroy(self) link

銷毀該精靈,防止其再次顯示,並從SpriteManager中移除。

set_child(d) link

將可視組件與精靈 d 關聯。

class SpriteManager(update=None, event=None, predict=None, ignore_time=False, **properties) link

這是個管理一組精靈的可視組件,並儘可能快地把所有精靈顯示出來。

update
若非None,每次SpriteManager渲染某個精靈都會調用的函數。調用時帶一個入參,值是從SpriteManager第一次顯示後的時間長度,單位為秒。返回值一般是該函數再次被調用以及SpriteManager再次被渲染的時間間隔,單位為秒。
event

若非None,當某個事件發生時會調用的函數。其使用以下事件消息作為入參:

  • 某個pygame事件對象。
  • 事件的x坐標調整。
  • 事件的y坐標調整。
  • 從SpriteManager第一次顯示開始計算的時間。

如果該函數返回了一個非空值,互動結束時將這個值返回。

predict
若非None,該函數返回一個可視組件列表。These displayables are predicted when the sprite manager is.
ignore_time
若為True,渲染可視組件時忽略的時間。當SpriteManager使用了一些數量不大的圖像,並且這些圖像不會變化時,才應該使用這項值。使用這項值的可視組件數量不能多,因為使用後的可視組件在SpriteManager對象的整個生命週期內,會一直保留在記憶體中。

在首次渲染後(在 update 函數調用前),SpriteManager如有下列欄位(field):

width, height
SpriteManager的寬度和高度,單位為像素。

SpriteManager包含下列方法:

create(d) link

為可視組件 d 創建一個新的精靈(Sprite),並添加到該SpriteManager中。

redraw(delay=0) link

delay 秒後重繪該SpriteManager。

SnowBlossom(d, count=10, border=50, xspeed=(20, 50), yspeed=(100, 200), start=0, fast=False, horizontal=False) link

雪花(snowblossom)效果可以讓某個精靈(sprite)的多個實例在界面中上下左右移動。當某個精靈離開界面時,其會返回起始點。

d
用作精靈的可視組件。
border
界面邊界(border)的尺寸。精靈會被看作處於界面內,除非它越出了邊界。需要確保精靈不會突然消失。
xspeed, yspeed
精靈移動速度,分別對應水平和垂直方向。這可以是一個數值或者兩個數值的元組。在後面那種情況,每個粒子(particle)的速度可以聲明為兩個值之間的隨機數。速度可以是整數或負數,只要保證後面的數值比前面的大。
start
每添加一個粒子(particle),延遲的時間,單位為秒。這項值允許粒子從界面頂部出發,跟“wave”效果不同。
fast
若為True,粒子從界面中心出發,而不是界面四邊。
horizontal
若為True,粒子在界面的左右兩邊出現,而不是上下兩邊。

Sprite樣例 link

SnowBlosson類是在界面內放置掉落物體的易用辦法。

image snow = SnowBlossom("snow.png", count=100)

這個樣例展示了如何使用一個SpriteManager創建複雜行為。在這個例子中,總共顯示了400個粒子,並讓粒子避開滑鼠。

init python:
    import math

    def repulsor_update(st):

        # 如果我們不知道滑鼠在哪裡,先放棄獲取滑鼠訊息
        if repulsor_pos is None:
            return .01

        px, py = repulsor_pos

        # 使用for循環檢測每一個精靈……
        for i in repulsor_sprites:

            # 計算從精靈到滑鼠的向量
            vx = i.x - px
            vy = i.y - py

            # 計算向量長度,將向量歸一化。
            vl = math.hypot(vx, vy)
            if vl >= 150:
                continue

            # 計算需要移動的距離
            distance = 3.0 * (150 - vl) / 150

            # 移動
            i.x += distance * vx / vl
            i.y += distance * vy / vl

            # 確保停留在界面上。
            if i.x < 2:
                i.x = 2

            if i.x > repulsor.width - 2:
                i.x = repulsor.width - 2

            if i.y < 2:
                i.y = 2

            if i.y > repulsor.height - 2:
                i.y = repulsor.height - 2

        return .01

    # 收到事件消息時,記錄滑鼠的坐標。
    def repulsor_event(ev, x, y, st):
        store.repulsor_pos = (x, y)


label repulsor_demo:

    python:
        # 創建一個SpriteManager。
        repulsor = SpriteManager(update=repulsor_update, event=repulsor_event)
        repulsor_sprites = [ ]
        repulsor_pos = None

        # 確保只有一個可視組件smile。
        smile = Image("smile.png")

        # 添加400個精靈。
        for i in range(400):
            repulsor_sprites.append(repulsor.create(smile))

        # 放置這400個精靈。
        for i in repulsor_sprites:
            i.x = renpy.random.randint(2, 798)
            i.y = renpy.random.randint(2, 598)

        del smile
        del i

    # 把repulsor添加到界面。
    show expression repulsor as repulsor

    "..."

    hide repulsor

    # 清理。
    python:
        del repulsor
        del repulsor_sprites
        del repulsor_pos