Tuesday, May 03, 2016

I Tried To Make Line Rider

It worked marginally well, but the rotational velocity was very, very difficult to figure out: it was never fully figured out. Firstly, SFML's Shape classes (2D) rely entirely on Euler angles to set the rotation of an object. No telling objects to look forward with a nice little forward vector, oh no. I figured I could just convert the forward vector into an angle... and I did. Using this function I added to my Vector Math class:















Seems like a reasonable approach, right? It was. Those functions determine the angle of any vector just fine as far as I could tell. Let's pop over to the Sled class (the sled rides the lines) and grab the Euler angle of the line (do you feel that chill in your spine?):





















Okay we're getting a little less reasonable now, but this was my solution to get the angle of the colliding line segment at least mostly correct.






























First, I have a bit of boolean functionality to test whether it is the first frame of collision (I wanted to do this all without using contact points, as time was running out and finishing making this was becoming less and less possible). To find the rotational velocity of an object that is revolving around a point, given the linear velocity, is a simple enough task. It's simply the linear velocity divided by the distance of the object to the axis of rotation. Since I was not using contact points, and was just rotating about the center of the object, that distance was zero. So I just took that part out, which is valid.

After all this, it appeared that my angle math just didn't align with SFML rotations. Which makes sense, I am pretty arbitrarily defining the point of rotation. I tried simply adding and subtracting 90, 180, 270 degrees to and from the draw angle, but things just didn't work.

So getting the rotational velocity didn't happen, but the rest of it works pretty well! I used a distance check to detect whether lines were worth trying the SAT (Separating Axis Theorem) test with the sled. I got to write a pretty special version of it to handle collision not with another convex polygon, but with a line. I also had to be able to collide with the bottom of the line, so I implemented a special, yet very close to normal, version of SAT.


Phase 1:


























Phase 2:






























I also did some tricky stuff with line drawing to make the lines. Each connected series of lines was its own std::vector of sf::VertexArrays contained within one big 2d vector of these lines. I made it so the user can, after drawing any amount of lines, continue drawing existing lines. I also added a few constraints on how the user can draw lines to avoid ridiculous angles and make smooth lines.

Even though this didn't work out as I had hoped, feel free to pull the repository and play around with it. It's a Mercurial repository, go ahead and

 hg clone https://nicholaspedalino@bitbucket.org/nicholaspedalino/line-rider

to play around with it. Here's a video link to see the final demo:


Cloth Demo

Springs are an integral part of any game programmer's arsenal. They are used everywhere: in cameras, ragdoll physics, water, soft-body physics, and the focus of this post: dynamic cloth. If you take quantum field theory to be the fabric of the universe, then energy springs are basically the fabric of the universe. (resist tangent)

Anyways, I made a "cloth," which could be better described as a 2d lattice of springs.

Looking at the interactions of the system as a whole can be overwhelming, so let's break it down. First let's work with the most basic structure: a point mass. Each vertex of the cloth is simply a point mass (also known as a Particle). Define a struct with the following members, and any others you'd like to add: a mass, a position, a velocity, a force, and a boolean indicating whether the point mass is fixed or not. Use any integrator you'd like: Euler works, but Verlet works better as it takes inertia into account. They are very similar, and there are many explanations of each method.

In addition to an integrator, also include a Post-Update method: an update function that runs immediately after your normal update. This Post-Update should perform the actual integration on the total force, while the update method should additively calculate force each frame. The usefulness of this will become apparent later. Simply put: since there are 4 distinct connections for all non-edge case PointMasses, we will need to find the cumulative force for all of them.

Next, we'll need to create a Spring class. This class will include the following members: two PointMasses, a spring constant, and a scalar equilibrium distance. You could add a breaking distance to define the max distance a spring can expand before it breaks, but I won't go over that in this post.

Next, we need to create a 2D array of PointMasses. While doing so, we want to create spring joints connecting each PointMass to the one above and to the left of it. The general algorithm for doing so is as follows:

 PointMass[][] pointMasses;
 Spring[] springs;
