programming

Auto fills specific components fields

Hello again guys!

So, after reading through some feedback entries, I stumbled across this one:
https://feedback.unity3d.com/suggestions/automatically-inject-requirecomponent-fields

I thought that this was a wonderful idea, what it basically is auto fills component fills marked with the attribute RequireComponent, it not only adds (if there is not) the component in the gameobject, it also fills a specific field which was marked with that attribute. So I decided to implement this myself. Of course, the component must be serialized to work, this means that the component must be expanded and the inspector cannot be in debug mode, it also will not work with abstract class components like Collider, it must be a CapsuleCollider, BoxCollider, etc.

Here are the scripts:

This one goes in an Editor folder:

using UnityEngine;
using UnityEditor;

[CustomPropertyDrawer(typeof(RequiredComponentAttribute))]
public class RequiredComponentDrawer : PropertyDrawer
{
	public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
	{
		EditorGUI.PropertyField(position, property);

		MonoBehaviour mono = property.serializedObject.targetObject as MonoBehaviour;
		if (typeof(Component).IsAssignableFrom(fieldInfo.FieldType))
		{
			if (property.objectReferenceValue == null)
			{
				Component comp = mono.GetComponent(fieldInfo.FieldType);

				if (comp == null)
				{
					comp = mono.gameObject.AddComponent(fieldInfo.FieldType);
				}

				property.objectReferenceValue = comp;

				Undo.RecordObject(mono.gameObject, "Add/Set Components to " + mono.gameObject.name);
			}
		}
		else
		{
			Debug.LogError("Field <b>" + fieldInfo.Name + "</b> of " + mono.GetType() + " is not a component!", mono);
		}
	}
}

And this one goes in any folder:

using UnityEngine;
public class RequiredComponentAttribute : PropertyAttribute
{
}

Yes, I like to keep attributes in a separate script, even if they are just a stub.

Thanks for reading, let me know if you can optimize it or add something to it.

Cheers,
Rodolfo Rubens

Preview Main Component Icon In Hierachy

Hey guys,
I made a simple script that shows the icon of the first component (after transform of course) of the gameobject in hierarchy and also show a toggle to toggle the active state of the object.
It can also show custom component icons, you just need to put them in Assets/Editor/Icons.
Also, it has some “smart” icon showing that shows differently depending if the object has components or not and if it has childs or not, if it’s a prefab or not too:
Plus:
– Mass deactivate/activate gameobject and its children by holding alt and clicking on its toggle.
ps.: The children will inherit the toggled object’s active state, IT WILL NOT TOGGLE THE CHILD ACTIVE STATE.
– Choose to only show specific component types and etc.
– If custom component type was added to the specific component types and there is no icon for it, it will show a gameobject icon
Here is the code:
// Main Component Icon, Active State Toggling and "Smart Empty Object Icon Display"
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;

[InitializeOnLoad]
class MainComponentIcon
{
	// only show these types if showAllTypes is false
	static Type[] componentTypes = new Type[]
	{
		typeof(Light),
		typeof(BoxCollider),
		typeof(Camera),
		typeof(ParticleSystem),
		typeof(TrailRenderer),
		typeof(MeshRenderer),
		typeof(MeshFilter),
		typeof(SpriteRenderer),
		typeof(AudioSource),
		typeof(Canvas),
		typeof(CanvasGroup),
		typeof(UnityEngine.UI.Image),
		typeof(UnityEngine.UI.Button),
		typeof(UnityEngine.UI.Text),

		// must add the custom types here if showAllTypes is false
		typeof(GameController),
		typeof(PlayerController),
		typeof(SpellScript)
	};
	static bool showActiveToggle = true;
	static bool showIndentedActiveToggle = true;
	static bool showAllTypes = true;
	static bool useFallbackIconForExcludedComponents = false;
	static bool prefabOverOthers = true; // don't show any component icon if the gameobject is a prefab, show the prefab icon instead
	static bool alwaysShowCustom = false; // will show all custom, even if they don't have custom images (will show the little script page icon)
	static bool alwaysShowPrefabContainer = true;
	static IdleObjectsView showEmptyPrefabIconInIdleObjects = IdleObjectsView.TransformIcon; // // gameobjects with no child or components
	static FallbackIcon fallbackIcon = FallbackIcon.GameObjectOrTransformsOrPrefab;

