How I made a 2D point&click adventure game with Blender

Background

I used Blender to create all the graphics in the game Quantum Derail. The game renders 2d images and sprites on HTML5 canvas, but I made these graphics by pre-rendering 3D geometry on Blender.

I had to figure out a number of things, and I thought I should share the workflow with others in case it is useful. Keep in mind that this is one of the many possible workflows, but it is one that has proven to work for me. This article will focus only on the workflow to produce the visuals for a point&click adventure game, not on the code needed to run the game. For the coding part I wrote a separate article.

I should mention first that I rendered everything with cycles, although the style is a bit cartoon-ish, but with realistic lighting.

Backgrounds and foregrounds

I’m going to focus first in the non-animated layers of the adventure game. The static background and foreground elements, which define every room of your game.

Background (with foreground included):

Background

Foreground:

Foreground

One of the things that you need to think first is which elements are rendered behind the player avatar (backgrounds) and which ones are rendered on top (foregrounds). You can have more layers, and have some that show sometimes behind and sometimes on top, but that complicates the code a bit, so think carefully if you want to deal with that.

What you can’t have is a single object with parts that show behind the avatar and parts that show on front. If you want to create that visual effect, you have to break the object into separate pieces, because the foreground and the background parts have to be rendered separately.

There are a number of ways you can organize the layers for rendering. A simple way is to use blender layers and switch them before triggering a render. I will discuss another approach later that supports automation (multiple scenes per file).

Another consideration is how to set up the camera. The best integration with moving sprites would be achieved by using an orthographic camera, but that would not be very interesting, so perspective cameras will look much better. You might need to make sure that the background doesn’t get too distorted with impossibly wide rooms, because towards the edges the avatar of the player will not be distorted in the same way and it will look terrible.

Sprites

If you are creating any kind of game chances are you already know what a sprite is. In essence, it is a sequence of images with transparent background that can be rendered in your game one after another to produce an animation effect. Like an animated GIF.

Sprite

Depending on the constraints of your adventure game, you can balance between having sprites be specific to rooms or have them generic and reuse them in all rooms. For example, in my game I used generic sprites for the main character, that I reuse in every room, and specific sprites for other characters.

The reason it matters is lighting. If you want your sprites to be really well integrated into the room, you want to render them inside the room, with the same set of lights and backgrounds, so that light can bounce properly.

But if you (like me) are constrained by the size of the game, then you might choose to make some of the sprites generic, render them with neutral lighting, and hope they will somehow integrate in all the rooms where you use them.

See the difference in the following image. On the left, the protagonist of my game using the generic lighting, which doesn’t integrate at all with the dark lighting of this room. On the right, the same sprite rendered with integrated lighting:

Difference when integrating a character

Looping sprites that move

Stay away from sprites that move and loop as much as possible, because they are painful to set up in general. However, for the player avatar there is no way around that. Its walk cycle loops and has to move.

Here is what you need to do to have a moving sprite that loops nicely and doesn’t show glitches when the animation starts over:

  • You need to have the initial pose twice: at the beginning of the animation and again after the last frame of the loop. If you do this, you will be able to check that it looks identical, and the animation is going to loop nicely. I even recommend rendering both, so that you can debug glitches by comparing these images.
  • This is up to you, but if you want to avoid sliding feet, you might want to have the character physically move as it walks, so that you can check directly in blender that the feet are pinned while holding the weight. If you don’t care about sliding feet, you can make the character walk in place and avoid the following steps.
  • The camera has to follow the character as it walks. It may be tempting to leave the camera static and use the pixel movement to estimate how many pixels the character has to move per frame, but if you use a perspective camera, the character will be projected differently as it moves, and you will have glitches.
  • Same as the camera, the lighting rig also has to move as the character walks. Otherwise, the first and last frames will be lit slightly differently, and you will also have glitches.

Render in the room without the room

One of the problems you will have to solve is rendering your sprites inside the room (so that they get the correct lighting), but not render the room itself. That can be solved with mask layers. These layers are used for bouncing light, but they don’t display in the final rendered image:

Setting up mask layers

Another problem is having transparent backgrounds. You can set that up in the main render options:

Transparent rendering