for (i < cloth_height):
  PointMass[] row;
 
  for (j < cloth_width):
    PointMass newPM;
    newPM.position = (initialPos.x + j * spawnDistance, 
                      initialPos.y + i * spawnDistance);
    pointMasses.add(newPM);
      

    //if there is a PM above this one
    if(i > 0):
      Spring newSpring;
      newSpring.PointMassA = newPM;
      newSpring.PointMassB =  pointMasses[i - 1][j];
      springs.add(newSpring);

    //make the top row fixed
    if(i == 0):
      newPM.isFixed = true;

    //if there is a PM to the left of this one
    if(j > 0):
      Spring newSpring;
      newSpring.PointMassA = newPM;
      newSpring.PointMassB =  pointMasses[i][j - 1];
      springs.add(newSpring);

Of course this is just pseudo-code, but you get the idea. Something to note: you can set any of the PointMasses to be fixed, which can lead to some interesting results.

I won't go into the spring integration method here, as it is also well documented online. One important note: make sure your force directions are correct!

And that's pretty much it, except one caveat. Since we update in-order, and since we are dealing with an interconnected lattice of springs, PointMasses indirectly effect all of the other PointMasses. So, if we move the bottom-right point on our cloth, the top left one may be effected. Say we update our PointMasses left-to-right, top-to-bottom. The new position of the bottom-right PointMass will update after we've already calculated the top right one.

We need to account for this, and the simplest (yet particularly inefficient) method I've found is to integrate multiple times in each frame: each time getting closer and closer to the actual position the PointMasses would be in ideally. If you have any better solution, or ideas for resolving this, email me or leave a comment! I'd love to find a better way to do this, but for now integrating multiple times is the best way I know.

Predicting Physics

Say you're playing a game of football with Sandra Bullock. Sandra is running in some arbitrary direction, so you will want to throw the ball somewhere in front of where she is at the time of your throw. In addition to this, since gravity exists, you will also want to throw the ball upwards a bit. We intuitively understand these concepts, and carry out basic, inexact predictions like this all the time.

Similarly, if you wanted to beam yourself from a planet onto a starship moving at warp speeds, I would imagine there would be a lot of physics predictions to take into account. Luckily, only rarely in games do we need to take relativity into account when predicting physics.

Predicting an object's physics is as easy as running your object's integrator (update) functions a bunch of times, without applying those new positions. If you have a fixed framerate, passing that fixed framerate into your special prediction integrator as its delta time will return a highly accurate prediction.

