Saturday, June 21, 2014

Dev Blog #2

Saturday, June 21 2014

Well, here we are, the end of Senior Project and the end of my career at DeVry. I am really excited to be done and to get on with my career, wherever that may take me. I am grateful for all of the friends I have made and for the professors who made the program fun and interactive.

Anyways, onto the project details. Since we are in the final few days of the session, we are all scrambling to fix little bugs and mistakes and get things ready for the final build and presentation. We have a trailer to put together, websites to make (for ourselves) and a host of bugs to fix. I FINALLY GOT THE PHYSICS TO WORK. I feel really dumb about it, as I was using a few wrong formulas, not to mention that the actual temperature of the atmosphere is not linear in terms of height, but more of a piece-wise function. So, it works really well now, and that model I found at the beginning of the project really helped me out. Since fixing the physics, I have been working on getting the 3 cinematics for the game ready to be implemented. I finished the final one earlier today, and used the same process as in one of my earlier blogs from the previous half of Senior Project. However, I used a different conversion software this time around, as the last time I converted the video files, they did not work at all in Android. They work now, we are just trying to iron out some resolution issues we are having. Android devices come in all shapes and sizes, and with different sized screens. Finding a resolution for the videos that will look nice on all of them is a real pain. But, I did learn a lot more about 3DS Max and animation than I knew before. So, at least I learned something.

I do not know if/when the game will be released, as it is a client based project and our client just so happens to be our professor. The entire game was his idea, our group was just the vehicle for bringing it to life. He has some plans for after we graduate, which I will not detail here. It may or may not come out, and I may or may not announce that on this blog. So, keep your eyes peeled on the Google Play Store and here to see if it gets released or not. We are all very proud of how far it has come in a short 16 weeks. We took an entirely code approach to this project, and I couldn't be happier with the results. Even though none of us are professional artists, the game looks really nice. We plan on entering it in the DeVry Senior Project Showdown. Google it and vote when voting opens. Take us to the top!

Since this is my final blog of my DeVry career, I do not know when/if I will be back here. I hope to keep on making games in my spare time, and might detail them here. Or I might make this into a place of learning for the code newbies who scour Google and blogs for hints and tips on programming. Who knows? Right now I am focused on my job search, as is to be expected of someone who is graduating in 8 days.

As always, thanks for reading and staying with me through all of these years. I enjoyed blogging about my projects, and I hope you enjoyed reading about them. Maybe you even learned a thing or two.

Monday, June 9, 2014

Dev Blog #1

Monday, June 9 2014

