Thursday, March 21, 2013

Developers Log. Development Date 123. Polish!

It's been a month since my last post. Most of my work has been on improving the camera and player controls. I have been hoping to get a blog post about the camera up, but it's not quite there yet. I want to post some of the ideas and logic involved in making an intelligent camera for 3D platforming. The camera is working pretty great, but I hope to explore a few more ideas to really make it shine, so I will save my post on that until a later date.

Aside from that, I have been working on adding polish and tying up loose ends for our GDC demo. After all of the work on the camera, I needed something a bit lighter to restore joy to my soul. I added a small feature I have been hoping for since pre-alpha. I really wanted to help set the atmosphere for the player being a ninja, not just a parkouring guy.

 For this I explored different ways to add a mystical essence scarf that follows the player (like the scarf of a ninja mask.) I first attempted to use a model with joints to allow physics to cause the scarf to swish around as the player moved. In the end this didn't feel feasible in the time constraints I have. Without getting everything right the scarf would fly around like mayhem, crashing through the player and just looking terrible. I then moved onto using a trail renderer, which was simple and much more fitting to my scope of time. I hope to spend more time to find a good texture to use that really gives it the feel I want. For placeholder, I changed my blend type to allow me to just create a black and blue effect.  In the picture below it's much much longer than it is in the current build. This was taken at an awkward time for our scarf.


Part of my essence scarf implementation required me to set up a component that attaches itself to a specific bone of the avatar. The scarf attaches to the head, so that even when the player does a flip, the scarf follows his head. I was able to use this same component to attach a katana to his back, further adding to the ninja feel. Good stuff.


Thursday, February 21, 2013

Developers Log. Development Date 95. Controls!

The main focus of this week was controls. I started off the week working on adding the ability to slightly adjust velocity for left/right movement. Last week I locked movement when in air, but I wanted the player to be able to add small corrections to their landing position. I accomplished this by adding two methods to the inputController (well, I slightly modified one we had been using, then added the other.)

 public override Vector3 GetWorldVectorRelativeToCamera()  
 {  
    float horizontalValue = ThumbSticks.Left.X;  
    float verticalValue = ThumbSticks.Left.Y;  
   
    Matrix cam = Matrix.Invert(Camera.View);  
   
    Vector3 vec = (cam.Forward * verticalValue) + (cam.Right * horizontalValue);  
    return new Vector3(vec.X, 0, vec.Z);  
 }  
   
 public override Vector2 GetLeftThumbstickRelativeToCamera()  
 {  
    Vector3 directionVec = GetWorldVectorRelativeToCamera();  
    float horizontalValue = Vector3.Dot(directionVec, physicsBody.Orientation.Right);  
    float verticalValue = Vector3.Dot(directionVec, physicsBody.Orientation.Forward);  
            
    return new Vector2(horizontalValue, verticalValue);  
 }  

GetWorldVectorRelativeToCamera returns the vector in world space of the left thumbstick. So if the player press forward, it returns the vector of forward from the camera (the camera can rotate 360 degrees around the player.)

GetLeftThumbstickRelativeToCamera returns the value one expects from calling Thumbsticks.Left but relative to the camera and player. This came into play for when the player was locked in a certain orientation. The player could be jumping in a direction that is equivalent to the camera's right. If the player pressed down on the thumbstick, the controls need to be the same as when the player is on the ground. If the player is on the ground and presses down, he runs at the camera. If the player is jumping right and presses down, he needs to slowly move towards the camera, still keeping his velocity and orientation going to the right of the camera.

In addition to in air controls, I added a new sliding state, for when the player slides down a wall, changed horizontal wall runs to cause the player to fall after 500 milliseconds rather than auto jumping for them. Requiring the player to jump rather than doing it for him/her adds a better feeling of play. Also, I now account for thumbstick directions when jumping to slightly alter the jump direction. This value needs testing, but it might be too small of an influence currently.

Outside of controls I added a few features to our level editor to make creating triggers easier on the level designer. I finished connecting all of the trigger creation for killzones, checkpoints, and ability pickup. Earlier in the week I helped architect the way we wanted to do triggers, I wanted to ensure we were taking advantage of our component/entity system.

We have a trigger component that listens for collisions from the physics body. This trigger can also have a flag set for what can trigger it (just a player, player and AI, bullets, etc.) When triggered, it raises events so that any other component that subscribed to the trigger will be notified. This is sort of a shadow to Unity3d's broadcast functionality, but I prefer this method.

Here is an example of how this pieces together:

Trigger class
 public class Trigger : Component  
 {    
     public delegate void TriggerEnter(Entity entity);  
     /// <summary>  
    /// Methods to be invoked upon the appropriate entity colliding with this trigger.   
    /// </summary>  
     public event TriggerEnter OnTriggerEnter;   
   
     ... [within collision handling, relative to whatever physics engine you are using]  
     if (OnTriggerEnter != null)   
       OnTriggerEnter.Invoke(entity);  
     ...  
  }  