In my asteroid physics prediction demo, the first thing that had to be done was to calculate a time value. How far in the future should we predict? I derived that time value based off of the distance of the mouse cursor to the missile silo. This asked and answered the question of: "How much time will have passed given the missile's initial position at the silo (P1), the missile's final position (the mouse position, P2), and the linear speed of the missile?" A simple calculation:
t = distance between P1 and P2 / missile speed

 Given this time variable, solving for the final position of the asteroid was now possible. While the missile moved at a constant rate, the asteroid moved not only at a variable rate (acceleration), but a variable acceleration (jerk). Quite a complex calculation to do all in one go (I'm not sure if this is solvable using one equation). Luckily, computers are great at repetitive tasks!

So, in a for loop: 
for (float i = 0.0f; i < TOTAL_TIME; i += FIXED_TIME_STEP)

I integrated i times, and saved off the final position after simulating real-time physics in one frame.
Pretty simple! This was so interesting to work with, however, because the asteroids moved with variable vector accelerations defined by a gravitational force. The asteroid relied on only two variables to move: an initial speed and the force of gravity. Below is the derivation I used to go from this gravitational force to a manageable vector acceleration (which was then simply added to the velocity).


And that was it! A cool thing about predicting physics is it has nothing to do with the accuracy of your game's physics: no matter what kind of integrator function (real or imaginary) is implemented, predicting this physics is as easy as running a special version of the integrator for any given time.

Saturday, March 19, 2016

Production Post 10 : End Game

We're about two weeks away from release and it's coming down to the wire. The project is dripping with my blood, sweat, and tears, and I have to just keep working harder and harder in order to deliver that release build in a state I will be satisfied with. I'll have so much time to sleep when I'm dead, so why bother sleeping now?

I would put the main menu at about 60% functionally complete, and 30% polished. The pause menu still breaks minor stuff and doesn't look good. The dragon movement is only mostly finished, but not in a state we can release with. The levels are looking a lot better, but the ghosts need new, better AI, the ocean level needs a lot of visual polish, the splash and boulder crush particle effects are severely lacking, and the wind obstacle particle effect needs some minor tweaking.

One huge area of our game we are missing entirely is prompts to tell the player how to play. We need to make this as soon as humanly possible, one shot, polished, ready for release. We don't have time to iterate on this.

The game needs a LOT more feedback to inform the player what exactly is going on. We need to polish the credits menu. It's too late to make that difficulty curve tool for Zac, so we're going to need to sit down and figure out a decent way to work around that limitation.

Will and I are still pushing heavily for the infinite play mode, which the systems are almost entirely already made for, but I'm going to put that at 50% probability of materializing.

We need to make it so the split orbs get destroyed (with feedback) when they get hit by an obstacle. The Overworld gate animations still aren't finished. We still need to add chapters, A LOT of chapters if we don't have time to make the infinite play mode.

We have a document on how we might optimize the game, but we need to sit down and optimize it. The framerate on mobile is still very not great. Load times are verging on atrocious, with no indications that loading is occurring.

There's still so much to do: these next two weeks are going to be critical. Compounding this with other classes, which are also coming down to the wire, and you get eight very stressed out, very overworked developers. But that's half the fun! We've all worked too hard on this to not come out with a polished, bug-free, beautiful game, and I know we will be able to do it. But wow are these two weeks ever going to push us to our limits.

Production Post 9 : Inspiration Outside of Games

I have a snake. Her name is Mona. She is a sweet babe and I love her. Here is a picture of her on my head.


As it turns out, she moves a lot like how our dragon moves! Watching her move actually inspired a lot of how the dragon moves.


This isn't her, I don't have a gif of her slithering around, so I found this other snake that looks like her on the internet! But notice how a turn will start with her head, and propagate down through the tail. In code, this ended up being the node system of motion I implemented. A turn starts with the head, and the nodes follow, but not directly, the motion of the head. It kind of smooths out down the tail:


In the past, the nodes would follow the path of the head exactly. It didn't feel right, it felt more like controlling a train than a dragon. It's hard to put into words the tiny details of how a snake moves, but as the turn propagates down the tail it tends to sort of straighten out.

When making games, I think most of the best inspirations come from anything that isn't a game. Observing the world around, and other forms of media, you makes great, original material for systems, functionalities, and games in general.

I haven't ever seen a game entirely made out of shadows, which means at the very least it's a relatively unique style of game. It also gave way to a series of really interesting effects and mechanics that work well with a game made of shadows. We got the idea to do this through a series of thoughts, the major breakthrough being shadow puppetry.

Self-sacrifice and protection are themes rarely seen in games: to arrive at these we thought a lot about motherhood. Given that none of us are mothers, this was a difficult thing to do accurately. But we keep this idea in mind as we develop the game, and I think it shows through.

But I think what we've done here has been important in shaping how I look at games: it's easy to think that all the good game ideas are already taken, but to create an original, interesting game I think you have to step outside of the gaming world and draw inspiration from anything else.

Production Post 8 : Particle Effect Vacations

I love implementing particle effects. So much. It relaxes me: after working on core systems, tearing my hair out over complex algorithms, and handling the responsibilities that come with being the lead programmer: making particle effects is practically a vacation. I just kind of zone out and mess around with sliders, values, and curves until things look pretty. I like making things in our game look pretty.

So I'm going to post a few gifs of some particle effects I've made, and briefly talk about them!

This was a pretty quick one to make, I wish I could have made the actual line thinner as it expanded, but that isn't how basic scaling works. The time it would take to make that work is more time than I'm willing to spend on something like that. Maybe when we get to pure polishing, but there are more pressing things to attend to at the moment.


There are two particle effects here: one when a boulder crumbles and another, more subtle fog/mist effect under the mountain. The boulder smashing was the first particle effect in the game, and I'm not particlary (heh) happy with it. The mist I made earlier today: a lot of stuff is happening with that but my favorite part is that as it rises, the second or third phase of transparency brings it slowly to zero alpha, which gives the illusion that it dissipates as it rises into the atmosphere.


I set the background dandelion effect to render as shadows on the same layer as the background, which I think looks really nice. If you notice, the dandelion tumbleweed thing actually effects the background dandelions! I attached a wind zone to effect the background particles, and a sphere trigger collider to impart a force onto the orbs. The dandelion ball obstacles aren't finished yet, but they look alright. To get them to fly around in a circle, I had to give it an x force over time as a sine wave, and a y force over time as a cosine wave. Circles! Everything is circles!

Ah Unity default particles. Maybe I'll change the texture of these to one of the smoke particles Shannon made, but then again... meh. I think this one looks pretty good. I do need to resize this: the ghosts used to be tiny, shitty hands until Amanda made them ghosts. So the effect would execute, and I destroyed the hand a couple split seconds after the effect started, which made it look like a smoke bomb kind of magic poof. You can see the ghosts disappear while the effect plays, and yeah me no like.

I'm looking through the game and, uh, I'm not seeing any more. That's really disappointing for me. I need to make more particle effects. Luckily, most of my tasks right now are particle effects now that the Overworld is done. Next week I'm thinking I'm going to spend a lot of time on these. It's going to be a good week :)

