This week, I'm going to write a brief technical devlog on how I have set up volume control options in Monumental Failure. Let's first show our final result.
Pretty typical sound options eh? In my implementation, the SFX and music channels can be affected individually, and the master will affect them both. I've also made the decision that 70% volume will be "normal", allowing the user to both decrease and increase volume.
Our first step is to create an Audio Mixer.
The audio mixer will have 1 group to start, I have named mine "Master". I then create two subgroups called Music and SoundEffects. You of course can create more groups as you need. For each group, you must expose the volume variable to script by right clicking and selecting Expose.
I'm not going to give details on how to do this next step, but there are two things you need in your scripts. The first is a reference to each of the AudioMixerGroups in your AudioMixer. This lets you set the volume variable you just exposed. The second is to ensure when your game plays audio, it is routed to the appropriate AudioMixerGroup. I solve these problems by having an audio controller class that stores references to the AudioMixerGroups. When I want to play a sound my scripts call a method in the audio controller which assigns the appropriate AudioMixerGroup.
The final step is translating the percentage in the Options menu into a value for volume. You will have noticed that the AudioMixerGroups have volume which can be set from -80 to +20 decibels. Decibels create a problem. Decibels work on a logarithmic scale, which means +10 is loud, and +20 is really really loud. Similarily anything below about -40 is nearly inaudible. How do we choose what decibel values our volume percentage translates to?
My solution starts by declaring a minimum DB, maximum DB and normal DB percentage (70% as mentioned above).
const float MAX_DB = 10f;
Here's where it gets a little ugly. I have a method that passes in a volume percentage as a float between 0 and 1. If that value is greater than my default percentage, I'll linearly interpolate between 0 and my max volume, otherwise, I'll use a circular out interpolation to find a value between 0 and my minimum volume.
public void SetMasterVolume(float iVolume)
Perhaps if my memory of how logarithmic scales work I could find a method better than this ugly code, but sometimes you just have to go with what works. Let me know if you have a better solution, or if my solution helped you!
This week I worked on adding a cooperative play mode to Monumental Failure. If you have 2, 3, or 4 local players, you can play through any level together, working on a single monument. Fun! I've mentioned before that I've been borrowing from local multiplayer game design, I thought today I'd take a moment to discuss why.
There's a game interview podcast I listen to where the host routinely asks the guest "what game has made you laugh?" I think there's a lot of insight into the state of comedy and games contained within this question. Asking it to myself, I'm immediately tempted to list the comedic games I've played. Games with good writing, absurd premises, and silly designs. Games like Just Cause, Octodad, or Jazzpunk. Funny games. While I have huge respect for design and achievements of those games, I feel that if I'm being honest with my answer, I can't really say these games made me laugh. Maybe a chortle here, a snicker there, and plenty of wry smiles, but never the full gut busting laugh.
For me, the games that make me laugh most are the games I play with my friends. With my friends, in the same room, specifically. Certainly there are the games designed to elicit comedy, something like Gang Beasts or a Jackbox game. But beyond the explicitly comedic, there is so much comedy to be found in the stories a game tells. Think of the comeback earned by a bullshit weapon pick up, the assured mutual loss ("I can't win and so you won't either"), getting hilariously screwed out of sheep in Catan, or whatever other story the game might tell. In the right context, with the the right friends, you have the potential not just to laugh, but create lasting memories.
Monumental Failure is supposed to be funny. From my experience, the way I can guarantee the humour resonates is to encourage playing it with friends. Be it competitive, cooperative, or maybe even asynchronously via a stream or video. Accounting for all the local multiplayer options guarantees more work for me, but I'm confident it will pay off.
Thanks for reading,
Happy Halloween! For this week's devlog I figured I would write the third installment of "Things I Use To Make This Game". Find the first installment here, and the second here. I have really enjoyed highlighting the tools that make my game development life easier, and hopefully it helps other devs too.
Kenney Nature Pack. I'd be surprised to learn of a game dev who hasn't seen that great work Kenney is doing, making free game art for anybody to use. As I move forward with locking in the visual aesthetic of Monumental Failure, having a bunch of low poly nature models ready to go is super valuable!
Unity3D - Simple Finite State Machine (C#). Finite state machines are extremely useful tools in game development, and a fundamental idea in computer science. It's with great irony that most programming languages don't easily represent state machines. Simple FSM does all the hard work, and you're left with a state machine that follows the same patterns of a standard Unity Monobehaviour. If you're a Unity programmer and need a finite state machine, this is the solution.
Probuilder. Probuilder is a mesh editor that runs inside Unity. Most of Monumental Failure has been prototyped using cubes and cylinders and every other basic shape built in to Unity. Probuilder let's me construct a mesh right on top of my prototypes, right in Unity. Very useful!
That's it for today. Maybe you can use one of these tools in your own project. Thanks for reading.
Last night Monumental Failure passed a significant milestone -- all the levels that will be included in the initial release are now done! Well, sort of... I still have several passes of game play and graphical polish to do, but none the less, we're getting there! Today I'm going to discuss some ideas that initially didn't work, and the solutions I found to make those bad ideas good.
I was inspired by the design from this Mario Party 2 mini-game to challenge the player to stay on top of a cylinder. The constant shuffle and adjustment left and right should be an interesting challenge. Well, unfortunately for our physics driven game, once you started to tip a little bit, it wasn't long before you tipped a lot. Loss was too sudden. The solution? Conveyor belts, alternating between pushing you left and right meant you had to readjust, and if you got pushed all the way off, well, you probably saw it coming.
I had designed this crazy crane vehicle to be used in the Bayon Temple level, and for a long time it was one of the most confusing and glitchiest aspects of the game. At the start, the characters were physics objects standing within the vehicle. While it seems like physics objects would be in the spirit with the rest of the game, the result was that your character couldn't consistently press the buttons to make the vehicle go, and worse, they could get bounced right out of the vehicle. Oops! The solution was to simply make the characters part of the vehicle, rather than making them physics objects.
When building the pyramid, you will have to traverse some crumbly stone columns that tip over, that ultimately help you get to your destination. The initial prototype used some green cylinders to represent these tipping platforms. When Jess tested them out, she didn't realise they were tipping and attempted to hop from one to another, and it didn't work and she was frustrated by it. The solution here was to better visualise that something was happening. Green cylinders got replaced with craggy, wiggling rocks. Particle systems create dust when the tipping starts. Crumbling sounds play, ending with a good thud when the tipping is done. The behaviour was then obvious.
Those are just a few of the tweaks I've made up till now, and like I mentioned above, there's bound to be a few more. Given that the level design is inherently antagonistic to the player, it's important that the challenge is clearly communicated, and that failure clearly feels like a fault of the player. Simply put, I need to create a fair game.
Thanks for reading,
The design of Monumental Failure is hugely influenced by the design philosophies of local multiplayer games. That doesn't mean it's exclusively multiplayer, you can play it solo, no problemo! But, let's say you have some friends over, maybe you'll have more fun if you split the screen and fail together!
Anyways, one of the design ideas we are appropriating is character customization. In a multiplayer game, getting the player to customize and familiarize themselves with their characters imbues an immediate connection with their characters. This is especially helpful to combat the "I was looking at the wrong character/screen" problem people often experience with local multiplayer games.
When I started working on implementing character customization I wasn't sure how I would introduce the user interface required to allow the player to set their customization. I started with examining what the player could be customizing.
We have 4 different character bodies, and while it would be possible to let the player pick which one to use, I use the different body types to help clarify gameplay elements within the levels. This means the player won't choose body type and will instead be customizing the whole "team" of characters.
The characters have three attributes that can be swapped around, their skin color, their clothes color, and their hat. It felt important to us that the characters' skin colour stay relevant to the culture they are representing. That leaves us with just the hat and clothes colour to customize.
Conventional wisdom would suggest that character customisation happens right around the time a player "presses START to join". This doesn't really make sense for Monumental Failure. Loading four characters in to a menu would make for a pretty crowded user interface. Additionally, not knowing your characters skin tone until you load a level would provide ambiguity to the characters finalised look. Not ideal for would-be fashionistas.
This implies that character customization should happen after the level has been chosen, and if the screenshots haven't made it obvious, that's exactly what I did!
This provided the additional benefit of having a pleasant character vignette to introduce each level, and even better, introduced a "Ready Up" feature. When the level loads, you have to press a button to start instead of being thrust immediately in to the gameplay. Honestly, that sounds like something I should have introduced a while ago :-P
I always find it to be a rewarding experience when the solution to a design problem is arrived on by this kind of deduction. Using design constraints and philosophies brought me to a unique solution for Monumental Failure's customization problem. A solution with benefits greater than the problem it solves.
Thanks for reading,
One of the challenges you'll navigate in Monumental Failure is steering characters who have roll around on giant balls. In this blog post, I'm going to walk through the implementation of such a character with a specific focus on how to correlate the character's speed to the ball's rotation. Let's take a look at the final product first.
In Monumental Failure, the characters a typically composed from a single rigidbody and a few primitive colliders to represent their physical form. In the case of the ball riders, they are represented by a capsule for the human, and a sphere for the ball. The animated components, the human and the ball, are rotated as child objects while the parent rigidbody has a frozen rotation.
When we animate this character, the result should be as follows: the character faces forward, the ball rolls forward, and the character walks backwards, implying they are rolling the ball forward. Facing the character the right way and getting them to walk backwards are trivial problems already implemented in other levels.
It took me a bit of trouble to figure out what was the best method to rotate the ball graphics object (remember it is a child of the top level rigidbody). The best way was simply Transform.Rotate, passing Space.World as the relativeTo parameter. The code is something like:
public GameObject sphere;
And the result is:
Not bad right? Take a closer look though, a little slidey maybe? Hmmmm. Be suspicious of my code above, I'm rotating stuff in FixedUpdate and not using Time.fixedDeltaTime. Something must be amiss!
At this point we've simply got lucky that our character's speed was close to the amount we need to rotate by, but it's not accurate!
We can do better!
What we want to do is exactly correlate the character's speed to the rotation of the ball. If we multiply the character's velocity by the fixed delta time, we will get how far the character has traveled in the last frame. To correlate that distance to an amount of rotation, we simply use the circumference of the sphere to figure out how many degrees we need to rotate per unit moved. For example, if our circle has a circumference of 4 units, and our character has moved 1 unit, we would rotate 90 degrees. Easy!
public GameObject sphere;
Not bad eh? I hope this bit of behind the scenes tech talk was interesting, or maybe even helpful!
Thanks for reading,
Last night I attended the monthly Unity User Group meetup here in Toronto (shout outs to Adam for organising and Uken for hosting). This month, a few of the boys from Blue Isle Studio did an informal postmortem of their newly released game Valley.
The presentation was great. The guys demo-ed the game to the room, showed how those scenes were reflected in the Unity editor, and shared great thoughts on design and development. I am now super duper looking forward to biting into Valley this weekend. It's basically got Tribes' skiing. And grapple hooks. And double jumps! And set in Canada. And has cool sprite buddies. And spoopy government facilities. And and and...
When it came time to ask questions, I seized the opportunity for some insight on marketing. The question I asked was, "Was there any one marketing move you made that provided the most return?"
The answer was a simple "no". Instead, they responded that one of their marketing failures was miscommunicating the size of their studio. Valley is a game that looks so good, the fact that it was made by less than 10 people is lost on the audience. The game didn't have a personal touch associated with its promotion. They felt this hurt the game's reception.
While we've tried to create our own branding and marketing for Monumental Failure, neither one of our two-man team here at Scary Wizard Games is a marketing expert. Hopefully we can take some of the lessons learned from Blue Isle Studio and make sure we push our small studio status. Maintaining this dev log has been our attempt so far at making our studio more personable (as are the pictures of our dog on Twitter), but only time will tell if we've succeeded.
Thanks for reading!
💖Your bloggy buddy,
P.S: Don't forget to e-mail us, or hit me up on Twitter. I love talking games, and would love to talk to you! :D
I received a lot of good feedback the last time I wrote about some of the tools we are using to make Monumental Failure. I thought I'd do a cheeky follow up.
ScreenToGif. I've been using ScreenToGif since it was a preview version. The current version has a full featured editor, with options for cropping and watermarking and changing playback speeds and drawing it's simply an amazing free tool. Best of all, it just works! I've never had a problem using it, and when gifs are a better way of communicating your game than static screenshots, it's pretty key for the indie developer.
Neil Cicierega's Work Thingy. Yeah, so, the guy who made Bustin' has this little app that judges you when you're not working. You tell it which applications are work (ie. Unity), and when you use them it's happy and the timer goes up. When you don't use those apps it turns red and judgey and the timer no longer counts up. Simple, motivating, enlightening.
EmojiKeyboard. I'm no marketing wizard, but, @ScaryWizard's most popular tweets have emojis in them. Hardly scientific, but ¯\_(ツ)_/¯
I'm going to keep this post short and sweet, thanks for reading.
In the last dev log, I mentioned that Monumental Failure's camera would be controlled by the game, not the player. In this post, I'd like to take some time to discuss lessons I've learned working on game cameras.
Before working on Monumental Failure, I had experience working on 2D game cameras, specifically with the games Battle Run and Super Battle Racers. In those games, the camera uses a few simple rules. The camera tracks the player character. If the character is within bounds, the camera asks the level where best to situate the camera. If the character is not within the bounds, the camera does its best to follow the character anyways. Though the actual implementation of this system would be represented by hundreds of lines of code and hundreds of points of information specified by the level designer, the key idea here is that 2D cameras are best left to the designer.
As a side note, Mushroom 11 creator Itay Keren, in his massive treatise on 2D game cameras, essentially comes to the same solution.
The question then is does a similar, level-design driven approach make sense for Monumental Failure, a 3D game? The simple answer is no. Battle Run and Super Battle Racers are concerned with tracking a single character who moves in 2D screen space along a level that is almost one dimensional i.e. you can move left and right, with little variance in up and down. The level designer need only provide a list of points that the camera then interpolates between. In Monumental Failure, I have a variable number of things to track - a piece of a monument, and the characters that are pushing it - all of which move in three dimensions of space. Trying to populate the levels with three dimensions of camera direction would be a nightmare. Instead, I need more general solutions, and need to be much more selective of the camera controls which I expose to the level designer.
The first rule I impart to the camera is to find a relative forward/backward (depth) axis. I define this as the axis made from the target position to the pushed stone's position, removing any vertical change. The camera uses this depth axis and is placed at a distance behind the stone's position, as well as an angle up from the stone's position. The distance and angle are defined by the level designer. The camera attempts to maintain the angle and distance from the stone as the stone moves. With a little bit of smoothing, this method is very good for keeping track of the stone, but I need to do a little more to make sure you can see your push-people.
To assure the push-people are seen by the camera, I call a function that returns their individual screen positions. If the function returns a number between 0 and 1, they're on-screen. If anybody is off-screen, I increase the distance that the camera is away from the stone until the characters are back on screen. To make this camera rule more graceful, two changes are needed. Instead of checking a range of 0 to 1, we instead want to check something more akin to 0.1 to 0.9, so if an object is maybe going to be off-screen, we are getting ahead of it and pulling the camera back preemptively. Secondly, the speed at which I pull the camera back needs to be able to accelerate in the case that something got off screen fast.
When the player approaches the target for their pushed stone, the level designer has the option of rotating the camera to give the player a better sense of how lined up their object is. This camera feature was implemented very early in the game's development, and my play-testing has me questioning whether this is a helper or a hindrance to the player. Level designer Spencer says, "it depends."
When I write it out, the rules for the camera may sound simple. The reality is that it's a living system that needs new features and tweaks as the level design informs them. Just this week, I needed a function that would allow me to provide an additional amount of positioning to better highlight action down-screen from the stone and people.
Despite my previously stated concerns that handling camera controls on the developer's side would be a headache, it's actually been a satisfying challenge. I make it easier by providing relatively few handles to tweak it on the level design side.
While I'm sure there are still challenges to come and changes to make, the current camera is actually pretty great.