Unity Experience

Hello! Thank you for visiting my Unity Portfolio. Here I will show you samples of my Unity and C# work. Lets get to it!

Summary of Content:

  • Mobile Experience
  • Enemy Scripting
  • Coroutines and UI

Mobile Experience

TreasureTap
An iOS prototype that I created as proof of concept where I practiced UI implementation and rapid prototyping techniques.

Enemy Scripting

The following is a snippet of Unity C# code from an AI patrol enemy. The goal with this system was to create an easily modifiable path of nodes for the worlds wandering NPCs. This enabled ambient ships to populate the seas to make the world feel active and alive.

void Update ()
{
  // Skip this we are not supposed ot be patroling
  if (!patroling)
    return;

  // Change speed to patrol speed
  ChangeSpeed(patrolSpeedLevel);

  targetSailLevel = Mathf.Clamp(targetSailLevel, 0, 3);
  sailLevel = Mathf.Lerp(sailLevel, targetSailLevel, 0.01f);

  transform.Translate(Vector2.right * speed * sailLevel / 2 * Time.deltaTime);
  CheckPosition();

  // Check how much we still need to rotate
  Vector3 diff = targetPosition - transform.position;
  diff.Normalize();

  float targetRotation = Mathf.Atan2(diff.y, diff.x);
  float currentRotation = Mathf.Atan2(transform.right.y, transform.right.x);
  if (Mathf.Abs(targetRotation - currentRotation) < 0.05)
    rotationDirection = 0;

  // Rotate towards target
  transform.Rotate(0, 0, turnSpeed * Time.deltaTime * rotationDirection);
}

void CheckPosition()
{
  float distanceToTarget = Vector3.Magnitude(targetPosition - transform.position);

  // Select next target if within buffer
  if (distanceToTarget < targetProximityBuffer)
    ProceedToNextPoint();
}

void ProceedToNextPoint()
{
  // Check if we are at the end of the list
  if (lastPointVisited == points.Length - 1)
    lastPointVisited = 0; // Loop Back to the first point
  else
    ++lastPointVisited;

  // Move on to the next point
  nextPoint = lastPointVisited + 1;
  if (nextPoint >= points.Length)
    nextPoint = 0;
  targetPosition = points[nextPoint];

  // Determine which direction to rotate
  Vector3 diff = targetPosition - transform.position;
  diff.Normalize();

  float targetRotation = Mathf.Atan2(diff.y, diff.x);
  float currentRotation = Mathf.Atan2(transform.right.y, transform.right.x);
  float rotationDiff = targetRotation - currentRotation;
    
  // Dont rotate if already within target rotation
  if (Mathf.Abs(rotationDiff) < targetRotationBuffer)
    rotationDirection = 0;
  else
    rotationDirection = rotationDiff > 0 ? 1 : -1;

  // If we need to rotate more than 180 deg, rotate the oposite direction instead.
  if (Mathf.Abs(Mathf.Rad2Deg * rotationDiff) > 180)
    rotationDirection *= -1;
}

Coroutines and UI

In this snippet I utilized coroutines to build a system that could be manipulated while executing to allow the player to skip through chunks of text. My goal on this project was to create an easy to edit dialog system that reads from a file and which enabled an exploration and story driven game.

void Update()
{
  if (inConversation)
  {
    // End Convo Cheat
    if (Input.GetKeyDown(KeyCode.P))
    {
      textLineQueue.Clear();
      EndConversation();
      return;
    }

    // Wait for input
    if (Input.GetButtonDown("Submit") || fakeSubmit)
    {
      fakeSubmit = false;
      if (!isTyping)
      {
        // If no more text
        if (textLineQueue.Count == 0)
        {
          if (waitForResponse)
          {
            if (!responseUIObject.activeSelf) // Turn on response UI if it is off
              responseUIObject.SetActive(true);
            return; // Wait
          }
          else
            EndConversation(); // Otherwise end the conversation
        }
        else // Next Line
          StartCoroutine(TextScroll(textLineQueue.Dequeue() as string));
      }
      else if (!cancelTyping)
        cancelTyping = true;
    }
  }
}

IEnumerator TextScroll(string textLine)
{
  if (textLine.Length == 1) // Next Line
  {
    if (textLineQueue.Count == 0)
      EndConversation();
    else // Next Line
      StartCoroutine(TextScroll(textLineQueue.Dequeue() as string));

    yield break;
  }

  int letter = 0;
  conversationText.text = "";
  isTyping = true;
  cancelTyping = false;

  while (isTyping && !cancelTyping && letter < textLine.Length - 1)
  {
    conversationText.text += textLine[letter];
    ++letter;
    yield return new WaitForSeconds(typeSpeed);
  }
  conversationText.text = textLine;
  isTyping = false;
  cancelTyping = false;
}

void StartConversation()
{
  if (inConversation)
    return;
  textWindow.SetActive(true);
  GameManager.BroadcastAll("OnStartConversation");
  StartCoroutine(TextScroll(textLineQueue.Dequeue() as string));
  inConversation = true;
}

void EndConversation()
{
  if (!inConversation)
    return;
  textWindow.SetActive(false);
  inConversation = false;
  GameManager.BroadcastAll("OnEndConversation");
}

public void QueueTextLines(TextAsset textFile, int startLine, int endLine)
{
  string[] textLines = textFile.text.Split('\n');

  for (int i = 0; i <= endLine - startLine; i++)
    textLineQueue.Enqueue(textLines[startLine + i - 1]);

  if (inConversation == false)
    StartConversation();
}

// Overloaded for when there is only one line
public void QueueTextLines(TextAsset textFile, int startLine)
{
  QueueTextLines(textFile, startLine, startLine);
}

public void QueueResponse(GameObject responseUI)
{
  if (responseUI != null)
  {
    responseUIObject = responseUI;
    waitForResponse = true;
  }
}

public void ConversastionButtonPressed()
{
  waitForResponse = false;
  fakeSubmit = true;
  responseUIObject.SetActive(false);
}