Production Post 7 : A Brave New Overworld

A couple days ago I rewrote how the Overworld functions! It extensively changes how the Overworld interacts with DataManager, and how a player navigates. Here's a clip:


All the tutorials are on a big wheel now! With zooming in and zooming out, proper level progression (persistent progression saving included with DataManager), and.... drumroll.... chapter progression! This is a pretty large step forward in development, and puts us significantly closer to a complete build ready for release. Also, it allows Zac to design and implement new chapters seamlessly.

In this post, I'll talk about how it works currently, and how it can be improved.

First off, there are six states the Overworld exists in:


This object-state design pattern is proving to be invaluable. There are different inputs that need to be processed and followed unique events for ZOOMED_IN and ZOOMED_OUT.

ZOOMED_IN recognizes, for now, a single tap to begin zooming out. If the tap was on a node; however, this zoom out event is overridden by the level entering.

ZOOMED_OUT recognizes a single tap which switches over to the ZOOMING_IN state. It also recognizes swipes left and right, and tells the chapter wheel to begin rotating in the correct direction. This instantiates either the next, or the previous (with exception handling for if we are on the first or last chapters and whatnot) chapter, rotated 90 degrees, and positioned either left-ward or right-ward from the wheel axis.

That instantiation makes the new chapter a child of the wheel, allowing me to simply rotate the wheel with the chapters following, without having to worry about moving the chapters at all.

As far as I know, this all works really well! No bugs have come up and everything seems fine from the player's point of view. But, I think the system is flawed and a bit hard to follow for a few reasons. I made this switch about 3/4ths of the way through writing this: I went from reading everything from DataManager to storing localized instances of data. The chapters are destroyed and then instantiated, which means the indices of the List of chapters does not line up with DM's list of chapters (the List of Lists of level IDs I talked about a couple posts ago). If I can change it to sync up perfectly, and hide inactive chapters on the wheel rather than destroy them, it would make saving level progressions a bit more sensical. I have a feeling that this convolution will lead to some minor bugs in the next week, so when those pop up (inevitably when Zac starts adding chapters), I'll redo a bit of how this class works. Until then, who really cares?

Production Post 6 : Data!

A couple weeks ago, the team and I went to implement some little thing. I don't recall what this thing was, but it did uncover a whole slew of issues that urgently needed resolving. We traced the issue back to GameManager, but to fix it we would have to change a lot about how we are saving and loading data. The team and I worked for a few hours to try and hack what was already there together, but it just wasn't working and we all went home at around 1AM. Side note, walking out of the lab with a fundamentally broken game is, like, really disheartening.

So I went home, got some sleep, and death-marched back to campus the next day hell bent on making this work.

Step one was to make an entirely new class: DataManager. DataManager would store all the World and Level data the game needed to operate. All objects, manager, and scripts that needed this data would run through this class. This was no small task: at the time, there was practically no management of this data: there were places that stored data that meant different things than the other places. The code was littered with pseudo saving and loading that sort of did the actual save file writing and loading pretty randomly. The previous SaveLoadManager was this tacked on thing that the game sometimes wrote to, but most of the time did not. It was a nightmare, but not unconquerable.

