Thursday, February 25, 2016

And the Most Popular award goes to...

Was checking the blog stats during my long lunch break, and something caught my eye: the most visited post is the isometric camera tutorial. Probably one of my best achievements with Unity3D, I think that I even have visits coming from Unity3D forums. Cant tell it for sure because Unity3d site is unreachable lately.

Took me sometime to put together that code, because I was just starting, but mostly due to a logic error. And, I have been thinking to refactory the system, this time with a freely movable camera, and discard orthographic projection. Orho projection is the ideal for isometric cameras, but Unity3D has some weird bug that prevents using deferred rendering in that projection mode.

Considering that my experiment with third person camera didnt produced perfect results, I have been wondering if my next official project should stick to isometric view. In our first deliberations the team agreed to use third person camera because we had excellent artists that can produce good looking models and we wanted to exploit the scenes in a way that isometric view cant achieve. But now I see that it depends on finding a good programmer (or several) that can deal with the visual side of the project better than I do.

Friday, February 19, 2016

Dealing with bad internet

Lately it is getting worse to develop games in Cuba. Since a week or two, the Unity3d site doesnt load; it is not blocked, like was a couple of months ago for a few days, but simply stays there, waiting.

Today, I have tried to download LunarG Vulkan SDK, but Im getting 403 errors, and the download speed is slow. And the project Im working has one month delay, because the artist mail can handle attachments. Yes, a technology as old as mail, cant properly work.

And the hope of having a relatively decent Internet connection at home have pushed away by the government, due to economic crisis.

Monday, February 15, 2016

No Lumberyard for me

Unless you have been living under a stone during the last week or so, you probably know that Amazon released some free CryEngine derivative. Being totally broke as I am, the word free tends to attract my attention, specially if we put it together with other works like commercial quality game engine. I took no time to start downloading Lumberyard.
I have a slow connection in my office. I would rather say that I have a prehistoric connection, subject to filters, rules, vigilance, etc. Yet, I can download big things if resume is supported, and Lumberyard zip file seemed to support it.
I got my first sign of problems last friday, when suddenly, 2Gb of Lumberyard downloaded were simply discarded. Ok, thats a sensible loss, but lets start again. This morning, I discover that, instead of 5-6Gb, I have again 2Gb. When I stopped the download, I lost those too. Lumberyard zip is 10Gb. Also, when decompressed, those 10 become 40, and I currently dont have so much space available. I can mek it, but having 40Gb permanently occupied would leave me without margin for maneuvers.
So, Ill have to pass. Lumberyard sounds like a tempting offer, but it is not for me. Not yet.

Thursday, February 11, 2016

My experience with Kindle Direct Publishing

Well, almost a month now since I published my first novel on Amazon KDP to see what happens. And the result: nothing happened, as expected. Lack of promotion, mostly.

We, readers, tend to be some sort of weird people. We want to find more books, yet we avoid the danger of unknown authors. For a reader to accept a book, it must be recommended by another reader, or by some big publisher marketing campaign. That means somebody risked his/her time before you to read the book, and considers it worth reading.

As I havent gathered a large number of readers on internet (all my good reviews come from locals), I have sold just a few copies. Definitely, Im not going to become famous this way.

So, my advice to new writers is, above all, to find a few good spots to promote your ebook. Specially, try to attract your friends (regrettably, mine bought the printed copy and cant review my ebook on Amazon). Get some cover, if it does not has an illustration, at least make it different from Amazon covers. Readers tend to find the most annoying excuses to discard your book, and the look is one of them. And of course, writing an actually good book will help.

Tuesday, February 9, 2016

TPS with free look tutorial, version 2 (and bugs)

After working a bit to improve the third person camera system I mentioned a couple of days ago, I found a few problems that I could fix, and other I cant. Here is the updated code:

public class PlayerControl : MonoBehaviour {

    public GameObject pivot;
    Animator anim;
    int direction = 0;
    int FORWARD  = 1;
    int BACKWARD = 2;
    int LEFT = 3;
    int RIGHT = 4;

    // Use this for initialization
    void Start () {
        //cam = gameObject.GetComponent<Camera> ();
        //Cursor.visible = false;
        //Cursor.lockState = CursorLockMode.Locked;
        anim = gameObject.GetComponent<Animator> ();
    }
   
