Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Saturday, July 8, 2017

Static UI

Some basics with using UI in Unity 5.  To get a static (non-interactive) UI element, go to GameObject > UI  and either select Text or Raw Image.


Adding one of these will automatically create a Canvas and an EventSystem.  For static purposes these two game objects can be ignored.  Note that the order at which the child objects appear will dictate what is "in front" of what in the view.  In this case CountBackground is behind the Text.


Final note, if referencing these objects within code make sure you have the header:

using UnityEngine.UI;

Global vs Local

There are times when it is beneficial to work either in what is referred to as Local or Global space.  This manifests itself in a few places.  In the editor, you may have seen these buttons.  They toggle where the center point of an object is [Center/Pivot], and the transform reference [Local/Global]

 

As an example of the distinction, Center will place the transform marker at the average center of the object including the shape of its children.  To the contrary, the Pivot will place the center at what I would call the "center reference" as defined in the original model.

In the same way Local and Global refer to the reference in space for the transform.  This can be most easily seen in the available transform functions.

  • eulerAngles/localEulerAngles
  • position/localPosition
  • rotation/localRotation
  • scale/localScale
Specifically with child objects, using one or the other makes a significant difference in behavior.  Making changes to the global transform of a child object will control it irrespective of what the parent is doing whereas local changes are relative to what the parent is doing.

List of Collided

As far as I can tell Unity doesn't have a mechanism natively that tells you all the objects that are currently collided (triggered) in your collider.  The most common approach seems to be managing the list on your own using the OnTriggerEnter and OnTriggerExit:

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "enemy")
        { 
            allCollisions.Add(other.gameObject);
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.tag == "enemy")
        {
            allCollisions.Remove(other.gameObject);
        }
    }

One extra point to note, that this approach breaks down if your objects are "exiting" because they are destroyed.  In my case, I wanted to destroy the entire list of objects via an event.  At first I used List.Clear(), however I found that this only nulls all the elements, but doesn't actually clear the elements.  Better was to blow away the list with a new instance.

if (Input.GetButtonDown("Fire1"))
{
   foreach (GameObject enemy in allCollisions)
   {
SeekToKill newBullet = (SeekToKill)Instantiate(bullet, bulletStart.transform.position, bulletStart.transform.rotation);
newBullet.SetTarget(deadbug);
   }

   // clear list including indicies
   allCollisions = new List<GameObject>();
}

OnTriggerEnter Re-entrance

This is more of a lessons-learned while developing a game, and I'm creating a post as a reminder for myself.  In this scenario I was using the OnTriggerEnter function to determine when the object would be destroyed.

The issue I was running into was that in some rare cases, multiple objects would trigger this function simultaneously, causing this function to call multiple times before the object was actually destroyed.

Adding a class flag solved my issue, in my case I called it isDead:

    private void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Bullet" && !isDead)
        {
            Destroy(this.gameObject);

            system.UpdateBugCount(-1);
            isDead = true;
        }
    }

The flag prevents re-executing the function after the object should technically be destroyed.

Detonator Explosion Framework

The Detonator Explosion Framework is an excellent free package that can be acquired through the Asset Store.  It does have some quarks to get it to work with Unity 5, and the following is what I've observed needed to be done to get the Tiny Detonator to work.

Saturday, February 6, 2016

Delegates or Callbacks

Here is an example for using Delegates to achieve a callback capability.

In the class that is going to call the callback function:

public class PointBasketManager : MonoBehaviour
{
   public delegate void GameOverEvent ();

   private GameOverEvent game_over;

   public void SetGameOverCallback (GameOverEvent newCallback)
   {
      game_over = newCallback;
   }

   public void BasketTriggered (uint points)
   {
      // trigger game is over
      game_over ();
   }
}

The using class calls the function SetGameOverCallback() and passes in the function that should be called when game_over() is called.

public class GameSystem : MonoBehaviour

{
   void Start()
   {
      point_mgr.SetGameOverCallback(OnGameEnd);
   }

   public void OnGameEnd ()
   {
      // end game stuff

   }
}

Friday, February 5, 2016

Pseudo Polymorphism in Inspector

This is the closest I've been able to come in creating polymorphic assignment with game objects in the inspector.

The interface or abstract-base-class would be defined as below.  Note the keyword "virtual" must be used here.

public class IEventTrigger : MonoBehaviour
{
   public virtual void OnEvent()
   {}
}

Next the derived class inherits from this pseudo-interface.  Note in this case, the implementation must be overridden using the "override" keyword.

public class TriggerPrint : IEventTrigger
{
   public override void OnEvent()
   {
      Debug.Log("Event Logged");
   }
}

An example now of a class that takes a game-object that has the TriggerPrint script component.  When eventHandler.OnEvent() is called, it will call the TriggerPrint.OnEvent().

public class InputManager : MonoBehaviour 
{
   [SerializeField]
   private IEventTrigger eventHandler;

   // Use this for initialization
   void Start ()
   {
      eventHandler.OnEvent();
   }
}

Class Fields in Inspector

Examples of making fields available to the inspector

   public int myInt;

or

   [SerializeField]
   private int myInt;