First thing I did was write make two structs. These structs went through a few iterations, especially with how we managed the completed nodes, but the final structs became:


There are two instances of these structs in DataManager, and EVERYWHERE in the code the previously referenced random half-assed versions of these could now just call a long series of getters and setters defined in DataManager to modify these values. Another neat thing I did to further make DataManager a pleasant black box: in all the setter functions, in addition to just setting the data, I also make a call to the Save() function. This means that absolutely nothing in the code has to deal with saving and loading, DataManager would just do it.

Previously, there were a few calls throughout the code to the Load() function. This now served absolutely no purpose, since the most recent data is always accessible from DataManager: no file-reading required. So, the ONLY place in the code where Load() is called is in DataManager's Awake() function, which only calls once at the start of the application. Beautiful!

Which brings me to the next big change: replacing the non-functioning, platform-dependent data file with Unity's built in PlayerPrefs. PlayerPrefs is essentially a managed data file with a simple Dictionary-style lookup system. It was exactly what we needed. The Save function is as follows:































Simple enough, and totally under the hood, taken care of, and nobody needs to worry about saving or loading. A huge improvement already!

But, PlayerPrefs can only save three data types: ints, floats, and strings (along with nice Dictionary-style lookup keys). So, as you may have noticed, the only data that isn't one of those data types is the List of Lists of integers which stores the CompletedNodes for each chapter. Saving this as a string was the obvious choice, and two functions had to be written to handle converting this list of lists of ints into a string: one to convert from string to List<List<int>>, and one to convert from List<List<int>> to string.

The main part of this was adding two unique identified characters: a '$' to indicate the end of a saved node ID, and a ';' to indicate the end of a chapter's list of node IDs.

Below, I'll post the (nicely commented, as usually) functions:

List<List<int>> to string for saving

string to List<List<int>> for loading
Reasonably elegant, I think, but ya know it doesn't really matter because, yet again, it's completely a black box. The only thing myself and my lovely programming team have to use from DataManager are the getters and setters to access and set data.

In addition to writing DataManager, I had to scroll through every single script in the entire project and make it all work with DataManager. It made a lot of stuff more elegant, and, more importantly, functional, which is something it was previously lacking. The DataManager opens a lot of doors there were previously either closed or really difficult and time-consuming to find.

And that's pretty much all of how DataManager works. So far, it's made the OverWorld possible, and sped up development time on pretty much anything that has to know about World or Level data.

Friday, March 18, 2016

Production Post 5 : I'M DROWNING IN RATIOS

The ocean level. The fucking ocean level. My god, my god, what have I done. There was a point where the ocean level worked fine and nobody really cared that you couldn't change the overall level time. The world was rose-colored and life was worth living. That all changed when we wanted to be able to change the overall level time.

The level functions along the same principles of object-state design I talked about in my last post, with the following managing enum:


The FLOOD states indicate that the waves are rising, and the DRAIN states indicate that the waves are falling. Below is a gif of the ocean level with the level time sped up:


The short rises and falls are what the MINI refers to, while the overall flood or drain are what the FLOOD and DRAIN refer to. I needed to relate the overall level time with the time for each of the above states. So, I made a public variable to decide what percentage of the level the FLOOD would take relative to the DRAIN (see how the drain takes longer than the flood? That was a major pain to accomplish in units of mini rises and falls). Then, I made another public variable to relate the distance a mini fall would cover compared to a mini rise. These variables were made with the FLOOD in mind, because a DRAIN is just an anti-FLOOD in the code (with a few caveats).

