This commit is contained in:
2026-05-30 09:16:35 +07:00
parent 2f87ce19a7
commit 1c0ee6efb7
4001 changed files with 3363438 additions and 1738 deletions

View File

@@ -0,0 +1,77 @@
using Invector;
using Invector.vMelee;
using UnityEngine;
public class DualSwordExample : vMonoBehaviour
{
public vMeleeWeapon secundaryWeaponPrefab;
public string otherSideHandlerName;
[vReadOnly, SerializeField] protected vMeleeWeapon secundaryWeapon;
[vReadOnly, SerializeField] protected Transform otherSideTransform;
[vReadOnly, SerializeField] protected vMeleeManager manager;
private void Start()
{
OnEnable();
}
private void OnDestroy()
{
OnDisable();
if (secundaryWeapon) Destroy(secundaryWeapon.gameObject);
}
private void OnEnable()
{
if (!otherSideTransform)
{
Animator animator = GetComponentInParent<Animator>();
if (animator)
{
var _otherSideHand = animator.GetBoneTransform(HumanBodyBones.LeftHand);
var childrens = _otherSideHand.GetComponentsInChildren<Transform>();
for (int i = 0; i < childrens.Length; i++)
if (childrens[i].gameObject.name.Equals(otherSideHandlerName))
{
otherSideTransform = childrens[i]; break;
}
}
}
if (otherSideTransform)
{
ActiveSecundaryWeapon();
}
}
private void ActiveSecundaryWeapon()
{
if (secundaryWeapon)
{
secundaryWeapon.gameObject.SetActive(true);
}
else
{
secundaryWeapon = Instantiate(secundaryWeaponPrefab);
secundaryWeapon.transform.parent = otherSideTransform;
secundaryWeapon.transform.localPosition = Vector3.zero;
secundaryWeapon.transform.localEulerAngles = Vector3.zero;
}
if (!manager) manager = GetComponentInParent<vMeleeManager>();
if (manager)
{
manager.SetLeftWeapon(secundaryWeapon);
}
}
private void OnDisable()
{
if (secundaryWeapon)
{
secundaryWeapon.gameObject.SetActive(false);
manager.leftWeapon = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d775d620143e8b349bb13648c1a96e29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 179104b96df266e4bb6d05725f7adbfd
folderAsset: yes
timeCreated: 1470444425
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,120 @@
using UnityEngine;
using System.Collections;
using UnityEditor;
using System;
namespace Invector.vMelee
{
public class vCreateMeleeWeaponEditor : EditorWindow
{
GUISkin skin;
GameObject obj;
Vector2 rect = new Vector2(480, 210);
Vector2 scrool;
[MenuItem("Invector/Melee Combat/Create Melee Weapon")]
public static void CreateNewWeapon()
{
GetWindow<vCreateMeleeWeaponEditor>();
}
void OnGUI()
{
if (!skin) skin = Resources.Load("vSkin") as GUISkin;
GUI.skin = skin;
this.minSize = rect;
this.titleContent = new GUIContent("Melee Weapon", null, "Melee Weapon Creator Window");
GUILayout.BeginVertical("Melee Weapon Creator Window", "window");
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
GUILayout.BeginVertical("box");
EditorGUILayout.HelpBox("Make sure that your object doens't have any colliders or scripts, just the mesh", MessageType.Info);
obj = EditorGUILayout.ObjectField("FBX Model", obj, typeof(GameObject), true, GUILayout.ExpandWidth(true)) as GameObject;
if (obj != null && obj.GetComponent<vMeleeWeapon>() != null)
{
EditorGUILayout.HelpBox("This gameObject already contains the component vMeleeWeapon", MessageType.Warning);
}
GUILayout.EndVertical();
GUILayout.BeginHorizontal("box");
EditorGUILayout.LabelField("Need to know how it works?");
if (GUILayout.Button("Video Tutorial"))
{
Application.OpenURL("https://www.youtube.com/watch?v=1aA_PU9-G-0&index=3&list=PLvgXGzhT_qehtuCYl2oyL-LrWoT7fhg9d");
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (obj != null)
{
if (GUILayout.Button("Create"))
Create();
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
private GameObject InstantiateNewWeapon(GameObject selected)
{
if (selected == null) return selected;
if (selected.scene.IsValid()) return selected;
return PrefabUtility.InstantiatePrefab(selected) as GameObject;
}
/// <summary>
/// Created the Third Person Controller
/// </summary>
public virtual void Create()
{
// base for the character
GameObject newWeapon = InstantiateNewWeapon(obj);
if (!newWeapon)
return;
newWeapon.gameObject.name = obj.name;
var weaponObj = new GameObject(newWeapon.name);
weaponObj.transform.position = newWeapon.transform.position;
weaponObj.transform.rotation = newWeapon.transform.rotation;
weaponObj.gameObject.tag = "Weapon";
var components = new GameObject("Components");
components.transform.position = newWeapon.transform.position;
components.transform.rotation = newWeapon.transform.rotation;
components.gameObject.tag = "Weapon";
var hitBox = new GameObject("hitBox", typeof(BoxCollider), typeof(vHitBox));
hitBox.transform.position = newWeapon.transform.position;
hitBox.transform.rotation = newWeapon.transform.rotation;
hitBox.gameObject.tag = "Weapon";
var layer = LayerMask.NameToLayer("Ignore Raycast");
hitBox.gameObject.layer = layer;
components.transform.SetParent(weaponObj.transform);
hitBox.transform.SetParent(components.transform);
var weapon = weaponObj.AddComponent<vMeleeWeapon>();
weapon.hitBoxes = new System.Collections.Generic.List<vHitBox>();
weapon.hitBoxes.Add(hitBox.GetComponent<vHitBox>());
newWeapon.transform.SetParent(components.transform);
newWeapon.transform.localPosition = Vector3.zero;
newWeapon.transform.localEulerAngles = Vector3.zero;
newWeapon.gameObject.tag = "Weapon";
this.Close();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e791ec4782e265840a301c30985e4b36
timeCreated: 1467828935
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections;
using UnityEditor;
using UnityEngine;
namespace Invector.vMelee
{
[CustomPropertyDrawer(typeof(vDamage))]
public class vDamageDrawer : PropertyDrawer
{
public bool isOpen;
public bool valid;
GUISkin skin;
float helpBoxHeight;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var oldSkin = GUI.skin;
if (!skin) skin = Resources.Load("vSkin") as GUISkin;
if (skin) GUI.skin = skin;
position = EditorGUI.IndentedRect(position);
GUI.Box(position, "");
position.width -= 10;
position.height = 15;
position.y += 5f;
position.x += 5;
isOpen = GUI.Toggle(position, isOpen, "Damage Options", EditorStyles.miniButton);
if (isOpen)
{
var attackName = property.FindPropertyRelative("damageType");
var value = property.FindPropertyRelative("damageValue");
var staminaBlockCost = property.FindPropertyRelative("staminaBlockCost");
var staminaRecoveryDelay = property.FindPropertyRelative("staminaRecoveryDelay");
var ignoreDefense = property.FindPropertyRelative("ignoreDefense");
var activeRagdoll = property.FindPropertyRelative("activeRagdoll");
var hitreactionID = property.FindPropertyRelative("reaction_id");
var hitrecoilID = property.FindPropertyRelative("recoil_id");
var senselessTime = property.FindPropertyRelative("senselessTime");
var obj = (property.serializedObject.targetObject as MonoBehaviour);
valid = true;
if (obj != null)
{
var parent = obj.transform.parent;
if (parent != null)
{
var manager = parent.GetComponentInParent<vMeleeManager>();
valid = !(obj.GetType() == typeof(vMeleeWeapon) || obj.GetType().IsSubclassOf(typeof(vMeleeWeapon))) || manager == null;
}
}
if (!valid)
{
position.y += 20;
var style = new GUIStyle(EditorStyles.helpBox);
var content = new GUIContent("Damage type and other options can be overridden by the Animator Attack State\nIf the weapon is used by a character with an ItemManager, the damage value can be overridden by the item attribute");
helpBoxHeight = style.CalcHeight(content, position.width);
position.height = helpBoxHeight;
GUI.Box(position, content.text, style);
position.y += helpBoxHeight - 20;
}
position.height = EditorGUIUtility.singleLineHeight;
if (attackName != null)
{
position.y += 20;
EditorGUI.PropertyField(position, attackName);
}
if (value != null)
{
position.y += 20;
EditorGUI.PropertyField(position, value);
}
if (staminaBlockCost != null)
{
position.y += 20;
EditorGUI.PropertyField(position, staminaBlockCost);
}
if (staminaRecoveryDelay != null)
{
position.y += 20;
EditorGUI.PropertyField(position, staminaRecoveryDelay);
}
if (ignoreDefense != null && valid)
{
position.y += 20;
EditorGUI.PropertyField(position, ignoreDefense);
}
if (activeRagdoll != null && valid)
{
position.y += 20;
EditorGUI.PropertyField(position, activeRagdoll);
position.y += 20;
EditorGUI.PropertyField(position, senselessTime);
}
if (hitreactionID != null && valid)
{
position.y += 20;
EditorGUI.PropertyField(position, hitreactionID);
}
if (hitrecoilID != null && valid)
{
position.y += 20;
EditorGUI.PropertyField(position, hitrecoilID);
}
}
GUI.skin = oldSkin;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return !isOpen ? 25 : (valid ? 210 : 130 + helpBoxHeight);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 92e130449b49ea045beeef72f43fea62
timeCreated: 1475778971
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Invector
{
[CustomPropertyDrawer(typeof(vEnumFlagAttribute))]
public class vEnumFlagDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
vEnumFlagAttribute flagSettings = (vEnumFlagAttribute)attribute;
string propName = flagSettings.enumName;
if (string.IsNullOrEmpty(propName))
propName = property.displayName;
if (property.propertyType == SerializedPropertyType.Enum)
{
EditorGUI.BeginProperty(position, label, property);
property.intValue = EditorGUI.MaskField(position, propName, property.intValue, Enum.GetNames(fieldInfo.FieldType));
EditorGUI.EndProperty();
}
else EditorGUI.PropertyField(position, property,property.hasChildren);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ac553591bf57eaf409b797cee1d1e145
timeCreated: 1470411358
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,226 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Invector.vMelee
{
[CustomEditor(typeof(vMeleeAttackControl))]
public class vMeleeAttackControlEditor : UnityEditor.Editor
{
vMeleeAttackControl attackControl;
string currentBodyPart;
string oldBodyPart;
bool inAddBodyPart;
bool inEditBodyPart;
bool isHuman;
vAttackType currentAttackType;
GUISkin skin;
GUISkin defaultSkin;
int indexSelected;
public Texture2D m_Logo;
enum WeponSide
{
LeftLowerArm, RightLowerArm
}
void OnEnable()
{
try
{
attackControl = (vMeleeAttackControl)target;
currentAttackType = attackControl.meleeAttackType;
skin = Resources.Load("vSkin") as GUISkin;
}
catch { }
indexSelected = -1;
isHuman = true;
m_Logo = (Texture2D)Resources.Load("icon_v2", typeof(Texture2D));
}
public override void OnInspectorGUI()
{
defaultSkin = GUI.skin;
if (skin) GUI.skin = skin;
GUILayout.BeginVertical("Melee Attack Control", "window");
GUILayout.Label(m_Logo, GUILayout.MaxHeight(25));
EditorGUILayout.HelpBox("Make sure that the <b>Exit Time</b> of this state to the next one in your Combo is <b>lower</b> then the Exit Time to the Exit state, otherwise it will always exit first and never play the next animation.\n\n" +
"For Example if your Exit Time to the Exit State is 0.7 then your transition to the next state must be 0.6 or lower.\n\n" +
"The same applies to the <b>End Damage</b>", MessageType.Info);
base.OnInspectorGUI();
GUILayout.BeginVertical();
GUILayout.BeginVertical("box");
GUILayout.BeginHorizontal();
GUILayout.Box("nº", GUILayout.Width(40));
GUILayout.Box("BodyPart", GUILayout.ExpandWidth(true));
GUILayout.Box("", GUILayout.Width(20));
GUILayout.EndHorizontal();
for (int i = 0; i < attackControl.bodyParts.Count; i++)
{
GUILayout.BeginHorizontal();
GUIStyle labelCenter = EditorStyles.miniLabel;
labelCenter.alignment = TextAnchor.MiddleCenter;
GUILayout.Box(i.ToString("00"), labelCenter, GUILayout.Width(40));
Color color = GUI.color;
GUI.color = indexSelected == i ? new Color(1, 1, 0, 1) : color;
if (GUILayout.Button(attackControl.bodyParts[i], EditorStyles.miniButton))
{
if (indexSelected == i)
{
inEditBodyPart = false;
indexSelected = -1;
oldBodyPart = "";
}
else
{
indexSelected = i;
inEditBodyPart = true;
oldBodyPart = attackControl.bodyParts[indexSelected];
try
{
oldBodyPart = Enum.Parse(typeof(vHumanBones), oldBodyPart).ToString();
isHuman = true;
}
catch { isHuman = false; }
}
}
GUI.color = color;
if (attackControl.bodyParts.Count > 1 && !inEditBodyPart && GUILayout.Button("X", EditorStyles.miniButton, GUILayout.Width(20)))
{
attackControl.bodyParts.RemoveAt(i);
GUILayout.EndHorizontal();
break;
}
else if (attackControl.bodyParts.Count == 1 || inEditBodyPart)
{
GUILayout.Label("", GUILayout.Width(20));
}
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
GUILayout.EndVertical();
if (inEditBodyPart)
{
EditBodyPart();
}
GUILayout.Space(20);
if (GUILayout.Button("Add New Body Part", EditorStyles.miniButton))
{
inAddBodyPart = true;
isHuman = true;
currentBodyPart = "RightLowerArm";
}
if (currentAttackType != attackControl.meleeAttackType)
{
currentAttackType = attackControl.meleeAttackType;
if (currentAttackType == vAttackType.MeleeWeapon)
{
var noMeleeWeapon = attackControl.bodyParts.FindAll(bodyPart => bodyPart != "LeftLowerArm" || bodyPart != "RightLowerArm");
if (noMeleeWeapon.Count > 0)
{
attackControl.bodyParts.RemoveAll(bodyPart => !(bodyPart == "LeftLowerArm" || bodyPart == "RightLowerArm"));
}
}
}
if (inAddBodyPart) AddBodyPart();
GUILayout.EndVertical();
GUI.skin = defaultSkin;
}
void AddBodyPart()
{
GUILayout.BeginVertical("box");
if (attackControl.meleeAttackType == vAttackType.Unarmed)
{
isHuman = Convert.ToBoolean(EditorGUILayout.Popup("Member Type", Convert.ToInt32(isHuman), new string[] { "Generic", "Human" }));
if (isHuman)
{
try
{
currentBodyPart = EditorGUILayout.EnumPopup("Body Part", (vHumanBones)Enum.Parse(typeof(vHumanBones), currentBodyPart)).ToString();
}
catch { currentBodyPart = "RightLowerArm"; }
}
else
{
currentBodyPart = EditorGUILayout.TextField("BodyPart Name", currentBodyPart);
}
}
else
{
currentBodyPart = EditorGUILayout.EnumPopup("Body Part", (WeponSide)Enum.Parse(typeof(WeponSide), currentBodyPart)).ToString();
}
bool isValid = true;
if (attackControl.bodyParts.Contains(currentBodyPart))
{
EditorGUILayout.HelpBox("This Body Part already exist,select another name", MessageType.Error);
isValid = false;
}
GUILayout.BeginHorizontal();
if (isValid && GUILayout.Button("Add", EditorStyles.miniButton))
{
attackControl.bodyParts.Add(currentBodyPart);
inAddBodyPart = false;
}
if (GUILayout.Button("Cancel", EditorStyles.miniButton))
{
inAddBodyPart = false;
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
void EditBodyPart()
{
GUILayout.BeginVertical("box");
GUILayout.Box("Editing BodyParty " + indexSelected.ToString("00"), GUILayout.ExpandWidth(true));
if (attackControl.meleeAttackType == vAttackType.Unarmed)
{
isHuman = Convert.ToBoolean(EditorGUILayout.Popup("Member Type", Convert.ToInt32(isHuman), new string[] { "Generic", "Human" }));
if (isHuman)
{
try
{
oldBodyPart = EditorGUILayout.EnumPopup("Body Part", (vHumanBones)Enum.Parse(typeof(vHumanBones), oldBodyPart)).ToString();
}
catch { oldBodyPart = currentBodyPart = "RightLowerArm"; }
}
else
{
oldBodyPart = EditorGUILayout.TextField("BodyPart Name", oldBodyPart);
}
}
else
{
oldBodyPart = EditorGUILayout.EnumPopup("Body Part", (WeponSide)Enum.Parse(typeof(WeponSide), oldBodyPart)).ToString();
}
bool isValid = true;
if (attackControl.bodyParts.Contains(oldBodyPart) && oldBodyPart != attackControl.bodyParts[indexSelected])
{
EditorGUILayout.HelpBox("This Body Part already exist,select another name", MessageType.Error);
isValid = false;
}
GUILayout.BeginHorizontal();
if (isValid && GUILayout.Button("Ok", EditorStyles.miniButton))
{
attackControl.bodyParts[indexSelected] = oldBodyPart;
inEditBodyPart = false;
indexSelected = -1;
}
if (GUILayout.Button("Cancel", EditorStyles.miniButton))
{
indexSelected = -1;
inEditBodyPart = false;
oldBodyPart = "";
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4f3c392a89026a3409419ffb5d7baa2d
timeCreated: 1470947572
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,641 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Invector.vMelee
{
[CanEditMultipleObjects]
[CustomEditor(typeof(vMeleeManager), true)]
public class vMeleeManagerEditor : vEditorBase
{
#region variables
protected vMeleeManager manager;
protected Animator animator;
protected int selectedID;
protected int seletedHitboxIndex;
protected int toolBarBodyMembers;
protected int damagePercentage;
protected bool selLeftArm, selRightArm, selLeftLeg, selRightLeg, selHead, selTorso;
protected bool showEvents;
protected bool showDefaultInfo;
protected bool inAddBodyMember;
protected bool isHuman;
protected bool inCreateHitBox;
protected bool inChangeHitBoxCollider;
protected Transform leftLowerArm, rightLowerArm, leftLowerLeg, rightLowerLeg;
protected vBodyMember currentBodyMember;
protected vBodyMember extraBodyMember;
protected Component hitCollider;
protected vHitBoxType triggerType;
protected string seletedBone;
protected virtual string[] ignoreProperties => new string[] { "m_Script", "Members", "defaultDamage", "hitProperties", "leftWeapon", "rightWeapon", "onDamageHit", "onRecoilHit", "openCloseWindow", "openCloseEvents", "selectedToolbar", "onEquipWeapon" };
#endregion
protected virtual void OnSceneGUI()
{
var renderers = manager.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (SkinnedMeshRenderer renderer in renderers)
{
EditorUtility.SetSelectedRenderState(renderer, EditorSelectedRenderState.Hidden);
}
DrawRecoilRange();
}
protected override void OnEnable()
{
manager = (vMeleeManager)target;
base.OnEnable();
m_Logo = Resources.Load("meleeIcon") as Texture2D;
if (!manager.gameObject.scene.IsValid())
{
return;
}
CreateDefaultBodyMembers();
CheckMembersName(manager.Members);
}
protected virtual void CreateDefaultBodyMembers()
{
animator = manager.GetComponent<Animator>();
if (animator && animator.isHuman)
{
leftLowerArm = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
CheckSingleHitBox(leftLowerArm, vHumanBones.LeftLowerArm);
rightLowerArm = animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
CheckSingleHitBox(rightLowerArm, vHumanBones.RightLowerArm);
leftLowerLeg = animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg);
CheckSingleHitBox(leftLowerLeg, vHumanBones.LeftLowerLeg);
rightLowerLeg = animator.GetBoneTransform(HumanBodyBones.RightLowerLeg);
CheckSingleHitBox(rightLowerLeg, vHumanBones.RightLowerLeg);
}
}
protected virtual void CheckMembersName(List<vBodyMember> Members)
{
foreach (var member in Members)
{
if (member.attackObject)
{
member.attackObject.attackObjectName = member.bodyPart;
}
}
}
protected virtual void CheckSingleHitBox(Transform transform, vHumanBones bodyPart, bool debug = false)
{
if (transform)
{
vMeleeAttackObject attackObject = transform.GetComponent<vMeleeAttackObject>();
if (attackObject == null)
{
attackObject = transform.gameObject.AddComponent<vMeleeAttackObject>();
}
var _hitBoxes = transform.GetComponentsInChildren<vHitBox>();
var validHitBoxes = _hitBoxes.vToList().FindAll(hitBox => hitBox.transform.parent == attackObject.transform);
attackObject.hitBoxes = validHitBoxes;
if (manager && manager.Members != null)
{
var bodyMembers = manager.Members.FindAll(member => member.bodyPart == bodyPart.ToString());
if (bodyMembers.Count > 0)
{
bodyMembers[0].isHuman = true;
bodyMembers[0].attackObject = attackObject;
bodyMembers[0].bodyPart = bodyPart.ToString();
bodyMembers[0].transform = transform;
if (bodyMembers.Count > 1)
{
for (int i = 1; i < bodyMembers.Count; i++)
{
manager.Members.Remove(bodyMembers[i]);
}
}
CheckHitBoxes(bodyMembers[0], true);
EditorUtility.SetDirty(manager);
}
else
{
vBodyMember bodyMember = new vBodyMember();
bodyMember.isHuman = true;
bodyMember.attackObject = attackObject;
bodyMember.bodyPart = bodyPart.ToString();
bodyMember.transform = transform;
manager.Members.Add(bodyMember);
CheckHitBoxes(bodyMember, true);
EditorUtility.SetDirty(manager);
}
}
}
serializedObject.ApplyModifiedProperties();
}
public override void OnInspectorGUI()
{
var oldSkin = GUI.skin;
GUI.skin = skin;
var script = serializedObject.FindProperty("m_Script");
GUILayout.BeginVertical("MELEE MANAGER", "window");
GUILayout.Label(m_Logo, GUILayout.MaxHeight(25));
openCloseWindow = GUILayout.Toggle(openCloseWindow, openCloseWindow ? "Close" : "Open", EditorStyles.toolbarButton);
if (openCloseWindow)
{
if (script != null)
{
EditorGUILayout.PropertyField(script);
}
GUI.enabled = !AssetDatabase.Contains(manager.gameObject);
if (manager.Members == null || manager.Members.Count == 0)
{
if (GUILayout.Button("Create Default Body Members", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
CreateDefaultBodyMembers();
}
}
GUILayout.BeginVertical("box");
OpenCloseDefaultInfo();
OpenCloseEvents(oldSkin);
AddExtraBodyPart();
//GUI.enabled = true;
GUILayout.EndVertical();
var seletedBodyMember = manager.Members.Find(member => member.bodyPart == seletedBone);
GUILayout.BeginVertical(seletedBodyMember != null ? "highlightBox" : "box");
DrawBodyMemberToogles();
if (seletedBodyMember != null)
{
bool canRemove = seletedBodyMember.bodyPart != vHumanBones.LeftLowerArm.ToString() && seletedBodyMember.bodyPart != vHumanBones.RightLowerArm.ToString() &&
seletedBodyMember.bodyPart != vHumanBones.LeftLowerLeg.ToString() && seletedBodyMember.bodyPart != vHumanBones.RightLowerLeg.ToString();
DrawBodyMember(ref seletedBodyMember, seletedBodyMember.bodyPart.ToString(), canRemove);
}
GUILayout.EndVertical();
GUILayout.BeginVertical("box");
GUILayout.Label("Who you can Hit?", GUILayout.ExpandWidth(true));
EditorGUILayout.PropertyField(serializedObject.FindProperty("hitProperties"), true);
GUILayout.EndVertical();
GUILayout.BeginVertical("box");
GUILayout.Label("Weapons");
GUILayout.BeginHorizontal();
GUILayout.BeginVertical("box");
GUILayout.Label("LeftWeapon", EditorStyles.miniLabel);
manager.leftWeapon = EditorGUILayout.ObjectField(manager.leftWeapon, typeof(vMeleeWeapon), true) as vMeleeWeapon;
GUILayout.EndVertical();
GUILayout.BeginVertical("box");
GUILayout.Label("RightWeapon", EditorStyles.miniLabel);
manager.rightWeapon = EditorGUILayout.ObjectField(manager.rightWeapon, typeof(vMeleeWeapon), true) as vMeleeWeapon;
GUILayout.EndVertical();
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
GUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
if (GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
protected virtual void OpenCloseEvents(GUISkin oldSkin)
{
var onDamageHit = serializedObject.FindProperty("onDamageHit");
var onRecoilHit = serializedObject.FindProperty("onRecoilHit");
var onEquipWeapon = serializedObject.FindProperty("onEquipWeapon");
GUILayout.BeginVertical(showEvents ? "highlightBox" : "box");
showEvents = GUILayout.Toggle(showEvents, showEvents ? "Close Events" : "Open Events", EditorStyles.miniButton);
GUI.skin = oldSkin;
if (showEvents)
{
if (onDamageHit != null)
{
EditorGUILayout.PropertyField(onDamageHit);
}
if (onRecoilHit != null)
{
EditorGUILayout.PropertyField(onRecoilHit);
}
if (onEquipWeapon != null)
{
EditorGUILayout.PropertyField(onEquipWeapon);
}
}
GUI.skin = skin;
GUILayout.EndVertical();
}
protected virtual void OpenCloseDefaultInfo()
{
GUILayout.BeginVertical(showDefaultInfo ? "highlightBox" : "box");
showDefaultInfo = GUILayout.Toggle(showDefaultInfo, showDefaultInfo ? "Close Default Info" : "Open Default Info", EditorStyles.miniButton);
var oldSkin = GUI.skin;
GUI.skin = oldSkin;
if (showDefaultInfo)
{
manager.defaultDamage.damageValue = EditorGUILayout.FloatField("DefaultDamage", manager.defaultDamage.damageValue);
DrawPropertiesExcluding(serializedObject, ignoreProperties);
}
GUI.skin = skin;
GUILayout.EndVertical();
}
protected virtual void AddExtraBodyPart()
{
GUILayout.BeginVertical(inAddBodyMember ? "highlightBox" : "box");
if (!inAddBodyMember && GUILayout.Button("Add Extra Body Member", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
extraBodyMember = new vBodyMember();
inAddBodyMember = true;
isHuman = true;
}
if (inAddBodyMember)
{
DrawAddExtraBodyMember();
}
GUILayout.EndVertical();
}
protected virtual void DrawRecoilRange()
{
var coll = manager.gameObject.GetComponent<Collider>();
if (coll != null && manager != null && manager.hitProperties != null && manager.hitProperties.useRecoil && manager.hitProperties.drawRecoilGizmos)
{
Handles.DrawWireDisc(coll.bounds.center, Vector3.up, 0.5f);
Handles.color = new Color(1, 0, 0, 0.2f);
Handles.DrawSolidArc(coll.bounds.center, Vector3.up, manager.transform.forward, manager.hitProperties.recoilRange, 0.5f);
Handles.DrawSolidArc(coll.bounds.center, Vector3.up, manager.transform.forward, (float)-manager.hitProperties.recoilRange, 0.5f);
}
}
protected virtual void DrawBodyMemberToogles()
{
var bmleftLowerArm = manager.Members.Find(member => member.bodyPart == vHumanBones.LeftLowerArm.ToString());
var bmrightLowerArm = manager.Members.Find(member => member.bodyPart == vHumanBones.RightLowerArm.ToString());
var bmleftLowerLeg = manager.Members.Find(member => member.bodyPart == vHumanBones.LeftLowerLeg.ToString());
var bmrightLowerLeg = manager.Members.Find(member => member.bodyPart == vHumanBones.RightLowerLeg.ToString());
GUILayout.BeginVertical();
GUILayout.Label("Body Members", GUILayout.ExpandWidth(true));
GUILayout.EndVertical();
// GUILayout.Box("Default Human Body Members", GUILayout.ExpandWidth(true));
GUILayout.BeginHorizontal();
if (bmleftLowerArm != null)
{
BodyMemberToogle(bmleftLowerArm.bodyPart, ref bmleftLowerArm, "LeftLowerArm");
}
if (bmrightLowerArm != null)
{
BodyMemberToogle(bmrightLowerArm.bodyPart, ref bmrightLowerArm, "RightLowerArm");
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
if (bmleftLowerLeg != null)
{
BodyMemberToogle(bmleftLowerLeg.bodyPart, ref bmleftLowerLeg, "LeftLowerLeg");
}
if (bmrightLowerLeg != null)
{
BodyMemberToogle(bmrightLowerLeg.bodyPart, ref bmrightLowerLeg, "RightLowerLeg");
}
GUILayout.EndHorizontal();
//GUILayout.Box("Extra Human BodyMembers", GUILayout.ExpandWidth(true));
for (int i = 0; i < manager.Members.Count; i++)
{
if (manager.Members[i] != bmleftLowerArm && manager.Members[i] != bmrightLowerArm &&
manager.Members[i] != bmleftLowerLeg && manager.Members[i] != bmrightLowerLeg)
{
var bodyMember = manager.Members[i];
BodyMemberToogle(bodyMember.bodyPart, ref bodyMember, bodyMember.bodyPart.ToString());
CheckHitBoxes(manager.Members[i]);
}
else
{
CheckHitBoxes(manager.Members[i], true);
}
}
}
protected virtual void CheckHitBoxes(vBodyMember bodyMember, bool isDefault = false)
{
if (AssetDatabase.Contains(manager.gameObject))
{
return;
}
var hitBoxes = bodyMember.transform.GetComponentsInChildren<vHitBox>();
var _result = hitBoxes.vToList().FindAll(hitBox => hitBox.transform.parent == bodyMember.transform);
if (_result.Count > 0)
{
if (bodyMember.attackObject) bodyMember.attackObject.hitBoxes = _result;
}
else
{
var hitBox = new GameObject("hitBox", typeof(vHitBox), typeof(BoxCollider));
var scale = Vector3.one * 0.15f;
if (isDefault)
{
var lookDir = bodyMember.transform.GetChild(0).position - bodyMember.transform.position;
var rotation = Quaternion.LookRotation(lookDir);
scale.z = Vector3.Distance(bodyMember.transform.position, bodyMember.transform.GetChild(0).position);
var point = bodyMember.transform.position + (lookDir.normalized) * (scale.z * 0.7f);
hitBox.transform.position = point;
hitBox.transform.rotation = rotation;
hitBox.transform.localScale = scale;
hitBox.transform.parent = bodyMember.transform;
}
else
{
hitBox.transform.localScale = scale;
hitBox.transform.parent = bodyMember.transform;
hitBox.transform.localPosition = Vector3.zero;
hitBox.transform.localEulerAngles = Vector3.zero;
}
}
}
protected virtual void DrawAddExtraBodyMember()
{
if (extraBodyMember != null)
{
isHuman = Convert.ToBoolean(EditorGUILayout.Popup("Member Type", Convert.ToInt32(isHuman), new string[] { "Generic", "Human" }));
extraBodyMember.isHuman = isHuman;
if (isHuman)
{
vHumanBones humanBone = 0;
try
{
humanBone = (vHumanBones)Enum.Parse(typeof(vHumanBones), extraBodyMember.bodyPart);
}
catch { }
humanBone = (vHumanBones)EditorGUILayout.EnumPopup("Body Part", humanBone);
extraBodyMember.bodyPart = humanBone.ToString();
var humanBodyBone = (HumanBodyBones)Enum.Parse(typeof(HumanBodyBones), extraBodyMember.bodyPart);
extraBodyMember.transform = manager.GetComponent<Animator>().GetBoneTransform(humanBodyBone);
}
else
{
extraBodyMember.bodyPart = EditorGUILayout.TextField("BodyPart Name", extraBodyMember.bodyPart);
}
extraBodyMember.transform = EditorGUILayout.ObjectField("Body Member", extraBodyMember.transform, typeof(Transform), true) as Transform;
var valid = true;
if (extraBodyMember.transform != null && manager.Members.Find(member => member.transform == extraBodyMember.transform) != null)
{
EditorGUILayout.HelpBox("This Body Member already exists, select another", MessageType.Error);
valid = false;
}
if (manager.Members.Find(member => member.bodyPart == extraBodyMember.bodyPart) != null)
{
EditorGUILayout.HelpBox("This Body Part already exists, select another", MessageType.Error);
valid = false;
}
GUILayout.BeginHorizontal();
if (valid)
{
if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
vBodyMember member = new vBodyMember();
member.attackObject = extraBodyMember.transform.gameObject.AddComponent<vMeleeAttackObject>();
member.transform = extraBodyMember.transform;
member.bodyPart = extraBodyMember.bodyPart;
var type = typeof(BoxCollider);
var hitObject = new GameObject("hitBox", typeof(vHitBox), type);
hitObject.transform.localScale = Vector3.one * 0.2f;
hitObject.transform.parent = member.transform;
hitObject.transform.localPosition = Vector3.zero;
hitObject.transform.localEulerAngles = Vector3.zero;
var hitBox = hitObject.GetComponent<vHitBox>();
hitBox.damagePercentage = 100;
hitBox.triggerType = vHitBoxType.Damage | vHitBoxType.Recoil;
member.attackObject.hitBoxes = new List<vHitBox>();
member.attackObject.hitBoxes.Add(hitBox);
inCreateHitBox = false;
manager.Members.Add(member);
extraBodyMember = null;
inAddBodyMember = false;
}
}
if (GUILayout.Button("Cancel", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
extraBodyMember = null;
inAddBodyMember = false;
}
GUILayout.EndHorizontal();
}
}
protected virtual void DrawBodyMember(ref vBodyMember bodyMember, string name, bool canRemove = false)
{
GUILayout.BeginVertical();
GUILayout.BeginHorizontal();
//GUILayout.Box("Selected " + name, GUILayout.ExpandWidth(true));
if (canRemove && GUILayout.Button("X"))
{
var hitColliders = bodyMember.attackObject.hitBoxes;
for (int i = 0; i < hitColliders.Count; i++)
{
DestroyImmediate(hitColliders[i].gameObject);
}
DestroyImmediate(bodyMember.attackObject);
manager.Members.Remove(bodyMember);
}
GUILayout.EndHorizontal();
bodyMember.attackObject = EditorGUILayout.ObjectField("Attack Object", bodyMember.attackObject, typeof(vMeleeAttackObject), true) as vMeleeAttackObject;
if (bodyMember.attackObject) bodyMember.attackObject.damageModifier = EditorGUILayout.IntField(new GUIContent("Damage Modifier +", "Use This to Change the Default damage"), bodyMember.attackObject.damageModifier);
GUILayout.Box("Hit Boxes", GUILayout.ExpandWidth(true));
DrawHitBoxesList(bodyMember.attackObject);
GUILayout.EndVertical();
}
protected virtual void DrawHitBoxesList(vMeleeAttackObject attackObject)
{
if (attackObject != null && attackObject.hitBoxes != null)
{
for (int i = 0; i < attackObject.hitBoxes.Count; i++)
{
try
{
GUILayout.BeginHorizontal();
if (attackObject.hitBoxes[i] != null && attackObject.hitBoxes[i].transform == attackObject.transform ||
(attackObject.GetComponent<vHitBox>() != null))
{
DestroyImmediate(attackObject.GetComponent<vHitBox>());
attackObject.hitBoxes.RemoveAt(i);
GUILayout.EndHorizontal();
break;
}
Color color = GUI.color;
GUI.color = seletedHitboxIndex == i ? new Color(1, 1, 0, 0.6f) : color;
if (GUILayout.Button("Hit Box " + (i + 1), EditorStyles.miniButton))
{
if (seletedHitboxIndex == i)
{
seletedHitboxIndex = -1;
}
else
{
seletedHitboxIndex = i;
}
}
GUI.color = color;
if (attackObject.hitBoxes.Count > 1 && GUILayout.Button("X", EditorStyles.miniButton, GUILayout.Width(20)))
{
if (attackObject.hitBoxes[i] != null && attackObject.hitBoxes[i].transform != attackObject.transform)
{
DestroyImmediate(attackObject.hitBoxes[i].gameObject);
}
attackObject.hitBoxes.RemoveAt(i);
GUILayout.EndHorizontal();
break;
}
GUILayout.EndHorizontal();
}
catch { }
}
}
if (seletedHitboxIndex > -1 && seletedHitboxIndex < attackObject.hitBoxes.Count)
{
GUILayout.BeginVertical("box");
var hitBox = attackObject.hitBoxes[seletedHitboxIndex];
if (hitBox)
{
EditorGUILayout.ObjectField("Selected Hit Box " + (seletedHitboxIndex + 1), hitBox, typeof(vHitBox), true);
//GUILayout.Box("Hit Settings", GUILayout.ExpandWidth(true));
hitBox.damagePercentage = EditorGUILayout.IntSlider("Damage Percentage", hitBox.damagePercentage, 0, 100);
#if UNITY_2017_3_OR_NEWER
hitBox.triggerType = (vHitBoxType)EditorGUILayout.EnumFlagsField("Trigger Type", hitBox.triggerType);
#else
hitBox.triggerType = (vHitBoxType)EditorGUILayout.EnumMaskField("Trigger Type", hitBox.triggerType);
#endif
if (GUI.changed)
{
EditorUtility.SetDirty(hitBox);
}
}
GUILayout.EndVertical();
}
GUILayout.Space(10);
if (!inCreateHitBox && GUILayout.Button("Create New Hit Box", EditorStyles.miniButton))
{
inCreateHitBox = true;
damagePercentage = 100;
triggerType = vHitBoxType.Damage | vHitBoxType.Recoil;
}
if (inCreateHitBox)
{
GUILayout.Box("New Hit Box", GUILayout.ExpandWidth(true));
damagePercentage = EditorGUILayout.IntSlider("Damage Percentage", damagePercentage, 0, 100);
#if UNITY_2017_3_OR_NEWER
triggerType = (vHitBoxType)EditorGUILayout.EnumFlagsField("Trigger Type", triggerType);
#else
triggerType = (vHitBoxType)EditorGUILayout.EnumMaskField("Trigger Type", triggerType);
#endif
GUILayout.BeginHorizontal();
if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
var type = typeof(BoxCollider);
var hitObject = new GameObject("hitBox", typeof(vHitBox), type);
hitObject.transform.localScale = Vector3.one * 0.2f;
hitObject.transform.parent = attackObject.transform;
hitObject.transform.localPosition = Vector3.zero;
hitObject.transform.localEulerAngles = Vector3.zero;
var hitBox = hitObject.GetComponent<vHitBox>();
hitBox.damagePercentage = damagePercentage;
hitBox.triggerType = triggerType;
attackObject.hitBoxes.Add(hitBox);
inCreateHitBox = false;
}
if (GUILayout.Button("Cancel", EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
inCreateHitBox = false;
}
GUILayout.EndHorizontal();
}
GUILayout.Space(10);
}
protected virtual void BodyMemberToogle(string bodyPart, ref vBodyMember bodyMember, string name)
{
if (bodyMember != null)
{
Color color = GUI.color;
GUI.color = seletedBone == bodyPart ? new Color(1, 1, 0, 0.6f) : color;
if (GUILayout.Button(name, EditorStyles.miniButton, GUILayout.ExpandWidth(true)))
{
if (seletedBone == bodyPart)
{
seletedBone = "null";
}
else
{
seletedBone = bodyPart;
}
seletedHitboxIndex = -1;
Repaint();
}
GUI.color = color;
if (bodyMember.attackObject)
{
foreach (vHitBox hitBox in bodyMember.attackObject.hitBoxes)
{
if (hitBox != null)
{
hitBox.gameObject.tag = "Ignore Ragdoll";
hitBox.gameObject.layer = LayerMask.NameToLayer("Ignore Raycast");
}
}
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c8ba06614993aa3418fcd2e6bc09bd15
timeCreated: 1470764862
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,259 @@
using UnityEngine;
namespace Invector.vMelee
{
using vCharacterController;
using vCharacterController.vActions;
[vClassHeader("Collect Melee Control", "This component is used when you're character doesn't have a ItemManager to manage items, this will allow you to pickup 1 weapon at the time.")]
public class vCollectMeleeControl : vMonoBehaviour
{
[HideInInspector]
public vMeleeManager meleeManager;
[Header("Handlers")]
public vHandler rightHandler = new vHandler();
public vHandler leftHandler = new vHandler();
[Header("Unequip Inputs")]
public GenericInput unequipRightInput;
public GenericInput unequipLeftInput;
[HideInInspector]
public vCollectableStandalone leftWeapon, rightWeapon;
public vControlDisplayWeaponStandalone controlDisplayPrefab;
protected vControlDisplayWeaponStandalone currentDisplay;
[vEditorToolbar("Melee Events")]
public UnityEngine.Events.UnityEvent onEquipMeleeWeapon, onUnequipMeleeWeapon, onEquipRightWeapon, onEquipLeftWeapon, onUnEquipRightWeapon, onUnEquipLeftWeapon;
internal bool wasUsingMeleeWeapon;
protected virtual void Start()
{
meleeManager = GetComponent<vMeleeManager>();
if (controlDisplayPrefab)
{
currentDisplay = Instantiate(controlDisplayPrefab);
}
}
protected virtual void Update()
{
UnequipWeaponHandle();
CheckIsEquipedWifhWeapon();
}
public virtual void HandleCollectableInput(vCollectableStandalone collectableStandAlone)
{
if (!meleeManager)
{
return;
}
if (collectableStandAlone != null && collectableStandAlone.weapon != null)
{
EquipMeleeWeapon(collectableStandAlone);
}
}
protected virtual void EquipMeleeWeapon(vCollectableStandalone collectable)
{
var weapon = collectable.weapon.GetComponent<vMeleeWeapon>();
if (!weapon)
{
return;
}
if (weapon.meleeType != vMeleeType.OnlyDefense)
{
var p = GetEquipPoint(rightHandler, collectable.targetEquipPoint);
if (!p)
{
return;
}
collectable.weapon.transform.SetParent(p);
collectable.weapon.transform.localPosition = Vector3.zero;
collectable.weapon.transform.localEulerAngles = Vector3.zero;
if (rightWeapon && rightWeapon.gameObject != collectable.gameObject)
{
RemoveRightWeapon();
}
if (collectable.twoHandWeapon || leftWeapon && leftWeapon.twoHandWeapon)
{
RemoveLeftWeapon();
}
meleeManager.SetRightWeapon(weapon.gameObject);
collectable.OnEquip.Invoke();
rightWeapon = collectable;
onEquipRightWeapon.Invoke();
UpdateRightDisplay(collectable);
}
if (weapon.meleeType != vMeleeType.OnlyAttack && weapon.meleeType != vMeleeType.AttackAndDefense)
{
var p = GetEquipPoint(leftHandler, collectable.targetEquipPoint);
if (!p)
{
return;
}
collectable.weapon.transform.SetParent(p);
collectable.weapon.transform.localPosition = Vector3.zero;
collectable.weapon.transform.localEulerAngles = Vector3.zero;
if (leftWeapon && leftWeapon.gameObject != collectable.gameObject)
{
RemoveLeftWeapon();
}
if (collectable.twoHandWeapon || rightWeapon && rightWeapon.twoHandWeapon)
{
RemoveRightWeapon();
}
onEquipLeftWeapon.Invoke();
meleeManager.SetLeftWeapon(weapon.gameObject);
collectable.OnEquip.Invoke();
leftWeapon = collectable;
UpdateLeftDisplay(collectable);
}
}
protected virtual Transform GetEquipPoint(vHandler point, string name)
{
Transform p = point.defaultHandler;
var customP = point.customHandlers.Find(_p => _p.name.Equals(name));
if (customP)
{
p = customP;
}
return p;
}
protected virtual void UnequipWeaponHandle()
{
if (rightWeapon)
{
if (unequipRightInput.GetButtonDown())
{
RemoveRightWeapon();
}
}
if (leftWeapon)
{
if (unequipLeftInput.GetButtonDown())
{
RemoveLeftWeapon();
}
}
}
public virtual void RemoveLeftWeapon()
{
if (leftWeapon)
{
leftWeapon.weapon.transform.parent = null;
leftWeapon.OnDrop.Invoke();
onUnEquipLeftWeapon.Invoke();
}
if (meleeManager)
{
meleeManager.leftWeapon = null;
}
UpdateLeftDisplay();
}
public virtual void RemoveRightWeapon()
{
if (rightWeapon)
{
rightWeapon.weapon.transform.parent = null;
rightWeapon.OnDrop.Invoke();
onUnEquipRightWeapon.Invoke();
}
if (meleeManager)
{
meleeManager.rightWeapon = null;
}
UpdateRightDisplay();
}
public virtual bool isUsingTwoHandWeapon
{
get
{
return rightWeapon != null && rightWeapon.twoHandWeapon || leftWeapon != null && leftWeapon.twoHandWeapon;
}
}
public virtual bool isUsingMeleeWeapon
{
get
{
if (!meleeManager)
{
return false;
}
return meleeManager.leftWeapon && meleeManager.leftWeapon.gameObject.activeInHierarchy ||
meleeManager.rightWeapon && meleeManager.rightWeapon.gameObject.activeInHierarchy;
}
}
protected virtual void CheckIsEquipedWifhWeapon()
{
if (wasUsingMeleeWeapon && !isUsingMeleeWeapon)
{
onUnequipMeleeWeapon.Invoke();
wasUsingMeleeWeapon = false;
}
else if (!wasUsingMeleeWeapon && isUsingMeleeWeapon)
{
onEquipMeleeWeapon.Invoke();
wasUsingMeleeWeapon = true;
}
}
protected virtual void UpdateLeftDisplay(vCollectableStandalone collectable = null)
{
if (!currentDisplay)
{
return;
}
if (collectable)
{
currentDisplay.SetLeftWeaponIcon(collectable.weaponIcon);
currentDisplay.SetLeftWeaponText(collectable.weaponText);
}
else
{
currentDisplay.RemoveLeftWeaponIcon();
currentDisplay.RemoveLeftWeaponText();
}
}
protected virtual void UpdateRightDisplay(vCollectableStandalone collectable = null)
{
if (!currentDisplay)
{
return;
}
if (collectable)
{
currentDisplay.SetRightWeaponIcon(collectable.weaponIcon);
currentDisplay.SetRightWeaponText(collectable.weaponText);
}
else
{
currentDisplay.RemoveRightWeaponIcon();
currentDisplay.RemoveRightWeaponText();
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 105ebe27587ce1f49b2f0a3abc6e1212
timeCreated: 1483988962
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
using UnityEngine;
using System.Collections;
using UnityEngine.Events;
namespace Invector.vCharacterController.vActions
{
using vMelee;
[vClassHeader("Collectable Standalone", "Use this component when your character doesn't have a ItemManager", openClose = false)]
public class vCollectableStandalone : vTriggerGenericAction
{
[vEditorToolbar("Collectable")]
public string targetEquipPoint;
public bool twoHandWeapon;
public GameObject weapon;
public Sprite weaponIcon;
public string weaponText;
[vEditorToolbar("Events")]
public UnityEvent OnEquip;
public UnityEvent OnDrop;
private vCollectMeleeControl manager;
public override IEnumerator OnPressActionDelay(GameObject cc)
{
yield return StartCoroutine(base.OnPressActionDelay(cc));
manager = cc.GetComponent<vCollectMeleeControl>();
if (manager != null)
{
manager.HandleCollectableInput(this);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0b164d939286a4b429909f275c09452d
timeCreated: 1483988962
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,98 @@
using UnityEngine;
namespace Invector
{
public class vControlDisplayWeaponStandalone : MonoBehaviour
{
[SerializeField]
protected vDisplayWeaponStandalone leftDisplay, rightDisplay;
#region Control Left Display
public virtual void SetLeftWeaponIcon(Sprite icon)
{
if (!leftDisplay)
{
return;
}
leftDisplay.SetWeaponIcon(icon);
}
public virtual void SetLeftWeaponText(string text)
{
if (!leftDisplay)
{
return;
}
leftDisplay.SetWeaponText(text);
}
public virtual void RemoveLeftWeaponIcon()
{
if (!leftDisplay)
{
return;
}
leftDisplay.RemoveWeaponIcon();
}
public virtual void RemoveLeftWeaponText()
{
if (!leftDisplay)
{
return;
}
leftDisplay.RemoveWeaponText();
}
#endregion
#region Control Right Display
public virtual void SetRightWeaponIcon(Sprite icon)
{
if (!rightDisplay)
{
return;
}
rightDisplay.SetWeaponIcon(icon);
}
public virtual void SetRightWeaponText(string text)
{
if (!rightDisplay)
{
return;
}
rightDisplay.SetWeaponText(text);
}
public virtual void RemoveRightWeaponIcon()
{
if (!rightDisplay)
{
return;
}
rightDisplay.RemoveWeaponIcon();
}
public virtual void RemoveRightWeaponText()
{
if (!rightDisplay)
{
return;
}
rightDisplay.RemoveWeaponText();
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5f34e1a96446b0d4b9761d0208d6026e
timeCreated: 1487018391
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using UnityEngine;
using UnityEngine.UI;
namespace Invector
{
public class vDisplayWeaponStandalone : MonoBehaviour
{
[Header("Weapon Display source")]
public Image weaponIcon;
public Text weaponText;
[Header("Weapon unarmed sources")]
public Sprite defaultIcon;
public string defaultText;
protected virtual void Start()
{
RemoveWeaponIcon();
RemoveWeaponText();
}
public virtual void SetWeaponIcon(Sprite icon)
{
if (!weaponIcon) return;
weaponIcon.sprite = icon;
if (!weaponIcon.gameObject.activeSelf)
weaponIcon.gameObject.SetActive(true);
}
public virtual void SetWeaponText(string text)
{
if (!weaponText) return;
weaponText.text = text;
if (!weaponText.gameObject.activeSelf)
weaponText.gameObject.SetActive(true);
}
public virtual void RemoveWeaponIcon()
{
if (!weaponIcon) return;
weaponIcon.sprite = defaultIcon;
if (weaponIcon.gameObject.activeSelf && weaponIcon.sprite == null)
weaponIcon.gameObject.SetActive(false);
}
public virtual void RemoveWeaponText()
{
if (!weaponText) return;
weaponText.text = defaultText;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c9273a5d06bc34a419fda6f3e81da1e2
timeCreated: 1487018582
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
using UnityEngine;
namespace Invector
{
[System.AttributeUsage(System.AttributeTargets.Field,AllowMultiple = true,Inherited = true)]
public class vEnumFlagAttribute : PropertyAttribute
{
public string enumName;
public vEnumFlagAttribute() { }
public vEnumFlagAttribute(string name)
{
enumName = name;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b94e6105bcb8ba743ab7041e1b64c593
timeCreated: 1529518809
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using UnityEngine;
using System;
namespace Invector.vMelee
{
[vClassHeader("HitBox", openClose = false)]
public class vHitBox : vMonoBehaviour
{
[HideInInspector]
public vMeleeAttackObject attackObject;
// [HideInInspector]
public Collider trigger
{
get
{
_trigger = gameObject.GetComponent<Collider>();
if (!_trigger) _trigger = gameObject.AddComponent<BoxCollider>();
return _trigger;
}
}
public int damagePercentage = 100;
[vEnumFlag]
public vHitBoxType triggerType = vHitBoxType.Damage | vHitBoxType.Recoil;
protected bool canHit;
protected Collider _trigger;
void OnDrawGizmos()
{
Color color = (triggerType & vHitBoxType.Damage) != 0 && (triggerType & vHitBoxType.Recoil) == 0 ? Color.green :
(triggerType & vHitBoxType.Damage) != 0 && (triggerType & vHitBoxType.Recoil) != 0 ? Color.yellow :
(triggerType & vHitBoxType.Recoil) != 0 && (triggerType & vHitBoxType.Damage) == 0 ? Color.red : Color.black;
color.a = 0.6f;
Gizmos.color = color;
if (!Application.isPlaying && trigger && !trigger.enabled) trigger.enabled = true;
if (trigger && trigger.enabled)
{
if (trigger as BoxCollider)
{
BoxCollider box = trigger as BoxCollider;
//var sizeX = transform.lossyScale.x * box.size.x;
//var sizeY = transform.lossyScale.y * box.size.y;
//var sizeZ = transform.lossyScale.z * box.size.z;
//Matrix4x4 rotationMatrix = Matrix4x4.TRS(box.bounds.center, transform.rotation, new Vector3(sizeX, sizeY, sizeZ));
//Gizmos.matrix = rotationMatrix;
//Gizmos.DrawCube(Vector3.zero, Vector3.one);
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
Gizmos.DrawCube(box.center, Vector3.Scale(Vector3.one, box.size));
}
}
}
void Start()
{
if (trigger)
{
trigger.isTrigger = true;
trigger.enabled = false;
}
var h_layer = LayerMask.NameToLayer("Ignore Raycast");
transform.gameObject.layer = h_layer;
canHit = ((triggerType & vHitBoxType.Damage) != 0 || (triggerType & vHitBoxType.Recoil) != 0);
}
void OnTriggerEnter(Collider other)
{
if (TriggerCondictions(other))
{
if (attackObject != null)
{
attackObject.OnHit(this, other);
}
}
}
bool TriggerCondictions(Collider other)
{
return (canHit && (attackObject != null && (attackObject.meleeManager == null || other.gameObject != attackObject.meleeManager.gameObject)));
}
}
[Flags]
public enum vHitBoxType
{
Damage = 1, Recoil = 2
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: fb97f58541b05b24ab37661346298ff2
timeCreated: 1470329607
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,63 @@
using UnityEngine;
namespace Invector.vMelee
{
[vClassHeader("Hit Effects", "Search for the 'AudioSource' prefab in the project or create your own custom AudioSource.")]
public class vHitEffects : vMonoBehaviour
{
public GameObject audioSource;
public AudioClip[] hitSounds;
public AudioClip[] recoilSounds;
public GameObject[] recoilParticles;
public AudioClip[] defSounds;
void Start()
{
var weaponObject = GetComponent<vMeleeWeapon>();
if (weaponObject)
{
weaponObject.onDamageHit.AddListener(PlayHitEffects);
weaponObject.onRecoilHit.AddListener(PlayRecoilEffects);
weaponObject.onDefense.AddListener(PlayDefenseEffects);
}
}
public void PlayHitEffects(vHitInfo hitInfo)
{
if (audioSource != null && hitSounds.Length > 0)
{
var clip = hitSounds[UnityEngine.Random.Range(0, hitSounds.Length)];
var audioObj = Instantiate(audioSource, transform.position, transform.rotation) as GameObject;
audioObj.GetComponent<AudioSource>().PlayOneShot(clip);
}
}
public void PlayRecoilEffects(vHitInfo hitInfo)
{
if (audioSource != null && recoilSounds.Length > 0)
{
var clip = recoilSounds[UnityEngine.Random.Range(0, recoilSounds.Length)];
var audioObj = Instantiate(audioSource, transform.position, transform.rotation) as GameObject;
audioObj.GetComponent<AudioSource>().PlayOneShot(clip);
}
if (recoilParticles.Length > 0)
{
var particles = recoilParticles[UnityEngine.Random.Range(0, recoilParticles.Length)];
var hitrotation = Quaternion.LookRotation(new Vector3(transform.position.x, hitInfo.hitPoint.y, transform.position.z) - hitInfo.hitPoint);
if (particles != null)
Instantiate(particles, hitInfo.hitPoint, hitrotation);
}
}
public void PlayDefenseEffects()
{
if (audioSource != null && defSounds.Length > 0)
{
var clip = defSounds[UnityEngine.Random.Range(0, defSounds.Length)];
var audioObj = Instantiate(audioSource, transform.position, transform.rotation) as GameObject;
audioObj.GetComponent<AudioSource>().PlayOneShot(clip);
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 00cc2b820c1fe174082aa779f79cb540
timeCreated: 1475624836
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
namespace Invector.vEventSystems
{
public interface vIAttackListener
{
void OnEnableAttack();
void OnDisableAttack();
void ResetAttackTriggers();
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 226f8db32d72b044cbdb1775783c5958
timeCreated: 1529517796
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace Invector.vEventSystems
{
public interface vIAttackReceiver
{
void OnReceiveAttack(vDamage damage, vIMeleeFighter attacker);
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 171cab8700dd703409c074ae54f09270
timeCreated: 1529517618
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
using UnityEngine;
namespace Invector.vEventSystems
{
public interface vIMeleeFighter : vIAttackReceiver, vIAttackListener
{
void BreakAttack(int breakAtkID);
void OnRecoil(int recoilID);
bool isAttacking { get; }
bool isArmed { get; }
bool isBlocking { get; }
Transform transform { get; }
GameObject gameObject { get; }
vCharacterController.vICharacter character { get; }
}
public static class vIMeeleFighterHelper
{
/// <summary>
/// check if gameObject has a <see cref="vIMeleeFighter"/> Component
/// </summary>
/// <param name="receiver"></param>
/// <returns>return true if gameObject contains a <see cref="vIMeleeFighter"/></returns>
public static bool IsMeleeFighter(this GameObject receiver)
{
return receiver.GetComponent<vIMeleeFighter>() != null;
}
/// <summary>
/// Apply damage using OnReeiveAttack method if receiver dosent has a vIAttackReceiver, the Simple ApplyDamage is called
/// </summary>
/// <param name="receiver">target damage receiver</param>
/// <param name="damage">damage</param>
/// <param name="attacker">damage sender</param>
public static void ApplyDamage(this GameObject receiver, vDamage damage, vIMeleeFighter attacker)
{
var attackReceiver = receiver.GetComponent<vIAttackReceiver>();
if (attackReceiver != null)
{
attackReceiver.OnReceiveAttack(damage, attacker);
}
else
{
receiver.ApplyDamage(damage);
}
}
/// <summary>
/// Get <see cref="vIMeleeFighter"/> of gameObject
/// </summary>
/// <param name="receiver"></param>
/// <returns>the <see cref="vIMeleeFighter"/> component</returns>
public static vIMeleeFighter GetMeleeFighter(this GameObject receiver)
{
return receiver.GetComponent<vIMeleeFighter>();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ac63b5b29df38024dbb34ba7a5db4483
timeCreated: 1529517788
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
using System.Collections.Generic;
using UnityEngine;
namespace Invector.vMelee
{
using vEventSystems;
public class vMeleeAttackControl : StateMachineBehaviour
{
[Tooltip("normalizedTime of Active Damage")]
public float startDamage = 0.05f;
[Tooltip("normalizedTime of Disable Damage")]
public float endDamage = 0.9f;
public int damageMultiplier;
public int recoilID;
public int reactionID;
public vAttackType meleeAttackType = vAttackType.Unarmed;
[Tooltip("You can use a name as reference to trigger a custom HitDamageParticle")]
public string damageType;
[HideInInspector]
[Header("This work with vMeleeManager to active vMeleeAttackObject from bodyPart and id")]
public List<string> bodyParts = new List<string> { "RightLowerArm" };
public bool ignoreDefense;
public bool activeRagdoll;
[vHideInInspector("activeRagdoll"), Tooltip("Time to keep Ragdoll active")]
public float senselessTime;
[Tooltip("Check true in the last attack of your combo to reset the triggers")]
public bool resetAttackTrigger;
private bool isActive;
public bool debug;
private vIAttackListener mFighter;
private bool isAttacking;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
mFighter = animator.GetComponent<vIAttackListener>();
isAttacking = true;
if (mFighter != null)
mFighter.OnEnableAttack();
if (debug)
Debug.Log("Enter " + damageType);
}
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (stateInfo.normalizedTime % 1 >= startDamage && stateInfo.normalizedTime % 1 <= endDamage && !isActive)
{
if (debug) Debug.Log(animator.name + " attack " + damageType + " enable damage in " + System.Math.Round(stateInfo.normalizedTime % 1, 2));
isActive = true;
ActiveDamage(animator, true);
}
else if (stateInfo.normalizedTime % 1 > endDamage && isActive)
{
if (debug) Debug.Log(animator.name + " attack " + damageType + " disable damage in " + System.Math.Round(stateInfo.normalizedTime % 1, 2));
isActive = false;
ActiveDamage(animator, false);
}
if (stateInfo.normalizedTime % 1 > endDamage && isAttacking)
{
isAttacking = false;
if (mFighter != null)
mFighter.OnDisableAttack();
}
//if (stateInfo.normalizedTime % 1 > allowRotationAt && isAttacking)
//{
// isAttacking = false;
// if (mFighter != null)
// mFighter.OnDisableAttack();
//}
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (debug)
Debug.Log("Exit " + damageType);
if (isActive)
{
isActive = false;
ActiveDamage(animator, false);
}
if (isAttacking)
{
isAttacking = false;
if (mFighter != null)
mFighter.OnDisableAttack();
}
if (mFighter != null && resetAttackTrigger)
mFighter.ResetAttackTriggers();
if (debug) Debug.Log(animator.name + " attack " + damageType + " stateExit");
}
void ActiveDamage(Animator animator, bool value)
{
var meleeManager = animator.GetComponent<vMeleeManager>();
if (meleeManager)
meleeManager.SetActiveAttack(bodyParts, meleeAttackType, value, damageMultiplier, recoilID, reactionID, ignoreDefense, activeRagdoll,senselessTime, damageType);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f9058122f6ec699438581f28f117350d
timeCreated: 1470332631
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,224 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace Invector.vMelee
{
using vEventSystems;
[vClassHeader("Melee Object", openClose = false)]
public partial class vMeleeAttackObject : vMonoBehaviour
{
[vReadOnly(false)] public string attackObjectName;
public vDamage damage;
public Transform overrideDamageSender;
public List<vHitBox> hitBoxes;
public int damageModifier;
[HideInInspector]
public bool canApplyDamage;
/// <summary>
/// Event called when attack was successful
/// </summary>
[vHelpBox("Event called when attack was successful")]
public OnHitEnter onDamageHit;
/// <summary>
/// Event called when the attack causes recoil
/// </summary>
[vHelpBox("Event called when the attack causes recoil")]
public OnHitEnter onRecoilHit;
/// <summary>
/// Event called when causes damage
/// </summary>
[vHelpBox("Event called when causes damage ")]
public OnReceiveDamage onPassDamage;
[vHelpBox("Events called when Damage applier (HitBoxes) is enabled or disabled ")]
public UnityEvent onEnableDamage;
public UnityEvent onDisableDamage;
private Dictionary<vHitBox, List<GameObject>> targetColliders;
[HideInInspector]
public vMeleeManager meleeManager;
protected virtual void Start()
{
// init list of targetColliders
targetColliders = new Dictionary<vHitBox, List<GameObject>>();
if (hitBoxes.Count > 0)
{
// initialize hitBox properties
foreach (vHitBox hitBox in hitBoxes)
{
hitBox.attackObject = this;
targetColliders.Add(hitBox, new List<GameObject>());
}
}
else
{
this.enabled = false;
}
}
/// <summary>
/// Set Active all hitBoxes of the MeleeAttackObject
/// </summary>
/// <param name="value"> active value</param>
public virtual void SetActiveDamage(bool value)
{
canApplyDamage = value;
for (int i = 0; i < hitBoxes.Count; i++)
{
var hitCollider = hitBoxes[i];
hitCollider.trigger.enabled = value;
if (value == false && targetColliders != null)
{
targetColliders[hitCollider].Clear();
}
}
if (value)
{
onEnableDamage.Invoke();
}
else
{
onDisableDamage.Invoke();
}
}
/// <summary>
/// Hitboxes Call Back
/// </summary>
/// <param name="hitBox">vHitBox object</param>
/// <param name="other">target Collider</param>
public virtual void OnHit(vHitBox hitBox, Collider other)
{
// check first condition for hit
if (canApplyDamage && !targetColliders[hitBox].Contains(other.gameObject) && (meleeManager != null && other.gameObject != meleeManager.gameObject))
{
var inDamage = false;
var inRecoil = false;
if (meleeManager == null)
{
meleeManager = GetComponentInParent<vMeleeManager>();
}
//check if meleeManager exists and apply his hitProperties to this
HitProperties _hitProperties = meleeManager.hitProperties;
// damage conditions
if (((hitBox.triggerType & vHitBoxType.Damage) != 0) && _hitProperties.hitDamageTags == null || _hitProperties.hitDamageTags.Count == 0)
{
inDamage = true;
}
else if (((hitBox.triggerType & vHitBoxType.Damage) != 0) && _hitProperties.hitDamageTags.Contains(other.tag))
{
inDamage = true;
}
// recoil conditions
else if (((hitBox.triggerType & vHitBoxType.Recoil) != 0) &&
(_hitProperties.hitRecoilLayer == (_hitProperties.hitRecoilLayer | (1 << other.gameObject.layer))))
{
inRecoil = true;
}
if (inDamage || inRecoil)
{
// add target collider in the list to control the frequency of hit
targetColliders[hitBox].Add(other.gameObject);
vHitInfo hitInfo = new vHitInfo(this, hitBox, other, hitBox.transform.position);
if (inDamage == true)
{
// If there is a meleeManager then call onDamageHit to control damage values
// and it will call the ApplyDamage after filter the damage
// if meleeManager is null the damage will be directly applied
// Finally the OnDamageHit event is called
if (meleeManager)
{
meleeManager.OnDamageHit(ref hitInfo);
}
else
{
damage.sender = overrideDamageSender ? overrideDamageSender : transform;
// ApplyDamage(hitBox, other, damage);
}
if (!hitInfo.targetIsBlocking)
{
onDamageHit.Invoke(hitInfo);
}
}
// recoil just work with OnRecoilHit event and meleeManger
if (inRecoil == true)
{
if (meleeManager)
{
meleeManager.OnRecoilHit(hitInfo);
}
onRecoilHit.Invoke(hitInfo);
}
}
}
}
/// <summary>
/// Apply damage to target collider (TakeDamage, damage))
/// </summary>
/// <param name="hitBox">vHitBox object</param>
/// <param name="other">collider target</param>
/// <param name="damage"> damage</param>
public virtual bool ApplyDamage(vHitBox hitBox, Collider other, vDamage damage)
{
vDamage _damage = new vDamage(damage);
_damage.receiver = other.transform;
_damage.damageValue = Mathf.RoundToInt(((damage.damageValue + damageModifier) * (hitBox.damagePercentage * 0.01f)));
_damage.hitPosition = hitBox.transform.position;
other.gameObject.ApplyDamage(_damage, meleeManager.fighter);
if (_damage.hitReaction && _damage.damageValue > 0)
{
onPassDamage.Invoke(_damage);
}
return _damage.hitReaction;
}
}
}
namespace Invector.vMelee
{
#region Secundary Class
[System.Serializable]
public class OnHitEnter : UnityEvent<vHitInfo> { }
public partial class vHitInfo
{
public vMeleeAttackObject attackObject;
public vHitBox hitBox;
public Vector3 hitPoint;
public Collider targetCollider;
public bool targetIsBlocking;
public vHitInfo(vMeleeAttackObject attackObject, vHitBox hitBox, Collider targetCollider, Vector3 hitPoint)
{
this.attackObject = attackObject;
this.hitBox = hitBox;
this.targetCollider = targetCollider;
this.hitPoint = hitPoint;
}
}
[System.Serializable]
public class HitProperties
{
[Tooltip("Tag to receive Damage")]
public List<string> hitDamageTags = new List<string>() { "Enemy" };
[Tooltip("Trigger a HitRecoil animation if the character attacks a obstacle")]
public bool useRecoil = true;
public bool drawRecoilGizmos;
[Range(0, 180f)]
public float recoilRange = 90f;
[Tooltip("layer to Recoil Damage")]
public LayerMask hitRecoilLayer = 1 << 0;
}
#endregion
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c0befb9e9384ab34d9dfc9d3cabf04b3
timeCreated: 1470333665
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
using Invector.vMelee;
namespace Invector.vItemManager
{
[vClassHeader("Melee Equipment", openClose = false, useHelpBox = true, helpBoxText = "Use this component if you also use the ItemManager in your Character")]
public partial class vMeleeEquipment : vEquipment
{
vMeleeWeapon _weapon;
protected bool withoutMeleeWeapon;
protected virtual vMeleeWeapon meleeWeapon
{
get
{
if (!_weapon && !withoutMeleeWeapon)
{
_weapon = GetComponent<vMeleeWeapon>();
if (!_weapon) withoutMeleeWeapon = true;
}
return _weapon;
}
}
public override bool IsEquipped
{
get
{
return base.IsEquipped;
}
set
{
base.IsEquipped = value;
if (meleeWeapon) meleeWeapon.IsEquipped = value;
}
}
public override void OnEquip(vItem item)
{
if (meleeWeapon)
{
var damage = item.GetItemAttribute(vItemAttributes.Damage);
var staminaCost = item.GetItemAttribute(vItemAttributes.StaminaCost);
var defenseRate = item.GetItemAttribute(vItemAttributes.DefenseRate);
var defenseRange = item.GetItemAttribute(vItemAttributes.DefenseRange);
if (damage != null) this.meleeWeapon.damage.damageValue = damage.value;
if (staminaCost != null) this.meleeWeapon.staminaCost = staminaCost.value;
if (defenseRate != null) this.meleeWeapon.defenseRate = defenseRate.value;
if (defenseRange != null) this.meleeWeapon.defenseRange = defenseRate.value;
}
base.OnEquip(item);
}
public override void OnUnequip(vItem item)
{
base.OnUnequip(item);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4b02b25f3302cf04fb8e4a1a80f0b12e
timeCreated: 1525812721
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,523 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Invector.vMelee
{
using Invector.vItemManager;
using vEventSystems;
/// <summary>
/// Event called when you equip a weapon (Weapon, isLeftWeapon)
/// </summary>
[System.Serializable]
public class OnEquipWeaponEvent : UnityEngine.Events.UnityEvent<vMeleeWeapon, bool> { }
public class vMeleeManager : vMonoBehaviour, IWeaponEquipmentListener
{
#region SeralizedProperties in CustomEditor
public List<vBodyMember> Members = new List<vBodyMember>();
public vDamage defaultDamage = new vDamage(10);
public HitProperties hitProperties;
public vMeleeWeapon leftWeapon, rightWeapon;
public vOnHitEvent onDamageHit, onRecoilHit;
public OnEquipWeaponEvent onEquipWeapon;
public OnEquipWeaponEvent onUnequipWeapon;
#endregion
[Tooltip("NPC ONLY- Ideal distance for the attack")]
public float defaultAttackDistance = 1f;
[Tooltip("Default cost for stamina when attack")]
public float defaultStaminaCost = 20f;
[Tooltip("Default recovery delay for stamina when attack")]
public float defaultStaminaRecoveryDelay = 1f;
[Range(0, 100)]
public int defaultDefenseRate = 100;
[Range(0, 180)]
public float defaultDefenseRange = 90;
public virtual vIMeleeFighter fighter { get; set; }
protected virtual int damageMultiplier { get; set; }
protected virtual int currentRecoilID { get; set; }
protected virtual int currentReactionID { get; set; }
protected virtual bool ignoreDefense { get; set; }
protected virtual bool activeRagdoll { get; set; }
protected virtual float senselessTime { get; set; }
protected virtual bool inRecoil { get; set; }
protected virtual string attackName { get; set; }
protected virtual void Start()
{
Init();
}
/// <summary>
/// Init properties
/// </summary>
public virtual void Init()
{
fighter = gameObject.GetMeleeFighter();
///Initialize all bodyMembers and weapons
foreach (vBodyMember member in Members)
{
///damage of member will be always the defaultDamage
//member.attackObject.damage = defaultDamage;
if (member.attackObject == null)
{
var attackObjects = GetComponentsInChildren<vMeleeAttackObject>();
if (attackObjects.Length > 0)
member.attackObject = System.Array.Find(attackObjects, a => a.attackObjectName.Equals(member.bodyPart));
if (member.attackObject == null)
{
Debug.LogWarning("Can't find the attack Object " + member.bodyPart);
continue;
}
}
member.attackObject.damage.damageValue = defaultDamage.damageValue;
if (member.bodyPart == HumanBodyBones.LeftLowerArm.ToString())
{
var weapon = member.attackObject.GetComponentInChildren<vMeleeWeapon>(true);
leftWeapon = weapon;
}
if (member.bodyPart == HumanBodyBones.RightLowerArm.ToString())
{
var weapon = member.attackObject.GetComponentInChildren<vMeleeWeapon>(true);
rightWeapon = weapon;
}
member.attackObject.meleeManager = this;
member.SetActiveDamage(false);
}
if (leftWeapon != null)
{
leftWeapon.SetActiveDamage(false);
leftWeapon.meleeManager = this;
}
if (rightWeapon != null)
{
rightWeapon.meleeManager = this;
rightWeapon.SetActiveDamage(false);
}
}
/// <summary>
/// Set active Multiple Parts to attack
/// </summary>
/// <param name="bodyParts"></param>
/// <param name="type"></param>
/// <param name="active"></param>
/// <param name="damageMultiplier"></param>
public virtual void SetActiveAttack(List<string> bodyParts, vAttackType type, bool active = true, int damageMultiplier = 0, int recoilID = 0, int reactionID = 0, bool ignoreDefense = false, bool activeRagdoll = false, float senselessTime = 0, string attackName = "")
{
for (int i = 0; i < bodyParts.Count; i++)
{
var bodyPart = bodyParts[i];
SetActiveAttack(bodyPart, type, active, damageMultiplier, recoilID, reactionID, ignoreDefense, activeRagdoll, senselessTime, attackName);
}
}
/// <summary>
/// Set active Single Part to attack
/// </summary>
/// <param name="bodyPart"></param>
/// <param name="type"></param>
/// <param name="active"></param>
/// <param name="damageMultiplier"></param>
public virtual void SetActiveAttack(string bodyPart, vAttackType type, bool active = true, int damageMultiplier = 0, int recoilID = 0, int reactionID = 0, bool ignoreDefense = false, bool activeRagdoll = false, float senselessTime = 0, string attackName = "")
{
this.damageMultiplier = damageMultiplier;
currentRecoilID = recoilID;
currentReactionID = reactionID;
this.ignoreDefense = ignoreDefense;
this.activeRagdoll = activeRagdoll;
this.attackName = attackName;
this.senselessTime = senselessTime;
if (type == vAttackType.Unarmed)
{
/// find attackObject by bodyPart
var attackObject = Members.Find(member => member.bodyPart == bodyPart);
if (attackObject != null)
{
attackObject.SetActiveDamage(active);
}
}
else
{ ///if AttackType == MeleeWeapon
///this work just for Right and Left Lower Arm
if (bodyPart == "RightLowerArm" && rightWeapon != null)
{
rightWeapon.meleeManager = this;
rightWeapon.SetActiveDamage(active);
}
else if (bodyPart == "LeftLowerArm" && leftWeapon != null)
{
leftWeapon.meleeManager = this;
leftWeapon.SetActiveDamage(active);
}
}
}
/// <summary>
/// Listener of Damage Event
/// </summary>
/// <param name="hitInfo"></param>
public virtual void OnDamageHit(ref vHitInfo hitInfo)
{
vDamage damage = new vDamage(hitInfo.attackObject.damage);
damage.sender = transform;
damage.reaction_id = currentReactionID;
damage.recoil_id = currentRecoilID;
if (this.activeRagdoll) damage.activeRagdoll = this.activeRagdoll;
if (this.attackName != string.Empty) damage.damageType = this.attackName;
if (this.ignoreDefense) damage.ignoreDefense = this.ignoreDefense;
if (this.senselessTime != 0) damage.senselessTime = this.senselessTime;
/// Calc damage with multiplier
/// and Call ApplyDamage of attackObject
damage.damageValue *= damageMultiplier > 1 ? damageMultiplier : 1;
hitInfo.targetIsBlocking = !hitInfo.attackObject.ApplyDamage(hitInfo.hitBox, hitInfo.targetCollider, damage);
onDamageHit.Invoke(hitInfo);
}
/// <summary>
/// Listener of Recoil Event
/// </summary>
/// <param name="hitInfo"></param>
public virtual void OnRecoilHit(vHitInfo hitInfo)
{
if (hitProperties.useRecoil && InRecoilRange(hitInfo) && !inRecoil)
{
inRecoil = true;
var id = currentRecoilID;
if (fighter != null) fighter.OnRecoil(id);
onRecoilHit.Invoke(hitInfo);
Invoke("ResetRecoil", 1f);
}
}
/// <summary>
/// Call Weapon Defense Events.
/// </summary>
public virtual void OnDefense()
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
leftWeapon.OnDefense();
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
rightWeapon.OnDefense();
}
}
/// <summary>
/// Get Current Attack ID
/// </summary>
/// <returns></returns>
public virtual int GetAttackID()
{
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyDefense && rightWeapon.gameObject.activeInHierarchy) return rightWeapon.attackID;
return 0;
}
/// <summary>
/// Get StaminaCost
/// </summary>
/// <returns></returns>
public virtual float GetAttackStaminaCost()
{
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyDefense && rightWeapon.gameObject.activeInHierarchy) return rightWeapon.staminaCost;
return defaultStaminaCost;
}
/// <summary>
/// Get StaminaCost
/// </summary>
/// <returns></returns>
public virtual float GetAttackStaminaRecoveryDelay()
{
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyDefense && rightWeapon.gameObject.activeInHierarchy) return rightWeapon.staminaRecoveryDelay;
return defaultStaminaRecoveryDelay;
}
/// <summary>
/// Get ideal distance for the attack
/// </summary>
/// <returns></returns>
public virtual float GetAttackDistance()
{
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyDefense && rightWeapon.gameObject.activeInHierarchy) return rightWeapon.distanceToAttack;
return defaultAttackDistance;
}
/// <summary>
/// Get Current Defense ID
/// </summary>
/// <returns></returns>
public virtual int GetDefenseID()
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
GetComponent<Animator>().SetBool("FlipAnimation", false);
return leftWeapon.defenseID;
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
GetComponent<Animator>().SetBool("FlipAnimation", true);
return rightWeapon.defenseID;
}
return 0;
}
/// <summary>
/// Get Defense Rate of Melee Defense
/// </summary>
/// <returns></returns>
public virtual int GetDefenseRate()
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
return leftWeapon.defenseRate;
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
return rightWeapon.defenseRate;
}
return defaultDefenseRate;
}
/// <summary>
/// Get Current MoveSet ID
/// </summary>
/// <returns></returns>
public virtual int GetMoveSetID()
{
if (rightWeapon != null && rightWeapon.gameObject.activeInHierarchy) return rightWeapon.movesetID;
// if (leftWeapon != null && leftWeapon.gameObject.activeInHierarchy) return leftWeapon.movesetID;
return 0;
}
/// <summary>
/// Check if defence can break Attack
/// </summary>
/// <returns></returns>
public virtual bool CanBreakAttack()
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
return leftWeapon.breakAttack;
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
return rightWeapon.breakAttack;
}
return false;
}
/// <summary>
/// Check if attack can be blocked
/// </summary>
/// <param name="attackPoint"></param>
/// <returns></returns>
public virtual bool CanBlockAttack(Vector3 attackPoint)
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
return Math.Abs(transform.HitAngle(attackPoint)) <= leftWeapon.defenseRange;
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
return Math.Abs(transform.HitAngle(attackPoint)) <= rightWeapon.defenseRange;
}
return Math.Abs(transform.HitAngle(attackPoint)) <= defaultDefenseRange;
}
/// <summary>
/// Get defense recoilID for break attack
/// </summary>
/// <returns></returns>
public virtual int GetDefenseRecoilID()
{
if (leftWeapon != null && leftWeapon.meleeType != vMeleeType.OnlyAttack && leftWeapon.gameObject.activeInHierarchy)
{
return leftWeapon.recoilID;
}
if (rightWeapon != null && rightWeapon.meleeType != vMeleeType.OnlyAttack && rightWeapon.gameObject.activeInHierarchy)
{
return rightWeapon.recoilID;
}
return 0;
}
/// <summary>
/// Check if angle of hit point is in range of recoil
/// </summary>
/// <param name="hitInfo"></param>
/// <returns></returns>
protected virtual bool InRecoilRange(vHitInfo hitInfo)
{
var center = new Vector3(transform.position.x, hitInfo.hitPoint.y, transform.position.z);
var euler = (Quaternion.LookRotation(hitInfo.hitPoint - center).eulerAngles - transform.eulerAngles).NormalizeAngle();
return euler.y <= hitProperties.recoilRange;
}
/// <summary>
///
/// </summary>
/// <param name="weaponObject"></param>
public virtual void SetLeftWeapon(GameObject weaponObject)
{
if (weaponObject)
{
leftWeapon = weaponObject.GetComponent<vMeleeWeapon>();
SetLeftWeapon(leftWeapon);
}
else
{
if (leftWeapon) onUnequipWeapon.Invoke(leftWeapon, true);
leftWeapon = null;
}
}
/// <summary>
///
/// </summary>
/// <param name="weaponObject"></param>
public virtual void SetRightWeapon(GameObject weaponObject)
{
if (weaponObject)
{
rightWeapon = weaponObject.GetComponent<vMeleeWeapon>();
SetRightWeapon(rightWeapon);
}
else
{
if (rightWeapon) onUnequipWeapon.Invoke(rightWeapon, false);
rightWeapon = null;
}
}
/// <summary>
///
/// </summary>
/// <param name="weaponObject"></param>
public virtual void SetLeftWeapon(vMeleeWeapon weapon)
{
if (weapon)
{
leftWeapon = weapon;
leftWeapon.IsEquipped = true;
leftWeapon.SetActiveDamage(false);
leftWeapon.meleeManager = this;
onEquipWeapon.Invoke(weapon, true);
}
else
{
if (leftWeapon) onUnequipWeapon.Invoke(leftWeapon, true);
leftWeapon = null;
}
}
/// <summary>
///
/// </summary>
/// <param name="weaponObject"></param>
public virtual void SetRightWeapon(vMeleeWeapon weapon)
{
if (weapon)
{
rightWeapon = weapon;
rightWeapon.IsEquipped = true;
rightWeapon.meleeManager = this;
rightWeapon.SetActiveDamage(false);
onEquipWeapon.Invoke(weapon, false);
}
else
{
if (rightWeapon) onUnequipWeapon.Invoke(rightWeapon, false);
rightWeapon = null;
}
}
public virtual vMeleeWeapon CurrentActiveAttackWeapon
{
get
{
var weapon = CurrentAttackWeapon;
if (weapon && weapon.IsEquipped) return weapon;
return null;
}
}
public virtual vMeleeWeapon CurrentActiveDefenseWeapon
{
get
{
var weapon = CurrentDefenseWeapon;
if (weapon && weapon.IsEquipped) return weapon;
return null;
}
}
public virtual vMeleeWeapon CurrentAttackWeapon
{
get
{
if (rightWeapon && (rightWeapon.meleeType == vMeleeType.OnlyAttack || rightWeapon.meleeType == vMeleeType.AttackAndDefense)) return rightWeapon;
if (leftWeapon && (leftWeapon.meleeType == vMeleeType.OnlyAttack || leftWeapon.meleeType == vMeleeType.AttackAndDefense)) return leftWeapon;
return null;
}
}
public virtual vMeleeWeapon CurrentDefenseWeapon
{
get
{
if (rightWeapon && (rightWeapon.meleeType == vMeleeType.OnlyDefense || rightWeapon.meleeType == vMeleeType.AttackAndDefense)) return rightWeapon;
if (leftWeapon && (leftWeapon.meleeType == vMeleeType.OnlyDefense || leftWeapon.meleeType == vMeleeType.AttackAndDefense)) return leftWeapon;
return null;
}
}
protected virtual void ResetRecoil()
{
inRecoil = false;
}
}
#region Secundary Classes
[Serializable]
public class vOnHitEvent : UnityEngine.Events.UnityEvent<vHitInfo> { }
[Serializable]
public class vBodyMember
{
public Transform transform;
public string bodyPart;
public vMeleeAttackObject attackObject;
public bool isHuman;
public void SetActiveDamage(bool active)
{
attackObject.SetActiveDamage(active);
}
}
public enum vHumanBones
{
RightHand, RightLowerArm, RightUpperArm, RightShoulder,
LeftHand, LeftLowerArm, LeftUpperArm, LeftShoulder,
RightFoot, RightLowerLeg, RightUpperLeg,
LeftFoot, LeftLowerLeg, LeftUpperLeg,
Chest,
Head
}
public enum vAttackType
{
Unarmed, MeleeWeapon
}
#endregion
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c11b181c688f7664aba8ba5b38942ac9
timeCreated: 1470329607
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
namespace Invector.vMelee
{
[vClassHeader("Melee Weapon", openClose = false)]
public partial class vMeleeWeapon : vMeleeAttackObject
{
[Header("Melee Weapon Settings")]
public vMeleeType meleeType = vMeleeType.OnlyAttack;
[Header("Attack Settings")]
public bool useStrongAttack = true;
[Tooltip("Simple AI Only")]
public float distanceToAttack = 1;
[Tooltip("Trigger a Attack Animation")]
public int attackID;
[Tooltip("Change the MoveSet when using this Weapon")]
public int movesetID;
[Header("* Third Person Controller Only *")]
[Tooltip("How much stamina will be consumed when attack")]
public float staminaCost;
[Tooltip("How much time the stamina will wait to start recover")]
public float staminaRecoveryDelay;
[Header("Defense Settings")]
[Range(0, 100)]
public int defenseRate = 100;
[Range(0, 180)]
public float defenseRange = 90;
[Tooltip("Trigger a Defense Animation")]
public int defenseID;
[Tooltip("What recoil animatil will trigger")]
public int recoilID;
[Tooltip("Can break the oponent attack, will trigger a recoil animation")]
public bool breakAttack;
[HideInInspector]
public UnityEngine.Events.UnityEvent onDefense;
/// <summary>
/// Weapon is in equipped in hand
/// </summary>
public virtual bool IsEquipped { get; set; }
public virtual void OnDefense()
{
onDefense.Invoke();
}
}
public enum vMeleeType
{
OnlyDefense, OnlyAttack, AttackAndDefense
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0ebe2ea9c9ea0544d84d9c27f7470915
timeCreated: 1470329607
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
using UnityEngine;
namespace Invector.vMelee
{
public class vRandomAttackBehaviour : StateMachineBehaviour
{
public int attackCount;
//OnStateMachineEnter is called when entering a statemachine via its Entry Node
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.SetInteger("RandomAttack", Random.Range(0, attackCount));
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d2940e852eb9b874798e470ed9ebf5c3
timeCreated: 1495128674
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using Invector;
using UnityEngine;
[vClassHeader(" Weapon Constrain ", "Weapon Constrain Helper: call true OnEquip and false OnDrop by CollectableStandalone events to avoid handler movement on 2018.x", iconName = "meleeIcon")]
public class vWeaponConstrain : vMonoBehaviour
{
Rigidbody m_Rigidbody;
protected virtual void Start()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
// Call OnEquip (true) / OnDrop (false)
public virtual void Inv_Weapon_FreezeAll(bool status)
{
if (status)
{
m_Rigidbody.constraints = RigidbodyConstraints.FreezeAll;
}
else
{
m_Rigidbody.constraints = RigidbodyConstraints.None;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 2ec807b121fb8d94e8a2c5d76766cdc4
timeCreated: 1535635580
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: