Customizable Navigation Bar

Sunday, February 27, 2011

Building A Game In Unity Part 2: Basic Character and Background Movement

OK, so the game that I have decided to build for these tutorials is a top down shooter. This way I can create a simple game and can spend more time going over how to do stuff within the engine. This week I am covering basic character movement using the mouse, and how to set up a parallax background.

Also, follow me on twitter at http://twitter.com/#!/purdyjo!







So the first thing I recommend doing since we are creating a top down shooter is create the camera movement script. The way this game is going to be set up down the road is so that either the main character or the camera passes through triggers and spawns enemies.

So what we are going to start with is the main camera movement script. This is a very simple script that just makes any object that it is attached to move at the set speed and velocity.

using UnityEngine;
using System.Collections;

public class ConstantVelocity : MonoBehaviour
{

/*I keep the movement direction and speed as separate variables because it is easier to keep track of and change when needed*/

        public Vector3 movementDirection = new Vector3(0.0f, 0.0f, 1.0f);
        public float movementSpeed = 5.0f;

        // Update is called once per frame
        void Update ()
        {

/*Simply just add the direction times speed to the position. Time.deltaTime adds the time since the last frame, which will make it so that no matter what the framerate is, it will move at 5 units per second for example, instead of 5 units per frame.*/

                transform.position += movementSpeed * movementDirection * Time.deltaTime;
        }
}



That's all you need for the constant velocity script. Pretty easy eh? Now just attach it to the camera and you're good to go for the next script.


The next script makes whatever object is attached to it follow the mouse.



using UnityEngine;
using System.Collections;

public class MouseFollow : MonoBehaviour
{

/*Let's make a public Camera variable so that in the editor we can choose what camera this script should take into account.*/

        public Camera mainCamera;


/*Our start function should be making sure that the main camera variable is set to something. If it's not then we should try and find something to take its place. If there is nothing that we can find then we just throw an error.*/

        void Start ()
        {
                if(mainCamera == null)
                {

/*If the mainCamera is set to null, then we start looking for a camera. The main camera has a default name of "Main Camera", so we look for that.*/

                mainCamera = GameObject.Find("Main Camera").GetComponent<Camera>();

/*If that is null we check Camera.mainCamera, which returns the camera with a tag of Main Camera*/

                        if(mainCamera == null)
                        {
                                mainCamera = Camera.mainCamera;
                        }


/*If the mainCamera is still set to null then we throw an error because there is no other camera that we know to look for*/

                if(mainCamera == null)
                {
                        Debug.LogError("No camera designated as main game camera. Either set camera manually in editor or set tag to Main Camera");
                        Debug.Break();
                        }
                }

/*Then we move the object to the center of the screen*/

                transform.position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y - 60, mainCamera.transform.position.z );
        }


/*In the update function we want to find where the object would be in relation to the mouse, and then we want to ease the object into that position*/

        void Update ()
        {
                Vector3 mousePosition = Input.mousePosition;

/*The Z of the mousePosition is 0, so if we just project the mouse position to the world it will show up ontop of the camera, so if we set to to 60, it will project the position outwards 60 units, this is useful because in this case, we keep the main character 60 units away from the camera at all times.*/

                mousePosition.z = 60;



/*Now we want to make sure that the object doesn't go off the screen. This next section makes sure of that by comparing the mouse position to boundaries created in the code*/

                mousePosition.x = Mathf.Max(Screen.width * 0.05f, Mathf.Min(mousePosition.x, Screen.width * 0.95f));
                mousePosition.y = Mathf.Max(Screen.height * 0.05f, Mathf.Min(mousePosition.y, Screen.height * 0.95f));

/*We then project the mouse into world space and smoothly transition the position of the object to the mouse by using Vector3.Lerp which stands for linear interpolation*/

                mousePosition = mainCamera.ScreenToWorldPoint(mousePosition);

                transform.position = Vector3.Lerp(transform.position, mousePosition, 0.4f);
        }
}


Now if you attach this object to your ship or main player or whatever it is that you are using, it should smoothly move to follow the mouse around on the screen. Make sure that the main camera is set in the script otherwise you will just get errors.


So now that we have these first two scripts, we should be able to move the player around and the camera should be moving forward at a constant velocity.