I'll post this here, but you shouldn't read it really. It demonstrates the ridiculousness required just to get the correct variables to make this thing work (that was half the battle, I'll admit, and it was very uphill).




































That was fun to work out. All of those variables were absolutely necessary, though. I had to relate every single type of interpolation time and distance to each other using the rations, and make sure the entire monstrosity took exactly <LEVEL_TIME> seconds. It was a labor of love, and totally worth it, because the ocean level actually works with the rest of the game.

I'm not going to post any more code, as it is pretty repetitive going down, but because of that initialize function, the level runs off of just four major state functions: HandleFloodMiniRise(), HandleFloodMiniFall(), HandleDrainMiniRise(), and HandleDrainMiniFall().

I remember writing all this crap: I made a lot of hand gestures to think about these ratios and how they fit into the level as a whole. shudder

Production Post 4 : "Object State" Architecture

The way I've been writing a lot of my scripts has been similar to what a finite state machine accomplishes. A finite state machine usually implies a somewhat complex AI to make those state changing decisions, but for my purposes I've been running these object states on timers.

The problem is that objects often need to execute a series of functions, in order, when timers are completed. This is especially true when we need to interpolate through a series of positions, rotations, scales, colors, etc for polish. I've seen this problem solved by ugly, ugly boolean checks that increase in complexity and decrease in readability very quickly as more states are required. I've been taking advantage of enums to resolve this.

This is a bit hard to explain, but it's actually a very simple concept, and one that has made my code very readable and easy to add and remove functionalities. So, to explain, I'll use the Wind Level as an example:

The important functionality of the wind level is that an invisible wind represented in code by a changing force vector blows the orbs off screen. It was easy enough to get the base wind blowing, but in order to feel like wind I couldn't just have a constant force vector for the wind, I needed to add turbulence. I accomplished this with a series of interpolations that execute in-order. This is the enum that I used:


Then, in the update loop, I have a switch statement that calls the proper functions for the current "turbulence" (object) state (mTS):


Really simple, highly readable, and yes all of these comments were in there to begin with I didn't just write them for this post. So, the HandleNone() function increments a timer, and when the timer runs out, it resets the timer for the BUILDUP state and changes mTS to BUILDUP. Super easy to follow, and with no nasty boolean checks.

I like to use this kind of structure even if I only have two states (which one would typically default to a boolean variable). This is because whenever there are two states, odds are we'll want to add another one later for some polish reason. In this way, the code becomes very modifiable. Maybe we want to make it so the orbs all shoot off a windy particle effect, but only during the COASTING state. Without having to really search through any code, we can accomplish this very easily by going into the HandleCoasting() function and writing some code there!

In short, using enums to manage object states is a really good idea; it makes your code readable, modifiable, and gives you a mini finite state machine to work with in the future!














Friday, February 12, 2016

Production Post 3 : "A link is only as long as your longest strong chain"

Simple, elegant, and intuitive solutions to programming challenges are always ideal. One particular programming challenge we have been faced with throughout the project has been making the tail move properly, and unfortunately an intuitive solution is not possible. There are a lot of caveats that come with making our dragon move, and documenting the current approach should make for a useful blog post.

In the midst of these huge modifications and upgrades to the game to get the game ready for feature lock, fixing the tail has become a lower priority task. But, last night, I stepped Zac through the tail code, explaining a lot of the how's and the why's of the algorithm. It proved to be very valuable, so I'm going to do the same in this post. Specifically, I will focus on the section of the algorithm that deals with the dragon bouncing off the bounds of the world (a circle).

Before we start, I'd like to note a couple things. The tail is broken up into individual node structures, each doubly linked with a parent node and a child node. This structure is contained in the DragonHead class. I have already explained in my previous post how the dragon's head acts as the managing class for the tail, so I won't go into that here.

The Reflect Component of the Algorithm

Let's start with the simplest part: the physical reflection. It is one line of code:







This line of code simply reflects the node off the wall, in the exact opposite way it was facing (without inverting the head's up vector like it used to).

Now, we'll go in-order in code with what happens when the head first hits the wall. The head hits the wall and calls that Reflect() function on itself; the rigidbody also accounts for this reflection.

The head then tells its child (the first tail node behind the head) that it has reflected. It's functionality is described in the comments.






























Without worrying about the math here, the crux of this function is to calculate the time it will take the current node to reach its parent's reflect position given its current velocity. Then, given this reflectionTFinal, the node knows when to reflect itself. A new gameobject with the same transform and velocity as the parent is created, and the node follows that transform for the given time in the same way it would follow its real parent.

The Problem

This is inherently wrong, as the velocity changes due to an acceleration (via rotation), if the parent was not moving perfectly straight at the time of collision. I will address this later. A funny tidbit about this function: when Zac came over we got to this and I was calculating the distance with a standard distance check using Pythagorean distance. But, after changing it to a Vector3.Distance call from Unity's Vector3 library, we saw a significant increase in reflection stability. We were baffled by this: how could this very rudimentary calculation be wrong?? A little while later we realized that, through a slight oversight, I was square rooting the square distance... twice. Of course, though, that was only one factor of why the tail breaks apart so often.

Let's take a look at how the problem here manifests itself in the game:














The first thing I notice here is that the head is the source of the problem. A side effect of how the tail is written is that it corrects itself over time, especially when the dragon moves in circles without hitting the boundary. The head being the source of the problem makes my proposed solution that much more likely to resolve at least most of the tail bugs.

Let's focus on JUST the dragon head and the node behind it, as the dragon head controls rotations and the node behind it is the most screwed up.

Blue: child node
Black Dotted: the initial transform of the parent at time of reflection
Black Solid: parent node final transform at time of child reflection
Grey Dotted: parent node copy initial transform when created by child
Grey Solid: parent node copy final transform at time of child reflection
Green Arrow: Trajectories from initial position to final position






















This works great, but only when the head is not turning at any point in time between the reflection of the head and the reflection of the child tail node. Since most of the game is spent turning, this simple position derivative will not work for changing velocities.

It just creates a copy of the parent node, and makes that transform continue forward until the child reflects. During this time period, the child node does it's usual "RotateTowards" behavior on the head copy. At which point, the parent node copy switches parents back to the real head, and destroys the copy.

The Conclusion

So, my conclusion is that the parent node copy must account for changes in rotation and velocity due to actual parent node turning. There are a few ways to do this, but first let's look at a diagram of what this will look like when rotations are accounted for. Compare the transforms of this diagram with those of the above diagram and it should become apparent why the latter should theoretically work:



















The idea here is simple: Just continue the trajectory as if the head had never hit the wall. This is where we'll have to test and see what happens. The gold trajectory is where I predict the correct final position of the head to be, but the green trajectory is also possible.

The Code Solution to the Conclusion

Theoretically, if in every physics step I set the head copy's trajectory equal to the inverse of the real head, it should work. The child node will reach the point of collision under the EXACT same conditions (with the correct rotation and velocity) that the head experienced when it reflected. As such, the child should reflect in the EXACT same manner as the head did, and the reflection should be successful.

Alternatively, if this slightly more elegant solution doesn't work, I have another. Instead of even creating a copy of the head:
1) Save off the position of the head at the impact point.
1.5) For testing, save off the rotation of the parent at the time of impact as a unit vector. We can use this to check against the actual unit vector of the reflection of the child.

