Tuesday, December 15, 2015

Capstone Post 7 : Post Mortem

What Went Right

1. Iteration

We nailed this on the head. At the beginning of the project, we had a new game direction about once a week. We started with a super simple game: Tap Zap, which was a game where you controlled lightning by tapping and tried to avoid obstacles. We decided we liked the trail left behind by the lightning and pretty much nothing else, so the next week we had a game where you moved a little particle ball around and collected spheres. Those spheres became your tail, which is where the idea of controlling something with a tail came into play.

The following week we took that and wanted to make a game about making little solar systems. So we prototyped that out, where you would circle around and eat your tail to make planets that orbited a sun. We needed some sort of gameplay, and we were thinking about how bodies interact in space. Obviously, when a planet hits an asteroid (the nodes of the tail), the asteroids break apart. So now we had this game where you flew around collecting asteroids and making planets: the planets would break your tail. This was frustrating to testers, so we did away with what didn't work and kept what worked.

I won't go into every iteration here, but the reason our game turned into what it is now is because we kept throwing away the stuff that didn't work and prototyping new ideas. It was sort of a running joke in the class: nobody could really tell where we were headed or what the game even was from week to week. Each week was a surprise to both the class and to us. Most of the development process was a cycle of prototyping, followed by critique, followed by new ideas, and back to a new prototype. For this reason, I was worried throughout the whole project that our game would fall short, that the idea would fall apart and we would never recover, and that the ideas we had didn't have enough depth or complexity. This drove innovation -- I think now that we're halfway through we have something that is truly unique, and large iteration moving forward is certainly not off the table.


2. Planning

Even though for most of the process we had only inklings of what we were going to end up making, we followed a rigid schedule. I have to give a shout-out to Shannon, our producer, for driving us through each milestone. We had overarching things we had to accomplish by specific dates, but this schedule was purposefully vague enough to be able to iterate as heavily as we did. We blazed through the stage challenges, each time with something very different but clearly more complete than the last. This certainly wasn't without frustrations and conflicts (it still isn't on iOS, sorry Shannon!!). We had to push a couple deadlines back because we had so radically changed the game that there was just no way we could prototype the newest idea in two or three days. But since we had now pushed the deadline back, as developers it seemed we had to just get the new idea finished for the next stage challenge. This pressure definitely kept us all busy, with a drive to stay on schedule. The schedule was made with a release in mind next semester, so we were always working towards that ultimate goal and if we pushed things back, it became very clear how it would affect the trajectory of this project.

In addition to this, we had a set weekly schedule for meetings. There was no confusion over when meetings were: if for some reasons someone forgot, our Slack had Google Calendar integration so slackbot would give everyone a little heads up 30 minutes before each meeting. Every single night at 11pm we had an online Scrum meeting, which only took about 5-15 minutes, but kept us all up to date with everyone else's work.

3. Adaptability and Cross-Discipline Utilization

Being a four person team gave us the obvious limitations that come with a small development team. We realized that a full, textured 3D game just wasn't going to happen with the limitations our artist presented us with. So, we came up with the idea to make the whole game shadow puppets, stemming from a concept of having planets cast shadows away from the sun (when it was still a solar system game). This let us keep the game fully 3D, but instead of rendering textures we just rendered shadows. This gave us a unique an interesting art style while also significantly lowering the art scope. When this proved to still be too much for our artist, our designer and producer made a few assets to make up for this absence. This is what I mean when I say cross-discipline utilization: Our designer helped with the programming, the whole team (besides me, I can't art well) made art, Our designer did all the audio for our game, and we all helped with the design.

4. We Liked Each Other

This is huge for any team, but we all genuinely appreciated each others' company for the most part. I remember coming up with the "you're a dragon putting on a ballet-like performance for the gods" with Zac: we were walking towards his apartment and needed a new direction for the game to take. So we brainstormed, and after a few left-field ideas we left the ballpark almost entirely with this new idea. It was all very casual: we hadn't scheduled a meeting to come up with a new direction, but rather it came naturally on an otherwise innocuous walk. Stuff like this happened a lot: I think the majority of our game-changing ideas came from outside meetings, which paid off in the end.


What Went Wrong

1. Weekly Task Confusions

