Controller Clash - Lessons "Learned"
Previously posted here: http://www.burpyfresh.com/unde...
As alluded to in the last Game Dev with the Underdev'd, here at Burpy Fresh, we love writing about games, but we also love making them. We're proud to announce the alpha version of our very first game, Controller Clash. Now available here for Mac. (Windows etc coming soon, we had to rush to get something out for BitSummit!*) It's Almost Fun (TM)!
Controller Clash is more of a exercise in learning C# and the Unity interface than making an actual marketable game. In reality very little about this project makes it in any way commercially viable. As our tag line says above, it's "Almost Fun (TM)!" In this post, I'll explain about the game, and more importantly the problems I faced, and how I overcame (read: blindly struggled my way through) them. Maybe someone starting out will find this useful, or perhaps more advanced people will be able to remember how to explain issues to us n00bs again.
About the Game
Controller Clash is a four player local multiplayer game where bases shaped like controller buttons battle for the control of Controllerscape (TM??). Each player claims a controller button base. Pressing their own button shields themselves. Pressing any of the other face buttons sends a missile towards the corresponding enemy. Left and right bumpers shimmy your base left and right to dodge some attacks. Using the D-pad, you can compose simple fighter style moves.
That's about it. You can only do one action at a time, so you can only defend or attack. There's a cool down timer of one second on each action. Your shield has 10 HP, but if you get hit with your shield down, you die automatically. There's a lot of politics going on in this game, piss people off and you'll be outed pretty quick.
Things Learned - Things "Solved" - Face Palmed
What is a GameObject?
A GameObject is an entity that exists in a scene. Holy crap did that take me a while to figure out. GameObjects have either predefined features, or features that you define with code. They can be instantiated, destroyed, turned on, turned off, and basically manipulating them is how you create anything in Unity.
Mind Blown. I should have paid more attention when I learned Java in like 199...umm.. 7?
Understanding Unity - Understanding Code Execution
Honestly, it took me about a year to understand the Unity interface. Don't get me wrong, I think it's really good, but it took me a long time to understand certain key factors. In Unity, you need to create scenes, which houses the environment your player will traverse, the camera that will view it, and all of the entities you'd like to have present.
The hardest thing for me to understand was that Unity, as an engine and an interface, was basically a piece of code that executed itself and the rest of your project. When you create a piece of custom code, you need to attach it as a component to something that will be present in the scene upon execution. Many people in tutorials attached their scripts to the camera, which really confused me, as I thought that the camera was executing code somehow. Unity will go through the list of GameObjects and execute what code is there to execute. Really though, the camera is just always present, which is why I guess people do it.
In a similar note I now get why variables need to be public for you to assign values to them in the Unity interface. If they're not public the Unity code can't see them due to the way scope works. Again, something completely obvious, yet I didn't get it for a long long time.
Understanding Classes - Understanding MonoBehaviour
Basically, I've been trying to make a game for years, and while I understood that a class was an abstract entity that could be assigned features and behaviour, I didn't understand the level of recursion and abstraction that was possible. In Controller Clash, there are four players, basically Cross, Triangle, Circle and Square, and they're all slightly different. They move and throw up their shield the same way, but the moves they can make with their missiles are different. I wrote four different classes, called PlayerCross, PlayerTriangle, PlayerCircle and PlayerSquare and duplicated the code I needed to duplicate in each one. I was worried that at some point I may want to give one player or another an advantage, so I figured duplicating code was the easiest way to do individual manipulations later.
What I didn't understand was that inheriting MonoBehaviour wasn't just some text you had to put in the code to make everything work, it's what you need to do to make sure that your class has all of the methods you need to use in Unity. I didn't understand that MonoBehaviour was a class that contained the declarations for essential methods such as Awake, which activates as soon as the class loads, Start, which is very similar to Awake, but comes after it, and Update, which activates every frame, basically every tick of the clock in the game. I also didn't understand that you could make a class that inherited from something other than MonoBehaviour.
So, I created a class called Player, that housed everything needed for each player, and then made PlayerCross etc inherit from Player instead of MonoBehaviour. Player held all the variable declaration and the methods, which PlayerCross etc initialized all the variables, and called methods in the MonoBehaviour Awake, Start, or Update methods. There was still code duplication, but only 40 or so lines as opposed to about 600. Optimization!
How to Handle Translation (The Wrong Way)
If I was more intelligent, I would have set up some sort of data file, like a plist on Apple-based products, and I would have called the text from all three languages in the game on runtime based on the language selection. Instead I created a gameObject that acted as a Game Manager, made a script attached to it that had all the strings in it, plus a public variable for selected language. Every time a text box loaded, the Game Manager was called, and the placeholder text was subbed out at run time, which basically meant I was translating every piece of text in the app as it was being displayed.
Effective? Yes. Cost Effective? I don't see how it could be.
While I didn't learn how to do this the right way (some help?), I did learn something crucial. Code first, clean up later. While it's always advisable to keep code tight and well optimized, at the end of the day, it's more important to have spaghetti code done than a few neatly written modules that only do half of what you want them to do. People may disagree on this, but I don't think I would have ever been able to put anything out at all if I didn't swallow some pride and just hack some mess together.
How to Do Fighter Style Moves - Understanding Update.
Update is a function that is called on every frame, or every tick of the computer clock. What do you do when something, like a fighter-style move that requires multiple things to happen over multiple frames? This took me about four hours to work out.
In the end I made a public iterator variable, and variables called moveOne, moveTwo... etc. There is a method called MoveGenerator that takes a series of inputs and spits out a move based on the input. Right now, all moves involve a single tap on the D-pad followed by a button press. MoveGenerator reads the iterator variable, and if it's one, it initiates a move if the input is a face button, or it stores the direction of the D-pad pressed as a string in moveOne, and the iterator is incremented.
The trick at this point, which took me, again, four hours to figure out, is to exit the MoveGenerator method, and then re-enter it on the next frame where a button has been pressed, this time the MoveGenerator is looking for a face button. It records any face button press as a string in MoveTwo, and then it determines which move has been selected from a list of moves, initiates that move (an attack or a defensive maneuver, and then it sets the iterator back to one, ready for the next move to start. Any improper input sends the iterator back to one and empties the strings MoveOne and MoveTwo.
This feels right to me. You're listening every frame for a button press, and when you get it you store it away until you find a combination that makes a move, and then you fire it off. I'm not sure I could think of anything simpler.
I did have a problem initiating animations in update until I understand how flags worked. Basically, I would set an animation to go upon some condition, and then because update was called every frame, often several animations would occur when there should have been just one. By having a bool that I could turn on when an animation was happening, and then off when it stopped, I ensured that there was only one animation at a time... which brings up...
Why You Need an Instantiated GameManager
If you have anything you need Unity to carry with it throughout the whole game, you need a GameManager. Basically, make an empty gameObject, call it GameManager, and then throw a script on it to ... erm... manage the game. Basically, player stats, environmental settings, whether or not something is visible, these can all handled here.
Instantiating the GameManager when you start (ie. not having it in your object hierarchy when you start to begin with), and then always checking before instantiating when the game starts over ensures that all of your crucial variables are always stored in one safe place.
This, like everything else, took me several hours to figure out.
How to Tween
Download DOTween. It just works. I mean, I got it to work in like 5 minutes. Literally, 5 minutes.
Failures of the Game
When all is said and done, there's still a lot wrong with the game.
- No way to understand what's going on if you aren't playing (not fun for larger groups watching)
- Not a lot of fun. It's a bit of fun to be honest, but you need a group of people willing to take the piss.
- Conceptually flawed, especially when only two players are remaining.
That said, if some people play it, I might be able to get some minor suggestions that could make this more balanced, and then more fun. Right now, the shield can turn on and off, and that's it. Perhaps creating a move to recover HP or prevent players from riding the shield could work. Need to think about it.
Where to Go From Here
So, honestly there's a lot of work left to do on Controller Clash. The game will always be free on itch.io, but still I should "complete" it before moving on. Mostly, it's a way to experiment in learning new things in an environment that I'm very familiar with, so expect some useless features.
What's Left To Do
Make it fun - Right now, it's Almost Fun (TM), but I think there can be a way to tweak things to make it more enjoyable. Toying with the idea of having a shield generator move that allows you to get HP back, and maybe some way to keep people from riding the shield. Also, Bomberman style dead players that attack random people might work too.
SFX Volume - It's in the settings menu, but it's not implemented now. The only way I've found to actually make it work is to tag every one of the SFX file entities in Unity with some tag, or put them in a list or something, and then iterate through them one by one, changing the volume of each file individually as the user changes the volume. It's really cumbersome, but I can't find another way.
Graphics - Bullet trails? More glowy bases? There's a lot of room for improvement.
Animations - So, right now the characters just fade out into nothingness. I'd like to add a sprite animation for when they die. Maybe put some crystal shattering sound effect in there as well.
Collision Effects - Maybe a short pause when some player or shield gets hit with a missile? Something like that would improve the game feel a lot I think.
Neaten Code - The code right now is basically a mess. Every now and then I went through and organized everything, but as it got more complicated, the mess grew and grew. It'll take a little while to find the best way to do things, so this is a long term goal.
Other Polish - Anything I haven't really mentioned here.
Making this game has been (and continues to be) an amazing learning experience, which I'll take with me on the development of my second title, which I think actually has legs to stand on. If you've read this far, and have thoughts on what I've done wrong (or right?) drop me a line here, or on twitter. Or wherever fine comments are sold.
I'll just be over here, on Itch, fiddling around.
Get Controller Clash
Leave a comment
Log in with itch.io to leave a comment.