2) Every physics step, obtain a vector from the collision point to the position of the actual head, NOT normalized.

3) Subtract this vector from the reflect position we defined in step 1.
4) We now have the position the dragon head would have been if it hadn't reflected (the gold dotted line)

One problem I haven't completely worked out with these methods is recalculating the time it will take for the child to reach the parent reflect position. Currently, it derives this time from a linear distance, but, as you can see, the distance is not linear. I need to measure the length of that curve. That cannot be one calculation, though, due to the case that the player stops or starts rotating during that time period. So, like the updating position, that time variable will also need to be updated according to the trajectory of the parent node.

Friday, January 29, 2016

Production Post 2 : Moving the Node Dragon

The first (and still ongoing, but coming to a close) tasks for the new programming team have been regarding dragon movement. We wanted 5 different movement schemes (including the legacy rotation scheme) to be changeable at runtime, so we can add new types of playable dragons. Given the relatively large size of the programming team (4), it is crucial that these schemes are highly detailed and polished; and bug free. I couldn't have thought of a better set of tasks to welcome three new programmers to the team than four new movement schemes. It gives us a chance to all work relatively independently on 4 unique sets of code, while requiring that that code be implemented in such a way that it can be brought together easily at runtime.

This hasn't been an easy task by any means, though. Given that the tail functioned in some pretty heinous ways (if it looks polished enough move on to the next thing), and that the tail is the better half of all five movement schemes, getting everything going has been a challenge.


But let's talk about the state we've gotten it to! I'll start with how the head moves, as it is the driving force of the whole system.


