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
Message
Author
User avatar
Geckos
Veteran
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
Contact:

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.
parallax_example_potd1.gif
Perceptions of the Dead clip

Code: Select all


init 800 python:
    class MouseParallax(renpy.Displayable):
        def __init__(self,layer_info):
            super(renpy.Displayable,self).__init__()
            self.xoffset,self.yoffset=0.0,0.0
            self.sort_layer=sorted(layer_info,reverse=True)
            cflayer=[]
            masteryet=False
            for m,n in self.sort_layer:
                if(not masteryet)and(m<41):
                    cflayer.append("master")
                    masteryet=True
                cflayer.append(n)
            if not masteryet:
                cflayer.append("master")
            cflayer.extend(["transient","screens","overlay"])
            config.layers=cflayer
            config.overlay_functions.append(self.overlay)
            return
        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):
            ui.add(self)
            for m,n in self.sort_layer:
                renpy.layer_at_list([self.parallax(m)],n)
            return
        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
            return
    MouseParallax([(40,"farback"),(20,"back"),(-20,"front"),(-40,"inyourface")])
            
    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
Borisu
Newbie
Posts: 2
Joined: Fri Apr 29, 2016 2:26 am
Contact:

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

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

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
Andredron
Regular
Posts: 161
Joined: Thu Dec 28, 2017 2:37 pm
Location: Russia
Contact:

Re: Layered Parallax Code

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

Geckos wrote:
Tue Jan 09, 2018 5:07 pm

http://renpyfordummies.blogspot.com/201 ... -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)
            return

        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)
            return

        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
            return

    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
            else:
                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 ()
            renpy.show (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 https://yadi.sk/d/ZX_DonP63USRru Update 22.06.18

KingsCard
Newbie
Posts: 8
Joined: Sat Feb 17, 2018 8:58 am
Contact:

Re: Layered Parallax Code

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

Worked like a charm, thank you very much :)

Post Reply

Who is online

Users browsing this forum: No registered users