Unity Penelope Tutorial update for Unity 3 and C# – Part 1, Pages 19-33

Oct
22

I like to get familiar with Unity3d v3, mobile device development, and c#.

MonoDevelop is a great tool for developing Unity 3. It has excellent code completion and line by line debugging. Unfortunately it doesn’t support UnityScript/JavaScript for code completion, so I decided to suck it up and just force myself to go with C#.

Being unfamiliar with Unity development as a whole, I found the Penelope Tutorial fantastic. It is written using the old unity api and with UnityScript. I figured, since I’m going to be going though the tutorial and converting everything to C# and the Unity 3 API I might as make the coding snippets though out the tutorial available as well.

http://unity3d.com/support/resources/tutorials/penelope.html
Here is the first part: pages 19 – 33 of the Penelope PDF converted to c# and using the latest Unity 3 API

So read and follow the text (there are also some coding bits ‘hidden’ in the text not as coding snippets) and when you get to a coding piece just refer to these snippets below.

Complete source from pages 19-33.

Part 2

Page 19

private GUITexture gui;

public void Start ()
{
    gui = (GUITexture)GetComponent( typeof(GUITexture) );
}

.
.
Pages 19-20
Since Android is a new platform, looks like unity 3 updated their API to be less specific, so iPhoneInput has turned into Input, these changes are littered though out, so keep an eye out.

public void Update ()
{
    int count = Input.touchCount;

    int i;
    for( i = 0; i < count; i++)
    {
        Touch touch = Input.GetTouch(i);

        if( gui.HitTest( touch.position ) )
        {
            // error is thrown when setting gui.pixelInset directly in c#
            Rect tempRect = gui.pixelInset;
            tempRect.x = touch.position.x;
            tempRect.y = touch.position.y;
            gui.pixelInset = tempRect;
        }
    }
}

.
.
Page 21

private GUITexture gui;
private Rect defaultRect;
private Vector2 guiTouchOffset;

public void Start ()
{
    gui = (GUITexture)GetComponent( typeof(GUITexture) );
   
    // get where the gui texture was originally placed
    defaultRect = gui.pixelInset;
   
    // get our offset for center instead of corner;
    guiTouchOffset.x = defaultRect.width * 0.5f;
    guiTouchOffset.y = defaultRect.height * 0.5f;
}

public void Update ()
{
    int count = Input.touchCount;
   
    int i;
    for( i = 0; i < count; i++)
    {
        Touch touch = Input.GetTouch(i);
       
        Vector2 guiTouchPos = touch.position - guiTouchOffset;
       
        if( gui.HitTest( touch.position ) )
        {  
            Rect tempRect = gui.pixelInset;
            tempRect.x = guiTouchPos.x;
            tempRect.y = guiTouchPos.y;
            gui.pixelInset = tempRect;
        }
    }
}

.
.
Pages 22-24

private GUITexture gui;
private Rect defaultRect;
private Vector2 guiTouchOffset;

public void Start ()
{
    gui = (GUITexture)GetComponent( typeof(GUITexture) );
   
    // get where the gui texture was originally placed
    defaultRect = gui.pixelInset;
   
    // get our offset for center instead of corner;
    guiTouchOffset.x = defaultRect.width * 0.5f;
    guiTouchOffset.y = defaultRect.height * 0.5f;
}

public void Reset()
{
    gui.pixelInset = defaultRect;  
}

public void Update ()
{
    int count = Input.touchCount;
   
    // no fingers are touching, so we reset the position
    if( count == 0 )
    {
        Reset();   
    }
    else
    {
        int i;
        for( i = 0; i < count; i++)
        {
            Touch touch = Input.GetTouch(i);
           
            Vector2 guiTouchPos = touch.position - guiTouchOffset;
           
            if( gui.HitTest( touch.position ) )
            {  
                Rect tempRect = gui.pixelInset;
                tempRect.x = guiTouchPos.x;
                tempRect.y = guiTouchPos.y;
                gui.pixelInset = tempRect;
               
                // another check to see if fingers are touching
                if( touch.phase == TouchPhase.Ended
                    || touch.phase == TouchPhase.Canceled )
                {
                    Reset();   
                }
            }
        }
    }
}

.
.
Page 24

public class Boundary
{
    public Vector2 min = Vector2.zero;
    public Vector2 max = Vector2.zero;
}

.
.
Pages 24-25

private Boundary guiBoundary = new Boundary();

public void Start()
{
    // ...
    guiBoundary.min.x = defaultRect.x - guiTouchOffset.x;
    guiBoundary.max.x = defaultRect.x + guiTouchOffset.x;
    guiBoundary.min.y = defaultRect.y - guiTouchOffset.y;
    guiBoundary.max.y = defaultRect.y + guiTouchOffset.y;
}

public void Update()
{
    // ...
    tempRect.x = Mathf.Clamp( guiTouchPos.x,
                                guiBoundary.min.x,
                                guiBoundary.max.x );
    tempRect.y = Mathf.Clamp( guiTouchPos.y,
                                guiBoundary.min.y,
                                guiBoundary.max.y );
    // ...
}

