Layered Parallax Code

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
User avatar
Posts: 469
Joined: Fri Aug 17, 2012 8:33 am
Completed: Brilliant Shadows, Perceptions of the Dead, The Phantom Icecream Truck
Projects: Embers of Magic, Pale Spectrum, Perceptions of the Dead
Organization: Ithaqua Labs
Tumblr: geckosart
Deviantart: sitaart

Layered Parallax Code

#1 Post by Geckos » Tue Jan 09, 2018 5:07 pm

Thought I'd share the parallax code that's floating around the forums, but in one place with all the fiddly bits fixed.

This code was not written originally by me. I am just sharing what I found on the forums.
This code lets you use different layers to give a parallax effect to in-game elements with the movements of your mouse.
Perceptions of the Dead clip

Code: Select all

init 800 python:
    class MouseParallax(renpy.Displayable):
        def __init__(self,layer_info):
            for m,n in self.sort_layer:
                if(not masteryet)and(m<41):
            if not masteryet:
        def render(self,width,height,st,at):
            return renpy.Render(width,height)
        def parallax(self,m):
            func = renpy.curry(trans)(disp=self, m=m)
            return Transform(function=func)
        def overlay(self):
            for m,n in self.sort_layer:
        def event(self,ev,x,y,st):
            import pygame
            if ev.type==pygame.MOUSEMOTION:
    def trans(d, st, at, disp=None, m=None):
        d.xoffset, d.yoffset = int(round(m*disp.xoffset)), int(round(m*disp.yoffset))
        return 0
Note: for this line of code "if(not masteryet)and(m<41):" the number must be higher than your highest number. Such as, for this code, 41 (as it is greater than the 40 for 'farback'.)

Example of code in use.

Code: Select all

show background_image onlayer farback
show midground_image onlayer back
show sprite1 onlayer front
show sprite2 onlayer inyourface
Other things to note: When using this layered method you must hide each layer individually to display new images. You cannot just 'wipe' the scene by putting
Scene black

you have to go

Code: Select all

hide background_image 
hide midground_image 
hide sprite1 
hide sprite2 
Hope this helps others! I enjoyed this code a lot.
Image ImageImage

User avatar
Posts: 2
Joined: Fri Apr 29, 2016 2:26 am

Re: Layered Parallax Code

#2 Post by Borisu » Sun Jan 14, 2018 5:38 pm

Really interesting dude! I'll see in what this can be used

Posts: 5
Joined: Mon Jan 01, 2018 5:44 pm
Soundcloud: dirtydonnie

Re: Layered Parallax Code

#3 Post by dirtydonnie » Fri Mar 09, 2018 6:08 pm

Can this be applied to screen elements such as choice buttons as well? If so, how?

User avatar
Posts: 174
Joined: Thu Dec 28, 2017 2:37 pm
Location: Russia

Re: Layered Parallax Code

#4 Post by Andredron » Mon Aug 06, 2018 3:31 pm

Geckos wrote:
Tue Jan 09, 2018 5:07 pm ... -post.html

Modified parallax. Now the list of layers and their parameters can be changed on the fly. Show layers (showp) and remove them (scenep) with one command. You can add one or more transform effects to the images (see the description of the showp function).

Code: Select all

# Parallax example:

# label start:
    # $ mouse_parallax.set (-20, -5, "l0"), (-40, -10, "l1"), (-60, -15, "l2"))
    # $ showp ("city0", "city1", "city2", "bg room")
    # with dissolve
    # "Move the mouse. \ NParallel parallax. Moving closer to the camera layers."
    # $ scenep ()
    # with dissolve
    # $ mouse_parallax.set (-60, -15, "l0"), (-40, -10, "l1"), (-20, -5, "l2"))
    # $ showp ("city0", "city1", "city2", "bg room")
    # with dissolve
    # "Move the mouse. \ NMirror parallax: The values ​​for the layer shift are reset, the far layers are moving harder now." As if we are looking in the mirror. "
    # $ scenep ()
    # with dissolve
    # return

