Monday, September 16, 2013

UNITY: Digital Tutors: Introduction to Unity 4



CH11: Working with Physics

Mesh Collider:

  • Mass: no more than 100x other 
  • Is Kinematic: Not affected by forces or gravity, until acted upon by another rigidbody (best for doors, etc).
  • Interpolate: (change if there's glitches and twitches)
    • > None
    • > Interpolate
    • > Extrapolate 
  • Collision Detection:
    •  collision checks are done on certain frames, if object moves so fast that it misses collision check, it could pass through objects.
      • > Discreet (sparse checking)
      • > Continuous (medium checking)
      • > Continuous Dynamics (most/fast checking)
  • Constraints: Can be used to restrict rigidbody movement in specific axis
    • Freeze Position XYZ
    • Freeze Rotation XYZ
  • Rigidbodies should not intersect

CH 12: Getting Started with Scripting

A game is essentially a set of rules and systems set in place for the player to follow, which creates gameplay.
  • Before scripting, create SCRIPTS folder.
  • Three different available scripting languages:
    • JavaScript
    • C#
    • Boo
  • Use whichever language you're most comfortable with (this tutorial series uses C#)
  • Name the file using some kind of naming convention for your own sanity.
  • Unity uses MonoDevelop, but you can use Visual Studio etc. as well.

C#:

  • "using" statements allow for use of pre-made code already present in the UNITY game engine.
  • CLASS is a script in C#
    • public class HelloWorld : MonoBehavior
      • in this instance, HelloWorld is the class name
      • in this instance, MonoBehavior is the type
        • MonoBehavior inside of UNITY is a script object
  • two default functions:
    • void Start()
      • runs once for initialization
    • void Update()
      • runs once per frame
  • Debug.Log(); // basically a 'print to console' command
    • every "statement" should end with semi-colons.
  • Create a GameObject called "MessageMachine" and drop message related scripts onto this object. (or drop on to MainCamera)
    • All scripts need to be attached to an object in the hierarchy.
    • Once attached, it becomes a "component" of the GameObject
  • void Start();
    • good for initialization
  • void Update();
    • good for updating stats
      • game state win/lose conditions
      • player health, ammo, etc
      • boss health

CH 13: Creating the Player Spawn Controller

Goal: to have the player randomly spawn at one of the many designated spawn points.

Steps:

  • Create new Empty GameObject
  • Name it "PlayerSpawn_01"
  • Position "PlayerSpawn_01" into the scene
  • Duplicate and rename to "PlayerSpawn_02"
  • Position "PlayerSpawn_02" to your liking
  • Duplicate and rename to "PlayerSpawn_03" and position
  • Duplicate and rename to "PlayerSpawn_04" and position
  • Group all objects into a "TAG"
    • add TAG
    • name it "PlayerSpawn"
    • this allows us access to these objects via code
  • Make sure "First Person Controller" object is tagged as "Player"
  • Create C# Script "PlayerSpawnController"
    • Talk out what you want do first, which will give you a hint as to what you're going to need to script.
    • Will be needing arrays (lists)
    • Align the curly brackets first { }
    • Use void Awake()
      • gather all of player spawn objects:
Example:
void Awake()
{
    playerSpawnArray = GameObject.FindGameObjectsWithTag("PlayerSpawn");
}

Must declare a public variable before it can be used.


EX:
public GameObject[] playerSpawnArray;

CH14: Finishing the Player Spawn Controller

An array is basically a list to hold multiple pieces of data for a single variable.  What the above script is doing is looking for any GameObject in the scene with the tag "PlayerSpawn" until there are no more.

To get random player spawn, we need to create a new function to handle that.  We only want it to run whenever it's called, which is also another reason to embed into a function.

EX:
public GameObject GetRandomPlayerSpawn(int randNum)
{
    randNum = Random.Range( 0 ,  (playerSpawnArray.Length) );    
// set range to max playerSpawns found.

    if (playerSpawnArray.Length > 0 )
    {
        return playerSpawnArray[randNum];
    }
    // need to put something as a failsafe, in case the IF statement isn't met.
    else
    {
        return null;
    }
}

Need to initialize the "randNum" variable at the beginning, so under the main class, declare a private variable:

EX:
private int randNum;


Create an empty game object and call it "Controllers", then create another empty game object and call it "PlayerSpawnController".  Freeze both transforms, then parent "PlayerSpawnController" to "Controllers".

Add appropriate script to "PlayerSpawnController" object.

Exposing variables in Unity editor is crucial for gameplay creation.  Once you hit play, this script will populate the exposed variable with items that it has found.

CH15: Creating the GameState Script

In this tutorial, we're going to create the GameState script.  This script handles the core rules of the game.  All other scripts connect to this script, and communicates through.  Handles Player spawn, enemy spawn, placing objects, etc.

Create another C# script, and name it "GameState".  What do we want the GameState script to do?

  • find the player
  • find the playerSpawnController script
  • take the player and move the player object to one of the random spawn points
Note: Scripting is an iterative process.  Don't expect everything to work the first try.  It's a process of bug hunting + refinement.  

First step: create variables that we'll need.

Example script:

public class GameState : MonoBehavior
{
private GameObject player;
private PlayerSpawnController playerSpawnCTRL;  
// creates an object of this script class so we can access it through this script.
private GameObject randPlayerSpawn;
// create a variable to hold data created by the random player spawn script.

void Awake ()
{
     player = GameObject.FindWithTag ("Player");
     playerSpawnCTRL = GameObject.FindGameObjectWithTag("PlayerSpawnControl").GetComponent ();
     // make sure PlayerSpawnController is properly tagged
}

void Start ()
{  // we need to initialize our randNum value in this script
     int randNum = 0;
     randPlayerSpawn = playerSpawnCTRL.GetRandomPlayerSpawn(randNum);

    // actually spawn the player
     SpawnPlayer();
}

void SpawnPlayer()
{
     // take player object and move to random player spawn transform.position.
     player.transform.position = randPlayerSpawn.transform.position;
     Debug.Log("You have spawned at " + randPlayerSpawn.name );
}

}

Variable declaration tip:  " scope type name = initialValue "

Add another empty game object into the scene and rename it "GameState", then drop this script into it.



CH 16: Scripting the HUD

This chapter teaches you how to create a HUD to display feedback to the player.  I'll be doing this script in Unity, so only important notes will be put here.  Refer to project script ( available at request ) for details.

- you have to let Unity know what type of textures these are, so under "Texture Type" in the inspector, switch them over to "GUI".
- add "GUITexture" component to "HUD" object.
- you can manipulate the position of the "lantern" texture by changing the transform of the HUD object.
- Set SCALE to 0,0 and use PIXEL INSET (in pixels)
- Set Width and Height to half of what the icon size should be.

Creating a feedback C# script: " Inventory ", but it could be named anything (weapons, ammo, lantern fuel, etc)

- STATIC what is it?  Simply means "global"
- create "Texture2D" array variable to hold the textures to be used by lantern.
- Declaring Arrays requires the "[ ]" after the type of variable to indicate that it's that type, but an array.  Example:

public Texture2D[] hudFuelAmount;

- we only need updates when items are picked up, so don't use "Update()".
- create a "FuelPickup" function instead.

- Apply script to PlayerObject
- assign texture2D array elements in Unity UI (can probably use this technique for texture swapping too, for different zombie skins)

- clicking on the GEAR icon will bring up available options, rather than dragging and dropping

CH17: Creating Items in Unity

Create an item pickup that'll update our HUD.  Again, like the last chapter, this will only be notes and not a summary.  Refer to the scripts and the training videos for the actual lesson.

- import LanternFuel object
- create LanternFuel prefab
- create C# script "LanternFuel"

- use "OnTriggerEnter" event

"player.gameObject.SendMessage("FuelPickUp"); " is a form of running the function "FuelPickup". Great way of communication between scripts.  NAME HAS TO MATCH.

- " Destroy(this.gameObject); " refers to the object the script is currently on, and destroys the gameObject.

 - make sure to add a BoxCollider to your prefab, and select "Is Trigger".

Adding sound to Inventory.cs:
Add a public AudioClip variable "fuelCollectedSound"

then in your function add:
AudioSource.PlayClipAtPoint(fuelCollectedSound, transform.position);


CH18: Creating Lantern Functionality

CH19: Loading Levels

Application.LoadLevel("MainMenu"); //use this to go back to main menu
http://docs.unity3d.com/Documentation/ScriptReference/Application.LoadLevel.html

CH20: Publishing Our Game






Thursday, September 12, 2013

MAYA | UNITY: Character Joint Hierarchy

Hierarchy based off of the Official Unity Mecanim Tutorial Robot:

ROBOT (model):

  • Robot2 (geometry)
  • Root (joints)
    • Neck
      • Head
    • Ribs
      • Left_Shoulder_Joint_01
        • Left_Arm_Joint_01
          • Left_Wrist_Joint_01
            • Left_Thumb_Joint_01
              • Left_Thumb_Joint_01b
            • Left_Index_Finger_Joint_01a
              • Left_Index_Finger_Joint_01b
                • Left_Index_Finger_Joint_01c
            • Left_Middle_Finger_Joint_01a
              • Left_Middle_Finger_Joint_01b
                • Left_Middle_Finger_Joint_01c
            • Left_Ring_Finger_Joint_01a
              • Left_Ring_Finger_Joint_01b
                • Left_Ring_Finger_Joint_01c
            • Left_Pinky_Finger_Joint_01a
              • Left_Pinky_Finger_Joint_01b
                • Left_Pinky_Finger_Joint_01c
      • Right_Shoulder_Joint_01
        • Right_Arm_Joint_01
          • Right_Wrist_Joint_01
            • Right_Thumb_Joint_01
              • Right_Thumb_Joint_01b
            • Right_Index_Finger_Joint_01a
              • Right_Index_Finger_Joint_01b
                • Right_Index_Finger_Joint_01c
            • Right_Middle_Finger_Joint_01a
              • Right_Middle_Finger_Joint_01b
                • Right_Middle_Finger_Joint_01c
            • Right_Ring_Finger_Joint_01a
              • Right_Ring_Finger_Joint_01b
                • Right_Ring_Finger_Joint_01c
            • Right_Pinky_Finger_Joint_01a
              • Right_Pinky_Finger_Joint_01b
                • Right_Pinky_Finger_Joint_01c
    • Hip 
      • Left_Thigh_Joint_01
        • Left_Knee_Joint_01
          • Left_Ankle_Joint_01
            • Left_Toe_Joint_01
      • Right_Thigh_Joint_01
        • Right_Knee_Joint_01
          • Right_Ankle_Joint_01
            • Right_Toe_Joint_01

Monday, September 9, 2013

UNITY: DAN Cannon Prototype

Personal Game Dev Note:

I wasn't allowed to drag my instance of the "_GameScoreKeeper" that was in the Hierarchy into the public "Game_Commander" type object slot on the "Target", but once I turned it into a prefab I was able to drop it in no problem.

Also, didn't declare it as a "GameObject", but as a "Game_Commander" after giving the object a Game_Commander Class script.

Also(2), don't forget to declare the method as "public", otherwise it's inaccessible to other scripts.


UPDATE (2013.SEP.18):

STATIC:
Use "Static" variables, methods, classes, etc. to declare something to be part of the CLASS itself, and not the INSTANCE of the class.

Statics

You can just use the dot operator "." to access the method, and don't need to instantiate an object of that class to use it's members.

Entire classes can be static.  However, STATIC classes can not be instantiated.

NON-STATIC:
Non static variables and methods belong to the instance of the class.


ENABLE / DISABLE USING IF-STATEMENTS
Use this technique to disable GUI Buttons, etc.

PROPERTIES:


UNITY: Adding Vector Data

Figured out Vector data can be added together as variables.  Example:

"      private Vector2 offset = new Vector2(200, 200);
private Vector2 screenDim = new Vector2( Screen.width, Screen.height );
private Vector2 textLocation = new Vector2( (Screen.width / -2), (Screen.height / -2));

         void WriteCountText()
{
countText.pixelOffset = textLocation + offset;
countText.text = "Count: " + count2.ToString();
}
"

Sunday, September 8, 2013

PHOTOSHOP: Laggy Path Selection

If your interface is lagging (namely the path tools), disable Open GL draw under "Preferences" and everything is fixed.

Thursday, September 5, 2013

Scott Robertson: Rendering Form with Value

http://www.youtube.com/watch?v=OZlpcrpA5u0

Notes:

  • drop in a gradient background (dark grey on top, medium grey on bottom) to start.
    • gradient value opposite of light direction
  • Brain interprets "form" change through "value" change, not color change.
  • If you have a nice line drawing, you can put it on a top layer and set it to "Multiply" and leave it across the top.
  • Whenever you want to introduce a form change, introduce a value change.
  • Use simple top lighting.
  • Opposite value gradient to main light will ensure the silhouette is always visible.
  • Put object on a layer on it's own and check 'preserve transparency' for masking out the background.
  • Quick and dirty:
    • Use Burn and Dodge tools after setting a medium grey fill on object.
    • Dodge on any surfaces where light will hit.
      • Perpendicular to the light will be the brightest.
      • Tangent to light you get "Core Shadow", aka "Terminator"
  • Better way:
    • Make a new layer on top.
    • Click division line between base and top layer while holding "Alt", and you get a clipping path layer.
    • Set to "Multiply" so as to not lose any of the line work.
  • Look to the outside of your silhouette, and if it's an undercut, wrap the shadows around to the front surface.
  • Again, Tangent to your light source is your "Core Shadow"
  • Fill in the "Lights", Fill in the "Darks", then come back and paint in-between the values.
  • Since it's on another layer, you can tweak layer opacity to your liking.
  • Create "Cleanup" layer on top and add refinement and details.
  • Duplicate canopy section and put it on Multiply.
  • Paint in the small details inside the canopy.
    • paint in driver to show scale.
    • paint on specular.
      • soft overall
      • sharp point highlight
Refinement:
  • Take value below from background, and start painting in the bounce light on to the vehicle.
  • It's okay to airbrush over the top of line art.
  • Make sure bounce light doesn't overpower main light.
  • Any forms in the shadow side can be shown using the bounce light.
  • Begin switching from line work to "Surface"
    • To show nice lines, you need nice Surfaces.
    • Two surfaces form an Edge.
  • Put "Radius" on the flat panel edges, as well as 'hard' edges.
  • Work quickly without zooming in, "Just to make things go bump."
  • Form Change = Value Change
  • Side profile drawings are a good practice for rendering because you have to work your values.
  • Also good to work in grayscale because you can concentrate on form.
  • Tutorial currently uses a simple airbrush, but you can use a more textured brush if needed.
    • Could use a flattened elliptical brush for more of a 'painterly' look.
  • Once you get your base forms working, everything looks 3D, you can go in and start "Sculpting" the form.
  • A technique from traditional media, clean up your silhouette with colors from your background. 
That's basically it, other than adding in some color and texture on top.  More to do:
  • Noodle time!:
    • keep refining the:
      • forms
      • volumes
      • cut lines
      • radii
      • fillets
      • planes
      • adding graphics
  • Tip for graphics:
    • Marquee areas to be decals
    • Duplicate layer with marquee info
    • Darken
    • Go back and erase to clean up
  • Can also continue adding details, like mechanical bits, etc.
  • Other render tips:
    • Cool to Warm (outdoor rendering)
    • "Color Dodge" mode gives very metallic surfaces
      • have to go into layer settings and disable:
        • Blend Clipped Layers as Group
        • Transparency Shape Layers
    • CTRL + SHIFT + V: Paste back into place.
    • Incorporate value change into reflections.


Sunday, September 1, 2013

UNITY: Roll-A-Ball Tutorial

Official Roll-A-Ball Tutorial by Unity3D

http://www.youtube.com/watch?v=lv0SqtSzBxc

Tutorial 01: Setting Up the Game

  • Unity primitives are all either 1x1x1 or 1x2x1 in size when created
  • Empty Game Objects are used as directories in the Hierarchy

Tutorial 02: Moving the Player

  • Rigidbody
    • required for physics interaction
    • can be created and added directly via "Add Component" in the inspector.
  • void Update();
    • used for controller inputs, etc.
  • void FixedUpdate();
    • used for anything physics related
  • CTRL + ' when highlighting an object in MonoDevelop will bring up the reference page
  • Store "Input.GetAxis" calls in a float variable
  • use "rigidbody.Addforce" for physics based movement
  • create new Vector3 type variable to store movement
    • " Vector3 movement = new Vector3(x, y, z); "
    • " rigidbody.AddForce (movement); "
  • use " Time.DeltaTime " as frames per second

Tutorial 03: Moving the Camera

  • Tying the camera to the Player game object
    • not as simple as parenting the camera to the Player object
    • add a new script to the Camera object via Add Component
    • scripts always get added to the root assets directory, so move it to " scripts "
    • create a " GameObject " type public variable called "player" so a field will open up for drag and drop inside of Unity.
    • create a Vector3 type private variable called "offset" that the script can alter under the Start() function.
    • void LateUpdate();
      • follow cameras, procedural animations, gathering last known states
    • create reference to player GameObject by dragging in to previously created "player" slot

Tutorial 04: Play Area and Pickup Objects

  • Creating environment
    • create empty game object as a holder / folder
    • reset position back to origin
    • create geometry and put it under empty game object for organization
  • Creating Pickup items
    • create new cube
    • lift it, shrink it, and rotate 45 degrees on all axis
    • add component: script (for rotating animation)
    • not using forces, so we can use " void Update() "
    • use lower case "t", " transform.Rotate(new Vector3(15, 30, 45) * Time.DeltaTime); "
    • make into Prefab:
      • Create "Prefab" Folder
      • Drag "Pickup" item from Hierarchy into Prefab folder
        • When this is done, a Prefab Item is created
        • Item in Hierarchy now shows BLUE
    • Create empty GameObject named "Pickups" to hold our pickups in the Hierarchy view
      • Reset position to 0,0,0
    • Spread Pickup items around
      • make sure the blue prefab item itself is selected for duplication, not the group node
      • change move to "Global" instead of "Local" 

Tutorial 05: Collecting and Counting

  • In order to count items, we have to create collision detections
  • collisions have to be detected to trigger new behaviors
  • collisions have to be "tested" to see which object has been pinged
  • edit "PlayerController" script
    • but before that, let's inspect the player object
      • We're interested in the "Sphere Collider"
      • In object header:
        • turn down arrow (reveals more info)
        • icon
        • enable/disable checkbox
        • types of component
        • object sensitive gear gizmo
        • icon of little book with question mark (help)
      • Use book icon to go to offline Reference
        • Offline Reference (PC)
        • Component Help
        • Switch to Scripting Help
        • we want to use "OnTriggerEnter" function
          • can be used for detecting object collision, without actual physical collision occuring
        • "void OnTriggerEnter(Collider other)"
          • references the "other" item we collide with
        • "Destroy(other.gameObject);" 
          • destroys referenced game object that we collided with
          • destroyed game objects and all their children are removed from the scene
        • In this tutorial, we'll deactivate gameObject instead of destroying it
          • Remove the "Destroy" code
          • look up "Tag" under "GameObject"
            • Tags can be assigned to objects for identification
            • Tags must be declared in the "Tag Manager" before using
          • look up "SetActive"
            • method used to activate or disable objects
        • example code:
          • if(other.gameObject.tag == "Pickup")
          • {
            • other.gameObject.SetActive(false);
          • }
        • Basically checks if other object collided with has a Tag called "Pickup, and if it does, executes the code. In this instance, it tells the other game object to execute "SetActive" method to false.
        • In UNITY, select Pickup object and under the inspector, check the TAG list
          • add TAG
          • under the first element (0), add "Pickup"
            • name has to match exactly to the script
          • apply tag to prefab
        • Turn colliders into "Triggers"
          • static objects don't get recalculated
          • dynamic objects get recalculated
          • must add RigidBody objects
            • turn off Use Gravity
            • activate "Is Kinematic"
        • performane Tidbit:
          • UNITY calculates all Static items and holds it in memory cache
          • if we rotate a static collider, the cache gets rebuilt globally
          • adding RigidBody and turning on "Is Kinematic" excludes items from Static collider cache
          • "Is Kinematic" allows for animation through transforms (IE: elevators and moving platforms)

Tutorial 06: Displaying Text

  • We need a tool to store collection count, and tool to add on top
  • Add these tools to "PlayerController" script
    • add private variable "count"
    • initialize to zero under Start();
      • count = 0;
    • under "void OnTriggerEnter(Collider other)"
      • add: " count = count + 1 "
  • Displaying Info via GUI Text:
    • Add new empty GameObject: " Display_Text", transform 0,0,0
    • Create "GUI Text" gameObject
      • Parent to "Display_Text" game object
    • Move to " Upper Left "
      • 0,0 = lower left
      • 1,1 = upper right\
    • Set Transform to 0,1,0
    • Then use "Pixel Offset" setting in the GUIText
      • X = 10, Y = -10
    • Under "PlayerController" script:
      • add new public "GUIText" variable called "countText"
        • this opens up another slot in Unity that allows for drag and drop
      • initialize "countText" to: 
        • "Count: " + count.ToString(); 
          • count.ToString(); must be after "count" has an initialized value
      • update "countText" everytime an object is picked up
        • under "void OnTriggerEnter(Collider other)"
          • add "countText.text = "Count: " + count.ToString();
      • create new function instead of typing "countText.text = ....." repeatedly
        • void SetCountText()
        • {
          • countText.text = "Count: " + count.ToString();
        • }
      • add function call to respective locations of the script
      • drag GuiText object into new "PlayerController" script slot
      • VOILA!
  • Displaying WIN condition:
    • create new GUIText object "WinText"
    • parent to DisplayText game object
    • add reference to PlayerController script:
      • create new public GUIText variable: " winText "
      • initialize winText.text = ""; // empty text
      • under " SetCountText()" function:
        • add:
          • if (count >= 12)
          • {
            • winText.text = "YOU WIN!";
          • }
      • save and return to unity
      • drag-associate WinText object to the PlayerSphere reference call (drop it into the field)

Tutorial 07: Publishing the Game

  • Unity can build to all to all target platforms
  • Open Build Settings
  • Current build settings are denoted by the UNITY icon
  • Switch build platform by highlighting target platform, and hitting "Switch Platform"
  • Add current scene to build by clicking "Add Current", or drag and drop any scenes from Project folder to the "Scenes to Build" field
    • include only the scenes needed
  • Hit "Build" button
  • Create new folder under main project root folder called "Builds"
  • Name the build, and Save