	// UI exceptions
	static bool canvasOverPrefab = true;

	static List<GameObject> allChildGOsForToggle;
	static bool toggleActiveAllChildInheritToggleObject = true; // Attention: if hold alt and clickin on object toggle, it will set all childs active state to the same of the clicked object

	static MainComponentIcon()
	{
		// Init
		EditorApplication.hierarchyWindowItemOnGUI += HierarchyItemCB;
	}

	static void HierarchyItemCB(int instanceID, Rect selectionRect)
	{
		GameObject obj = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
		var backupColor = GUI.color;

		if (obj)
		{
			Rect r = new Rect(selectionRect);
			if (showActiveToggle)
			{
				// Toggle active button
				r.x = showIndentedActiveToggle ? selectionRect.x - 28 : 2;
				r.width = 18;
				r.height = 16;

				EditorGUI.BeginChangeCheck();

				backupColor = GUI.color;
				if (!obj.activeInHierarchy && obj.transform.parent != null) GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.5f);
				var toggleValue = GUI.Toggle(r, obj.activeSelf, "");
				GUI.color = backupColor;
				if (toggleActiveAllChildInheritToggleObject && Event.current.alt)
				{
					if (EditorGUI.EndChangeCheck())
					{
						if (allChildGOsForToggle == null) allChildGOsForToggle = new List<GameObject>();
						allChildGOsForToggle.Clear();
						allChildGOsForToggle.Add(obj);
						FetchAllChildGameObjects(obj.transform);
						Undo.RecordObjects(allChildGOsForToggle.ToArray(), "Toggle GameObjects Active");
						allChildGOsForToggle.ForEach(child => child.SetActive(toggleValue));
					}
				}
				else
				{
					if (EditorGUI.EndChangeCheck())
					{
						Undo.RecordObject(obj, "Toggle " + obj.name + " Active");
						obj.SetActive(toggleValue);
					}
				}
			}

			// Icon
			r.x = EditorGUIUtility.currentViewWidth - 38;
			r.width = 18;
			r.height = 18;
			backupColor = GUI.color;
			if (!obj.activeInHierarchy) GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.5f);
			var components = obj.GetComponents<Component>();
			if (components != null)
			{
				// FIRST COMPONENT IS ALWAYS TRANSFORM OR RECT TRASNFORM
				if (components.Length > 1)
				{
					// HAS COMPONENTS
					Type type = components[1].GetType();
					Texture image = EditorGUIUtility.ObjectContent(null, type).image;
					bool isInComponentTypesList = Array.Exists(componentTypes, x => x == type);

					if (image == null)
					{
						// put your custom components icons in Assets/Editor/Icons, name it the same name of your class and change the extension below as accordingly
						image = AssetDatabase.LoadAssetAtPath("Assets/Editor/Icons/" + type.ToString() + ".psd", typeof(Texture)) as Texture;
					}

					if (canvasOverPrefab && type == typeof(Canvas))
					{
						GUI.Label(r, EditorGUIUtility.IconContent("Canvas Icon"));
					}
					else if (prefabOverOthers && CanShowAsPrefab(obj))
					{
						ShowFallbackIcon(obj, r);
					}
					else if (!image && alwaysShowCustom)
					{
						GUI.Label(r, EditorGUIUtility.IconContent("cs Script Icon"));
					}
					else if (showAllTypes || isInComponentTypesList)
					{
						if (image)
						{
							GUI.Label(r, image);
						}
						else
						{
							ShowFallbackIcon(obj, r);
						}
					}
					else if (image && useFallbackIconForExcludedComponents || alwaysShowPrefabContainer && CanShowAsPrefab(obj))
					{
						ShowFallbackIcon(obj, r);
					}
				}
				else
				{
					// IDLE OBJECTS
					if (obj.transform.childCount == 0)
					{
						if (CanShowAsPrefab(obj))
							GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
						else if (showEmptyPrefabIconInIdleObjects == IdleObjectsView.WhitePrefabIcon) // no child nor components
							GUI.Label(r, EditorGUIUtility.IconContent("Prefab Icon"));
						else if (showEmptyPrefabIconInIdleObjects == IdleObjectsView.TransformIcon) // no child nor components
						{
							if (obj.GetComponent<RectTransform>())
								GUI.Label(r, EditorGUIUtility.IconContent("RectTransform Icon"));
							else
								GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
						}
					}
					// NO COMPONENTS BUT HAS CHILDREN
					else if (obj.transform.childCount > 0)
					{
						if (CanShowAsPrefab(obj))
							GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
						else
							GUI.Label(r, EditorGUIUtility.IconContent("Prefab Icon"));

						GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
					}

				}
			}