init 1111 python:
    # class for parallax
    class MouseParallax (renpy.Displayable):
        def set (self, * args):
            self.xoffset, self.yoffset = 0.0, 0.0
            self.layer_info = args
            for i in self.layers ():
                if i in config.layers + ["master2"]:
                    config.layers.remove (i)
            index = config.layers.index ("master") + 1
            for xdist, ydist, layer in args:
                if not layer in config.layers:
                    config.layers.insert (index, layer)
                    index + = 1
            config.layers.insert (index, "master2")

        def __init __ (self, * args):
            super (renpy.Displayable, self) .__ init __ ()
            self.set (* args)
            config.overlay_functions.append (self.overlay)

        def layers (self):
            layers = []
            for dx, dy, layer in self.layer_info:
                layers.insert (0, layer)
            return layers

        def render (self, width, height, st, at):
            return renpy.Render (width, height)

        def parallax (self, xdist, ydist):
            func = renpy.curry (trans) (xdist = xdist, ydist = ydist, disp = self)
            return Transform (function = func)

        def overlay (self):
            ui.add (self)
            for xdist, ydist, layer in self.layer_info:
                renpy.layer_at_list ([self.parallax (xdist, ydist)], layer)

        def event (self, ev, x, y, st):
            import pygame
            if ev.type == pygame.MOUSEMOTION:
                self.xoffset, self.yoffset = ((float) (x) / (config.screen_width)) - 0.5, ((float) (y) / (config.screen_height)) - 0.5

    def trans (d, st, at, xdist = None, ydist = None, disp = None):
        d.xoffset, d.yoffset = int (round (xdist * disp.xoffset)), int (round (ydist * disp.yoffset))
        if xdist! = 0 or ydist! = 0:
            xzoom = (config.screen_width + abs (xdist + xdist)) / float (config.screen_width)
            yzoom = (config.screen_height + abs (ydist + ydist)) / float (config.screen_height)
            if yzoom> xzoom:
                d.zoom = yzoom
                d.zoom = xzoom
            d.anchor = (.5, 1.0)
            d.align = (.5, 1.0)
        return 0

    # list for storing images with layers
    parallax_images = []

    # show multiple images, each on its parallax layer
    # possible with the effect of transform or even with several
    # the number of images should not exceed the number of layers
    # otherwise superfluous will be displayed on the master2 layer on top of the rest
    # $ showp ("city1", ("city2", truecenter), ("city3", [truecenter, woo]))
    def showp (* args):
        global parallax_images
        layers = mouse_parallax.layers ()
        for i in args:
            at = []
            image = i
            if isinstance (image, tuple):
                image, at = image
                if not isinstance (at, list):
                    at = [at]
            l = "master2"
            if len (layers)> 0:
                l = layers.pop ()
   (image, at_list = at, layer = l)
            i = (image, l)
            if not i in parallax_images:
                parallax_images.append (i)

    # remove one image from the specified (or from any) layer
    def hidep (image, layer = None):
        global parallax_images
        if not layer:
            layer = "master2"
            for ii, ll in parallax_images:
                if ii == image:
                    layer = ll
        i = (image, layer)
        renpy.hide (image, layer = layer)
        if i in parallax_images:
            parallax_images.remove (i)

    # clear all parallax layers
    # and, if necessary, add new images
    def scenep (* args):
        global parallax_images
        for i in parallax_images:
            image, layer = i
            renpy.hide (image, layer = layer)
        parallax_images = []
        if args:
            showp (* args)

    mouse_parallax = MouseParallax ((-60, -15, "l0"), (-40, -10, "l1"), (-20, -5, "l
I know, I have terrible English
I'm writing a Renpy textbook (in Russian). I would be glad if someone translated into an English or German textbook Update 22.06.18

Posts: 8
Joined: Sat Feb 17, 2018 8:58 am

Re: Layered Parallax Code

#5 Post by KingsCard » Wed Aug 29, 2018 3:24 am

Worked like a charm, thank you very much :)

Posts: 1
Joined: Sat Sep 22, 2018 9:29 am

Re: Layered Parallax Code

#6 Post by Invader777 » Sat Sep 22, 2018 9:49 am

Really cool piece of code.
I tried the Gecko's code and it worked smoothly. I had all the layers loading in and animating the way I wanted them to. but when it came time to hide the layers to bring up a new scene.
hide background_image
did not remove the parallaxed layer in question. (A layer I'd created earlier in the script by typing
show backgroundimage onlayer farback at truecenter

I modified it back to read
show backgroundimage at truecenter
and from that point it was hidden like it was supposed to (But obviously not parallaxing like I wanted)

The Parallax works real nice and smooth like. It's exactly what I wanted. I layered it up with 5 layers of depth, put in a nice additive blend overlay for some light effects, put in a character with a blink animation... it was looking pretty sweet. I can even add new parallax layers when I need them
but it's kind of useless unless I can find a way to change a scene, or remove a layer when I need to.

any idea what I'm doing wrong?

(and as a side question - it seems to self arrange layer priorities by the number listed in Mouse Parralax.. is there any way to set manual layer priority? - typing 'behind' functions no longer seems to work")

Post Reply

Who is online

Users browsing this forum: No registered users