I am part of the camp of people who feels that reducing the number GetComponent calls is always a good idea. So I prefer all that GetComponent to be done at the start of the game and be done and over with.
So for convenience sake I was thinking perhaps we could create a Manager to handle ScriptComponents that may be accessed by other scripts often

So using the previous post example of an FPS Game, I did not wish for my trigger script to keep calling GetComponent every time it needs the players HealthScript to access its Subject.

So I decided on creating something like a ManagerScript that houses all players GameObject, HealthScript, InverntoryScript etc. It will have a static instance of itself stored within the class, so there will exist only one instance of itself throughout the game.

So something like the picture below . . .





For the manager script I actually used a Tuple to hold information, but honestly I still have yet to figure out a substantive reason why anyone would want to use a Tuple rather than a struct.

But either ways if you still wish to use a Tuple you can set it up by following this steps.

  1. Enabling .Net framework 4.6 so that we can download the System.ValueTuples package.
    (File) -> (Build Settings) -> (Player Settings located at Bottom Left) -> (Other Settings) -> (Scripting Runtime Version change to 4.6)
  2. Download the nuGet Package Manager.
  3. This is so that you can use it to install the System.ValueTuple package

Further links about Tuples are provided below this page.

So for the benefit of those whom did not download the file I linked to on this post, I will put in the code implementation for the TriggerDamageObject below.


using System;

public class ManagerScript : MonoBehaviour
{
    private static Dictionary<string, Tuple<GameObject, HealthScript>> mydictionary;
    //Probably better to use a struct instead since it has named properties, but if you`re lazy i guess a Tuple works
    static readonly Tuple<GameObject, HealthScript> nulltworeference = Tuple.Create<GameObject, HealthScript>(null,null);

	void Awake()
	{
		if(mydictionary!=null)
		{
			this.Destroy();
		}
		
		mydictionary = new Dictionary<string, Tuple<GameObject, HealthScript>>();
	}
	
    public static void addToDictionary(GameObject item1, HealthScript item2, string key)
    {
        if(mydictionary.ContainsKey(key))
        {
            mydictionary[key] = Tuple.Create<GameObject, HealthScript>(item1,item2);
        }
        else
        {
            mydictionary.Add(key, Tuple.Create<GameObject, HealthScript>(item1, item2));
        }
    }

    public static Tuple<GameObject,HealthScript> returnMyTuple(string key)
    {
        if (mydictionary.ContainsKey(key))
        {
            return mydictionary[key];
        }
        else
        {
            return nulltworeference;
        }
    }

    public static void removeFromDictionary(string key)
    {
        if (mydictionary.ContainsKey(key))
        {
            mydictionary.Remove(key);
        }
        else
        {
            Debug.Log("Referenced key does not exist . . .");
        }
    }
}


Dictionary<string,bool> inmytrigger = new Dictionary<string,bool>(); //Name : TriggerDamage

public class TriggerDamageScript : MonoBehaviour , ISingleDamage<HealthScript>

void OnTriggerEnter(Collider other)
{
	if(!inmytrigger.TryGetValue(other.name))
	{
		inmytrigger.Add(other.name, true);
	}
}

Tuple<GameObject, HealthScript> temptuple;

void OnTriggerStay(Collider other)
{	
	if(inmytrigger.TryGetValue(other.name))
	{
		temptuple = ManagerScript.returnMyTuple(other.name)
	
		if(inmytrigger[other.name]==true) //If the object should receive damage
		{
			inmytrigger[other.name] = false; //Toggle to not receive anymore damage
			singleDamage(temptuple.Item2); // The field containing the HealthScript this is where the actual damage is inflicted to the player by changing its subjects state
			storefunction = IToggleDamage(temp,tupleintrigger[temp].Item1); 
            Invoke("invokethis", 2.0f); //This function resets the supposed to receive damage value to true after 2 seconds
		}
	}
	else
	{
		inmytrigger.Add(other.name, true);
	}
}
</br>

public void singleDamage(HealthScript input)
{
	//Do Damage E.g. Subject.setState()
}

void OnTriggerExit(Collider other)
{
	int temp = inmytrigger.FindIndex(x=>x==other.name);

	if(temp!=-1)
	{
		inmytrigger.RemoveAt(temp);
	}
}

public interface ISingleDamage<T>
{
	void singleDamage(T input);
}

IEnumerator storefunction;

void invokethis()
{
    StartCoroutine(storefunction);
}

IEnumerator IToggleDamage(string name)
{
	if(inmytrigger.TryGetValue(name))
	{
		inmytrigger[name] = true;
	}
	
    yield return null;
}


I am in the mood to make an FPS game as well so perhaps the next post will be about how I`ll structure the Gameplay Flow and actual Game World to ease coding of the game.

By the way, I probably learned about the concept of managers from this youtube channel, which was when I first started out coding for a multiplayer game. The game did not see itself through to completion because I was working together on it with my friend and we both lost the motivation to continue working on it. Do check out that website, its free and I think they also teach about the new Unity3D Networking system.


< < Using Queues in an FPS > >


So I thought I should probably stay true to my words and begin some work on the FPS. XD

So over here I am going to write about implementing a queue system for processing player damage input.

Often times when a player gets shot we wish to figure out whether the shot killed him and if so, who was the one that fired the shot.

We could do so by implementing a simple Queue Data Structure (First-In_First-Out Data Structure) for the players HealthSubject

Something like so . . .



//code for the Queue Data Structure
List<type> QueueDataStructure = new List<Type>();
public int queueCount = 0; //If you dont wish to keep accessing QueueDataStructure.Count

public void enqueue(type input)
{
	queueCount++;
	QueueDataStructure.Add(input);
}

public type dequeue()
{
	if(queueCount>0)
	{
		queueCount--;
		return QueueDataStructure.RemoveAt(0);
	}
	else 
	{
		Debug.Log("dequeue() was called but QueueDataStructure was empty");
		return null;
	}
}