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!