			GUI.color = backupColor;
		}
	}

	static void ShowFallbackIcon(GameObject obj, Rect r)
	{
		switch (fallbackIcon)
		{
			case FallbackIcon.TransformOrRect:

				if (obj.GetComponent<RectTransform>())
					GUI.Label(r, EditorGUIUtility.IconContent("RectTransform Icon"));
				else
					GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
				break;

			case FallbackIcon.GameObjectOrPrefab:
				if (CanShowAsPrefab(obj))
					GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
				else
					GUI.Label(r, EditorGUIUtility.IconContent("GameObject Icon"));
				break;

			case FallbackIcon.GameObjectOrTransformsOrPrefab:
				if (CanShowAsPrefab(obj))
					GUI.Label(r, EditorGUIUtility.IconContent("PrefabNormal Icon"));
				else
				{
					if (obj.GetComponents<Component>().Length > 1)
					{
						GUI.Label(r, EditorGUIUtility.IconContent("GameObject Icon"));
					}
					else
					{
						GUI.Label(r, EditorGUIUtility.IconContent("Transform Icon"));
					}
				}
				break;
		}
	}

	static bool IsPartOfPrefab(GameObject prefab)
	{
		return PrefabUtility.GetPrefabParent(prefab) != null;
	}

	static bool IsPrefabParent(GameObject prefab)
	{
		return PrefabUtility.FindPrefabRoot(prefab) == prefab;
	}

	static bool CanShowAsPrefab(GameObject prefab)
	{
		if (IsPrefabParent(prefab) &&
			IsPartOfPrefab(prefab) &&
			PrefabUtility.GetPrefabType(prefab) == PrefabType.PrefabInstance ||
			PrefabUtility.GetPrefabType(prefab) == PrefabType.ModelPrefabInstance)
		{
			return true;
		}

		return false;
	}

	public static void FetchAllChildGameObjects(Transform transform)
	{
		if (allChildGOsForToggle == null) allChildGOsForToggle = new List<GameObject>();
		foreach (Transform t in transform)
		{
			if (!allChildGOsForToggle.Contains(t.gameObject)) allChildGOsForToggle.Add(t.gameObject);
			FetchAllChildGameObjects(t);
		}
	}

	//static bool
}

enum FallbackIcon
{
	None,
	GameObjectOrTransformsOrPrefab,
	GameObjectOrPrefab,
	TransformOrRect
}

enum IdleObjectsView
{
	None,
	TransformIcon,
	WhitePrefabIcon
}

I hope you enjoy!

Video Log #2 Even more battle system

Hello guys, long time no see!!

It’s time for another devlog video!