It is now Week 6 of the second portion of Senior Project, and I probably should have done this blog awhile ago. However, things have been moving quickly with the project. We have an animation system in place to animate the space jumper as he does his tasks in Phase 1, a media player for cinematics (which was supposed to be done in the first half of this class, but I won't go into details), acclerometer controls, improved models and ones that didn't make it into the first half of this class, and a bunch of other things that I am probably forgetting. Anyways, onto my problems with the project.

I was told by one of our other members that my physics was off. I knew things needed to be tweaked and worked on, but what I did not realize is that the way I am calculating temperature as a function of height was completely wrong. Take a look at the picture at the following link:

Click here to see picture

As you can see, the temperature in the Earth's atmosphere is more or less a piece-wise function. It is rather strange, as you would think that going higher in the atmosphere would make you colder. Well, it does, for the most part. But between 10-20 Km above sea level, the temperature doesn't change at all, and there are some other weird things going on as you go higher. So, using some linear algebra, I was able to come up with some formulas for how to solve for temperature given some height. The way I was doing the calculations was strictly linear. As you can see by the graph, its not linear. For example, the temperature that was calculated in the first update call came out as 40 degrees Kelvin... yea not right at all. At that height, temperature is more like 248 degrees Kelvin (or around there). My temperature calculations still rely on height, but the formulas are different for different ranges of height. There are 4 different ranges, with heights between 10000-20000 meters not changing at all (as per the graph).

It seems to work better now. I should probably get going on the other 2 cinematics that I have to do for the game, as our professor wants us done by Wednesday.

Tuesday, April 22, 2014

Dev Blog #3

Tuesday April 22, 2014

Here we are, last day before our Alpha build is due and our presentation. The project has come a long way since the beginning. I would estimate that we are about 50-60% done, with most of the important features implemented but in need of bug fixing/more tweaks. I will talk about my physics tweaks that I did last night in a little bit. Everyone, save for a couple, did their work and contributed to the project. I applaud my team members for their hard work and dedication. Now, on to the good stuff.

So, yesterday August informed me that his text drawing for our HUD (that displays time, velocity and height) was crashing because the jumper would accelerate so fast that his speed became NaN almost instantaneously. I pounded my head against the code for awhile, then decided to comment out all of the physics I had put in and just simply make the jumper fall under the force of gravity. This allowed August to make sure his text was working fine, which it did. After that was done, I was not happy with having to scrap all of that nice physics code. So, I went back and looked over everything. I took out the gravity changes I made and put back in the original physics. I went through it line by line, and even did the calculations by hand for a couple of height values to make sure my calculations were correct. Turns out they weren't. Oops. Sign issues everywhere. I guess that's what happens when you are tired and coding at 2 AM, but I digress as there is no excuse for sign errors in the simple physics I used. I went back through it again, line by line, doing calculations by hand. I finally got all of my pre-calculated values correct (those not directly affected by height that needed to only be calculated once, and not on a per update basis. Saved us so many clock cycles and memory.) Then it was time to re-test my physics equations. Again, sign issues everywhere. I even had an arithmetic mistake (put something in the Java function Math.pow() that needed to be outside that function). Hehe, oops again. After re-writing that equation and doing hours of research to make sure that I was doing the physics correctly, I tested it one last time and HUZZAH it worked. But, with one major bug. The jumper accelerates just fine now and his terminal velocity (the real max velocity Felix hit, ~372 m/s or ~834 mph) but never slows back down. Don't know why or how. It will take a little while longer and some testing with our delta time value to see if it is a delta time issue (I think it is). But, for the alpha, it is fine as it shows that the physics model works.

Here is what the code looks like for our physics: (Keep in mind, its still a work in progress. Also, excuse formatting. Blogger doesn't have <code> tags...)

public void update(float dt)
{

//deltaT += dt;

//update the jumper's height based on the y component of position (since we are falling in the y direction)
height = position.y;

//updating our falling physics data
temperatureAtHeight = seaLevelTemp - (tempLapseRate * height);
pressureAtHeight = 1000.0f * (seaLevelPressure * (float)(Math.pow((1.0f - (height * preCalcPressureFraction)), preCalcPressureExponent)));
//pressure has to be in Pa, not kPa. so we multiply by 1000

densityAtHeight = (pressureAtHeight * molarMassOfAir) / (gasConstant * temperatureAtHeight);

//calculate air resistance
airResistance = new Vector3D(0.0f, 0.5f * densityAtHeight * (float)Math.pow(-velocity.y, 2.0f) * 0.579f , 0.0f);

//calculate net force
airResistance.add(new Vector3D(0.0f, -gravity, 0.0f));
//Vector3D netForce = new Vector3D(0.0f, airResistance.y, 0.0f);

Vector3D weight = new Vector3D(0.0f, mass * gravity, 0.0f);

acceleration = weight.subtract(airResistance).scale(1.0f / mass);
//from the formula a = (W-D)/m where W is weight, D in our case is the netForce and m is mass

//v = v0 + at
velocity = velocity.add(acceleration.scale(dt));

//check to see if we are at terminal velocity or not
if(-velocity.y > maxSpeed)
{
//if we are, we have to use -maxSpeed because we are falling in the downward direction, not up
//changing the sign below will cause the height to go back up after you hit maxSpeed
velocity.y = -maxSpeed;
}

//position = p0 + vt + (at^2)/2
position = position.add(velocity.scale(dt)).add(acceleration.scale((float) Math.pow(dt, 2)).scale(0.5f));
}

I was also able to complete the spacepod model and get it into the game. It looks really nice, especially after Matt L fixed some tessellation issues with the models themselves. I was also able to complete the cinematic for Phase 1 which I detailed and documented in my last blog post.

Until next session, thanks for reading.

Thursday, April 17, 2014

Dev Blog #2

Thursday April 17, 2014

For the second blog that is required for my class, I am going to talk about how I made the cinematic for Phase 1 of our game. The cinematic consists simply of the spacepod moving upwards, to signify that it is starting its ascent to the jump altitude. This is a very, very simple animation as it just consists of a vertical translation of the spacepod over 100 frames. I chose to make the animation take 100 frames as it would slow down the speed of the animation. So, on with the details.

I first imported our spacepod model and its door into 3DS Max. In the same scene, I made a sphere object and converted it to an editable poly. I then scaled the sphere up uniformly to the size I thought would look good in the cinematic. I moved the sphere above the spacepod and focused my attention on the bottom set of faces. I highlighted those faces and extruded them down towards the spacepod. After I made the balloon and the spacepod "touch", I went ahead and attached the balloon to the spacepod using Max's Attach feature. This turns all of the different components into one model allowing you to do things to the model as a whole and not having to select each individual component. You would only do this after you were done working on each individual component and only if you wanted the model to be one component and not many components.

After I attached the balloon to the spacepod, it was time to start the animation process. I selected my model, changed to the Motion tab in the right hand side of 3DS Max and selected the Auto Key option. The Auto Key option allows you to just move the frame slider and adjust your model. It will mark the key frame automatically. So, the first frame is simply the spacepod on the ground. I moved the frame slider to the last key frame (100 in this case) and moved the spacepod up into the air. This caused the second key to be placed. Once this process was done, I went to the Render Setup menu to render out the animation. The easiest way to do this, if you want a video file of your animation, is to open the Render Setup menu, select the radio button that allows you to select a range of frames (0-100 in my case), scroll down until you see the Render Output section, click the Files button, change the output file type to a movie file (in my case, I used .avi), give your file a name and hit save. This will pop open a new window that will allow you to select a compressor for your file. I used the MJPEG compression, which cut my frames down to around 80 (this is ok, as it did not affect the speed of the animation. Just its file size). Hit the OK button and then click the Render button on the Render Setup window. Wait a few seconds/minutes depending on the complexity and frame count of your animation(s) and... Voila! You now have a rendered movie of your animation. You can then use the .avi file if your engine/framework supports it or convert it to some other file type. I converted mine to a .mp4 and a .3gp in order to test out the Android Media Player with different file types.

I followed a tutorial on this process at this link. Everything I described above can be seen in that video.

Monday, March 24, 2014

Senior Project Blog #1

Monday, March 24 2014

We are entering Week 4 now of our Senior Project, and this is my first post. Whoops. Really should have started this sooner, but I did not have anything to talk about. Over the past few weeks, my team and I have been breaking the project up into teams and tasks, and we finally got everyone put into something. My job, as it stands right now, is to write the Physics system and make a model of the Earth for our game. Since modeling is really self-explanatory, let's talk about the physics.

The Stratos Jump, as it is formally called, was a remarkable feat of human engineering and endurance. From 120,000 feet, Felix Baumgartner jumped, broke the speed of sound, and landed safely on the ground. The physics involved with this jump are fairly straightforward, but it will take some explaining and extra research to get the formulas correct to model the behavior correctly.

So, what do we know about the physics of this jump? First of all, the atmosphere at the height of the jump has a much lower density than the atmosphere does at ground level (or sea level, for that matter). This density also changes with the temperature, and we all know that it gets colder the higher you go. There is a great post by Rhett Allain over at scienceblogs.com (link here) that explains the physics behind this jump. I will try and explain it in my own words here, but if something does not make sense, I would suggest going and reading that article and looking at the formulas.

LATER THAT SAME DAY...

Well, it appears this is going to be harder than I expected. Our client wants this to be as realistic as possible, which means my physics simulation will have to be as realistic as possible. After looking over a ton of reports and articles written about the subject, I have come to the conclusion that I will probably use the model put together by Allain in his initial article and a followup he wrote after data was released from one of Felix's test jumps (link here). Sure it isnt the actual data from the real jump, but I can modify the model to include the real data. I am merely going to use the formulas he used to calculate his model. Here is how I see it as of right now:

Physics update loop:

1) Calculate temperature as a function of height using this formula: 
T = T_0 - L h \,
Where T is temperature, T0 is the standard sea-level temperature in Kelvin, L is the temperature lapse rate in Kelvin/meter and h is height in meters.
2) Calculate air pressure as a function of height using this formula: p = p_0 \left(1 - \frac{L h}{T_0} \right)^\frac{g M}{R L}
Where p is pressure, p0 is standard air pressure at sea level in kPa, L is the temperature lapse rate, h is height, T0 is standard sea-level temperature, g is the gravitational constant (can probably get away with 9.8 m/s^2 here), M is the molar mass of dry air and R is the universal gas constant.

