Thursday, May 28, 2015

Me vs Qt and Windows

I always say that when you are a programmer, you should be ready to throw your work and start again whenever necessary. And I always expect that others apply that, not me. Yesterday I started porting the dialog editor tool to Windows. In the end, the dialog writers (in this project, or the next) probably will be using Windows, not Linux. Keeping a parallel Linux port is trivial.

I should have started in Windows. Probably I have to throw the previous UI I have been working on, or spend some time to figure out why does it produces a compilation error. Well, I will try to see the good side: now I have a chance to rethink the UI. The dialog editor is a complex tool, I must try to make it easy to underestand to people that never used anything more exotic than Office 2007.

The process of downloading Qt havent been easy, I even had to pay some internet time, which was lost money. Also, I found that I could have downloaded an older version instead of the 5.x, after all, cant use the VS plugin with Visual Studio Express. Im forced to use QtCreator. Of course, that isnt too bad, as it has the QtDesigner integrated. Im just sorry for the wasted money and time.

Ah, it is worth mention that I ported my day/night cycle to Unity3d. Will talk about that later.

Tuesday, May 26, 2015

I tried to run The Witcher 3

And failed. I built my home PC with a very short budget, aiming to cover  Wasteland 2 requirements (mostly, the 4Gb of RAM). It is an old Core 2 6850, in  a basic G41 motherboard, rather limited. I managed to place 2 DDR2 memories running at 800Mhz, 1TB SATA drive, an AMD R7 250 video card, and a 500W PSU, which died a couple of months ago. I was quite happy with that (well, actually I wasnt, but I couldn't afford anything else), but then, some games I wanted to play asked for more RAM and more hard drive space than I had. Ok, I can miss Call of Duty Whatever Warfare, but Dragon Age... thats painful.

Obviously, The Witcher 3 doesnt runs. I managed to see the main menu, even the intro cinematic (a bit bumpy), but in-game framerate is not enough even to move the character. Perhaps I have to recover my AMD card, as I have now a GT 520 which is not the choice to run demanding games, but I dont expect a big perfomance gain.

Anyway, at least I can do game development!

Tuesday, May 19, 2015

Re-learning C++

Back to C++. It is weird to compile or to type -> again after several months programming in AngelScript and C#. Also, Im learning to use PugiXML and recovering my little Qt knowledge.

I have restarted work on dialog editor. This time Im going to bring the development process to Windows, since a long time ago I wanted to know how is Qt development under platforms other than Linux. I think it is going to be a good training for me. I will create a public github repo as soon as I have the code working on Visual Studio, together with the file format documentation.

The tool is far from simple, because it needs to manage and display a quite complex tree of lines an answers, currently Im just writing basic foundation code. My head spins of just looking at interface and thinking how much work still needs to be done.

Wednesday, May 13, 2015

Tutorial: building a modular character

Building character models with body parts have been an obsession for me in the last weeks. I have googled, asked, googled, and asked again, played with Unity3d editor, tested code, and so on. You can see the result of my work in the previous post. First of all, I have to say that what I achieved is mostly derived from this thread and the sample posted there. My code is a copy&paste of that sample. Also, you can find a more extense solution in this Gamedev.net forum thread.

First, lets start with the model, which obviously, is divided in the required sections. Lets say we have head, torso and legs. Each part must be exported to a separate fbx file, but it must include the skeleton. Then, export the skeleton without geometry to another fbx.

Im going to assume that you want to instantiate all components, and even player, at runtime, from a  C# script (no Unity editor involved, except for creating prefab an position marker), so, we will place the sections, the skeleton and everything inside Assets/Resources. Then we will create a prefab for the character hierarchy, which we will call char-prefab. Drag and drop the skeleton to the prefab, and create an animation controller for the Animator component.

And here starts the code!

#region TransformCatalog
class TransformCatalog : Dictionary<string, Transform>
{
    #region Constructors
    public TransformCatalog(Transform transform)
    {
        Catalog(transform);
    }
    #endregion
   
    #region Catalog
    private void Catalog(Transform transform)
    {
        Add(transform.name, transform);
        foreach (Transform child in transform)
            Catalog(child);
    }
    #endregion
}
#endregion


#region DictionaryExtensions
class DictionaryExtensions
{
    public static TValue Find<TKey, TValue>(Dictionary<TKey, TValue> source, TKey key)
    {
        TValue value;
        source.TryGetValue(key, out value);
        return value;
    }
}
#endregion

/**
 * Manages all game info, instancing character, NPCs, etc
 * */
public class GameInstance : MonoBehaviour {

    public GameObject player;
    string[] BodyParts;
  
    // Use this for initialization
    void Start () {
        pause = false;
        BodyParts = new string[2];
        BodyParts[0] = "head";
        BodyParts[1] = "torso";
        BodyParts[2] = "legs";
        InstancePlayer ();
    }
       
    // Update is called once per frame
    void Update () {
            }

    void InstancePlayer() {
        string[] test = new string[3];
        test [0] = "mesh-head";
        test [1] = "mesh-torso";
        test [2] = "mesh-legs";

        GameObject playerPrefab = Resources.Load("char-prefab") as GameObject;
        player = Instantiate (playerPrefab, Vector3.zero, Quaternion.identity) as GameObject;
        //find the empty gameobject marking the player position
        var playerPos = GameObject.Find ("player");
        player.transform.position = playerPos.transform.position;
   
        BuildCharacter (player, test);
    }

    void BuildCharacter(GameObject parentGO, string[] pieces) {
        GameObject temp;        //temporary game object to hold pieces
        GameObject[] body = new GameObject[5];
        var boneCatalog = new TransformCatalog(parentGO.transform);
        for (int i=0; i<=2; i++) {
            var obj = Resources.Load(pieces[i]);
            temp = Instantiate(obj) as GameObject;
            body[i] = new GameObject(BodyParts[i]);
            body[i].transform.SetParent(parentGO.transform);
            body[i].transform.localPosition = Vector3.zero;
            body[i].transform.localRotation =  Quaternion.Euler(Vector3.zero);
            body[i].transform.localScale = parentGO.transform.localScale;
            //copy skinned mesh renderer components
            CopySkinnedMeshRenderer(temp, body[i], boneCatalog);
            //destroy it, or you will end with several pieces floating around
            Destroy(temp);
        }
    }

    void CopySkinnedMeshRenderer(GameObject source, GameObject target, TransformCatalog bones) {
        var skinnedMeshRenderers = source.GetComponentsInChildren<SkinnedMeshRenderer> ();
        foreach (var sourceRenderer in skinnedMeshRenderers)
        {
            var comp = target.AddComponent<SkinnedMeshRenderer>();
            comp.sharedMesh = sourceRenderer.sharedMesh;
            comp.materials = sourceRenderer.materials;
            comp.bones = TranslateTransforms(sourceRenderer.bones, bones);
        }
    }

    private Transform[] TranslateTransforms(Transform[] sources, TransformCatalog transformCatalog)
    {
        var targets = new Transform[sources.Length];
        for (var index = 0; index < sources.Length; index++)
            targets[index] = DictionaryExtensions.Find(transformCatalog, sources[index].name);
        return targets;
    }

}

What does this code does? It instantiates each piece, creates an empty GameObject in the character parent GameObject, and copies the SkinnedMeshRenderer component from the the first to the second. Then, it copies the bones from one to another. Yep, it is not clear for me from what one to what another. Sorry, I just copied the code and played with it until it worked, it doesnt means that I know why or how does it works. Also, I warn you that perhaps Im missing something. Judging from the sample posted in Gamedev, there could be more than simply copying SkinnedMeshRenderer and bones.

What I can confirm is that the previous code takes N body pieces and builds an animated mesh. Hope it works, and if it is useful to you, remember that our project needs donations!

Monday, May 11, 2015

Almost there!

Got results today in the implementation of modular character meshes!


Ill be posting a detailed tutorial, including the script code as soon as I organize it and underestand how does it works a little better. What you see in the above picture is the character before (right) equip items, and after (left), when all  the meshes but the head have been replaced by the armor components.

Wednesday, May 6, 2015

Unity3d isometric camera tutorial

I had pending this since a month ago, so Im forcing myself to post it today. The goal is to provide a fully functional isometric like system that you can use with few or none modifications in your own game. So, lets get started.

Start Unity3d and in your scene, add an empty GameObject, we will call it target. Create a camera object and drag it to target to make it child. The result looks like this:


Now select Camera and set the values to this:


For a true isometric like feeling, ortho projection is essential. You could use perspective, but it is not the same. Play with Size to suit your needs (we will be using this later, when implementing zoom).

Now, lets create an script named CameraController, or whatever, and drag it to target GameObject. Lets implement scrolling, the easier part: go to Update() and add the following code:

if (Input.GetKeyDown(KeyCode.W)) {
            dir = UP;
        } else if (Input.GetKeyDown(KeyCode.S)) {
            dir = DOWN;
        } else if (Input.GetKeyDown(KeyCode.A)) {
            dir = LEFT;
           
        } else if (Input.GetKeyDown(KeyCode.D)) {
            dir = RIGHT;
        } else if (Input.GetKeyUp(KeyCode.W) | Input.GetKeyUp(KeyCode.S) | Input.GetKeyUp(KeyCode.A) | Input.GetKeyUp(KeyCode.D)) {
            dir = 0;
        }

// and here is the actual camera scroll
        if (dir==UP) {
                         transform.Translate(0,0,20*Time.deltaTime);
        } else if (dir==DOWN) {
                          transform.Translate(0,0,-20*Time.deltaTime);
        } else if (dir==LEFT) {
                         transform.Translate(-20*Time.deltaTime,0,0);               
        } else if (dir==RIGHT) {   
                          transform.Translate(20*Time.deltaTime,0,0);       
        }

Done, we already have a very basic scrolling! The idea is to detect the key down event, set a variable and start scrolling until the key release is detected. Now, lets add mouse scrolling, which is very simple too, we want that the camera scrolls when the mouse cursor reaches the screen edges:

//mouse scroll
        if (Input.mousePosition.x >= Screen.width - 10 ) {
            //scroll right
            transform.Translate (20*Time.deltaTime,0,0);
        } else if (Input.mousePosition.x <= 10 && transform.position.x>10) {
            transform.Translate(-20*Time.deltaTime,0,0);
        }

        if (Input.mousePosition.y >= Screen.height - 10 && transform.position.z>10) {
            transform.Translate (0,0,20*Time.deltaTime);
        } else if (Input.mousePosition.y <= 10 ) {
            transform.Translate(0,0,-20*Time.deltaTime);
        }

Looks easy, isnt it? Now, lets make it better by adding rotation using middle mouse.

//camera rotation with middle mouse
        if (Input.GetMouseButton(2)) {
                if(Input.GetAxis("Mouse X")>0) {
                    //moving left
                    transform.Rotate(0,45*Time.deltaTime,0);
                    transform.LookAt(transform.position);
                    }
                if(Input.GetAxis("Mouse X")<0) {
                    transform.Rotate(0,-45*Time.deltaTime,0);
                    transform.LookAt(transform.position);
                    }
                }

And using keys is trivial too, lets use Q and R to rotate the view:

if (Input.GetKeyDown(KeyCode.Q)) {
            rot = RLEFT;
        } else if (Input.GetKeyDown(KeyCode.E)) {
            rot = RRIGHT;
        } else if (Input.GetKeyUp(KeyCode.Q) | Input.GetKeyUp(KeyCode.E)) {
            rot    = 0;
        }

if (rot == RLEFT ) {
            transform.Rotate(0,25*Time.deltaTime,0);
            transform.LookAt(transform.position);
        } else if (rot == RRIGHT ) {
            transform.Rotate(0,-25*Time.deltaTime,0);
            transform.LookAt(transform.position);
        }

So far we havea quite complete system, yet, we can add a couple of details more, like zoom, via mouse wheel.

// Mouse wheel zoom in/out
        if (Input.GetAxis("Mouse ScrollWheel") < 0)
        {
            if (Camera.main.fieldOfView<=125)
                Camera.main.fieldOfView +=2;
            if (Camera.main.orthographicSize<=19)
                Camera.main.orthographicSize +=0.5f;
           
        }

        if (Input.GetAxis("Mouse ScrollWheel") > 0)
        {
            if (Camera.main.fieldOfView>2)
                Camera.main.fieldOfView -=2;
            if (Camera.main.orthographicSize>=8)
                Camera.main.orthographicSize -=0.5f;
        }

Done! Now the isometric view is complete with scrolling, rotation and zoom. But we still can add a little trick: the camera should not go beyond scene limits. I will show you a simple solution based on terrain: by calculating the terrain size, you can prevent the camera from moving beyond the terrain borders. Go to Start() and add this code:

GameObject go = GameObject.FindGameObjectWithTag ("Terrain");
tsize = go.GetComponent<Terrain>().terrainData.size;   

HEre we take the terrain object and get its size, storing it in a class member tsize of type Vector3. Now we modify the scrolling code like this:

if (dir==UP) {
            if (transform.position.z<tsize.z-10)    //is inside terrain border?
                transform.Translate(0,0,20*Time.deltaTime);
        } else if (dir==DOWN) {
            if (transform.position.z>10)    //is inside terrain border?
                transform.Translate(0,0,-20*Time.deltaTime);
        } else if (dir==LEFT) {
            if (transform.position.x>10)    //is inside terrain border?
                transform.Translate(-20*Time.deltaTime,0,0);               
        } else if (dir==RIGHT) {   
            if (transform.position.x<tsize.x-10)    //is inside terrain border?
                transform.Translate(20*Time.deltaTime,0,0);       
        }

Fix the mouse scrolling method too, and your system is really complete. This is all, hope it works for you, and remember you can get the code from our github repo.