Setting Up


We'll start by defining these four variables, publicly modifiable in the editor. These will control the rate at which our movement schemes move.


Next, in our Start() function, we add all five movement scheme scripts to the dragon's head, as components. We immediately disable all of them, and then make a call to the same function that will allow us to change movement type at runtime.



The function that lets us switch movement schemes at runtime. When the previous movement type != the current one, we switch contexts to the new one.


Movement_Behavior abstract class


Now that everything's instantiated, we can get the head moving. I'm only going to post about the base class that our behaviors inherit from:

abstract public class Movement_Behavior : MonoBehaviour

Since all of our movement schemes always move forward (unless paused), we can always move forward in the direction we are facing:

head.velocity = head.transform.forward * mForwardSpeed;

For now, we'll separate the forward motion from the rotation, and just focus on making the tail nodes smoothly look at the node in front of it. A simple LookAt vector can make the dragon function, but making it smoothly function is a bit more difficult.

AngleSigned is a function which returns the angle between two vectors as a value between [-180, 180].
mRigidbody is the dragon's head's Rigidbody component

Currently, adding a meaningful rotational acceleration seems to make the tail separate, and is largely unnoticeable. So, in our current implementation, we just set the acceleration to be higher than the max velocity so it always rotates at the max velocity.

Tail_Behavior

In order for the tail nodes to not slowly separate from each other, we use about the same RotateTowards function above. I've found that if the angular velocity of the tail is shorter than that of the head, then the tail will peel apart. This is because the magnitudes of the tail node velocities are the same, but the directions are not, so this slightly-off direction will in a sense steal some of the velocity's speed. These effects are amplified the further away a tail node is from the head.

We tell each tail node about the node in front of it, like a forward linked list. That parent node's position is used as the seekPos parameter we passed into the function above. Here's a snippit from that:




And that's the core of how the dragon moves!







Saturday, January 23, 2016

Production Post 1 : A New Team

Before now, I hadn't worked with more than one other programmer on a game. Now, halfway through the project with a codebase I wrote, the lovely Abner, Vasily, and Will have joined the team. This makes me the de-facto lead programmer, a role I am not terribly familiar with but am quickly getting used to. What this really means is I have a few more responsibilities, and a bit more work to do than usual.

For one I have to, in certain ways, manage the programming team. I am completely confident in Abner, Vasily, and Will to get their work done on their own, but I have to make sure we all have tasks to be working on, and I have to make sure the tasks are divvied up fairly and according to their skillsets when applicable. Our first task was to make 4 different movement styles for the dragon, all of which are predicted to be in the game. The first thing we did to make this happen was to fix the tail that I had hacked together months ago. It worked "fine," but any change in speed would have to be accompanied by manually changing this variable called "power" through trial-and-error to some arbitrary value so the tail wouldn't drift apart. The first work session went, I think, fairly smoothly for a first work session with an unfamiliar codebase. Will had a fix in mind that I did not agree would work, and I had a fix in mind, so Will and over-the-shoulder Abner worked together on that fix while over-the-shoulder Vasily and I worked on my fix. About an hour later, mine worked and Will's didn't, which was to be expected considering I wrote the code to begin with.

Unfortunately, about an hour of that 2.5 hour session was spent with essentially everyone watching me program since that work was blocking everyone else from working. I see this as a failure on my part, but now I know going into the next session that I need to be sure there is no pipeline block like that.

The next work session went a lot better. We all sat at our own computers, all working in tandem on our respective movement schemes. There was a point where we were all actually trying to solve the same problem: converting touch position in screen pixel coordinates to 3D world coordinates. Abner found a great solution for getting the proper z-axis coordinates, and we all used it.

As far as lead programmer responsibilities go, I am also responsible for making sure we have proper build numbers and making a changelog every week. I also want to make it clear that all four of us have an equal say: if there is dispute over how we should approach a problem we will discuss it and reach a unanimous decision. I'd say we are all about equally competent programmers: the main thing I will be doing as lead programmer is scheduling work sessions, taking large tasks and breaking them up into smaller tasks, making sure everyone always has something to do, and writing up documents. Fun! I'm looking forward to seeing the technical achievements we can accomplish with four programmers!