Hello World


The aim of this tutorial is to show you how to create a simple scene so that you can understand the basic mechanism involved in the creation of a game world.

Scene Creation

A scene is the module that contains the global logic of your game (scripts will contain the rest of the logic). It is loaded and updated and you should at least include instructions in the LoadContent method to create your 2D or 3D world. The scene is managed automatically by the engine, there is no need to perform any call to this class.
First, we are going to create a new scene that contains our hello 3D world.
  • Make a copy of the EmptyScene class located in the Scenes folder of the Application Project. Like the name indicates this class is a frame to create new classes.
  • Rename this class with the name HelloWorldScene.
Now we set up the program class so that the engine loads this scene.
  • Open the Program class located in the root of the Application Project.
  • If you look into the Main method of this class you will see that the EngineManager is started using a specific scene. Change that scene with the HelloWorld scene you just created.
  • Run the solution. You should see a beautiful black screen.
BlackScreen.png

Engine Configuration

There are several global parameters that govern how the engine starts. These parameters are placed in a XML document in the root of the Content Project. Most of them are self-explained and some of them have special values. If width or height is 0 then the window will start maximized. If aspect ratio is 0 the aspect ratio will be calculated as width/height. If update frequency is 0 the game loop will be updated whenever it can.
  • Feel free to change any of these values and execute the engine to see the result.

Hello World

It is not a Hello World tutorial if we don’t write hello world to screen, don’t you think?
The objective is to add a 2D text on the screen. To accomplish this we need to create world entities (called game objects) and give them some behavior.
  • We are going to work entirely in the Hello World scene, so start by opening the HellowWorld class.
  • Add a reference to the XNAFinalEngine.Components namespace to have access to the game objects and components classes.
   using XNAFinalEngine.Components;
  • Add a 2D game object field.
   private GameObject2D helloWorldText;
  • Now the game objects will be created in the LoadContent method and some specific components will be added to this object. Game Objects by default have a transform component that can’t be detached. A 2D Game Object has a 2D transform component that place the object in screen space and a 3D Game Object has a 3D transform component that place the object in the 3D world.
   helloWorldText = new GameObject2D();
   helloWorldText.AddComponent<HudText>();
  • Then the components will be configured. We need to add a text to the HUD Text component of the hello world object and place this text a little off the border of the screen using the transform component. To avoid garbage generation the text is stored in a StringBuilder class instead of the popular string class.
   helloWorldText.HudText.Text.Append("Hello World");
   helloWorldText.Transform.LocalPosition = new Vector3(10, 10, 0);
  • Play the solution.
       HelloWorld.png

Creating a 3D World

Now the best part begins. We will add a 3D object and configure some parameters of the graphic pipeline.
  • Add a reference to the XNAFinalEngine.Assets namespace to have access to the assets classes.
  • Create two 3D game objects, one called camera and one called body and attach two components to the last one and one to the camera. The first component will be a Model Filter component that contains the model information and the second a Model Renderer component that indicate how to render this model. Both components need assets to achieve a real meaning, a model and a material respectively. The camera will just have a Camera component attached.
   camera = new GameObject3D();
   camera.AddComponent<Camera>();
   body = new GameObject3D();
   body.AddComponent<ModelFilter>();
   body.ModelFilter.Model = new FileModel("LamborghiniMurcielago\\Murcielago-Body");
   body.AddComponent<ModelRenderer>();
   body.ModelRenderer.Material = new Constant();
  • Since that adding a model filter and a model renderer is a typical operation, the game object class brings a constructor with two parameters, the model and the material, that automatically adds the two components and the two assets to their respectively components.
   body = new GameObject3D(new FileModel("LamborghiniMurcielago\\Murcielago-Body"), new Constant());

If you play the solution you will see a dark abstract painting. We have two problems, the illumination and the camera placement. We will fix the later first.
  • The camera position and orientation is defined by the Transform component. We will use the Transform’s LookAt operation to look the game object from a little far away point.
   camera.Transform.LookAt(new Vector3(5, 0, 10), Vector3.Zero, Vector3.Up);
  • A Constant material is one that has the same color no matter how is the local illumination of the scene, that's the reason why it looks so awful. We will change this material for Blinn-Phong, change its color and add a directional light to see it. A directional light of course is another game object that has a Directional Light component and its direction is defined by its Transform component.
    body.ModelRenderer.Material = new BlinnPhong();
    ((BlinnPhong)body.ModelRenderer.Material).DiffuseColor = Color.Yellow;
    directionalLight = new GameObject3D();
    directionalLight.AddComponent<DirectionalLight>();
    directionalLight.DirectionalLight.DiffuseColor = new Color(250, 250, 140);
    directionalLight.DirectionalLight.Intensity = 1f;
    directionalLight.Transform.LookAt(new Vector3(0.5f, 0.65f, 1.3f), Vector3.Zero, Vector3.Forward);
  • Play the solution.
       CreatingA3DWorld.png
  • Now add the following code to the UpdateTasks method. Remember to add the reference to the XNAFinalEngine.Input namespace to access the input devices classes.
    if (Keyboard.SpaceJustPressed)
    {
        if (directionalLight.DirectionalLight.Intensity == 1)
            directionalLight.DirectionalLight.Intensity = 4f;
        else
            directionalLight.DirectionalLight.Intensity = 1f;
    }

This code will be executed in each update. If you press the space key the directional light intensity will be stronger and you will see… just something ugly. What happens is that the color produced in the drawing pass was clamped to 1 and most of the color detail was lost. But why the color was clamped? Most displays work with colors in low dynamic range and that means there is no much color precision. The engine works in high dynamic range allowing the illumination to be calculated with higher precision. That is great but unfortunately we still need to map this resulting color in higher range to the lower range of displays. We accomplish this adding a tone mapping operator to the camera.
    camera.Camera.PostProcess = new PostProcess();
    camera.Camera.PostProcess.ToneMapping.ToneMappingFunction = ToneMapping.ToneMappingFunctionEnumerate.FilmicALU;

If you test it you will see a much reasonable result. High Dynamic Range Rendering is one of the pillars of photorealism but reaching a good artistic result is more complex than what we just did.

Conclusions

This concludes this simple tutorial but of course the engine brings a lot more possibilities. The objective is to present the basic principles that govern the engine functionality. At this moment you should know how to start the engine, what are scenes, how to define entities and add behaviors to them. You should also know that the engine controls the application pipeline reducing coding, making easy to program and reducing potential mistakes.


Last edited Jan 22, 2013 at 1:08 PM by jischneider, version 53

Comments

No comments yet.