I’m currently working on a Ren’Py game with a couple of other people and we’re not quite ready to post about it publicly yet, but I wanted to share some notes on handling variables between states and sessions as its caught me up a little bit!
Supporting Rollback and Save States
I’ve got a couple of classes that handle things like information about the main character and your current relationship with romancable characters. I was setting these up in the init, but it turns out that init variables do not participate in save states or rollback as they are often used for things like the ui.
The solution is to do variable initialisation in a callable label and then run this at start and load time. The hasattr function is used to check if the variable exists, with renpy.store containing every declared variable in the project.
if not hasattr(renpy.store, 'mc') : mc = MainCharacter()
The call in new context function creates a new context where rollback is disabled and save/load still happens in the top level context.
We wanted to have a list of achievements and ending so the player knows how many endings they’ve found. While ren’py does have a built in achievements system, this seems mostly for passing backend data to services like stream.
Instead, I used persistent variables. Adding ‘persistent.’ to a variable name saves it in persistent data, which remains the same between sessions.
$if persistent.achievements_list is None:persistent.achievements_list = 
I can then just add to this list when a player gets an achievement.
$ persistent.achievements_list.append("Started The Game")
Forcing Updates During Runtime
Variables are only checked when changed within the correct scope, which means that a class taking in a variable will only get the value at the point the class instance is created.
This feels hacky, but the accepted solution by the community seems to be to put all the variables that need to be constantly passed around into a screen, as it is forced to updated every frame.
The gersner wave function was made based on this video from the Dreams team. Its a fantastic watch, so I’m just going to pop this here in lieu of going through the graph.
The main change that I had to do to get this into unreal was to replace the loop with repeating the wave function over and over, which causes node spaghetti and makes the system far less flexible.
The bitshifting for the psudo random number had to be done in a custom hlsl node, as there is no other way to convert to int and to bitshift.
I also did the final calculation in a custom node, as it was simpler to read than trying to drag the pins from each variable in. Honestly, its still a mess. I was really missing just writing hlsl at this stage.
Normals and Light Stylisation
I had some issues with normals appearing incorrect, which was eventually was down to some dodgy order of operations and some calculations being done in meters when they should have been in centimeters. Caught out by a couple things when trying to move between code and nodes.
I rounded the normal in order to give a hard edged, toon look to the shader.
To create the smooth line pattern seen in the concept, I created a tiling texture in photoshop with outline on R and color variation on G.
I used the same smoothstep trick as with the gradient to have a color assigned to black, white and midgrey.
To add the outline, I took the black outline on the R channel of the texture and added the outline color to it. I then multiplied this with the lerped color.
In order to make the foam appear on top of the waves, I got the dot product of the surface normal and a vector parameter. This vector was used to control the angle of the foam. This was them multiplied with a noise texture to provide the breakup effect and rounded to keep the toon feel.
The outline on the foam was created by taking the above and creating an inverted version of it, with a slightly smaller wave. This multiplied by the original created an outline. This then hooked into the texture outline to receive the same color.
All together, we get a nice breakup wave effect.
Combine all of this and you get the ocean shader from the original gif!
I wanted the gradient to run vertically across the object, unaffected by the position of the object in world. I didn’t want to adjust my UV map in order to accommodate this, so decided to do my gradient in object space Z. (Unreal is Z up)
I used the ObjectLocalBounds node to get the top and bottom of the object bounds in Z (though I did include a mask parameter so the gradient could be used in other directions), then used a smoothstep to produce a 0 – 1 value between the two.
Three Part Gradient
The reference image actually has three colors in its gradient, and I wanted to get as close as possible. To do this, I had to lerp twice, breaking the initial 0 – 1 coming from my object bounds into two parts.
To do this, I smoothstepped between 0 and 0.5, to map the bottom half of the value range to 0 – 1, then smoothstepped between 0.5 and 1 to do the same to the top half. I then used the first value to lerp between two colors, and the second to lerp between the previous lerp and the third color.
The fresnel effect is very simple, literally just using the fresnel node to lerp between an edge color and the main gradient. This was used to provide the edge highlighting seen in the reference.
For context, the fresnel node does a dot product between the input normal (in this case either a normal map converted to world space or the the world space normal of the pixel) and the camera position to determine whether the surface is facing the camera. Facing returns 0, facing away returns 1, so we can use this to assign a color to faces at grazing angles.
The rocks also use this shader, but forego the gradient and have a normal map input to the fresnel, as well as a very high fresnel amount, giving a shadowed, two tone look.
The aim of the post process was to create an outline around the objects, provide a grainy look and tint the screen color.
There were two approaches I considered for this. One was the kernel based edge detection I used on a project a couple years back, and another was the simpler sampling depth offset technique found in the UE4 stylised rendering example.
Ultimately I went for Epic’s approach, as while it may have been slightly more expensive for the amount of times it sampled depth, it was far simpler to setup and read later down the line. For this project I was really focused on the aesthetic over performance or tech, but I do still like to consider these things.
Determining Line Width
I started off by creating a single line on one side, by by getting the screen uv and offsetting it. I then multiplied this by screen texel size so the offset appears to be the same width, regardless of screen resolution.
Subtracting one channel of this value from the scene depth will give a single line edge, but we want an edge on all sides!
Creating An Outline On All Sides
I then split this offset into its U and V parts and multiply each by minus one, leaving us with four sets of offset UVs, as seen in the image below. These are then used to sample scene depth, which creates four different samples of the depth, all with a slight offset in one direction.
Subtracting these from the initial scene depth then adding them together leaves us with a nice combined outline!
Depth Based Line and Wireframe Fix
With this approach, we start to get the internal wireframe being outlined at distance. As a fix, we take the scene depth, divide it, then take one minus this (as UE4’s depth is flipped) then clamp it. This is the multiplied with the outline. This lowers the outline amount for these faces.
I later added something very similar to the initial outline calculation, where this was multiplied with the result of the texel size multiplier. What this did was take the depth and as the object gets further away, reduces the size of the line. This allowed me to not lose detail at distance and stopped blobby looking outlines.
Putting It All Together
One this outline is created, it is used as the alpha to lerp between the line color and the scene color. Here I’ve multiplied the scene color with a texture and color to add a bit of grain and color tinting.
As talked about in my last post, I’ve been working on some shaders based on work by Owakita. Here’s part two of the breakdown!
I’ve written a number of posts breaking this down, and these can be found here:
Part 1 – Initial Plans
Part 3 – Post Processing Material
Part 4 – Gradient Fresnel Material
Part 5 – Ocean Material
The sky material for this project was pretty simple, as I made a copy of the base sky material found in the construction script of BP_Sky_Sphere, and replaced that reference with the copy.
Inside of that copy, I replaced the scrolling clouds texture with my moon, and the stars with my stars. I also added an additional cloud speed parameter so that I could control the speed of the stars and moon separately, for a nice parallax effect.
The most challenging part here was creating the moon texture. As it has such a large area to cover and is projected over a sphere, I had to get the moon shape in the correct area of the texture and bend it appropriately so that it looked correct on the sky sphere mesh. I got there after a lot of trial, error and free transform!
For the colors, I left the material as is but overrode the light based colouring in the details menu. I then tweaked zenith and horizon color until I got close to the reference image.
That’s all there was to it for the skybox! Next post will look at the post processing effect.
Most of this last week was dedicated to proofreading. This should have been the easiest part of the project really, but having my full dialog script inside of my game code made it quite tough. Spellcheck picked up on a lot of things it shouldn’t and it wasn’t super easy to write in flow when there’s game code dotted about.
It made me think about writing a tool to parse dialog from a text document/spreadsheet into .rpy files. At the very least I think next project I want to think about a file structure that allows me to keep game code and dialog separate.
Overall this game jam was a great experience – I finally finished a game! Its led me to have a bunch more VN ideas, so expect to see more of that in the future. First though…I have a shader I want to write…
I’ve now finished the first draft of the game (which now has a name!), including all art, sound and UI and am now in the process of proofreading and redrafting the script, fixing bugs and if I have time polishing art and audio.
Progress and Cutting Features
In order to get here I significantly cut what I wanted to do with the second act.
Originally, it was going to have a deductive reasoning section where you figured out the riddle in multiple stages, alongside an emotional conversation about the origin and nature of the dreams to potentially open up the second ending. I cut the deductive reasoning section as it involved the most design work and potentially more artwork and kept the emotional section.
While detective kind of puzzles are totally my jam, it seemed the most logical thing to cut as it only fed into a potential death ending. If I somehow have more time at the end of the jam I might resurrect it.
I did most of the last two week work on the Saturdays, as we’ve been really busy with the house. The situation right now has meant we had to try and get everything up and running in our new house as fast as possible, since we’re stuck here. The general anxiety surrounding corona has really not helped my productivity.
This did help me figure out that when all assets have been sourced it takes me about an hour to write a single scene. With each act having around five scenes, it means I’m not too bad for time if I can find a a free weekend afternoon or manage an hour before work each weekday.
Asset Naming Conventions
One thing I noticed that would help speed up/clarify the writing process is better naming conventions for character sprites. I used descriptive names in a common format like I would at work, but I realised that what I needed was not a description of the character and their expression, but for the name to be the exact emotion the character is displaying, so I can easily drop it in while writing. “Elieen_Sad” is actually much more useful than “Character_Elieen_1024_NormalEyes_PoutMouth”. The second name is a bit of an exaggeration, but its not far off names in most places I’ve worked, where we have so many assets that we need to be that precise.
I seem to be throwing all conventions out the window with this project!
On the topic of sprites and expressions, i seem to have settled on an expression change every two lines being about the correct amount for making things feel alive, while not being too distracting.
While I’ve not done anything major with the UI, I thought it was worth noting some of the lines to change for text, as most of the documentation is outdated and styles are split between options, gui and screens .rpy, making them not always easy to find.
I’m taking part in NaNoReno, a visual novel game jam running through March, inspired by national novel writing month. The aim is to make a complete vn in a month.
The game I’m working on is, for now, called ‘Dream Boy’. A rumour is going around town that many people are having the same dream – one where you have to answer a riddle which will reveal the location where you’ll meet your soulmate. Unfortunately, our protagonist finds that these dream riddles are far more sinister, and must solve them, or face a devastating future.
I wanted to talk a bit about my production methodology for this project – this is, basically none at all – as I’ve been incredibly motivated and got far further with this in a week than I have with other full game projects in much longer time frames.
‘Pantsing’ aka ‘I Am Banned From Trello ‘
I’ve approached this project very different to others, in that I’ve effectively planned nothing. I am by nature a planner and am always thinking about two steps ahead of where I’m at, which is great for my day job as a tech artist, but isn’t helpful for doing small solo projects.
Seeing how much needs to be done is completely paralysing and demoralising. For this project, instead of focusing on what needs done, I’m focusing on the deadline, and getting what I can done before then.
I did a tiny half an hour of planning on day one, where I decided on the general theme and scope. Here I decided that the game would be about riddles in dreams and that my minimum working hours for the month was 16, so I had to stick to something small, with no mechanics that aren’t built into ren’py and that doesn’t require any new art or sound – it all had to be bought or downloaded.
So far I’ve worked completely linearly, where I normally jump about and work on whatever I feel like that day. This has kept me motivated, as there’s parts I want to get to, but also got rid of time spent deciding what to work on, and doesn’t leave anything half-done, which is another demotivator.
I’m also avoiding writing down any random ideas I have for sections I’m not currently working on. If its a good idea, it will come back to me. This is very against my nature but working so far!
Once I’d naturally hit my first branching choice, I did a very small diagram for the story branching. It was incredibly simple, and added deaths and two different true endings. Using death as an ending kept scope small, and the different true endings, while based on a variable that is changed based on main branch choices, doesn’t branch itself until very near the end. I don’t intend to do any further planning.
Using Premade Assets
Art is one of the most time consuming and contentious part of development. Because my background is art based, I tend to be a lot more precious over this part of the game which slows my pace.
I also hate seeing placeholder art, because I get frustrated at it not looking good. Having full art in has made me excited to see my game everyday, which is so great!
To make this simple, I chose three artists with a wide library of assets for sale or download, and every time I need something I grab it from one of them. The second I see something I like, I just grab it, and don’t look through everything and deliberate. Usually I’d be totally against this, but treating this as a prototype and not being worried about getting things totally right has really sped things along.
I’ve done the same thing with audio, finding one site that has collections of music and using the first thing I find on there that fits.
I’ve made some edits to art and audio, but nothing that takes more than an hour.
No Complex Code
As mentioned in planning, I’m not using any gameplay that doesn’t come built into ren’py, so don’t need to allocate time for code. On previous projects I’ve tried copying and altering systems from games I like, which while very interesting, tends to push the scope of the project closer to those games, which I obviously can’t do alone.
Not adding functionality also means less debugging, so I can focus on just getting the game done.
I’ve also not spent too long on my puzzle design. They’re very simple, and could be worked out without any assistance from the game. This is probably something I’d completely re-do if taking the game beyond the jam, as if the puzzles aren’t fun I don’t have a game.
Do Something Every Day
Another of the major motivators here is that I’ve worked on it everyday. I’ve been getting up a little earlier and getting in around an hour’s work each morning, so even if things get unexpectedly busy in the evening I’ve still made progress.
The do something everyday rule is often talked about, but can be hard with projects where you have tools or levels that take a long time to load up. Thankfully, the time to start on ren’py is very low, just fire up atom and go. There’s no loading time for testing the game either, which is one of my pet hates!
I’m between 3DS Max licenses at the moment, so it seemed a good opportunity to try and learn blender! This has been so frustrating, but hopefully worth it to learn what is becoming more and more of an industry standard.
This is just a dump of some of the shortcuts and tools I’ve used so far so I can come back to it! Will probably just add to this post as I go.
Ctrl-B – Bevel
Ctrl-R – Edge Loop
S-X/Y/Z – Scale in x, y, or z axis
R-X/Y/Z – Rotate in x, y, or z axis
Tab – Go between edit and object modes
A – Select All
Shift-A – Creation Menu
Object Mode – Ctrl A – Rotation and Scale – Freezes all transform data
Modifier Menu – Mirror
Edit Mode – Mesh – Normals – Flip
Edit Mode – Mesh – Normals – Recalculate Outside
Edit Mode – Mesh – Normals – Average – Custom Normal (Good quick smoothing results)
Negative scale will flip normals randomly, freeze scale then recalculate outside.