So moving on, now we need a parallax background. If you don't know what a parallax background is, it's basically two or more planes that form a continuously moving background. Now what that means is, once one of the backgrounds is off of the screen, it moves to a position behind the other background, and so on and so forth, so that the background will keep scrolling forever without any breaks. Since we are making a top down shooter, we need something like this so that the player feels as though he/she is moving. 


It is a very basic script and is completed by doing the following:

using UnityEngine;
using System.Collections;

public class ParallaxPlane: MonoBehaviour
{



/*We want to create a public GameObject, which will hold the other parallax plane that it will be moving around*/

        public GameObject parallaxPartner;



/*We then want to create two variables, on float for speed and one Vector3 for the movement direction.*/

        public float speed;
        public Vector3 movementDirection = new Vector3(0.0f, 0.0f, -1.0f);

/*What we want to do in the start function is make sure that the parallaxPartner variable had something put into it, otherwise there is going to be a whole ton of errors in the update function*/

        void Start ()
        {
                if(parallaxPartner == null)
                {
                        Debug.LogError("parallax partner set to null");
                        Debug.Break();
                }
        }

/*In the update function we want to move the background and check to see if the appropriate edge is not visible by the camera*/

        void Update ()
        {
                transform.Translate(movementDirection * speed * Time.deltaTime);

/*Here we make 3 variables to hold the position of the edge we are checking or affect it in some way */

                Vector3 objectCorner = transform.position;
                Vector2 multiplier = new Vector2();



/*gameObject.GetComponent<MeshFilter>().mesh.bounds.size gets the size of the original bounding box of this object. This is useful for finding the size of the object for these specific movement purposes*/

                Vector3 objectSize = gameObject.GetComponent<MeshFilter>().mesh.bounds.size;

                objectSize.Scale(transform.localScale);

/*Here we check to see if the movement direction is set to 0 for anything. If it is then we just skip over that chunk of code, if not we figure out the actual direction and set the affector, which will determine which part of the parallax plane we should be checking for leaving the screen*/

                if(movementDirection.x != 0.0f)
                {
                        multiplier.x = movementDirection.x / Mathf.Abs(movementDirection.x);
                        objectCorner.x += multiplier.x * objectSize.x / -2.0f;
                }

                if(movementDirection.z != 0.0f)
                {
                        multiplier.y = movementDirection.z / Mathf.Abs(movementDirection.z);
                        objectCorner.z += multiplier.y * objectSize.z / -2.0f;
                }

/*We then find the size of and position of the parallax partner so that we can move to the proper position com time*/

                Vector3 viewportCoord = Camera.mainCamera.WorldToViewportPoint(objectCorner);
                Vector3 newPosition = transform.position;
                Vector3 partnersize = parallaxPartner.gameObject.GetComponent<MeshFilter>().mesh.bounds.size;
                partnersize.Scale(parallaxPartner.transform.localScale);

/*We then check to see which part of the screen we should be checking against and move to the proper position if we should*/

                if(multiplier.x != 0.0f)
                {
                        if(multiplier.x > 0.0f && viewportCoord.x > 1.0f)
                        {
                                newPosition.x = parallaxPartner.transform.position.x - (partnersize.x + objectSize.x) / 2.0f;
                        }
                        else if(multiplier.x < 0.0f && viewportCoord.x < 0.0f) 

                        { 
                                newPosition.x = parallaxPartner.transform.position.x + (partnersize.x + objectSize.x) / 2.0f;
                        }
                 }
                if(multiplier.y != 0.0f) 
                { 
                        if(multiplier.y > 0.0f && viewportCoord.y > 1.0f)
                        {
                                newPosition.z = parallaxPartner.transform.position.z - (partnersize.z + objectSize.z) / 2.0f;
                        }
                        else if(multiplier.y < 0.0f && viewportCoord.y < 0.0f)

                       {
                                newPosition.z = parallaxPartner.transform.position.z + (partnersize.z+ objectSize.z) / 2.0f;
                       } 
                }


/*We then set the position of this object to the newly modified position*/


                transform.position = newPosition; 
        } 
}

Now that we have this script completed, we can now attach it to the parallax planes and let them do there thing, except there is one problem. Run the game. They aren't moving! Well actually they are, but they are set to go the same speed as the main camera, and we need to change this. We are going to make one additional script that will move the planes based on the main camera's current velocity so that it will appear as though they are actually moving. This is very easy, and is done like so:


