Skip to content

Instantly share code, notes, and snippets.

@midgethetree
Last active April 11, 2024 18:41
Show Gist options
  • Save midgethetree/b449be114f21974ed21b3fbf3653433f to your computer and use it in GitHub Desktop.
Save midgethetree/b449be114f21974ed21b3fbf3653433f to your computer and use it in GitHub Desktop.
Parallax code for the Ren'Py visual novel engine.
python early:
class ParallaxLayer(renpy.Displayable):
def __init__(self, child, xmotion, ymotion, replaces=None, **kwargs):
super(ParallaxLayer, self).__init__(**kwargs)
self.child = renpy.displayable(child)
self.xmotion, self.ymotion = xmotion, ymotion
x, y = renpy.display.draw.get_mouse_pos()
self.get_targets(x, y)
if isinstance(replaces, ParallaxLayer):
self.x, self.y = old_widget.x, old_widget.y
else:
self.x, self.y = self.target_x, self.target_y
self.st = 0
def render(self, width, height, st, at):
if self.xmotion:
xspeed_mod = 2 * (st - self.st) / self.xmotion
self.x += (self.target_x - self.x) * xspeed_mod
if self.x < -self.xmotion * width:
self.x = -self.xmotion * width
if self.x > 0:
self.x = 0
if self.ymotion:
yspeed_mod = 2 * (st - self.st) / self.ymotion
self.y += (self.target_y - self.y) * yspeed_mod
if self.y < -self.ymotion * height:
self.y = -self.ymotion * height
if self.y > 0:
self.y = 0
self.st = st
rv = renpy.Render(width, height)
child = renpy.render(self.child, width, height, st, at)
rv.subpixel_blit(child, (self.x, self.y))
if self.target_x != self.x or self.target_y != self.y:
renpy.redraw(self, 0)
return rv
def event(self, ev, x, y, st):
old_x = self.target_x
old_y = self.target_y
self.get_targets(x, y)
if old_x != self.target_x or old_y != self.target_y:
renpy.redraw(self, 0)
def visit(self):
return [ self.child ]
def get_targets(self, x, y):
self.target_x = -x * self.xmotion
self.target_y = -y * self.ymotion
def _parallax(child, **properties):
xmotion = 0
ymotion = 0
if "motion" in properties:
xmotion = properties.pop("motion")
ymotion = xmotion
if "xmotion" in properties:
xmotion = properties.pop("xmotion")
if "ymotion" in properties:
ymotion = properties.pop("ymotion")
return ParallaxLayer(child, xmotion, ymotion, **properties)
renpy.register_sl_displayable("parallax", _parallax, None, replaces=True) \
.add_positional("child") \
.add_property("motion") \
.add_property("xmotion") \
.add_property("ymotion")
class ParallaxSprite(renpy.Displayable):
def __init__(self, child, xmotion, xpos=.5, xanchor=.5, **kwargs):
super(ParallaxSprite, self).__init__(**kwargs)
self.child = renpy.displayable(child)
self.xmotion = xmotion
self.x = 0
self.target_x = 0
self.st = 0
self.xpos = xpos
self.xanchor = xanchor
def render(self, width, height, st, at):
x = renpy.display.draw.get_mouse_pos()[0]
x *= -self.xmotion
if x != self.target_x:
self.x = x
self.target_x = self.x
xspeed_mod = 2 * (st - self.st) / self.xmotion
self.x += (self.target_x - self.x) * xspeed_mod
self.st = st
if type(self.xpos) == float:
xpos = width * self.xpos
else:
xpos = self.xpos
child = renpy.render(self.child, width, height, st, at)
cw, ch = child.get_size()
rv = renpy.Render(width, height)
rv.subpixel_blit(child, (xpos - cw * self.xanchor + self.x + width * self.xmotion / 2, height - ch))
if self.target_x != self.x:
renpy.redraw(self, 0)
return rv
def event(self, ev, x, y, st):
if ev.type == pygame.MOUSEMOTION:
if x * self.xmotion != self.target_x:
self.target_x = -x * self.xmotion
renpy.redraw(self, 0)
def visit(self):
return [ self.child ]
image eileen happy = ParallaxSprite("images/eileen happy.png", .05) # 5% of 1920 is 96, so that's how many pixels this sprite will move if you drag your mouse from one side of the screen to the other
image eileen vhappy = ParallaxSprite("images/eileen vhappy.png", .05) # you should keep the xmotion consistent for sprites of the same character
define e = Character('Eileen', image='eileen')
screen parallax:
layer 'master'
parallax "gui/main_menu1.png" motion .05 # main_menu1 is 1.05 times the game's resolution - eg. for a 1920x1080 game, this is 2016x1134
parallax "gui/main_menu2.png" motion .1 # main_menu2 is 1.1 times the resolution, eg. 2112x1188
parallax "gui/main_menu3.png" motion .2 # 2304x1296
label parallax:
show screen parallax
show eileen happy
'Move your mouse around and notice how the background and sprite move with it.'
'The dialogue can advance without any weird jumps.'
e vhappy 'And the parallax sprites can have their attributes changed just like normal sprites.'
return
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment