A collection of random thoughts on a variety of topics.
I'll try to spill my brains once a week on something I found interesting or useful in the hopes to better mankind or something.
I'm a freelance game developer working out of Melbourne. I work with Unity in C#, and I specialise in particle effects and game mechanics code.
Interested? Check out some of my previous work!
vid
Title: Airmada
Platforms: iOS, Android, PC (Unity3D)
Unreleased (A beta build is available on request)
On Airmada I worked on loads of stuff, from the visual effects to the boss designs. I built the systems for designing boss encounters and the game's levels, and also designed the boss attack patterns and animations. The art was designed by the beautiful artists I work with at Correct Rejection
Title: Primate Press
Released: December 2015
Primate Press was the first title Correct Rejection released, a simple puzzler for phone. I built the underlying systems and worked on the game design. A great little timewaster, check it out!
I was lucky enough to get to work with Polyphonic EP on their new title Resynth. Employed as a contractor, I designed the visual effects and particle systems used throughout the game. This title is wonderful and it was a joy to get a sneak peek (and an opportunity to contribute!)
OmniVS was produced during the Swinburne 48 hour game jam. A stylish little 3 player arcade game, I hammered out the gameplay code, designed all the visual effects, and even had time at the end to stick in some artificial intelligence for some fake players!
Over the last few weeks I've been attempting to teach myself to do some basic stuff with Shaders in Unity, it's gone pretty well, I've found some cool resources and I've experimented a lot (and I've seen this color a lot as well)
But all that learning had a few positive outcomes. I wrote a couple really neat shaders, one of them I'm pretty happy with, an ocean shader for a top down scrolling shooter I'm working on. It looks something like this:
It's not the best thing under the sun, but I'm fairly happy with it. It's not going to blow Crysis' water out of the, uh, water? But for mobile it's quite nice. One major note, there are no reflections, I'd like to add them but since the shader is for mobile we'd need to basically draw the entire screen twice and our game is unfortunately not running fast enough to do that. Shame, but you can't win em all. Anyway, I figured the best way for me to solidify my knowledge is to try and share it with the world. Lets have a look at how I did it!
First up is the start of the file, and the properties section. Shader declares it as a, shader, and the string afterwards tells unity what to label the shader as in the material menu, a forward slash indicates to set up a subfolder in the list of shaders.
Within properties I define 5 variables, Two colors to form the gradient you see on the water above (the edges are ever so slightly darker than the centre)
Next comes the distort factor, which is simply how powerful the distortion of the waves is.
Finally the Main texture and the Distortion map, the main texture is the texture that is getting distorted, basically the ocean floor. You can try different approaches, I found it looked quite nice without any detail just some blurry blue, but having some objects drawn onto the texture like rocks or maybe fish can look quite nice too. The distortion map is simply a map for how to distort and ripple the surface of the water. Simple stuff.
Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag
#include "UnityCG.cginc"
We open by declaring a subshader, and setting it's tags. For this one we render as opaque since it's the background. Everything else renders after this. LOD 100 declares the level of detail level, 100 is very low so even on low end devices, this shader will be used (which might actually be a bad idea since it's a little complex, maybe I should fix that...)
Then we go to the Pass which is where the shader actually draw stuffs, CGPROGRAM indicates the beginning of our shader code, we're not in Unity any more... The two pragma lines indicate we're mapping the vertex and fragment functions to vert and frag respectively. (Vertex is the function used to calculate color at each vertex, while fragment is used to calculate the color of the pixels) We also include UnityCG.cginc, it has some helper functions, honestly I can't remember if I use them. I'm new to this too so cut me some slack. struct appdata { float4 vertex : POSITION; float2 uv_MainTex: TEXCOORD0; float2 screenPos : TEXCOORD1; };
Finally we start to get into the shader proper... Here we start to declare our variables. The struct appdata contains information sent to the shader by Unity, in our case we access the position of the vertex (this is in local space, as far as I recall), the UV coordinates on each vertex (basically pointing to where on the texture we draw) and the screen position, in this shader I use screen position since the shader covers the whole screen, but with some simple tweaks getting it to work on a mesh itself shouldn't prove too difficult.
Next we declare v2f, this is the struct we'll passing to the frag function. Basically inside vert() we define our v2f object, fill in the data we want based on the vertex data, and send it off to the frag function. The graphics card automagically does some stuff to lerp the data between vertexes (so if vertex A is green and vertex B is red, the pixels in between those vertexes will know how to shade themselves between the two colors)
Next, we redeclare our variables from the properties section. Why? We're in CGPROGRAM now, which is running on the graphics card, not the CPU! This is a completely different program so it doesn't actually know about the stuff we declared in the properties field. Naming these variables the same as up in properties tells Unity to do some magic stuff and send the data we specify off to the graphics card. All you need to know is, if you redeclare the variables down here you can access them from the shader. Yay! v2f vert (appdata v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv_MainTex = v.uv_MainTex; o.screenPos = ComputeScreenPos(o.vertex); return o; }
Finally we get to some actual code getting run, a lot of stuff has to be declared and redeclared but hopefully it's all worth it. This is the vert function, which as I said earlier is run on each vertex. We hand in Appdata (which we declared before, and has been magically populated by Unity, thanks!) and we're expected to return a v2f, for use in the frag function. So this function creates a new v2f called o. Then, we set o's vertex to mul(UNITY_MATRIX_MVP, v.vertex) What the hell is that? You ask. Unity Matrix MVP is a helpful matrix which converts local coordinates into worldspace coordinates, MVP stands for Model View Projection. I don't have time to explain matrices or what all that stuff is (and to be honest, I don't actually know) but like I said before, multiplying it with the vertex position converts the vertex into a worldspace position.
Next, we set the v2f's uv coordinate to be the same as the one handed in by the appdata, we could modify it here if we wanted but we don't really care. Finally, we calculate the screen position based on the output vertex (this distinction is important, remember our output is in worldspace, not local space) and return our v2f object. All done and dusted happy as larry. Great stuff.
fixed4 frag (v2f i) : SV_Target { fixed xpos = i.screenPos.x; fixed val = xpos*2-1; val = abs(val);
And here is where the heavy lifting goes down, holy CRAP. This is the frag function, where we calculate the color of each pixel. The frag function retuns a fixed4, which is 4 fixed's stapled together (if you're unaware, a fixed is basically a float clamped in a small range, it's cheaper on memory requirements which can be important for older hardware but basically it's just a cheaper float, in our case we use it to represent RGBA values so the small size doesn't actually hurt us, fixed values are great for colors! So we return the color as a fixed4, which gets rendered to screen, sounds good. Lets go through how we calculate the damn thing. First, we declare and calculate val, val is used to draw the gradient and we modify the x position in order to determing where on screen we are. Multiplying xpos by 2 and subtracting 1 changes the range from 0->1 to -1->+1 which is useful for the next bit. We then abs(val) to ensure it's always positive, so we get a nice up and down as we travel across the screen, the far left val is 1, at the centre it's 0, and on the right it's 1 again. Moving on, we declare a fixed3 distort, this represents the RGB colors on our distortion map, for the ocean I used a normal map that came with the Unity standard assets, normally it's used for cliffs/rocky terrain but it looks fine as a water's surface. Anyway, we sample the distortion map at our current position and store the color as a fixed3. Reminder that a fixed3 is 3 fixed values stapled together.
Next, we offset distort's x and y coordinates by _SinTime and _CosTime, these two variables are supplied by Unity and are literally just sin(Time.time) if you're familiar with unity code, basically they're just sin and cos waves that animate over time, ideal for say, the swell of an ocean moving back and forth? I do some multiplications and additions here just to offset and tweak the numbers they give us so it feels a little more natural. Exposing these values might be wise, or unwise. Depends on your designers. I do a few other multiplications to distort the values a bit more based on time and the distortfactor (a variable exposed in the editor) Next we declare distort2, we sample the distortion texture AGAIN, but this time offset by the distortion we just calculated, giving us an offset offset value, weird shit but hey it looks good (I made this through trial and error, remember, so it's a little odd) We use distort2 to calculate the specular highlights, so having it offset in a strange way makes the water shimmer like real water as it bobs up and down. We then calculate a value called spec, this is a fake specular effect, I could have calculated this using actual light sources, but I figured it's probably a little cheaper to just fake it. To calculate the spec we perform a dot product between the distortion's xyz value, which while being an RGB can also represent a 3D vector, which is what we do with it here, so the distortion also functions as a direction for the surface of the water. The dot product compares it with another vector (0.9,0.3,0) and returns how similar it is. a value of 1 means the vectors are identical, 0 means perpendicular and -1 means opposite. We then raise this value to the power of 8 which creates a sharp falloff effect, which is what gives us the nice sparkles on the tips of the waves. Decreasing the power used will make the specular reflection softer, while increasing it makes it sharper. Since water is highly reflective, 8 is a good number as it results in very bright reflections in very small sections. Finally, it all comes together and we calculate the final color. First, we lerp from color1 to color 2, by val, calculated earlier to give us the baseline background gradient. Next we sample the original background texture, but offset the UV position by distort, this results in the murky distortion effect expected of water. Finally we multiply by 2 (since we multiply the gradient and the background color together we basically halve the brightness of the two) and finally, we add the spec value, since spec is always white it gives us those nice bright reflections on the top of waves. After all that, we return the color for the pixel, and ENDCG, tellilng Unity the shader is done, and that's the complete shader. Holy carp that was a long explanation, the shader itself has a lot of flaws honestly, but it gets the job done so I'm happy. Take everything here with a grain of salt please, learn from my mistakes and make your shader 10x better, I just wanted to share my thought process. The shader also behaves quite strangely out of orthographic camera modes, so there's homework if you want to try and fix it. I learned a lot of this stuff through hacking it and trawling the wiki, but I've also discovered a great series of tutorials on this stuff, check out this guy: https://www.youtube.com/channel/UCEklP9iLcpExB8vp_fWQseg In particular, a lot of this shader is based off his Spelunky Ice shader: https://www.youtube.com/watch?v=7fMCTVhEzmU Is it wise to link to a tutorial series significantly better than my own? Maybe not, but credit where credits due and his channel is kickass, besides if you've hammered through this much text you deserve a reward. Tune in next week for hopefully a lot less text. Here's the final shader by the way: https://my.mixtape.moe/vzjuxz.shader Feel free to play around with it. You have my permission to use it however you see fit. Except for hurting people. Don't hurt people with my code. Til next time.
So I wanted to talk about a crazy idea that I've been kicking around in my head, but I realised a blog post on it needs a bit of setup first. I need to explain a few ideas and have a working project I can actually try it out in, so rather than dive in the deep end and risk either not getting enough depth or just not being accessible I figured I'd just go over the foundations of it in another blog post, and in doing so I can get some setup done on a usable project. Two birds with one stone, and an extra few blog posts while I build a unity project and get it up to speed. So without further ado, let's talk about Boids!
Boids, if you've never heard of them are a super interesting way to make simple creatures. If you want some history and a deep description here's a link: http://www.red3d.com/cwr/boids/
So basically a Boid is a kind of framework for designing flocking creatures. Using only a few variables and some fairly simple functions we can create a lot of distinct realistic looking behaviours for schools or flocks of animals, like birds or fish. That's neat if you're marketing the newest Call of Duty game, but in a more indie game we don't really need that kind of background detail, right? Well it's actually useful for a variety of simple AI. Squads of ingame entities can use the same boids AI, they produce really convincing groupings for loose aircraft or spacecraft formations, I've used them in the past with some basic pathfinding to allow for swarms of simple melee attackers in a top down game and I'm fairly sure Blizzard used them to some degree for unit movement in Starcraft 2.
So without wasting time lets build some boids in Unity. So heres the beginning of our boids, an AI that randomly moves around. Pretty dumb, but they'll grow in time. They just choose a direction and head in it. That direction changes every 0.5s, the rest is just some simple code for sending their orders to the rigidbody attached. There's also a basic player in this simulation color coded gold.
So from these humble beginnings our AI will emerge. The next step will be making them try to cluster. To do this we simply keep track of every other boid, in my implementation I just get every other boid in the scene but for performance reasons in a real game you'll need a better way to do this, such as a manager that stores all living npcs or something. There's a million ways to do that kind of stuff so I'll leave the implementation up to you since that's not the point of this exercise, but for boids you essentially need each boid to know a few things about it's friends.
To start with it needs to know their positions, once we know all our friends positions it becomes trivial to work out the average position of the flock, we simply add up all positions and average it. It's a good idea at this point to only look at nearby flock members for the best effect, if you only check nearby boids you can have seperate flocks flying around in the same scene, but if you check all boids they have a tendency to just form one huge blob. Either might be ideal for your game, but in my case I also added a variable for controlling how far each boid can 'see'. So the result is this:
//calculate flock variables Vector3 flockCentre = Vector3.zero; int count = 0; foreach(Rigidbody body in friends) { //only add nearby friends to the average. if ((body.position - transform.position).sqrMagnitude < Mathf.Pow(weights.sightRange,2f)) { flockCentre += body.position; count++; } } flockCentre = flockCentre/(float)count; //find average position. Vector3 flockDirection = flockCentre - transform.position; //make it relative to our position flockDirection.Normalize(); //normalize our direction
Well they definitely look a bit more intelligent, they now cluster up and fly around kinda randomly. They have a tendency to slam into eachother however and just clump in general. In this version they treat me as one of their own so I'm able to lead them around since they're attracted to me, which is kinda neat. But they're still dumb as rocks so lets step it up another notch.
Next we'll add avoidance, slamming into eachother looks dumb so lets make it so if we see someone who is too close, we back off a tad. This has a couple benefits, one it makes them look much smarter and two it means you can actually disable their collisions (since they'll naturally avoid eachother they don't need to do physics checks) which can save you a lot of processing in larger swarms. Of course, you can still allow them to collide if you want for gameplay reasons, but they should do a fairly good job avoiding eachother.
So avoidance is a little different to clustering, instead of moving towards the average position, instead we move away specifically from nearby boids. One idea might be to move against the average position we calculated before, but it's actually better to specifically move away from each nearby boid, this allows them to still stick together, whereas if they simply moved away from the average position it would just be fighting against the previous clustering behaviour, so the small logical change adds enough variation to prevent it simply cancelling out.
Vector3 avoidVector = Vector3.zero; //direction away from nearby boids foreach(Rigidbody body in friends) { if ((body.position - transform.position).sqrMagnitude < Mathf.Pow(weights.nearRange,2f)) { avoidVector += transform.position - body.position; } } avoidVector.Normalize();
With some number tweaks and disabling collisions we get a pretty nice effect, but there's still a few issues. They tend to group up and then sit in one spot, which isn't ideal, and they like to kinda freak out on the spot which looks bad. They behave like metal shavings and magnets kinda, clumping up and then being a massive pain to seperate, they do follow the player in a cute fashion though.
So the final step in making basic boids is to make them head in the same direction as their fellows. By following the general movement of the crowd you get a much more realistic flock of creatures. Working out the heading of the flock is easy, while we're working out the average position of the flock we can also add up the velocity of each nearby boid, and by doing so we get a vector of the average direction, then we simply make our own acceleration move towards that and we get a nice flow with the crowd.
Vector3 flockHeading = Vector3.zero; //average direction of the flock velocity foreach(Rigidbody body in friends) { //only add nearby friends to the average. if ((body.position - transform.position).sqrMagnitude < Mathf.Pow(weights.sightRange,2f)) { flockHeading += body.velocity; count++; } } flockDirection.Normalize();
And there's the final product, beautiful. At this point it's actually possible to turn off the random heading entirely and they'll still roughly fly around in packs, but the randomisation helps them to split up now and then and prevents them blobbing up.
So the final logic for what direction to go is dictated roughly by the following logic:
Really it's rather simple but once put together you get quite a neat display.
This post has gone long, so I'll wrap it up here. I'll be returning to boids, this is just part one of many. I think they're a great little tool, next time I cover them I'll talk about weighting the variables to get specific behaviours such as flying in squads, swarming, fleeing and chasing other objects and maybe even (basic) pathfinding. Beyond that I'd like to look into some more advanced AI stuff and maybe even build a small RTS or something.
One last note, Boids work in 3D as well as 2D, I just did 2D since it's easier to see what they're doing.
Could be a good extension if you wanna play around a bit. Shouldn't be hard to get them to go in all directions.
Here's a copy of the current project if you'd like to play around yourself, it was built in v5.1.1f and so may not be compatible with other versions of unity. The variables are all exposed in the editor so feel free to play around: https://my.mixtape.moe/zrotux.rar
This week I wanna talk more about design than another tutorial. My week was spent learning the basics of shaders, and while it was fun and I learned a lot, it was also pretty unproductive and I don't have a firm enough grasp to really talk about it. I wouldn't want to misinform people since I'm so new to the craft, and I don't want to talk about something I'm not really familiar with.
So instead I'll talk about a bit of game design. Today I wanna talk about random loadouts. By this I basically mean random gear, weapons or tools for a player. There's lots of different ways to implement this across all genres, but I think it's really cool to play with for a variety of reasons.
Random outcomes in games are common, they're a good way to make a game more replayable. If a situation is less predictable then it'll play out in different ways more often and be more interesting in the long run, in theory. There are pros and cons to this though, a big one is bad luck can really ruin an otherwise good experience, bad rolls in an RPG, unlucky bullet spread in an FPS and other factors can take away from a players experience. The main reason being that the player had no control over those factors.
I'm gonna go a bit tangential for a sec but bear with it. Another problem in games is optimum strategies. Even in well balanced games there's often one or two strategies that run rampant and shut down a lot of alternative strategies. At high level play many games end up being very boring, with maybe 20% of the content actually being used since the rest is just straight up inferior. You can fight this with balance patches and effort, but that takes a lot of work and even a mostly balanced game can suffer from this, even in very tightly balanced games there is often one or two characters or units or whatever that just don't make the cut and nobody ever uses.
So what if I told you I had a silver bullet for both randomness taking away player control, and optimum strategies causing a game to become boring? Well you'd be right to be skeptical, but I do have a proposition. Random loadouts. Now, randomising the tools a player has doesn't quite solve both problems. The random factor will still often result in nearly unwinnable scenarios, since a player has no control over their gear, and dominant strategies will still exist to some degree, but in my experience it's a very interesting design space that isn't thoroughly explored.
So what are the pros? Well a random loadout actually mixes things up quite a bit, since your player has no control over their gear they have to really change how they look at your game. There is no weapon or class a player can "main", they have to adapt on the fly and use their kit to the best of it's ability, no matter what it is. Give a player a shotgun and even if he likes playing a long range careful game, he'll have to get up close. Give a player a stealth item and he'll be more inclined to be sneaky even if he's normally the aggressive player. I think that mixing up strategy and forcing players into certain roles outside their comfort zone is both a good way to keep the game fresh and interesting.
Another advantage is it's honestly addictive. I've designed and played a few games like this and in the right environment it really gets you wanting to stick around. If there's a specific tool or weapon you really like or want to try out you have to wait for the dice to favour you, and the suspense of an entirely new loadout really makes you want to stick around to see what you're going to get next. Additionally if the enemy you fight (in particular PvP) is also dealing with a random loadout it can be really cool too since you're excited not just for what you're going to bring, but what you'll be fighting against.
Finally, it lets you be a little bit, well I don't want to say lazy... But cheeky as a game developer. You can do things you could NEVER do in another game when players can't reliably choose. I worked on a small project called extraction point and we had a railgun that shot through walls, we also had a player class that could see through walls. In a normal game such a combination would be utterly gamebreaking, you'd choose him every time and the game would be awful. But with a random loadout players can't force it every game. Admittedly, occasionally it does randomly come up and certain combinations felt unfair or imbalanced, but since you knew it was very unlikely you'd see it again such problems were not really worrisome, and it let us have both of those awesome abilities in one game, without having to worry about abuse.
There are definitely downsides though. In such a game you still have the issue of lack of player control. While a random loadout makes you think on the fly, it can also leave you with a crappy loadout with no real chance of victory. As a developer you can mitigate this by making sure every tool and weapon is useful to some degree on it's own, or do what we did with our game and make it a team based shooter, so if your loadout is very narrow or unusual, your teammates can still back you up (usually). All that said, it still sucks when you get the worst possible combination, so be careful with it.
Another problem is high level play, lack of consistency turns competitive players off (and rightly so). While your casual players might enjoy the thrill of random loadouts, you'll never pull the esports crowd to your game if it's heavily random. It's also really damn hard to put in a progression system of some kind. A lot of games lock tools off from you until you progress, which is good for learning and is often (misused) to pad out a game. With random loadouts you kinda have to give the player everything from the beginning, or they can get an advantage through probability. If the stock weapon is really powerful, and a level 1 player is more likely to get that weapon he has an inherent advantage and nobody wants to get higher level.
All up I think randomized loadouts are an unexplored design space, particularly in PvP games. I'd love to see more games try it out and see where we can go with it, there are problems for sure but the advantages it lends, and problems it solves really makes me feel that with the right system it could make for an excellent mechanic. Time will tell if I'm just rambling or if it really has potential. Maybe next time you go to a game jam or something you can give it a shot?
Unity does a lot of things well, and a lot of things not so well. But one of the features I'm rapidly becoming enamored with is the animation system.
Now to the untrained eye the animation system might seem only useful for importing animations for 3D models, and it works for that. One nice feature is you can even tweak those animations once imported into Unity (that said, I wouldn't bother, your modeling suite probably has superior animation capabilities, like proper skinning and rigging, but if you need to patch something real quick it's handy!)
But beyond models, the animation system can do so much more. Did you know you can animate basically anything? And I mean anything. Want nicer UI? Whack some animations on it. Want your AI to do some interesting stuff? Animate your parameters. The state based machine that comes with the animation system is seriously powerful stuff, and being able to smoothly tween and use curves to animate basically anything is a great feature. So today lets just talk about one of these. (I love this system so we'll come back to it in future I'm sure.)
Animating UI is a good easy place to start, and can add loads of polish to your game. What's nicer than having smooth transitions, dropdown menus and other pretty stuff? I'll mostly skip over the basics, Unity themselves probably have a far better tutorial than I could write, so I'll hit the ground running, smash out some quick principles and hot tips and I'll let you do the legwork if you don't understand the basics. (I'd rather have a brief tutorial that loses a few people than a mighty tome that alienates even more)
So lets assume you have a basic canvas operation underway with a button or two. If you hit CTRL+6 you'll open the animation panel. Then, you can create a new animator + animation with the create button:
So now we've added an animation, I'm gonna create 2 clips, an idle and a hide animation. You can totally do more but for demo purposes there's no need.
So when you have the animator open, there's a little record button. This thing is amazing. Unbelievably cool. When you're recording, everything you do to your object will be keyframed. EVERYTHING, this is nuts. To start with I'm just gonna add a rotation:
So that adds a simple wobble to my menu. It's a little tacky, but you get the idea.
Now for some crazy stuff, I said you can animate anything and I mean anything. Check this out:
With the record button on I've clicked on the interactible bool for the button component. This keyframes the change, so when this animation plays it'll set the bool to whatever I choose, in my case I disable it. Once you press the button I want it to prevent you pressing another one while we animate and change scene.
Once animations are done, I jump into the animator (up top Window->Animator) which is where you can set up your transitions etc. I add a trigger called 'hide' (go parameters, then there's a + button) and then set up a transition between the two states. Then I set the transition trigger to be hide, and ensure that 'has exit time' is unticked. (Has exit time basically waits for the current animation to end before transitioning, but we want the animation to interrupt)
So once that's all set up we have a working animator and a working set of animations. Now comes the really cool part. I'm sure you've slogged through making fancy menus and the code can just get obscene, triggering this triggering that, setting things up moving them around. Well hooking this up is about as easy as it gets.
I'm gonna assume you've used buttons before to call events and stuff so I'll keep it brief. I've set it up here so it contacts some script (I just made a basic menu script which loads a level on command after 1 seconds, a 4 or 5 liner) but what I've also done is contact the Animator attached to our menu. Then, I've called it's "SetTrigger" function, feeding in "hide", which is identical to doing it in code, but we did it without even opening a script, which in my eyes is pretty damn sweet.
So the end result is we have a nicely animated menu, for basically no code effort and all up it took maybe 10 minutes? Obviously you can polish this up, my example is pretty damn tacky if I say so myself but with a little work you can make beautiful looking menus for little effort, using the basic stuff I've shown you here it's possible to make some really advanced stuff.
I know this was pretty crash course, honestly I'm not the tutorial type. If you get lost of have a question drop a comment down below and I'll try and get back to you. It's the nice cooperation between Unity's systems like this that make me really enjoy working in the engine, at first glance I wouldn't think animations could be so versatile but they interact really nicely with basically everything else in the engine and honestly it's just so damn convenient. You can save a lot of time and make your game seem way more slick.