using UnityEngine; 
using System.Collections; 


 public class ParallaxController : MonoBehaviour 
{


/*We want to create an array of the parallax objects so that we can move them properly*/


         public Transform[] parallaxObjects; 


/*We also want to access the ConstantVelocity script that we attached to the main camera for this*/


         private ConstantVelocity velocityObj; 


         // Use this for initialization
        void Start () 
        { 


/*Since this is attached to the camera we can just grab the ConstantVelocity component off of the GameObject*/

                velocityObj = gameObject.GetComponent<ConstantVelocity>();
        }

        // Update is called once per frame
        void Update ()
        {



/*for each object that is in the array, we just translate it the same amount that the camera is moving*/

                for(int i = 0; i < parallaxObjects.Length; i ++)
                {
                        parallaxObjects[i].Translate(velocityObj.movementSpeed * velocityObj.movementDirection * Time.deltaTime);
                }
        }
}



Once you have this script completed you should be able to attach it to the camera, drag the parallax objects into the array, and it should be good to go.

Saturday, February 19, 2011

Creating A Game In Unity Part 1: Main Menu

I'm starting an ongoing series about creating games in Unity3D. I will be doing the same for Ogre3D and Unreal, but they will not be happening for a little while. I just need a bit more time to get something prepared.

The first thing that I am going to talk about is the main menu, only because it is by far the easiest thing to start with in Unity. I have two different ways of doing a main menu that I am going to show you:
    -A 3D menu
    -A menu using delegates in C#
Along with the text tutorial there is a video to go along with it that will take you through each method step by step. Now the text tutorial is not as in depth as the video, as I can only do so much with words, so I highly recommend you check out the video.

Also, follow me on twitter at http://twitter.com/#!/purdyjo!




Check out a larger version of this video at http://www.youtube.com/watch?v=PbNGc_uGfRk&list=UU4ZoaV57lCuuzf5-MxAxmCg&index=4&feature=plcp


The first way to create a menu will be with Unity's 3D text mesh. This is by far the easiest way to get a menu up and running.

Basically to start, create a text mesh in GameObject/Create Other/3D Text, and change the text from "Hello World" to "Start Game". Also add a box collider to it; we need this box collider to make our script function properly. Once you get everything set up, duplicate the Start Game and move it downwards a few units. Change the text to "Quit Game". Now position these objects so that they are in front of the camera in a manner that you desire.

Create a new C# script, call it MenuObject and add the following code to it:


using UnityEngine;
using System.Collections;

//extend MonoBehaviour so that we can attach this script to an object
public class MenuObject: MonoBehaviour 
{
        //A public bool so that we can change in the editor whether or not the button will quit the application
        public bool isQuit = false;

        //For the next three functions, the collider is absolutely necessary
        //these functions will not fire off if there is no collider


        //Fires off when the mouse hovers over the collider
        //When the mouse is over the item, change the colour of it to 
        //red so that the player knows that it is interacting with it
        void OnMouseEnter()
        {
                renderer.material.color = Color.red;
        }

        //Fires off when the mouse leaves the object
        //We want to change the colour of the object back to it's original when the mouse 
        //is no longer over it so that is exactly what we do here
        void OnMouseExit()
        {
                renderer.material.color = Color.white;
        }


        //Fires off when the mouse is clicked while hovering over the object
        //Here we check if the bool was set to true or not and we load the level id not
        //or quit the application if true
        void OnMouseDown()
        {
                if(isQuit)
                {
                        Application.Quit();
                }
                else
                {
                        Application.LoadLevel(1);
                }
        }
}


Now just attach the scripts to the object, and make sure you set the isQuit to true on the quit game object. Once this is working, you need to go into the build settings and set the levels up so that they can be loaded properly. Also make sure that the main menu level is before the other levels. This seems obvious, but, you never know. Also, if the level you are loading is not 1 in the build settings, make sure that you change it to whatever it is that you need it to be, you can even change it to a string value that is the name of the actual level if you want to.

If these instructions were missing pieces, or something confused you check out the video at the end of this post, it should clear things up.