Some component that uses the trigger.
 public class ExampleComponent: Component  
  {     
     public override void Initialize()  
     {  
       Trigger trigger = OwnerEntity.GetComponent<Trigger>();  
       if (trigger == null) 
           throw new System.NullReferenceException("Trigger component did not exist on owner entity");  
       trigger.OnTriggerEnter += OnCollide;  
     }  
   
     protected override void OnCollide(Entity entity)  
     {  
         // Do something, play a sound, do damage, etc  
       OwnerEntity.Dispose(); // delete trigger  
     }  
 }  

Using this method, I can attach several components to an entity that has a Trigger component, and each one can listen for the on collide, and activate their respective code when that happens. Very dynamic, flexible, light, and powerful.

Tuesday, February 12, 2013

Developers Log. Development Date 86. The saving of a level.

Two weeks since my last update. Last weeks post sits as a draft, 90% complete, but due to things getting crazy it was never completed. Last week we realized the level we had was unusable. The artist that created the assets in Maya had not exported the models at the origin, this was causing discrepencies when we loaded the models at their positions in XNA. We had developed a tool in Unity3D to build the maps then export them as XML so that we could re-build the level in XNA. By modifying the model and setting it at the origin, the level would become messed up in Unity (as expected.)

I spent some some time scripting a Python script for Maya that would center the pivot on the model, then center the model at the origin (relative to the pivot), then it would freeze the transformation and clear the history. I created a second method to loop through all fbx files in a given folder and all sub-folders, importing the fbx into Maya, running the centering script, then re-exporting the fbx file. Next I scripted a Unity editor script that adjusted each model relative tot he original offset in Maya, so that everything matched up.

I then spent a lot of time getting quests and quest objectives to go from our unity level to our XNA level. Part of this included setting up triggers and the quest manager. The Quest Manager loads the first quest, spawns all of the objectives, then after all objectives have been completed, the next quest loads. Standard stuff.

After the playtest, I slept for 12 hours. Following that a little ranked League of Legends, a man must keep his elo up, of course.

This weekend I spent working on improving the controls. The biggest issue from the playtest was the controls are slippery. People seemed to really enjoy the game, the concept and the feel they got from doing ninja moves, but they couldn't master the controls the way that is essential to having this game succeed.

When I first sold myself on this game idea, before I pitched it, my selling point was having tight and sexy controls. I haven't had the time to sit down and make them sing, I've been needed on too many other fronts. Everything is coming together well, and I finally now have the time to really baby our controls.

First I improved our camera. It now considers more of the player to determine if the player is in view or if the camera needs to do something to get the player in view. I will be looking into either making objects transparent, or improving our logic for moving the camera in the coming days.

Next I removed rotation of the player whilst in the air (again.) This time, however, I added the ability to change direction when using the double jump. This feels great. I also added the ability to slightly shift to the left/right mid air. So while not turning and moving as freely, the landing position can be slightly altered.

The wall jumping was one of the biggest challenges during the playtest. The answer was "mash jump" to scale between the two walls. Terrible. I added a slide when holding your thumbstick towards the wall, megaman style. This slows down the jumping so the player can make precise and timed jumps. This has helped a great deal, but I will be re-visiting this soon to further improve it.

I'm excited to see these improvements coming along so well, and am also excited to finally be able to focus my time on gameplay.

Tuesday, January 29, 2013

Developers Log. Development Date 72. Animations and Profiling

Woops, forgot to blog last week. I blame the respiratory virus that had me in bed all week.

The first issue I addressed was animations. Our animations have been really glitchy. They would reset halfway through and/or flicker. I finally allocated time to go figure out why. It was a simple fix once the bugs were found (related to a poor implementation of a student last semester of my animation code and some blending animation code from the Microsoft education catalog.) Essentially some animations would be called to play twice or reset mid play-through. 

Second I found a profiler to help us identify where our draw and update calls are spending most of their time. It seems pretty solid but has awkward interface controls, so I lightly wrapped the controls to allow us to toggle the display on and off, enabling us to turn it on when we need to check what is going on when we start to see performance hits.

Lastly I worked on some scripts to help convert a level created by one of our artists in Unity to fit the format we have designed to be accepted into our content pipeline. Within a few clicks all of the prefabs become converted to the format now.

Tuesday, January 15, 2013

Developers Log. Development Date 58. A New Year!

With the end of alpha I never found time to return to the blog before the semester had ended, and had no ambition for blogging amid the Holiday break. With the spring semester of my Senior year here, it is time to rekindle the blog for our XBLIG game (current code name: "Ninja Avatar: The Trials.") Despite being MIA in from the blog over the past few months, I continued to work on the game.

I took advantage of the break to work on a some Unity3D scripts for the editor allowing us to harness the power of control and ease-of-use unity offers for level and prefab creation for our XNA level creation. The artists can now create a model, then use unity to set up custom collision walls, and save it as a custom xna prefab. They can even use the same model (and different ones) to build a collage of models into one prefab. (When loaded in xna it still only has to load the fbx just once, however.) These models are used for the level creation. Both the models and prefabs use xml serialization. On the XNA side we will simply reconstruct the prefabs as we build each level. This will greatly improve our performance and ideally our level creation/maintenance time. It was also key for quest/objective design for the levels.