.
.
Page 25 (bottom) Page 26(top) no change

.
.
Page 26:

public Vector2 deadZone = Vector2.zero;

public void Update ()
{
    float absoluteX = (float)Mathf.Abs( position.x );
    float absoluteY = (float)Mathf.Abs( position.y );
    if( absoluteX < deadZone.x )
    {
        position.x = 0.0f; 
    }
   
    if( absoluteY < deadZone.y )
    {
        position.y = 0.0f;
    }
// ...
}

.
.
Page 27

public int tapCount;

////////

static private float tapTimeDelta = 0.3f;
private float tapTimeWindow;

Page 27 (bottom) and 28 no change

private int lastFingerId = -1;

.
.
Page 28-31 And if you noticed, I brace all if statements. This little section here, personally, was very confusing to follow. Put some things out of scope my first go at it.

public void Update ()
{  
    int count = Input.touchCount;
   
    if( tapTimeWindow > 0 )
    {
        tapTimeWindow -= Time.deltaTime;
    }
    else
    {
        tapCount = 0;
    }
   
    // no fingers are touching, so we reset the position
    if( count == 0 )
    {
        Reset();   
    }
    else
    {
        int i;
        for( i = 0; i < count; i++)
        {
            Touch touch = Input.GetTouch(i);
           
            Vector2 guiTouchPos = touch.position - guiTouchOffset;

/////
///// Tutorial cuts in here: When we get to our hit test...
/////

            if( gui.HitTest( touch.position ) &&
                    ( (lastFingerId == -1) ||
                    (lastFingerId != touch.fingerId) ) )
            {  
                lastFingerId = touch.fingerId;
               
                if( tapTimeWindow > 0 )
                {
                    tapCount++;
                }
                else
                {
                    tapCount = 1;
                    tapTimeWindow = tapTimeDelta;
                }
               
            }

///
///  Tutorial cuts in here as well: We can then use a second check...
///
                   
            if( lastFingerId == touch.fingerId )
            {
                if( touch.tapCount > tapCount )
                {
                    tapCount = touch.tapCount;
                }
               
                Rect tempRect = gui.pixelInset;
                tempRect.x = Mathf.Clamp( guiTouchPos.x,
                                        guiBoundary.min.x,
                                        guiBoundary.max.x );
                tempRect.y = Mathf.Clamp( guiTouchPos.y,
                                        guiBoundary.min.y,
                                        guiBoundary.max.y );
                gui.pixelInset = tempRect;
               
                // another check to see if fingers are touching
                if( touch.phase == TouchPhase.Ended
                    || touch.phase == TouchPhase.Canceled )
                {
                    Reset();   
                }
            }
        }
    }
   
////
//// Tutorial cuts in for the last time: Update function...
////

    position.x = ( gui.pixelInset.x + guiTouchOffset.x - guiCenter.x ) / guiTouchOffset.x;
    position.y = ( gui.pixelInset.y + guiTouchOffset.y - guiCenter.y ) / guiTouchOffset.y;
   
   
    float absoluteX = (float)Mathf.Abs( position.x );
    float absoluteY = (float)Mathf.Abs( position.y );
    if( absoluteX < deadZone.x )
    {
        position.x = 0.0f; 
    }
   
    if( absoluteY < deadZone.y )
    {
        position.y = 0.0f;
    }
}

.
.
Page 31 – 32

static private Joystick[] joysticks;
static private bool enumeratedJoysticks = false;

public void Update ()
{  
    if( !enumeratedJoysticks )
    {
        joysticks = (Joystick[]) FindObjectsOfType( typeof(Joystick) );
        enumeratedJoysticks = true;
    }
       //...

.
.
Page 32

public void LatchedFinger( int fingerId )
{
    if( lastFingerId == fingerId )
    {
        Reset();
    }
}

.
.
Page 32 – again

foreach( Joystick j in joysticks )
{
    if( j != this )
    {
        j.LatchedFinger( touch.fingerId ); 
    }
}

.
.
Page 33

public void Disable()
{
    gameObject.active = false;
    enumeratedJoysticks = false;
}

.
.
Page 33 – Bottom. Included the whole deadzone part to make it a touch less confusing:

float absoluteX = (float)Mathf.Abs( position.x );
float absoluteY = (float)Mathf.Abs( position.y );
if( absoluteX < deadZone.x )
{
    position.x = 0.0f; 
}
else if( normalize )
{
    position.x = Mathf.Sign( position.x ) * ( absoluteX - deadZone.x ) / (1 - deadZone.x );
}

if( absoluteY < deadZone.y )
{
    position.y = 0.0f;
}
else if( normalize )
{
    position.y = Mathf.Sign( position.y ) * ( absoluteY - deadZone.y ) / ( 1 - deadZone.y);
}

Here is the whole Joystick.cs source from this point in the tutorial.

Part 2