    // Update is called once per frame
    void Update () {
        Vector3 rot;

        if (Input.GetKeyDown (KeyCode.W)) {
            direction = FORWARD;
        } else if (Input.GetKeyDown (KeyCode.S)) {
            //go back
            direction = BACKWARD;
        } else if (Input.GetKeyDown (KeyCode.A)) {
            direction = LEFT;
        } else if (Input.GetKeyDown (KeyCode.D)) {
            direction = RIGHT;
        } else if (Input.GetKeyUp (KeyCode.W) || Input.GetKeyUp (KeyCode.S) || Input.GetKeyUp (KeyCode.A) || Input.GetKeyUp (KeyCode.D)) {
            direction = 0;
        }

        switch (direction) {
            case 0: //do nothing
                anim.SetInteger("State",0);
                break;
            case 1:        //forward
                rot = gameObject.transform.localEulerAngles;
                rot.y = pivot.transform.localEulerAngles.y;
                gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
                anim.SetInteger("State",1);
                gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);               
                pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
                break;
            case 2: //
                rot = gameObject.transform.localEulerAngles;
                rot.y = pivot.transform.localEulerAngles.y+180f;
                gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
                anim.SetInteger("State",1);
                gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);               
                pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
                break;
            case 3:
                rot = gameObject.transform.localEulerAngles;
                rot.y = pivot.transform.localEulerAngles.y-90f;
                gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
                anim.SetInteger("State",1);
                gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);               
                pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
            break;
            case 4:
                rot = gameObject.transform.localEulerAngles;
                rot.y = pivot.transform.localEulerAngles.y+90f;
                gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
                anim.SetInteger("State",1);
                gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);               
                pivot.transform.position = Vector3.Slerp(pivot.transform.position, gameObject.transform.position, 5f *Time.deltaTime);
            break;
        }
    }
}

The above code handles player movement, the next, handles camera free look:

public class PivotControl : MonoBehaviour {
    float rotationY = 0F;
    Camera cam;
    Text label;

    // Use this for initialization
    void Start () {
        cam = gameObject.GetComponentInChildren<Camera> ();
        label = GameObject.Find ("Label").GetComponent<Text>();;
    }
   
    // Update is called once per frame
    void Update () {       
        if (Input.GetAxis ("Mouse X") != 0 || Input.GetAxis ("Mouse Y") != 0) {
                       float rotationX = gameObject.transform.localEulerAngles.y + Input.GetAxis("Mouse X") * 2f;

            rotationY += Input.GetAxis("Mouse Y") * 5f;       
            gameObject.transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
            cam.transform.LookAt(cam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, cam.farClipPlane)));
            //check if we are looking at something we can interact with                
            RaycastHit hit; 
            Ray ray =  cam.ViewportPointToRay(new Vector3(0.5F, 0.5F, 0));
            if (Physics.Raycast (ray, out hit, 100)) {
                                    if (hit.collider.tag=="Interactable")
                    label.text = "Press E to interact with "+hit.collider.name;
            } else {
                label.text = "";
            }
        }
    }
}

Ok,  whats the problem here? Well, the camera free look works, but I find that the picking system is not precise. Also, the player is not being rotated exactly towards the camera direction when the angle between player and camera orientation is large (like, the camera is looking to the screen left side). I think Im missing something important here, like resynch the camera to the screen center or something. Also, I havent implemented yet a crosshair system.
Sure you can make a game with the current code, but it lacks the polish a professional title should have.

Friday, February 5, 2016

Third person camera with free look in Unity3D

I first experienced this camera system in Mass Effect 1. Was a bit annoying during a couple of minutes, but then I got used to it and started to like it. Was also used in The Witcher 2 and 3, and I wanted to implement it for a future RPG project we are designing. But my lack of math skills prevented me from implementing a working prototype, until a few days ago, when I figured out a way to achieve it.So, I decided to post this little TPS tutorial, in case it can help somebody.

Look at the following gameobject hierarchy:



The relevant objects are player and Pivot. The first one is the player (model, collider, etc) obviously. The second is the parent of the camera and handles its rotations, via the following script:

float rotationY = 0F;
    Camera cam;

    // Use this for initialization
    void Start () {
        cam = gameObject.GetComponentInChildren<Camera> ();
    }
   
    // Update is called once per frame
    void Update () {
               
        if (Input.GetAxis ("Mouse X") != 0 || Input.GetAxis ("Mouse Y") != 0) {
           
            float rotationX = gameObject.transform.localEulerAngles.y + Input.GetAxis("Mouse X") * 2f;

            rotationY += Input.GetAxis("Mouse Y") * 5f;
           
            gameObject.transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
           
        }
    }

The player gameobject also has an script, that deals with player movements, and also keeps the pivot sinchronized with its own position:

public GameObject pivot;
    // Use this for initialization
    void Start () {       
        Cursor.visible = false;
        Screen.lockCursor = true;
    }
   
    // Update is called once per frame
    void Update () {
        pivot.transform.position = gameObject.transform.position;
        if (Input.GetKey (KeyCode.W)) {
            Vector3 rot = gameObject.transform.localEulerAngles;
            rot.y = pivot.transform.localEulerAngles.y;
            gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
            gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
            pivot.transform.Translate (0, 0, 20 * Time.deltaTime);
        } else if (Input.GetKey (KeyCode.S)) {
            //go back
            Vector3 rot = gameObject.transform.localEulerAngles;
            rot.y = pivot.transform.localEulerAngles.y+180f;           
            gameObject.transform.rotation = Quaternion.Slerp (gameObject.transform.rotation, Quaternion.Euler (rot), 5f * Time.deltaTime);
            gameObject.transform.Translate (0, 0, 20 * Time.deltaTime);
            pivot.transform.Translate (0, 0, 20 * Time.deltaTime);
        }
    }

Perhaps not the most elegant solution, but seems to work.