Since the semester started back up ago last week, I have been adding some functionality to the tool such as an opacity slider for the display/collision models. I've also fixed several bugs and cleaned up the process the user has to go through to make it a more smooth experience.

In addition to working with the tool, I've been working on tightening the controls for the game. This game absolutely needs tight controls, and they just aren't there yet. I've spent some time with Overgrowth (an indie game under development involving light parkour) observing the controls hoping to get a better feel for what makes something feel so good and tight.

Additionally, in my spare time, I began doing some research for prediction and smoothing for out networking side of the game.

Monday, November 26, 2012

Developers Log. Development Date 41 - Networking

I'm behind a few days, but that is for good reason. Alpha is approaching (10 days and counting! Yikes!) and there is so much to do. With the restriction that every system must be in place, we are, obviously, getting every system in place, and that is taking a lot of time and commitment! From a collection system to a UI, my team has really stepped up to get a lot done this sprint. I started off the sprint helping Adam to get the corner-wall shimmy maneuver working, as well as helping Mavin with the limbo state transition the player enters when jumping off of walls (a limbo state is a state where the player has no movement, either for a set amount of time, or until he/she hits the ground, grabs a ledge, etc.)

Post helping the team, I finished the problems we were having getting the game to work on the Xbox. Which reminds me: sadly, you still get a wall of text this week rather than the promised video. That will come next week, but my progress this week isn't quite ready to be shown in a video.

After fixing the xbox deployment, I set out to integrate multiplayer. First, I set up a screen system to allow us to have a lobby screen, a matchmaking screen, a game search screen, and, of course, the game screen. The player starts off, is forced to sign in if not signed in (currently only noticeable on pc, but once the game is launched this will be important too) then they can choose to host a game (local or live) or search for a game (local or live.) This all works rather well. Once in the lobby, the players signal they are ready and the game starts. A lot of this code framework came from step 4 of the xna Microsoft tutorial found here. However, I built my own network controller class that helps manage the creation of the different types of networks, and different actions the user can perform. Additionally I added a player class that helps keep the players Character entity paired up with actions such as transmitting the data to the other sessions.

I'm not entirely done with the last part, but it's getting pretty close. Once I'm done with the basics of multiplayer, I will be working on the abilities to the end of the sprint. The final sprint will be helping the team finish their respective tasks, and working on controls. The controls have gotten wonky, and need much love before I'll be happy to call it Alpha.

Thursday, November 15, 2012

Developers Log. Development Date 30 - AI Refactoring, Abilities, and Pair Programming

I learned the value of pair programming this week, at least i learned a new value to pair programming. I worked with Ron, who is the lead for out AI, and we did a lot of pair programming. When we first started to have some of our programmers work on AI, I mentioned the approach I felt would be best for implementing the AI character; however, I wasn't working on AI at all and so they ended up taking it a different direction. I think that even though I originally showed everyone the code and the way it was structured, the programmers didn't fully understand the strengths of the entities and components, and some might have even felt intimidated by the code base. But doing some pair programming helps to align everyone to the same vision of the game and the engine. I hope to do more of this to help instill more confidence in all of the programmers in going out into uncharted territories and build new systems needed for the game.

Having worked with Ron we ended up pretty much where I had originally envisioned the AI systems, being that there is a base Character entity that is used for both the player and NPCs.  This Character object then has different components for handling movement, state changing, ability control, etc. The player has a PlayerInputController and the AI has an AiInputController that the movement state machine uses to move the player around. This may or may not be the ideal way to do this, as I'm no expert on AI, but I felt this would be a good approach as harnesses our movement state machine which was in place for the player with no code duplication. The AI will now not be able to move when he is knocked off his feet by the player, without the AI code needing to know that. Each AI state (the AI also uses states to manage which task is at hand, such as patrolling, chasing the player, searching for the player, capturing the player, etc.) The AI can just continually "press" the thumbstick the direction he needs to go to get to his target, and if his movement state is affected by some external force, it won't break the game. His movement wont override the forces, as the movement is completely separate in a different component.

Aside from the refactioring I also finished setting up the AbilityController allowing abilities to easily be mapped to different buttons. When the button is pressed, the controller will spawn a new entity for the ability. Each ability will have it's own components (if needed) if it is a projectile, a mine, or an AOE. By being an entity the ability can exist for just a moment to apply the effect and disappear, or it can persist for however long.

Currently I am working on some new movement states for putting the player in Limbo. I intend to work with Mavin on this as it will help him manage player jumps off of walls and such. There are times when the player needs to lose control of movement, and these limbo states will accomplish that. This will enable us to allow the player to move exactly how he wants, even in the air, -most of the time.- If, however, the player is thrown into the air by another player/guard, or jumps off of a wall, we may want to restrict or remove his/her control all together. These limbo states can then serve to manage the control restrictions, while still transitioning the player to a new state (perhaps a SittingOnGroundLimboState, when landing after being thrown, which requires the player's avatar to stand up before he can start running again.)

On a different note, I'm hoping to start doing video blogs in the future, that should help kill the Great Wall of Text that appears on all of my posts. :)