3) Calculate air density as a function of pressure using this formula: 
\rho = \frac{p M}{R T} \,
The variables are all explained in the above steps. There is one caveat, though. The p on the right side of the equation has to be in Pa, not kPa as above.

4) Calculate force of air resistance using this formula: i-d7d39adb0a4fb7df70381ce1c496c258-2010-02-19_la_te_xi_t_1_9.jpg

Where p is air density, A is the cross sectional area of the thing falling (our skydiver in this case), C is the drag coefficient, and v is the velocity of the diver. Allain was nice enough to have already calculated an average AC value that should work for our purposes in his most recent article that I linked above. The AC value I will use is .579m^2.

5) Calculate net force on skydiver, which will be air resistance plus gravity.
6) Calculate the new velocity and update it
7) Calculate the new position and update it

This seems really inefficient. I might have to find some way of pre-computing some of these values. Maybe do it upon initialization of the physics object that the skydiver object will have inside it to access its physics properties. I could probably get away with pre-computing all of the values that don't deal directly with the height, which will be passed into the update function every update tick. That way I am only computing a few values that change every tick and not every value. Might save some clock cycles, we are on mobile after all. And if we are targeting Android 2.3.3, which is the most common Android install on the market currently, then there are going to be some very, very slow devices that will try and run this. That could get ugly. I think the pre-computing idea is the best way to handle this.