While we had sprint planning meetings every Monday, and those were super helpful with user stories, there were a few occasions where members of the team just did not know what to do during the week as far as specific tasks go. A couple times, we reached full on conceptual blocks which would not allow anyone to do any work because the game had to change drastically in the next day or two. We handled these, I think, about as best as we could, but it was certainly difficult to know you need to do work and not really know what that work is.

2. Repository Management

Especially at the beginning, this was pretty rocky. Our repository was a mess: meta files and clutter everywhere, projects named incorrectly (The most recent project file is, to this day, still called "HungryHungryHyppo"), and general disorganization in folder structure. Virtually zero naming convention in the art files and no organization in that folder structure made it difficult to find the assets we were looking for. Old builds and old project files cluttered up incorrect folders (branches, trunk, tags), and we didn't use build numbers. Currently we are in version 0.8.0, but wow that is very arbitrary. It certainly got better over time, but a more organized repository would have made us more efficient, especially towards the beginning of the project.

2. Production versus Game

At the beginning, our producer really drove home the point that we would be releasing this game. In order to do so, we would have to keep the game in scope. This turned out to be a great thing: today we sit in a very good position to be able to release a polished and complete game. Throughout the project, especially at the beginning, I think our producer underestimated our abilities a bit. While I understand keeping things in scope was a priority, there is a such thing as too little scope, and in my mind it's just as dangerous for a senior team. There was always this push from programming and design (art is always going to be out of scope) to make a more complex game, followed by a push back to keep the game in scope. This certainly wasn't an unhealthy relationship, but I just felt like I had a lot more to offer than what I was being assigned throughout the first half of the project. Fairly often, I would sit down and complete all my week's tasks in one sitting, without much strain on my programmer-brain. At the same time I didn't want to change the design to give myself more work, I do feel that I could have done more in the first half of the project than I was given to do. 





















Tuesday, November 17, 2015

Capstone Post 6: Interpolating Given Time

Linear Interpolation is a hugely powerful technique, and can be very easy to implement in your code! If you implement it properly. Simply, it is a function of time which returns a value between an initial value (a) and a final value (b), given a time (t). Time (t) is a normalized value which represents the fraction of how far along in the Lerp we are. Calling it time is a bit misleading, but bear with me.

Knowing this, let's take a look at the whole one line of code that let's us interpolate given an a, b, and t:

Taking a look at the above function, let's plug in some example values. If I am Lerping between 5 (a) and 15 (b), and I am 0% of the way there (t = 0.0), this function will return 5. If I am 100% of the way there (t = 1.0), then it will return 15. If I am 50% of the way there (t = 0.5), this function will return 10.

Now that we understand how Lerping fundamentally functions, let's do something super simple with it: move from point a to point b in Unity C#. A really simple interpolation we often must perform is moving something a distance in a given amount of time. Well here ya go, pretty much exactly as you might have expected:


It's as easy as that! But by no means does Lerp stop here. What Lerp is really good at is interpolating anything. Position, rotation, color, velocity, acceleration, scale, even strings of text! Anything with a start and desired value can be interpolated between.

The real power of linear interpolation heck yeah there's more comes in to play when we do fun things with our t variable. A graph of the distance over the time for the above code would look something like this:



Very simple. However, we can run t through ANY function and it will interpolate properly as long as we normalize it to [0.0, 1.0]. What this means is we can turn ANY graph into a change in position, rotation, color, etc.


smooth: t = t*t*(3-2*t)
smoother: t=t^3*(t*(6*t-15)+10)
If you can graph it, you can run t through a function and Lerp it that way. Have fun out there!












Friday, November 06, 2015

Capstone Post 5: With a Machete