So, in this video you can see how the map exploration and battle system is coming along, some improvements to the battle system and lots of bug fixes, by the way, the video has no sound, you can keep listening to your music!

Different types of movements (attacks) being used and their respective visual effect showing up, the creatures also reacts accordingly, you can also note that using moves that makes contact plays a different animation than special moves (moves that doesn’t make contact).

The temporary battle stats is also already working and works kinda like in the Pokémon games.

Also, as you could notice, some creatures flee from the player character when they see him, that’s the creature nature system, there are some that flee, others that doesn’t care about the player’s presence and others that goes towards the player when he gets too close, there will be more types of natures later like going towards just after spotting the player, also some that don’t care about the player presence but if he stays too much time close they will go towards the player anyway, engaging a battle.

You can also notice in the video that the battle arena is now different, each type of scenario will load a different type of battle arena when a battle starts, I also added some fancy to the camera. Oh, I also implemented a very nice feature in the battle system, when the player is in the “choose action” turn he can cycle through cameras, zoom in/out and orbit around the camera target which is very cool.

In summary, almost the entire battle system is done, just need to fix some bugs here and there and implements new items/moves usage and etc, things like experience gaining, level up, temporary stats, super effective and not very effective moves against certain creatures elements, all of this is already done.

Ah, another thing, the animations are very unpolished, be patient, they will get better as the projects follows.

Ok guys, that’s it for this video, I hope you liked it! I made lots of other stuff but unfortunately cannot be show because is just technical stuff, things from the engine.

What’s next? Now is time to model the rest of the creatures that will be available in the prototype!

See you guys/gals next time!

DevLog #14 First WIP Video (Battle system, etc…)

Hey guys, it’s been a long time (+2 months), I took all this time because I wanted to do something different so I worked a lot on the visuals to make a little video about the battle system and some other things, you can check the video here:

I will be making more devlog videos from now on so… subscribe!

I also show a little about map exploration and etc.

Here are some gifs too:
This is a preview of the battle system:

This is the player being chased by a hostile wild creature:

Of course, a lot more was made since the last time I posted here, almost the entire battle UI was designed and implemented including the window for switching creatures:

The items window:

Also the creatures summary window:

Note: don’t forget that everything is wip, so, yea, those items icons/descriptions/names/etc, etc are just placeholders, temporary stuff.

I don’t know if I will keep this design forever, but for now, that’s it. Maybe I improve it later.

The battle system also had a lot of bugfixes and improvements (internal improvements), that’s also why I took so long, the creature following coach system had lots of improvements too, now they (if you have more than 1 creature) will follow you in line, they will be instantiated according to your creatures list (of course) and everything just works, you get in a battle, they will be there, they suffer damage, use items in them and when you get out of the battle they will be in the same state that they had in the battle and they will be instantiated behind you again and already in line.

The experience/level up and move points was not implemented yet, so that’s subject for my next devlog.

See you next time!

DevLog #8 A Little More Battle System

Hey guys, how’s everything going?

I got some little updates, been working a lot on the game but not on stuff that I can show right now, but I have something I can show.

The battle system, I made some little tweaks on the interface that I’m using for prototyping, not important but anyway, also now the player is able to switch creatures anytime in battle:

You can cancel an already set action in the current turn, in case you already choose to attack an enemy you can press cancel and then the highlighted creature stats box will change, which is also something new, the current creature you’re selecting action to is highlighted:

Lots of bugs were fixed – when working on a battle system from scratch a lot of bugs is just there and you can’t see unless you test a lot, not like coding more simpler gameplay like movement and etc. I also changed a lot of things internally.

As you can see I’m using a font very known by Pokémon fans, just to give some nostalgia vibe while I prototype it, and by the way, ANYTHING and EVERYTHING shown here are placeholders, interfaces, models, anything, so just don’t worry I will work on the real artwork eventually, prototyping phases are like this, cubes, capsules, and etc.

