画面を揺らす(手ぶれ、地震の再現)

 Ren’Pyで画面を揺らす方法にはトランジションのvpunch, hpunchを使う方法、ワーパー関数を利用する方法がありますが、細かい調整が出来ないのでATLのfunction transform プロパティーを利用する方法を紹介します。

 まず、下のコードを適当な場所にコピーしてください。

init python:
    class Sin(object):
        def __init__(self, freq, amp, duration=0):
            if not isinstance(freq, tuple):
                freq = (freq, freq)
            self.x_freq, self.y_freq = freq
            if not isinstance(amp, tuple):
                amp = (amp, amp)
            self.x_amp, self.y_amp = amp
            self.duration = duration

        def __call__(self, tran, st, at):
            from math import sin, pi
            if self.duration and st >= self.duration:
                return
            tran.xoffset = self.x_amp*sin(2*pi*self.x_freq*st)
            tran.yoffset = self.y_amp*sin(2*pi*self.y_freq*st)
            return 1./60
 
    class Wiggle(object):
        def __init__(self, freq, amp, duration, octaves=1, ampMulti=.5, time=0):
            from random import random
            #予めランダムな値を生成しておく
            self.randoms = [(1+random(), 1+random()) for i in range(0, 100)]
            if not isinstance(freq, tuple):
                freq = (freq, freq)
            self.x_freq, self.y_freq = freq
            if not isinstance(amp, tuple):
                amp = (amp, amp)
            self.x_amp, self.y_amp = amp
            self.octaves = octaves
            self.ampMulti = ampMulti
            self.duration = duration
            self.time = time

        def __call__(self, tran, st, at):
            if self.duration and st >= self.duration:
                return
            from math import sin, pi, ceil
            rx1, rx2 = self.randoms[int(ceil(st*self.x_freq)%100)]
            ry1, ry2 = self.randoms[int(ceil(st*self.y_freq)%100)]
            tran.xoffset = rx1*self.x_amp*sin(2*pi*self.x_freq*st) + rx2*self.x_amp*self.ampMulti*sin(2*pi*self.x_freq*2*self.octaves*(st+self.time))
            tran.yoffset = ry1*self.y_amp*sin(2*pi*self.y_freq*st) + ry2*self.y_amp*self.ampMulti*sin(2*pi*self.y_freq*2*self.octaves*(st+self.time))
            return 1./60

 そうするとATLのfunctionプロパティーに次のようにSin, Wiggleクラスを指定出来るようになります。

Sin(freq, amp, duration=0)
x,yoffsetプロパティーを操作して振動する動きを再現します。
1つ目の引数freqはx,y方向それぞれの周波数のタプルを指定します。
2つ目のampは振幅のピクセル数です。
3つ目のdurationは振動時間で、デフォルトのゼロでは無制限に繰り返します。

Wiggle(freq, amp, duration)
引数は上と同じです。ランダムに振動します。freqはxとyで少し変えるとx, y平面上をランダムに揺れるようになります。

    #y方向に0.1hzで100pixel画面を上下する
    show bg:
        function Sin((0, 0.1), (0, 100))
        subpixel True

    #xy方向にランダムに最大10pixel幅でゆっくり画面を揺らす
    show bg:
        function Wiggle((0.5, 0.4), (0, 10))
        subpixel True

    #xy方向にランダムに最大10pixel幅で激しく0.5秒画面を揺らした後、0.1秒かけて元の位置にもどる
    show bg:
        function Wiggle((5, 4), (0, 10), duration=.5)
        subpixel True
        pause 0.5
        linear 0.1 xoffset 0
        linear 0.1 yoffset 0