Shadows in sprites.

Another problem you will probably find is shadows. This applies both to generic sprites and specific ones, although on generic sprites it is a bit fake, since you don’t know where the lights will be.

In any case, this will be much much easier if you can use Blender 2.79 or later, because it introduces the concept of the shadow catcher. This option was introduced for easy integration of CGI objects over real images, but it is super handy for sprites too.

First, you need to create a clone of the parts of the background where you expect the sprite to cast shadows. I typically join them all in a single mesh, and simplify the mesh by removing parts far away, to speed up rendering. You might also need to move that mesh a bit so that it rests over the background objects, otherwise they might be occluded.

Then you enable shadow catcher in that cloned mesh:

Shadow catcher

The last part is to set up compositing nodes to mix the sprite with the shadow. You could also try and render the sprite and the shadow catcher in the same layer without using compositing, but it is very likely that you won’t like the results right away and it is really hard to tune this way. Here are the steps for the compositing:

  1. Put the sprite in one render layer, and the shadow catcher in another. Render layers
  2. Create a compositing tree that combines both render layers as you wish.

Here is the compositing tree I’ve been using. I created a group node with the standard setup so I could import it in all the scenes:

Shadow composition

Here is a brief explanation of that tree:

  • Character is the sprite that casts the shadow.
  • ShadowAlpha is the alpha channel of the shadow pass. That’s what we will use for computations, instead of the shadow map.
  • ShadowZ is the z channel of the shadow pass. It is required for compositing correctly with the background if the sprite or its shadow is partially occluded.
  • BuildingZ is the z channel of the stuff that can occlude your sprite. If nothing occludes it, just set it to a large value.
  • The brightness/contrast node is there just to fine-tune the shadow. If it is too strong you can tune it with the brightness, and if it is too large, you can tune it with the contrast.
  • The set alpha node produces a new translucent black shadow map.
  • Z Combine clears the parts of the shadow that are occluded.
  • The final Alpha Over node combines the sprite with the shadow into a single image.

Dynamic lighting of generic sprites

Dynamic lighting is a strong word, perhaps I should call this technique hacked lighting, because it is a big hack.

The avatar of the player uses generic sprites. That means I reuse the same sprites in every single room. But each room has different lighting, with significant changes in the color of light in some cases. If I use the exact same sprites unchanged in all rooms, it doesn’t integrate at all. See the images on the left in the following two examples:

Difference when integrating a character
Difference when integrating a character

The trick I used is to tint the sprites based on the color of each room.

Initially, I tried just extracting a key color for each room and tinting the sprite at runtime(multiplying pixels by that color). That already improved the integration dramatically. But there are a few rooms where there are strong lamps, and it is a bit sad that the character doesn’t get influenced when walking below those.

To improve integration even further what I did was extracting a lightmap for each room, directly from blender, and using that lightmap to tint the character dynamically, as it walks around the room (by reading the pixel in the lightmap located right between his feet).

Dynamic lighting

Generating that lightmap is really easy, it is just a matter of adding yet another layer with a single large quad, and let it be influenced by lights and walls. I render it just like sprites, and then use an image editor (GIMP in my case) to extend it a bit so the avatar doesn’t go black if it walks too close to a wall.

Multiple scenes in the same file

This technique was used to address the following issues:

  1. In some cases it was convenient to have more than one room in a single blender file. For example, for the front and back of the station. You can have multiple cameras in the same scene, but they must all have the same aspect ratio. That is a problem in adventure games with side scrolling, because some rooms might scroll more than others, and thus require a different aspect ratio.
  2. I wanted to be able to render the background and the foreground without having to manually switch layers, because I was making mistakes and wasting render times.
  3. Related to #2, I also wanted to automate rendering. That is, launch all the renders from the command line, so I can leave them running overnight.

One option that I tried for #1 was creating a master scene for the station model and then linking that scene from two other scenes for the front and the back specifics (the camera and aspect ratio). That quickly got annoying because I had to switch back and forth between scenes to do small tweaks. For multi-person teams where one person does modelling and another does rendering, that setup might be convenient, but for me it wasn’t.

Besides, that approach with linked scenes was also very annoying for foreground/background splits.

