A physical Platformer
Videoblog #6: Click here
You can download the Platformer Example here. It contains a project template that will set up the example project from the video. Just use it to create a new project.
Today I’m going to show you some new or improved features and how to develop a simple platformer.
One of the things I’ve recently improved is the smooth animation system. Instead of regular frame-by-frame sprite animation Duality is also able to blend smoothly between animated frames by using a special shader. This will make your animations look more fluent, especially when few frames are available. In that case, the difference becomes obvious, while on high frame rates it might just make it look a little nicer.
In my first approach, I was simply using a linear blend between the current and the next animation frame. However, this would introduce visible artifacts in all pixels that are fully transparent in one frame and fully opaque in the other. In a simple linear blend, the transparent pixels color would bleed into visibility because they’re mixed with visible pixels.
This unwanted behavior was fixed by introducing some more lines to the shader code that will weight each pixel colors total involvement by their transparency values relative to each other. If there is a pixel visible in one frame and invisible in the second, it will simply fade in or out without changing its color at all.
So let’s begin with our example platformer. Click on File / New Project to bring up the new project dialog. By default, Duality can create and empty project or one based on the currently opened one. It is also possible to use a custom configuration by clicking the “Browse” button next to “Project Template”. The download package comes with an example template in case you want to try it out. However, we’ll go with “Empty Project”. Duality now creates a new project folder, applies the selected template and updates the required binaries.
First we’ll need a player character. I’m going to import a simple sprite sheet by dragging its file into the Project View. A new Pixmap Resource will appear. Right-click on it and select “Create Texture”, then select the new Texture Resource and adjust its number of animation columns and rows to fit the image. You can check the per-frame preview to if the values you entered made any sense.
To see it in action, just grab Pixmap or Texture and drag it into the Cam View. Duality will create a new GameObject for you. Now enter the sandbox mode by clicking the “Play” button above. You will see animation playing in its default configuration. If you want to take a closer look, use the mouse wheel to move the camera closer. Press it and move the cursor for regular 2D camera navigation. Because we’re now viewing an upscaled version of our character, it looks a little blurry. To achieve a pixelated look, selected the Texture Resource and set its interpolation mode to “Nearest” instead of “Linear”.
The player animation is currently running through all available frames. Let’s change that to use a walk cycle in one direction. Select the player GameObject and open the sprite Components tab. Set the AnimFrameCount property to three, which is the length of a single walk cycle in our sprite sheet. You may also set the first frames index to change directions or adjust the animation speed.
However, something doesn’t look right yet. Our character walks a little.. strange. A quick look at the sprite sheet reveals that we’re using the wrong animation type for it. To fix that, select the GameObject again and change the animation mode to “PingPong”. It should look much better now.
To improve it a little further, you can activate the smooth animation feature. To do that, select the characters Material Resource and change its rendering technique to one from the SmoothAnim folder. As always, just use dragdrop.
The following step is entirely optional, but illustrates a concept that will prove to be useful in the future. First, stop the sandbox mode. Then, click the player character GameObject and drag it into the Project View. This will create a new Prefab Resource of our player object. You can think of a Prefab as a global template for objects that will exist multiple times throughout the level or game – like enemy characters, powerups, etc. An immediate advantage is that it’s very easy to create new instances of a prefab object programmatically. The next big advantage is that prefab instances maintain a link to their Prefab and will be updated when you modify it globally. That way, you can change an enemies hit points globally instead of individually for each enemy.
I’m now fast forwarding a little because what you can see here is nothing new: Just importing sprites for back- and foreground and creating some GameObjects out of them via dragdrop. After finishing a first level setup, click the “Save” button in the Scene View to save it. A new Scene Resource will appear in the Project View, which I’ll rename to FirstLevel.
Of course we’ll also need some kind of collision detection. To allow physical interaction between our objects, they will need a RigidBody Component. Right-click on the world object and select New / Physics / RigidBody. Then open the RigidBody tab and set the BodyType property to “Static”. This will assure our level affects other physical objects without being affected itself. Next, open the RigidBody editor and define the objects shape. After doing the same for the player character, you can hit the “Play” button and see how they interact. If you want to drag the object around, don’t forget to switch back to the Scene Editor.
I don’t want this video to get too long and I’m really running out of time, so I’ll just fast-forward the following while talking a little about the theory: There is more than one way to create a platformer and Duality doesn’t really favour any specific way. In this example, which will be included in the download as a project template, I’m taking the 100% physics-driven approach. A character is constructed out of two objects like you can see in this scheme. The upper part is a fixed-angle RigidBody which is joined to its lower part using a RevoluteJoint. This kind of joint allows the lower part to rotate freely while maintaining a constant relative position, like a wheel. A RevoluteJoint also allows us to apply a rotational motor force to that wheel – and that’s basically how our character will move. It’s one of the more physically correct approaches, so it will be more suitable for a Limbo type of game than a Super Mario clone.
In matters of programming, there isn’t really much work. All the character controller needs to is check the keyboard input and adjust some Component properties according to it and that’s basically all it takes to walk around. Jumping isn’t more complex either. Although it’s not a big deal of setting up the basics for a physical platformer, I found out one disadvantage of it to be very hard to maintain. It takes a lot of balancing, property adjustments and little hacks to make the platformer controls actually “feel” good. But still – although not quite easy to handle, physical simulation also remains the main advantage of this approach, because it allows you to incorporate physical puzzles, enemies or other gameplay elements seamlessly. But I guess the best advice is to acquire your own experience.