post

How to set up a panning system (like Danganronpa) in Ren’py

For my next release, Serafina’s Crown, I want to use the programming knowledge I’ve accumulated from my first two games to add a lot of fun and new features to the experience. One really big thing I wanted to add was a scene in a large room that pans from one character to another, sort of like the game Danganronpa. But if you’ve ever used Ren’py, you know that setting this up isn’t easy.

Picture something like what’s in my picture above, but zoomed in so only one character shows on the screen at a time. Sounds simple, right? But this is actually difficult to achieve in Ren’py if you want to keep your characters dynamic (changing expressions or moving if needed).

I went to the Ren’py forums for help, and they suggested I try using the layer systems. It required a lot of tweaking, but I finally got it to work. So I thought I would share my system here in case anyone else finds it useful.

For reference, my background is a 5000 pixel-wide layer. My characters are sized 800 x 1200 pixels. The screen size of my game is 1280 x 720.

First, I defined my own layer called pan in the options script:

Code:

init -1 python hide:

config.layers = [ ‘master’, ‘pan’, ‘transient’, ‘screens’, ‘overlay’ ]

Then I defined camera angles and character placements using transforms in my own init code. This part required a whole lot of trial and error. The “a_characters” position the overall layer, or camera angle; the “p_characters” place the character on a certain point. For some reason, the xpos needed to be very different for each, even though you’d think they’d be the same. But these are the coordinates that worked for me:

Code:

init python:

def cameraMove(x):

global currentX
currentX = x
return currentX

transform a_center:

xpos currentX
linear 0.4 xpos -1700 yalign 0.0
cameraMove(0)

transform a_Arken:

xpos currentX
linear 0.4 xpos 0 yalign 0.0
cameraMove(0)

transform p_Arken:

xpos 50 yalign 0.0

transform a_Serafina:

xpos currentX
linear 0.4 xpos -1250 yalign 0.0
cameraMove(-1250)

transform p_Serafina:

xpos 1400 yalign 0.0

transform a_Reuben:

xpos currentX
linear 0.4 xpos -2000 yalign 0.0
cameraMove(-2000)

transform p_Reuben:

xpos 2200 yalign 0.0

transform a_Kendal:

xpos currentX
linear 0.4 xpos 1700 yalign 0.0
cameraMove(1700)

transform p_Kendal:

xpos -1450 yalign 0.0

I created the function cameraMove(x) so that I would have a global variable keeping track of the camera’s location. Otherwise, when the camera panned from one direction to another, it would always start at the center and *then* pan to a character (very headache-inducing). This way it’s a lot smoother each time.

And finally, here’s the code I use for the scene itself:

Code:

label Duma:

$ currentX = -1700

with None
show Arken onlayer pan zorder 1 at p_Arken
show Serafina at p_Serafina onlayer pan
show Reuben at p_Reuben onlayer pan
show Kendal at p_Kendal onlayer pan
show Duma onlayer pan zorder 0 at a_center behind Arken, Serafina, Reuben, Kendal
with dissolvea “Praise be upon the gods; praise be upon Darzia. I call to form a special session of the Royal Duma of Queen Belatrix Grandil… who can no longer preside, may she rest in peace.”
a “Members of the Petit Duma, please announce your presence.”show layer pan at a_Serafina
s “Serafina, of House Elborn.”

show layer pan at a_Reuben
r “Reuben, of House Jeridar.”

show layer pan at a_Kendal
k2 “Kendal, of House Terrace.”

show layer pan at a_Arken
show Arken 2 onlayer pan at p_Arken
a “May it be heard …”

And there you have it. The camera pans around the room from one character to the next.

I noticed that while using the layer system, you need to mention the layer and sprite placement every time (hence I couldn’t just say “show Arken 2” when he changed expressions; I needed to say “show Arken 2 onlayer pan at p_Arken.” But if it works, it works. So I’m just excited I’ll be able to pull this off!