I worked a lot today. I woke up after working on capstone and then went to class and then worked on capstone and then went home quite late to write an indefinite number of blog posts (it's going to be two, counting the one before this).

A period of this particularly stuck out as the happiest. Zac and I got on the same page in terms of the new design direction of our game, discussing exactly how everything should work mechanically so I can program these things without having to make too many as-I-go-decisions. So, with this very specific approach to how everything would work, I began brain scheming and dug into the code. I knew I needed to change how things were set up because of the new design I talked about in my previous post. Having done a bit of work on it already, the architecture was headed in the direction of being a complete mess of useful code mixed in with outdated or useless code.

If you're building a house and you mess it up in the beginning it's fine; just knock down the house and start over. But if you already have the wooden frames of most of the rooms up, and you realize you put the kitchen inside the living room or something, you can't just tear down the house and start over. You tear down the studs and other wooden things and rebuild the kitchen somewhere else.

And so began the most joyous time of this night. So I got to both analyze and make changes to the existing, useful code and all that, but the code we didn't need anymore. Since we cut orbiting for cooler motion and arrows because they were lame, I had the pleasure of spending like an hour hacking through this codebase
with a machete.
As I was making boulders collide with the tail and the biomes, I came across the arrow collision code. Since we did away with the arrows, I got to select that code, and delete it. And every time I pressed that backspace key thereafter, my heart grew warmer. I fell down a beautiful rabbit hole: arrows spawn in Game Manager *SLASH!* arrows have a prefab *DELETE!* arrows have a script *NO PRISONERS*. Then I compiled, and wow look at all those lines of code that reference the arrows I had deleted out of existence. Well time for all that code to die *OVERKILL!!*.


But wait, planets still orbit and we don't want that, also the way the planets move (if at all) needs to be dictated from the BiomeProgressionManager. And so I went on to remove probably about a third of all the code in our game. It was a blast.


 Special thanks to Subversion! Without you that would have been significantly more worrisome.

Capstone Post 4: Progression Zoom???

The amount of work I have to get done on this game between now and Saturday, and subsequently the following Monday when we will be challenging Vertical Slice, is a little terrifying. We've taken yet another screeching left turn with Serpent Shadows, and this is the last turn we get this semester. I'm actually really excited about this! I've scheduled out everything I have to do (half on the task board, half in my brain board), and I know this is possible on my end (with room for polish, of course!). While the mechanics of the game have not changed that much, it turns out the code will need (and as of tonight, has received) heavy iteration.

We are working with leveled system now: at the end of a "round," the player will enter one of the biomes. The game will then pick up inside that biome, with challenges themed based off the theme of the biome. This biome will have another set of biomes in it, and those will have sets of biomes in them, and as you go deeper into the very-hard-to-explain game world, the biome themes stack with each other. So you go into a mountain biome, there are falling rocks, then from there you go into a river biome, there is both a river and falling rocks, and so on. We've dubbed it "biome-ception," for lack of a better explanation.

Concept: I shrink myself and eat pizza forever
This calls for a pretty big paradigm shift in the code I've been working with. I hadn't structured this in a way that is conducive to this new biome-ception, as I had no way of predicting that we would go this way. I don't typically set up code to work this way. So I had my GameManager, ya know, spawning arrows and keeping track of planets and whatnot. But now all of a sudden, I need to have some sort of "GameManager" for each level of biome-ception. I don't want to load a new level to do this. I want the transition between levels to be a seamless zoom, like the above pizza.

So I've been tasked with creating a code paradigm that's pretty significantly different than anything I've attempted before. It's one thing to load the next level, or move from one region to another in a game space. It's another to keep zooming into the next "level." So I have a BiomeProgressionManager class attached to my GameManager GameObject. This class handles all the biome spawning for sub-levels (but not the overworld, because we will revisit the overworld later in the game). GameManager still handles the biomes in the overworld, as well as data saving/ parsing from the overworld.

BiomeProgressionManager holds integers to keep track of how many levels of type mountain, river, etc we have gone into. It also keeps track of the current spawned biomes, as we do not need to save the ones from the previous level (unless that level was the overworld). It also holds the level prefabs to instantiate: let's talk about those.

So I currently only have the MountainLevel prefab, which has the MountainLevel script attached to it. This script will handle all obstacle spawning, and decide the difficulty curve as the number of mountain levels the player has been through increases. On instantiation, it will do it's own thing. The RiverLevel prefab will do much the same thing. So, say the player goes through a Mountain level, another Mountain level, and then a River level. Well, the next level would be Mountain (level2), River (level1). Since I'm using these prefabs, I can simply stack them on top of each other to handle this "branching" progression. The river level can be seamlessly combined with the two mountain levels to create the mountain1-river2 level. Interestingly enough, the code has taken on an inception-style structure, much like the game.

Luckily Zac and I have no problem sitting next to each other in a lab until the sun rises because it's going to take a lot of balancing to execute this well.

Side note: I effing LOVE this idea. We needed a weird progression in the game, and we came up with one. No currency, no stars or coins or powerups. It fits the game so well I just want to hug it. And make it happen. It's going to be a long week.

Wednesday, October 28, 2015

Capstone Post 3: Circles!

Let's talk about why anything involving circles is both interesting and easy to program. First off, what is a circle? All it really is is a radius. With no information besides a radius, we know everything about the dimensions of that circle (thanks pi!). Alternatively, we can deduce the radius only knowing the circumference, but this is much rarer to find applications for and follows the same algebraic process. And the only algebra involved is a singular multiplication or division, since PI is the ratio of the circumference of any circle to its diameter.


In my first capstone blog post, I discussed programming perfect circular orbits around a body using Newton's gravitational formula. For fun, you can scroll down a bit and replace distance with radius (the radius of our orbit), and it all means the same thing.

Imagine a screen with two circles floating around, given some random velocities. We want those circles to collide with each other in the simplest way possible so they never intersect. What can we do? If we want things to look very bad, we could use AABB collision to define a bounding box around our circles, but that would look silly and actually be more complex than we even need.

We want our circles to collide like circles should! Well, its as easy as knowing the radius of our circles and performing a distance check between them. Each frame, we can check the distance between our two circles. We store that number in a variable: distance.


If our distance is less than the radius of the first circle plus the radius of the second circle, we have a collision! We can simply reflect our velocity vectors and we have created the simplest collision physics I can imagine.



So in Serpent Shadows, I was faced with the problem of spawning planets semi-randomly around the sun. I started out by defining a bounding box of coordinates they could randomly pick from, and it worked fine! Except this box was rectangular, which is about as sensical as performing AABB collision on circles.

In the refactoring phase of the project, I scrapped all that code and replaced it with something much more elegant. I wrote a general use function that returns a random position with the range of a donut shape around the sun. When you call this function, you simply pass the radius of the first layer of donut and the radius of the second layer of donut: the min and max radii.




*min radius = minor radius
*max radius = major radius










Here's a snapshot of the function. The purpose of each line is shown in the comments.


Our game abides by 2D game logic in a 3-dimensional environment, so I needed to return a Vector3 at our fixed z position, so I simply return this function with the zPos variable declared outside this function. But if you replace all the Vector3 stuff with Vector2 stuff, this is very easily translated into 2-dimensional space.

While this is very simple, distance checks can, depending on how often you are performing them, be a burden on the speed of your application. This is a whole other topic that you should absolutely research if you're interested, but there are a lot of other ways to approximate distance without performing that pesky square root operation. But this is really only a problem when you are trying to calculate many, many distances every frame. For our purposes, we do not care as the effect on performance is negligible.

Capstone Post 2: Possessive Protection

Figure 1: Hugging a planet back together.


I'm excited with the thematic, feel-y direction our game has taken. After teetering between arcade and casual markets, we've reached a nice middle ground with a leaning towards casual. More importantly, we've nailed down a core experience we want the player to have: an abstraction of motherhood.

There are many types of play we as developers can craft for players. Combat games are quite common, but a lot of games that aren't directly about war can be seen as analogs for war: typically there is some sort of enemy force that you the player must defeat. Mario versus Bowser's minions, Leon Kennedy v zombies, Gordon Freeman v the Combine, etc. While this type of experience is tried and tested fun, with Serpent Shadows we are aiming for an experience that I haven't really seen before.

I think we are used to seeing a lot of masculine experiences in video games, and feminine experiences get chalked up to not a whole lot of fun. I'd like to keep masculine and feminine in the abstract: let's take a look at adjectives usually associated with these two genders:
I think games largely lean towards the masculine side: in characters, in theme, in challenges: most elements of popular games lean heavily towards masculinity. While there is always some crossover, somewhere along the way we decided that masculine energy is more fun to have in video games than feminine energy. 

What we are trying to accomplish with Serpent Shadows is not a game marketed towards women, but rather a game that puts the player into a character radiating with feminine energy, with challenges and rewards that are very feminine in nature.

In the game, you play as a dragon with this long tail flying around its little solar system, protecting the planets that reside in it. When arrows hit your planets, the glass casing around them shatters, leaving them unprotected. In this state their "bubble," so to speak, is broken and they venture out of the solar system until you come along and encircle them, "hugging" their protective bubbles back. The underlying idea here is that you are a mother figure to these planets; protecting them from harm by using your own body as a shield.

So, without outright saying it, we want the player to, on a more unconscious level, be playing a game that is an analog for a specific type of protective parenting. Our design choices moving forward will revolve around this idea. We will probably make it so you can create planets by encircling yourself, and a planet will be born from your tail, severing your tail. This works both thematically and mechanically: your tail is shorter so it's harder to defend your planets, but you have another planet. Many, many iterations have brought us to this mode of play, and I have to say I'm excited to see where we go with it!





Tuesday, October 27, 2015

Capstone Post 1: Programming Gravity

Simple forms of Newtonian gravity are very simple to emulate in code. We will take a look at how to achieve the effect of bodies moving about a perfectly circular orbit around a fixed point in space. The essence of this code will work in any environment; I will be using Unity C# to demonstrate the concept.

To start, let's create a new Unity project and set it to 2D mode. Then let's toss some planets and a sun into our game world.



Next, let's attach a script to our planets that will give them this gravity behavior. Let's also attach a rigidbody that, ironically, does not use gravity. In the editor, simply turn off gravity for our rigidbody. We don't need predefined gravity; we are going to write our own!

























Now that we've finished setting up our scene, let's give these planets some Newtonian physics! To perform our calculations, we're going to need some information about our scene. We can start by defining the following variables in our script:
























A good practice with Unity C# is to define your components as member data to avoid littering your code with GetComponent calls. In the editor, we can simply grab our sun GameObject and drop it into the public variable slot for sun, and set the sun's mass and G to be whatever we would like.

Newton's actual gravitational constant (G) is approximately equal to 6.67 x 10^-11, but we can define our own G for this simulation (and I would recommend you not actually use that value unless you are placing your planets millions of miles away in Unity, which will cause you floating point errors). 

Let's step away from our code for a minute and examine the physics we are attempting to emulate. Newton defines the force of gravity between two bodies as follows:


where m1 is the mass of one body, m2 is the mass of the other body, and r is the distance between their centers of mass. 

Often, with this formula, one mass is so large in comparison to the other, that we can remove the smaller mass from the equation altogether. We will be doing this in our code. Let's start our calculation by finding the force of gravity between our two objects, in precisely the same way Newton's formula says to:












Here, we do a simple distance calculation to find r. We then use this distance in our Fg calculation, removing the mass of the planet because it is negligible in our system. This in reality only gives us the magnitude of force, a directionless value.

So, we must apply this force in the direction towards the sun. We do this by subtracting the position of the sun from the position of the planet of the sun, normalizing it so we can get our x and y components to be between 0 and 1, and then applying our force magnitude into our force vector.

 If we were to apply this force to our rigidbody, the planets would plummet into the sun quite quickly (distance squared). So, we must apply a velocity perpendicular to the direction of Fg in order to retain orbit. In essence, we want our planets to fall into the sun due to the force of gravity, but maintain a perpendicular velocity which makes it miss.

To achieve this, we can use the following simple formula to find our magnitude:


And finally, some code:


And that's it! We simply plug in our values, give that velocity magnitude a direction and apply Fg and our velocity to the rigidbody attached to the planet. The -90 degrees is so we apply this velocity perpendicular to the direction of our Fg vector.

I implemented this Newtonian gravity into Serpent Shadows, and frankly it was more because I felt like having fun with it. Spoiler alert, about the same effect could be achieved by creating a new transform at the position of the sun, child-ing the planet to this transform, and rotating the transform. But this only took about an hour, and I had a bunch of residual physics excitement from my physics class that day.

Programming gravity is quite interesting, especially when you attempt to put lots of bodies with varying masses and velocities, however the principles of Newtonian motion can apply in a virtual space. If nothing more, by doing so we can, in a sense, write proofs (in a theoretical sense) of Newton's gravitational formula in a virtual environment which can emulate the impossible perfection that comes from elimination of real-world variables.