Monday, October 21, 2013

Blog #2: Flash-UDK Workflow

Monday, October 21, 2013

Hello again. It has been a few weeks since my last blog posting, and I am back again to do another. This time around, I am going to explain the Flash-UDK Workflow and take you through something I created for my most recent project. I will be showing you how I made a custom HUD in Flash, with a checkpoint counter on it, and how I got it to work in UDK. Let's begin.

First off, I will show you the final product:


As you can see, the HUD does not really do anything except display the number of checkpoints the player has left to use in the lower right hand corner. This differs drastically from the normal UDK HUD which has things like health, ammo and what weapon is currently equipped. For our custom game, all we needed was this very simple HUD. Getting this working in UDK, however, is another challenge.

There are two ways to get a HUD in UDK. The first way, and not the recommended way, is to create your HUD, import it into UDK and use Kismet to open a GFxMovie to display your HUD. It works, but it can be very buggy and unpredictable. Especially if you need to use other Flash elements in your game. The way I did it, and the recommended way to do it, is to create your HUD, import it into UDK and make a custom gametype script that will tell UDK to use your HUD and not the default one. 

I am going to start by showing you the Flash first. Below is a picture of the HUD from the above picture open in Adobe Flash:


You cannot see anything as the text is colored white, but it is contained within those two blue boxes in the lower right. The left box holds text that is static, meaning it does not change. The right bow contains a dynamic text field, which means it can change at some point. Now, I have named the dynamic field CPLeft. Let's see the actual ActionScript that controls this HUD:

stop();

var checkpointsLeft:Number;

var keyListener = {};


function setCheckPointsLeft()
{
checkPointsLeft = 5;
_root.CPLeft.text = checkPointsLeft.toString();
}

function useCheckPoint()
{
if(checkPointsLeft > 0)
{
checkPointsLeft--;
}
else
{
checkPointsLeft = 0;
}
_root.CPLeft.text = checkPointsLeft.toString();
}

setCheckPointsLeft();

keyListener.onKeyDown = function()
{
    var theKey = Key.getCode();
if(theKey == 88)
{
useCheckPoint();
}
};

Key.addListener( keyListener );