So in the end I learned that a single blender file can contain multiple scenes, and have objects linked internally. Each scene can have its own aspect ratio and cameras, even some specific objects if you need to optimize render times, so that was the approach I followed.

Multiple scenes per file

This approach proved so convenient that I ended having lots of scenes per file. Essentially, one scene for each image or sequence of images I wanted to render.

Automated rendering

I work in Linux, so I’m quite comfortable with Makefiles. What I did was to write a simple python script for blender that extracts the list of scenes and generates Makefile rules, and then just run make from the console to trigger all the renders. The advantage of using a build system is that it understands dependencies and will only re-render some image files if the blender file they depend on has changed. Given that it takes a full night to render all the graphics of Quantum Derail, it is important to avoid rendering scenes that weren’t modified.

Sprite sheets

If you are not familiar with this step, it turns the sequence of images produced by Blender when rendering sprites (you should output images, not video files) into a single image with all the frames inserted in a mosaic.

Spritesheet

This part was the easiest. Turns out there is already a tool called montage (part of ImageMagick) that does most of the heavy lifting. Here are the useful command line options:

montage -geometry +0+0 -background none $filenames /tmp/__montage.html

That HTML file you specify at the end is an image map, and I just use it to know where the tool decided to place each frame, so I can use it from code. It would have been more convenient for me if it was JSON, but parsing that HTML is not that hard. Here is a regular expression you can use from nodejs:

javascript
const regex = /

About quantum derail

The game will be available from Feburary 15 2018 on itch.io. In the meantime you can check out the trailer and screenshots at https://quantumderail.com.

Did you find this article helpful? I could use your help to reach many gamers. When you support my daycause campaign, you will be posting an update in your social network on the day of the launch at the same time as everyone else. Let’s make a big splash!

Anuncios

Acerca de Rubén L.

Software Engineer
Esta entrada fue publicada en English y etiquetada , , , , , , , . Guarda el enlace permanente.

5 respuestas a How I made a 2D point&click adventure game with Blender

  1. I I the only thing that I can help is in 3d design and css (html)

    • Rubén L. dijo:

      Thanks! The game is almost complete. I need help raising awareness, which is why I created the daycause compaign above. Daycause is similar to kickstarter, but instead of money, you contribute with a social post on one of your social networks. The daycause system already does that for all the supporters exactly at the same time.

      I know it might be scary to let a random system post for you, so if you want to post yourself a link to the game, that’s also super helpful!

      Thank you!

  2. Hello Ruben,
    congratulations for your game! I’m very happy to find a person creating such a game in blender. I grew up playing old school p&c adventures and always wanted to create one. I consider myself good in blender and i’ve put some effort on writing a story and modeling some sprites for my game. My question is have you tried BGE instead of creating your own engine? If yes why not use BGE? One other thing. Is your engine available for other users to utilise?
    BR,
    Billy

    • Rubén L. dijo:

      Hi Billy,

      Thanks for the comment! I hope that your game is successful. Do you post development updates somewhere I could follow?

      I tried BGE in the past and it’s awesome. I’m convinced it would be more than enough for this game. I know “creating your own engine” is a taboo in the games industry, and I would never make my own engine because “it’s better than X or Y” or “I miss feature X in BGE or Unity”. The reason I went with my own engine is that this is pretty much the part of making a game I love the most. In a way, making a game is an excuse to make an engine, for me 🙂 I know it feels backwards, but I wouldn’t be able to keep the motivation if I was using someone else’s engine.

      My engine is not publicly available at the moment. I have been thinking about open sourcing the reusable parts, but there are so many open source game engines already that I’m not sure it’s worth adding more noise to github…

      I’m finishing an article on the design of the engine. If I see many people interested in the design choices I made and accessing the code, I might revisit the idea of open sourcing it.

    • Rubén L. dijo:

      Hi Vasilis,

      Although I haven’t published the game engine, I did publish yesterday the engine I used for the first prototypes. The game prototyping space is not so crowded so I thought it might be useful to others. It’s really simple, and aimed at getting early feedback on the concept of the game.
      It’s available on github here: https://github.com/rubenlg/quaderno

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s