Next: Items using and accuracy check!

Until next time!

DevLog #7 Basic Interaction, Item Grabbing, Etc

Hello guys, after 2 weeks I have a couple of more things to add!

First, now the game is in the third person:
Shot taken 16-1-2016 at 13h34m32s

2. I added a very a basic interaction system:
Shot taken 16-1-2016 at 13h34m40s
Shot taken 16-1-2016 at 13h34m46sRight now you can only open things, talk to things (dialog box will appear with some text), talk to NPCs, toggle lights and so on. Soon I’ll code some kind of item containers so the player can get and store items to it.

3. Very basic item grabbing and inventory:
Shot taken 16-1-2016 at 16h1m33sShot taken 16-1-2016 at 16h4m27sShot taken 16-1-2016 at 16h1m38sThe item gets added to the inventory, destroyed from the scene and they also stack on the inventory.

Creating all the models to make this indoor level study took more time then coding the stuff above.

I hope you are having a very nice weekend, until next time!

DevLog #5 Battle System Prototyping

Hello again!

Ok, now I finally have something about the battle system! Oh, and don’t mind the graphics, they are all placeholders/temporary stuff/wip and etc.

Animation 0

Let’s pretend these blocks are tall grasses, okay?

So, basically it is working almost like the Pokémon games, turn based, everyone choose its actions first then these actions are all executed at once later, the one with the higher speed strikes first, etc, etc. But I will make thing a little bit different, there will be 6vs6 battles, it will work almost like Disciples and Heroes games, except that the characters will have their moves (but the moves will not have PPs, they will have their move points cost – or MPs – and this move points, which will be spent are associated with the character and not with the move, also there will be moves which spend no move points, I’ll get in to this in another post), the creatures on the back rows (the creatures will be place in a grid of 2×3 slots) will not be able to use physical moves on the creatures on the other side if there is creatures in the front row, only ranged moves, unless you want your creatures to attack themselves (or if you’re in battle with an ally and want to attack some ally creature) but still, this creatures needs to be adjacent to them. 6vs6 battles are already implemented but checking for physical and ranged moves and if they are adjacent or not is not implemented yet. There will be a limit of 3 teams (or players) per side, teams means that if it’s a 6vs6 battle, each side will be able to send 2 creatures to battle each, if someone doesn’t send enough creatures another member of the team can send. I worked on this having network battles and co-op in mind.

Shot taken 13-12-2015 at 22h7m41s

This is a 2vs2 battle against a NPC

The coaches (trainers in Pokémonish) are placed on their right spawn pointas the battle begins, the creatures are spawned according to its species index and placed on their right spawn point too. For now, the AI behavior is to select a random foe creature and a random move and attack, items cannot be used yet and other actions too. There is something that will be very handy for me — you can attack yourself — I will use this in my favor and make heal moves this way, if you want to attack your enemy you click on them or on their status box, but if you want to use a “Tail Whip” (let’s use this, since I didn’t create any move yet) you click on you own creatures, if you want to heal an ally creature you click on them while selecting an action for another creature.

Currently you can get in and out of battles, every info is kept with the player, experience is not being yield yet and if the player loses nothing happens, the game world loads and that’s all, you can get in another battle with your creature unable to fight. These cubes I told you to pretend it’s tall grass I’m calling creatures areas, they will also be used on seas, rivers, caves and etc (some creatures will be spawned on the game world so you can walk towards them to fight), they hold info about which creatures may appear on that trigger, how much steps (minimum and maximum steps) to encounter a creature (or creatures, since there will be wild creatures group fights, if that area is set to), based on this a creatures team is generated and the battle starts. I also made that small log box below in the battle system, for now it’s only a quick resume of what’s happening in the battle, soon I will make a much better and different too, it will be more like a narration and the box will appear below and sometimes on the top too.

I hope you have liked this post, stay tuned for more!