NOTE: This code is attached to the stage itself, not the text fields. If you are unfamiliar with Flash, I suggest you look up how to add code to things in Flash.

Don't worry, I will go through this code line by line to show you how it works. First of all, the stop() call just makes sure that Flash will not advance to another frame. The next two lines are variable declarations, one being a Number (like int in most other languages) and the other being just another variable. In Flash, you do not need to give your variable types if you don't have to, which is why the keylistener variable has no type. 

The next two functions are purely declarations and implementations. They do nothing on their own. They are put in that spot to make sure they are declared before use. The function setCheckPointsLeft does a very simple job. It sets the global variable checkPointsLeft to 5, then assigns the number 5 to be written in the dynamic text field I described earlier. The call to the dynamic text field is quite simple, _root tells the code we are accessing the root of the stage (where the text fields are located), CPLeft is that name of the dynamic text field (can be thought of as an object) and text is the name of the variable that holds the text that will be written in the dynamic text field. The toString() function call turns the data in the variable checkPointsLeft into a string so it can be displayed by the text field. So, in simple terms, it sets the field to display the number 5.

The function useCheckPoint does what its name implies, it uses a checkpoint and subtracts it from the number left. The if-else statement is a bit of error checking to make sure the number displayed in the text field does not go below 0. Then the line _root.CPLeft.text = checkPointsLeft.toString() uses the same idea as the above description.

Then we call the setCheckPoints() function so it is run when the Flash is started (i.e. when UDK draws it on the screen). The next line is another function declaration. However, it is a little different from the other two. In this case, we are telling the keyListener variable to use its onKeyDown function in a certain way, which we define below that line. We create a variable to hold the key code that is returned from the keyListener. We then check it against whichever key we want that will serve as the button to decrease the amount of checkpoints we have left (meaning the key we setup in UDK as the set checkpoint key). 88 is the ActionScript keycode for the letter x, without having the shift button pressed. Then, after that function declaration, we tell Flash to add our custom keyListener and use it to determine if we have pressed the x button or not.

Now, that wasn't so bad. Let's move on to the UDK stuff. First of all, you would need to save your Flash file in this path (assuming you installed UDk to your C drive, otherwise change that letter to the drive letter where UDK is installed): C://UDK/UDKGame/Flash and put it into a folder with a different name. In my case, the file path of my Flash files was C://UDK/UDKGame/Flash/CPFlash. Now that it is saved, you will need to publish the Flash using FlashPlayer 8 and ActionScript 2.

Now, inside UDK, you would open the Content Browser and click the Import button on the lower left. Navigate to the place where your Flash is stored, and double click the file you want to import. UDK will create a package for you with the name being the same as the folder where the Flash is stored, then click OK. Now, we step into UnrealScript.

This part is not very hard. If you are familiar with how to write a custom gametype and get it to work in UDK, you can skip this step.

What we are going to do is create a custom gametype that will use our HUD instead of the default UDK HUD. 

Navigate to your UDK install folder, and go to Development/Src/MyMod/Classes. Create a new text file and name it NewGame.uc. Open that file and paste in this code:

class NewGame extends UTDeathMatch;


DefaultProperties
{
    HUDType = class'MyMod.NewHUD'
    bUseClassicHUD = true            
}

The first line tells us the name of the class (MUST BE THE SAME AS THE FILE NAME) and what it extends from. In our case, NewGame is extending from UTDeathmatch. DefaultProperties can be found in all UDK scripts, and is the place where variables can be set. So, we are telling UDK that our HUDType is of a class we are going to create soon called NewHUD. Then, the bUseClassicHUD = true tells UDK that we are using a classic HUD. Save this file.

Next, make two new text files in the MyMod folder and name them NewHUD.uc and NewGFxHUD.uc. Open NewGFxHUD and paste in this code:

class CPGFxHUD extends GFxMoviePlayer;

function Init(optional LocalPlayer PC)
{
  Start();
  Advance(0.0f);

}

function UpdateHUD()
{
}

DefaultProperties
{
 MovieInfo = SwfMovie'<insert name of package where your Flash is stored in UDK>.<name of Flash file>'
}