The next way of creating a main menu is through delegates in C#. It is very easy, and the code is fairly clean also, so you don't have to worry about it being a jumbled mess.

Basically to get started, create a C# script called DelegateMenu and attach it to the main camera. There is no real set up to this scene unless you are adding some sort of background texture etc. just make sure the build settings are correct before you try and test it. The code that goes inside DelegateMenu.cs is :



using UnityEngine;
using System.Collections;

public class DelegateMenu : MonoBehaviour 
{
        //we have to declare a delegate so that we can use it in the OnGUI function
        private delegate void MenuDelegate();

        //in order to use a delegate we need to create a variable of MenuDelegate type so that it can be used throughout the code.
        private MenuDelegate menuFunction;

        //these variables are only here because it is cheaper to access a value from memory instead of through a static class
        private float screenHeight;
        private float screenWidth;
        private float buttonHeight;
        private float buttonWidth;

        // Use this for initialization
        void Start ()
        {
                screenHeight = Screen.height;
                screenWidth = Screen.width;

                buttonHeight = screenHeight * 0.3f;
                buttonWidth = screenWidth * 0.4f;

                //here we set the menuFunction to point to the anyKey function, which is further down in the code
                menuFunction = anyKey;
        }

        void OnGUI()
        {
        //in order to use a delegate we just call it like a function. Simple!
                menuFunction();
        }

        //in order to change the GUI we just change the function that menuFunction points to. It will basically take care of itself from that point.
        void anyKey()
        {
                //check if the user pressed anything, if it did, change the menuFunction to show the main menu
                if(Input.anyKey)
                {
                        menuFunction = mainMenu;
                }

                //this is just text in the center of the screen telling the user to press any key
                GUI.skin.label.alignment = TextAnchor.MiddleCenter;
                GUI.Label(new Rect(screenWidth * 0.45f, screenHeight * 0.45f, screenWidth * 0.1f, screenHeight * 0.1f), "Press any key to continue");
        }

        //mainMenu only has two buttons in the version, one to play the game, and one to quit the game
        void mainMenu()
        {
                if(GUI.Button(new Rect((screenWidth - buttonWidth) * 0.5f, screenHeight * 0.1f, buttonWidth, buttonHeight), "Start Game"))
                {
                        Application.LoadLevel("Level1");
                }

                if(GUI.Button(new Rect((screenWidth - buttonWidth) * 0.5f, screenHeight * 0.5f, buttonWidth, buttonHeight), "Quit Game"))
                {
                        Application.Quit();
                }
        }
}

Saturday, February 12, 2011

Proper Design Patterns Part 1: Singletons

Now, before we get started, follow me on twitter at http://twitter.com/#!/purdyjo, that way you'll know exactly when new posts are up. They are weekly, but I might throw in a few here and there just to keep you on your toes.

This is going to be the first of a few posts based on design patterns and their uses. A lot of programmers forget these simple programming methods, and it makes their lives that much harder.

The first pattern that I am going to talk about is the Singleton pattern. What is a Singleton anyways? Why would we use them? Why is this way better in certain situations? I will answer all of these questions and more providing you with examples and a piece by piece walk-through on how to build a simple Singleton to get the job done.

Saturday, February 5, 2011

1st Screenshot

1st Screenshot of my game, just to show off my really bad art.


















I used fancy shaders to make them look better.(teehee)

Also, follow me on twitter at http://twitter.com/#!/purdyjo!

First Post

Awesome, so the blog is set up and things are well on their way. I currently working on a Unity3D game now, that I am hoping to see on the web and possibly iPhone at some point. It's pretty basic, just a top down shooter, but I just wanted to get something out there quickly.

I am a programmer, so the art is going to be bad, thats somewhat of a given, but once thats done the game development should move along fairly quickly, and i should have the game complete a week or so after(depending on how many levels I decide to put into it).

My plan is to put up tutorials for Unity3D, Flash, Unreal and possibly even Ogre3D depending on how much time i have. I'll most likely set up the tutorials as a game that will be built from start to finish over multiple days, so if that is what you are trying to accomplish, I'll make it easy for you.

Anyways, I'm hoping to get some tutorials out there quickly, and the first ones might even consist of the game I am currently working on, so keep an eye out, a new post could be any time.

Also, follow me on twitter at http://twitter.com/#!/purdyjo!