Again, we are first defining the class and what it extends from. Then, our Init function tells UDK to start the Flash file with Start() (this MUST be called) and to keep executing the function with Advance(0.0f). Putting something larger than 0 in the parameter list of Advance() will make UDK sleep for that duration before continuing.

UpdateHUD does nothing, but if we wanted to have dynamic health bars or ammo counters, we would put code in that function to update those specific HUD elements when needed. The DefaultProperties is where we tell UDK what Flash file to use for the HUD. We are setting it to the Flash file you imported into UDK earlier. Save this file.

Open NewHUD.uc and paste in this code:

class NewHUD extends UTHUDBase;

var NewGFxHUD HUDGFx;

simulated function PostBeginPlay()
{
  super.PostBeginPlay();

  HUDGFx = new class 'NewGFxHUD';

  HUDGFx.setTimingMode(TM_Real);

  HUDGFx.Init(LocalPlayer(PlayerOwner.Player));
}

event PostRender()
{
 HUDGFx.UpdateHUD();
}

DefaultProperties
{

}

We are declaring our class and what it extends from, and then creating a variable named HUDGFx that is of type NewGFxHUD. Remember the class we created earlier with the same name? We are using an object of that class to tell UDK to draw our HUD. The function PostBeginPlay is defined next. The first line super.PostBeginPlay() tells UDK to call the PostBeginPlay function and continue from that point. Then, we set the variable to a new object of type NewGFxHUD. Then, we set the timing mode of the HUD to Real, which tells UDK to keep updating the Flash, no matter what. We then call the Init function from our previous class and tell it to set the HUD to the Player so that they can see the HUD.

The next function is not really a function, but an event. This even calls the UpdateHUD function from the previous class. DefaultProperties can be left blank in this class, but it has to be present or UDK will error out.

Now, save that file and close it. You will now have to navigate to UDK/UDKGame/Config and open DefaultEngineUDK.ini. Navigate to the line that says ;ModEditPackages=MyMod and remove the semi-colon. This tells UDK to include scripts you wrote in the MyMod folder, as it does not do this by default. Then save that file.

Open UDK and you will be prompted to rebuild the scripts. Click yes and let it run. If we did everything right, it will have no errors or warnings. Now, open UDK again and it will load the editor. Under the View menu, click World Properties. Then, expand the Game Type field and change both dropdowns to NewGame. Then start the game by clicking the green arrow in the upper right corner. I would suggest testing this on a pre-built level. If everything worked, you should see your HUD on screen. Press the X button to make sure our HUD updates the number of checkpoints left.

I hope you enjoyed this tutorial. The above example can be applied to anything that has to be counted down (or up, by changing the Flash) on key press. We used it to keep track of the number of checkpoints left, but you can edit it to be anything you want.

Monday, September 30, 2013

Blog #1: Grayboxing

Monday September 30, 2013

Hey all, this is my first blog in a long time. As of right now I am in GSP 340, which is Level Design and Modification. This blog is going to focus on one portion of this huge topic, which is grayboxing.

What is grayboxing? Grayboxing is a technique used by level designers in order to map out in rough detail the shape and design of the level they are working on. With a graybox level, there are no textures, particles effects and minimal lighting. The object of building a graybox level is to see how the level flows from its different areas and if the proportions you planned out are either too big or small. It can also help you determine if your initial design is going to work or not. In our group project, our graybox level was a real pain to build, but that is because the shape of our towers is octagonal and not very easy to line the brush up with. Since UDK has weird snapping when you change the rotation of an object, some of the geometry isnt flush with the walls. Just something to keep in mind if you decide to build octagonal towers.

In our graybox, which I will post a picture of below, you can see that we have no textures whatsoever. The only texture/lighting is the skydome and the sun that allows us to see everything we need to.


After you are satisfied with the design and function of your graybox level, you can begin adding textures and static meshes into your level. If you built geometry that is serving as a placeholder for a static mesh or other actor, you can delete those and put in the correct object. It really is a simple concept, but it helps tremendously in the planning and initial building of your level. It keeps you from having to constantly delete textures/meshes/lighting that would mess up your level if you had those things placed in there. Not having textures/meshes/lighting allows you to work with the simplest form of your level.

That's all for today, keep an eye out for my next blog in a few more weeks.