update
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93f58340e1f868c45a68a6c99d47608f
|
||||
folderAsset: yes
|
||||
timeCreated: 1471705410
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ef974dc08c6164c40ace6831a186d447
|
||||
folderAsset: yes
|
||||
timeCreated: 1476379025
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,298 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Invector.vMelee
|
||||
{
|
||||
using Invector.vCamera;
|
||||
using Invector.vItemManager;
|
||||
using vCharacterController;
|
||||
public class vCreateMeleeCharacterEditor : EditorWindow
|
||||
{
|
||||
GUISkin skin;
|
||||
public GameObject template;
|
||||
|
||||
public bool useGameController = true;
|
||||
public bool useInventory = true;
|
||||
|
||||
public GameObject inventory;
|
||||
public vItemListData itemListData;
|
||||
|
||||
public GameObject charObj;
|
||||
Animator charAnimator;
|
||||
|
||||
Vector2 rect = new Vector2(500, 660);
|
||||
UnityEditor.Editor humanoidpreview;
|
||||
Texture2D m_Logo;
|
||||
|
||||
/// <summary>
|
||||
/// 3rdPersonController Menu
|
||||
/// </summary>
|
||||
[MenuItem("Invector/Melee Combat/Create Melee Controller", false, 1)]
|
||||
public static void CreateNewCharacter()
|
||||
{
|
||||
GetWindow<vCreateMeleeCharacterEditor>();
|
||||
}
|
||||
|
||||
bool isHuman, isValidAvatar, charExist;
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
m_Logo = Resources.Load("icon_v2") as Texture2D;
|
||||
if (Selection.activeObject)
|
||||
{
|
||||
charObj = Selection.activeGameObject;
|
||||
}
|
||||
if (charObj)
|
||||
{
|
||||
charAnimator = charObj.GetComponent<Animator>();
|
||||
humanoidpreview = UnityEditor.Editor.CreateEditor(charObj);
|
||||
}
|
||||
|
||||
charExist = charAnimator != null;
|
||||
isHuman = charExist ? charAnimator.isHuman : false;
|
||||
isValidAvatar = charExist ? charAnimator.avatar.isValid : false;
|
||||
}
|
||||
|
||||
public virtual void OnGUI()
|
||||
{
|
||||
if (!skin)
|
||||
{
|
||||
skin = Resources.Load("vSkin") as GUISkin;
|
||||
}
|
||||
|
||||
GUI.skin = skin;
|
||||
|
||||
this.minSize = rect;
|
||||
this.titleContent = new GUIContent("Character", null, "Third Person Character Creator");
|
||||
GUILayout.BeginVertical("Character Creator Window", "window");
|
||||
GUILayout.Label(m_Logo, GUILayout.MaxHeight(25));
|
||||
GUILayout.Space(5);
|
||||
|
||||
GUILayout.BeginVertical("box");
|
||||
|
||||
if (!charObj)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Make sure your FBX model is set as Humanoid!", MessageType.Info);
|
||||
}
|
||||
else if (!charExist)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Missing a Animator Component", MessageType.Error);
|
||||
}
|
||||
else if (!isHuman)
|
||||
{
|
||||
EditorGUILayout.HelpBox("This is not a Humanoid", MessageType.Error);
|
||||
}
|
||||
else if (!isValidAvatar)
|
||||
{
|
||||
EditorGUILayout.HelpBox(charObj.name + " is a invalid Humanoid", MessageType.Info);
|
||||
}
|
||||
|
||||
template = EditorGUILayout.ObjectField("Template", template, typeof(GameObject), true, GUILayout.ExpandWidth(true)) as GameObject;
|
||||
charObj = EditorGUILayout.ObjectField("FBX Model", charObj, typeof(GameObject), true, GUILayout.ExpandWidth(true)) as GameObject;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("--- Optional---");
|
||||
|
||||
useGameController = EditorGUILayout.Toggle("Add GameController", useGameController);
|
||||
useInventory = EditorGUILayout.Toggle("Add Inventory", useInventory);
|
||||
|
||||
if (useInventory)
|
||||
{
|
||||
inventory = EditorGUILayout.ObjectField("Inventory Prefab", inventory, typeof(GameObject), true, GUILayout.ExpandWidth(true)) as GameObject;
|
||||
itemListData = EditorGUILayout.ObjectField("ItemListData", itemListData, typeof(vItemListData), true, GUILayout.ExpandWidth(true)) as vItemListData;
|
||||
}
|
||||
if (GUI.changed && charObj != null && charObj.GetComponent<vThirdPersonController>() == null)
|
||||
{
|
||||
humanoidpreview = UnityEditor.Editor.CreateEditor(charObj);
|
||||
}
|
||||
|
||||
if (charObj != null && charObj.GetComponent<vThirdPersonController>() != null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("This gameObject already contains the component vThirdPersonController", 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=KQ5xha36tfE&index=1&list=PLvgXGzhT_qehtuCYl2oyL-LrWoT7fhg9d");
|
||||
//}
|
||||
//GUILayout.EndHorizontal();
|
||||
|
||||
if (charObj)
|
||||
{
|
||||
charAnimator = charObj.GetComponent<Animator>();
|
||||
}
|
||||
|
||||
charExist = charAnimator != null;
|
||||
isHuman = charExist ? charAnimator.isHuman : false;
|
||||
isValidAvatar = charExist ? charAnimator.avatar.isValid : false;
|
||||
|
||||
if (CanCreate())
|
||||
{
|
||||
DrawHumanoidPreview();
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("Create"))
|
||||
{
|
||||
Create();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
public virtual bool CanCreate()
|
||||
{
|
||||
return isValidAvatar && isHuman && charObj != null && charObj.GetComponent<vThirdPersonController>() == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the Preview window
|
||||
/// </summary>
|
||||
public virtual void DrawHumanoidPreview()
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (humanoidpreview != null)
|
||||
{
|
||||
humanoidpreview.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(100, 400), "window");
|
||||
}
|
||||
}
|
||||
|
||||
private GameObject InstantiateNewCharacter(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 newCharacter = InstantiateNewCharacter(charObj);
|
||||
|
||||
if (!newCharacter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject _template = Instantiate(template, newCharacter.transform.position, newCharacter.transform.rotation);
|
||||
|
||||
// finds the '3D Model' gameobject or crate one if it doesn't exist
|
||||
Transform modelParent = _template.transform.Find("3D Model");
|
||||
|
||||
if (modelParent == null)
|
||||
{
|
||||
modelParent = new GameObject("3D Model").transform;
|
||||
modelParent.parent = _template.transform;
|
||||
}
|
||||
|
||||
// finds the 'Invector Components' gameobject or crate one if it doesn't exist
|
||||
Transform componentsParent = _template.transform.Find("Invector Components");
|
||||
|
||||
if (componentsParent == null)
|
||||
{
|
||||
componentsParent = new GameObject("Invector Components").transform;
|
||||
componentsParent.parent = _template.transform;
|
||||
}
|
||||
|
||||
newCharacter.transform.parent = modelParent;
|
||||
newCharacter.transform.localPosition = Vector3.zero;
|
||||
newCharacter.transform.localEulerAngles = Vector3.zero;
|
||||
_template.name = "vMeleeController_" + charObj.gameObject.name;
|
||||
|
||||
Animator animatorController = newCharacter.GetComponent<Animator>();
|
||||
Animator animatorTemplate = _template.GetComponent<Animator>();
|
||||
|
||||
animatorTemplate.avatar = animatorController.avatar;
|
||||
animatorTemplate.Rebind();
|
||||
DestroyImmediate(animatorController);
|
||||
|
||||
newCharacter.tag = "Player";
|
||||
|
||||
var p_layer = LayerMask.NameToLayer("Player");
|
||||
newCharacter.layer = p_layer;
|
||||
|
||||
foreach (Transform t in newCharacter.transform.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
t.gameObject.layer = p_layer;
|
||||
}
|
||||
|
||||
Selection.activeGameObject = _template;
|
||||
|
||||
// search for a MainCamera and attach to the tpCamera
|
||||
var mainCamera = Camera.main;
|
||||
var tpCamera = _template.GetComponentInChildren<vThirdPersonCamera>();
|
||||
|
||||
if (mainCamera == null)
|
||||
{
|
||||
mainCamera = new GameObject("MainCamera", typeof(Camera), typeof(AudioListener)).GetComponent<Camera>();
|
||||
mainCamera.tag = "MainCamera";
|
||||
}
|
||||
|
||||
if (mainCamera.transform.parent != tpCamera.transform)
|
||||
{
|
||||
mainCamera.transform.parent = tpCamera.transform;
|
||||
mainCamera.transform.localPosition = Vector3.zero;
|
||||
mainCamera.transform.localEulerAngles = Vector3.zero;
|
||||
}
|
||||
|
||||
// add the gameController example
|
||||
if (useGameController)
|
||||
{
|
||||
GameObject gC = null;
|
||||
var gameController = FindObjectOfType<vGameController>();
|
||||
if (gameController == null)
|
||||
{
|
||||
gC = new GameObject("vGameController_Example");
|
||||
gC.AddComponent<vGameController>();
|
||||
}
|
||||
}
|
||||
|
||||
if (useInventory)
|
||||
{
|
||||
// add prefab inventory to the 'Invector Components' gameObject inside the Controller
|
||||
inventory = Instantiate(inventory, componentsParent.transform.position, componentsParent.transform.rotation);
|
||||
inventory.gameObject.transform.parent = componentsParent.transform;
|
||||
inventory.transform.localPosition = Vector3.zero;
|
||||
inventory.transform.localEulerAngles = Vector3.zero;
|
||||
|
||||
// add shooter melee item list data
|
||||
var _itemManager = _template.GetComponent<vItemManager>();
|
||||
_itemManager.itemListData = itemListData;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove ItemManager from the character
|
||||
var _inventory = _template.GetComponent<vItemManager>();
|
||||
DestroyImmediate(_inventory as vItemManager, true);
|
||||
}
|
||||
|
||||
// load bones for the BodySnapControl
|
||||
var _bodySnap = _template.GetComponentInChildren<vBodySnappingControl>();
|
||||
_bodySnap.LoadBones();
|
||||
|
||||
UnityEditor.SceneView.lastActiveSceneView.FrameSelected();
|
||||
this.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02a4e7a48de713e4c9a33da11544a1c8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_PersistentViewDataDictionary: {instanceID: 0}
|
||||
- template: {fileID: 123100320241753025, guid: d9a4707ba2be96f49b3704765aafa732,
|
||||
type: 3}
|
||||
- inventory: {fileID: 3444320678111530354, guid: 3ae53b796aaabf94ba9bd40ed132f17d,
|
||||
type: 3}
|
||||
- itemListData: {fileID: 11400000, guid: 96e918a0f3173b14dbbbe08b7523b670, type: 2}
|
||||
- charObj: {fileID: 199726, guid: 5563b2c1cf35cae4f8490dfea2d2aa41, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Invector
|
||||
{
|
||||
// MELEE COMBAT FEATURES
|
||||
public partial class vMenuComponent
|
||||
{
|
||||
public const string path = "Invector/Melee Combat/Components/";
|
||||
|
||||
[MenuItem(path + "Melee Manager")]
|
||||
static void MeleeManagerMenu()
|
||||
{
|
||||
if (Selection.activeGameObject)
|
||||
Selection.activeGameObject.AddComponent<vMelee.vMeleeManager>();
|
||||
else
|
||||
Debug.Log("Please select a vCharacter to add the component.");
|
||||
}
|
||||
|
||||
[MenuItem(path + "WeaponHolderManager (Player Only)")]
|
||||
static void WeaponHolderMenu()
|
||||
{
|
||||
if (Selection.activeGameObject && Selection.activeGameObject.GetComponent<Invector.vCharacterController.vThirdPersonInput>() != null)
|
||||
Selection.activeGameObject.AddComponent<Invector.vItemManager.vWeaponHolderManager>();
|
||||
else
|
||||
Debug.Log("Please select the Player to add the component.");
|
||||
}
|
||||
|
||||
[MenuItem(path + "LockOn (Player Only)")]
|
||||
static void LockOnMenu()
|
||||
{
|
||||
if (Selection.activeGameObject && Selection.activeGameObject.GetComponent<Invector.vCharacterController.vThirdPersonInput>() != null)
|
||||
Selection.activeGameObject.AddComponent<vCharacterController.vLockOn>();
|
||||
else
|
||||
Debug.Log("Please select a Player to add the component.");
|
||||
}
|
||||
|
||||
[MenuItem(path + "DrawHide MeleeWeapons")]
|
||||
static void DrawMeleeWeaponMenu()
|
||||
{
|
||||
if (Selection.activeGameObject && Selection.activeGameObject.GetComponent<Invector.vCharacterController.vMeleeCombatInput>() != null)
|
||||
Selection.activeGameObject.AddComponent<vDrawHideMeleeWeapons>();
|
||||
else
|
||||
Debug.Log("Please select a Player to add the component.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff99e6ba5dc57ab43b12c4177a80f216
|
||||
timeCreated: 1495232492
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.vCharacterController
|
||||
{
|
||||
public class vBlockUnarmedAttack : MonoBehaviour
|
||||
{
|
||||
private vMeleeCombatInput meleeCombatInput;
|
||||
[SerializeField] protected bool useUnarmedAttack;
|
||||
public bool IsActiveUnarmedAttack
|
||||
{
|
||||
get
|
||||
{
|
||||
return useUnarmedAttack;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
useUnarmedAttack = value;
|
||||
}
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
///Get the melee combat input component
|
||||
meleeCombatInput = GetComponent<vMeleeCombatInput>();
|
||||
///Use update event of the input to handle attack input
|
||||
meleeCombatInput.onUpdate += HandleAttackInput;
|
||||
}
|
||||
|
||||
private void HandleAttackInput()
|
||||
{
|
||||
///Disable input usage if Unarmed
|
||||
if (!IsActiveUnarmedAttack)
|
||||
{
|
||||
meleeCombatInput.weakAttackInput.useInput = meleeCombatInput.isArmed;
|
||||
meleeCombatInput.strongAttackInput.useInput = meleeCombatInput.isArmed;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetActiveUnarmedAttack(bool value)
|
||||
{
|
||||
if (value != IsActiveUnarmedAttack)
|
||||
{
|
||||
IsActiveUnarmedAttack = value;
|
||||
meleeCombatInput.weakAttackInput.useInput = value;
|
||||
meleeCombatInput.strongAttackInput.useInput = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3186834037368c4bb284972a79d82c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,361 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.vCharacterController
|
||||
{
|
||||
using vEventSystems;
|
||||
using vMelee;
|
||||
|
||||
// here you can modify the Melee Combat inputs
|
||||
// if you want to modify the Basic Locomotion inputs, go to the vThirdPersonInput
|
||||
[vClassHeader("MELEE INPUT MANAGER", iconName = "inputIcon")]
|
||||
public class vMeleeCombatInput : vThirdPersonInput, vIMeleeFighter
|
||||
{
|
||||
#region Variables
|
||||
|
||||
[vEditorToolbar("Inputs")]
|
||||
[Header("Melee Inputs")]
|
||||
public GenericInput weakAttackInput = new GenericInput("Mouse0", "RB", "RB");
|
||||
public GenericInput strongAttackInput = new GenericInput("Alpha1", false, "RT", true, "RT", false);
|
||||
public GenericInput blockInput = new GenericInput("Mouse1", "LB", "LB");
|
||||
|
||||
internal vMeleeManager meleeManager;
|
||||
protected virtual bool _isAttacking { get; set; }
|
||||
public virtual bool isAttacking { get => _isAttacking || cc.IsAnimatorTag("Attack"); protected set { _isAttacking = value; } }
|
||||
public virtual bool isBlocking { get; protected set; }
|
||||
public virtual bool isArmed { get { return meleeManager != null && (meleeManager.rightWeapon != null || (meleeManager.leftWeapon != null && meleeManager.leftWeapon.meleeType != vMeleeType.OnlyDefense)); } }
|
||||
public virtual bool isEquipping { get; protected set; }
|
||||
|
||||
[HideInInspector]
|
||||
public bool lockMeleeInput;
|
||||
|
||||
public void SetLockMeleeInput(bool value)
|
||||
{
|
||||
lockMeleeInput = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
isAttacking = false;
|
||||
isBlocking = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetLockAllInput(bool value)
|
||||
{
|
||||
base.SetLockAllInput(value);
|
||||
SetLockMeleeInput(value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual bool lockInventory
|
||||
{
|
||||
get
|
||||
{
|
||||
return isAttacking || cc.isDead || cc.customAction || cc.isRolling;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
}
|
||||
|
||||
protected override void LateUpdate()
|
||||
{
|
||||
UpdateMeleeAnimations();
|
||||
base.LateUpdate();
|
||||
}
|
||||
|
||||
protected override void FixedUpdate()
|
||||
{
|
||||
base.FixedUpdate();
|
||||
}
|
||||
|
||||
public override void InputHandle()
|
||||
{
|
||||
if (cc == null || cc.isDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
base.InputHandle();
|
||||
|
||||
if (MeleeAttackConditions() && !lockMeleeInput)
|
||||
{
|
||||
MeleeWeakAttackInput();
|
||||
MeleeStrongAttackInput();
|
||||
BlockingInput();
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetAttackTriggers();
|
||||
isBlocking = false;
|
||||
}
|
||||
}
|
||||
|
||||
#region MeleeCombat Input Methods
|
||||
|
||||
/// <summary>
|
||||
/// WEAK ATK INPUT
|
||||
/// </summary>
|
||||
public virtual void MeleeWeakAttackInput()
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (weakAttackInput.GetButtonDown() && MeleeAttackStaminaConditions())
|
||||
{
|
||||
TriggerWeakAttack();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void TriggerWeakAttack()
|
||||
{
|
||||
animator.SetInteger(vAnimatorParameters.AttackID, AttackID);
|
||||
animator.SetTrigger(vAnimatorParameters.WeakAttack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// STRONG ATK INPUT
|
||||
/// </summary>
|
||||
public virtual void MeleeStrongAttackInput()
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (strongAttackInput.GetButtonDown() && (!meleeManager.CurrentActiveAttackWeapon || meleeManager.CurrentActiveAttackWeapon.useStrongAttack) && MeleeAttackStaminaConditions())
|
||||
{
|
||||
TriggerStrongAttack();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void TriggerStrongAttack()
|
||||
{
|
||||
animator.SetInteger(vAnimatorParameters.AttackID, AttackID);
|
||||
animator.SetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BLOCK INPUT
|
||||
/// </summary>
|
||||
public virtual void BlockingInput()
|
||||
{
|
||||
if (animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
isBlocking = blockInput.GetButton() && cc.currentStamina > 0 && !cc.customAction && !isAttacking;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override the Sprint method to cancel Sprinting when Attacking
|
||||
/// </summary>
|
||||
public override void SprintInput()
|
||||
{
|
||||
if (sprintInput.useInput)
|
||||
{
|
||||
bool canSprint = cc.useContinuousSprint ? sprintInput.GetButtonDown() : sprintInput.GetButton();
|
||||
cc.Sprint(canSprint && !isAttacking);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conditions
|
||||
|
||||
protected virtual bool MeleeAttackStaminaConditions()
|
||||
{
|
||||
var result = cc.currentStamina - meleeManager.GetAttackStaminaCost();
|
||||
return result >= 0;
|
||||
}
|
||||
|
||||
protected virtual bool MeleeAttackConditions()
|
||||
{
|
||||
if (meleeManager == null)
|
||||
{
|
||||
meleeManager = GetComponent<vMeleeManager>();
|
||||
}
|
||||
|
||||
return meleeManager != null && cc.isGrounded && !cc.customAction && !cc.isJumping && !cc.isCrouching && !cc.isRolling && !isEquipping && !animator.IsInTransition(cc.baseLayer);
|
||||
}
|
||||
|
||||
public override bool JumpConditions()
|
||||
{
|
||||
|
||||
return !isAttacking && base.JumpConditions();
|
||||
}
|
||||
|
||||
public override bool RollConditions()
|
||||
{
|
||||
return base.RollConditions() && !isAttacking && !animator.IsInTransition(cc.upperBodyLayer) && !animator.IsInTransition(cc.fullbodyLayer);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Update Animations
|
||||
|
||||
protected virtual void UpdateMeleeAnimations()
|
||||
{
|
||||
if (animator == null || meleeManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
animator.SetInteger(vAnimatorParameters.AttackID, AttackID);
|
||||
animator.SetInteger(vAnimatorParameters.DefenseID, DefenseID);
|
||||
animator.SetBool(vAnimatorParameters.IsBlocking, isBlocking);
|
||||
animator.SetFloat(vAnimatorParameters.MoveSet_ID, meleeMoveSetID, .2f, vTime.fixedDeltaTime);
|
||||
isEquipping = cc.IsAnimatorTag("IsEquipping");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default moveset id used when is without weapon
|
||||
/// </summary>
|
||||
public virtual int defaultMoveSetID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used to ignore the Weapon moveset id and use the <seealso cref="defaultMoveSetID"/>
|
||||
/// </summary>
|
||||
public virtual bool overrideWeaponMoveSetID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current moveset id based if is using weapon or not
|
||||
/// </summary>
|
||||
public virtual int meleeMoveSetID
|
||||
{
|
||||
get
|
||||
{
|
||||
int id = meleeManager.GetMoveSetID();
|
||||
if (id == 0 || overrideWeaponMoveSetID)
|
||||
{
|
||||
id = defaultMoveSetID;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ResetMeleeAnimations()
|
||||
{
|
||||
if (meleeManager == null || !animator)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
animator.SetBool(vAnimatorParameters.IsBlocking, false);
|
||||
}
|
||||
|
||||
public virtual int AttackID
|
||||
{
|
||||
get
|
||||
{
|
||||
return meleeManager ? meleeManager.GetAttackID() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int DefenseID
|
||||
{
|
||||
get
|
||||
{
|
||||
return meleeManager ? meleeManager.GetDefenseID() : 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Melee Methods
|
||||
|
||||
public virtual void OnEnableAttack()
|
||||
{
|
||||
if (meleeManager == null)
|
||||
{
|
||||
meleeManager = GetComponent<vMeleeManager>();
|
||||
}
|
||||
|
||||
if (meleeManager == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cc.currentStaminaRecoveryDelay = meleeManager.GetAttackStaminaRecoveryDelay();
|
||||
cc.currentStamina -= meleeManager.GetAttackStaminaCost();
|
||||
isAttacking = true;
|
||||
cc.isSprinting = false;
|
||||
}
|
||||
|
||||
public virtual void OnDisableAttack()
|
||||
{
|
||||
isAttacking = false;
|
||||
}
|
||||
|
||||
public virtual void ResetAttackTriggers()
|
||||
{
|
||||
animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
|
||||
public virtual void BreakAttack(int breakAtkID)
|
||||
{
|
||||
ResetAttackTriggers();
|
||||
OnRecoil(breakAtkID);
|
||||
}
|
||||
|
||||
public virtual void OnRecoil(int recoilID)
|
||||
{
|
||||
animator.SetInteger(vAnimatorParameters.RecoilID, recoilID);
|
||||
animator.SetTrigger(vAnimatorParameters.TriggerRecoil);
|
||||
animator.SetTrigger(vAnimatorParameters.ResetState);
|
||||
animator.ResetTrigger(vAnimatorParameters.WeakAttack);
|
||||
animator.ResetTrigger(vAnimatorParameters.StrongAttack);
|
||||
}
|
||||
|
||||
public virtual void OnReceiveAttack(vDamage damage, vIMeleeFighter attacker)
|
||||
{
|
||||
// character is blocking
|
||||
if (!damage.ignoreDefense && isBlocking && meleeManager != null && meleeManager.CanBlockAttack(damage.sender.position))
|
||||
{
|
||||
var damageReduction = meleeManager.GetDefenseRate();
|
||||
if (damageReduction > 0)
|
||||
{
|
||||
damage.ReduceDamage(damageReduction);
|
||||
}
|
||||
|
||||
if (attacker != null && meleeManager != null && meleeManager.CanBreakAttack())
|
||||
{
|
||||
attacker.BreakAttack(meleeManager.GetDefenseRecoilID());
|
||||
}
|
||||
|
||||
meleeManager.OnDefense();
|
||||
cc.currentStaminaRecoveryDelay = damage.staminaRecoveryDelay;
|
||||
cc.currentStamina -= damage.staminaBlockCost;
|
||||
}
|
||||
// apply damage
|
||||
damage.hitReaction = !isBlocking || damage.ignoreDefense;
|
||||
cc.TakeDamage(damage);
|
||||
}
|
||||
|
||||
public virtual vICharacter character
|
||||
{
|
||||
get { return cc; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
public static partial class vAnimatorParameters
|
||||
{
|
||||
public static int AttackID = Animator.StringToHash("AttackID");
|
||||
public static int DefenseID = Animator.StringToHash("DefenseID");
|
||||
public static int IsBlocking = Animator.StringToHash("IsBlocking");
|
||||
public static int MoveSet_ID = Animator.StringToHash("MoveSet_ID");
|
||||
public static int RecoilID = Animator.StringToHash("RecoilID");
|
||||
public static int TriggerRecoil = Animator.StringToHash("TriggerRecoil");
|
||||
public static int WeakAttack = Animator.StringToHash("WeakAttack");
|
||||
public static int StrongAttack = Animator.StringToHash("StrongAttack");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6422a02e39355444d9497a080cf1a955
|
||||
timeCreated: 1470415245
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e9bb6ba89c8fad47ad921c78711ce66
|
||||
folderAsset: yes
|
||||
timeCreated: 1529363021
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Invector.DefineSymbolsManager
|
||||
{
|
||||
public class MeleeDefineSymbols : InvectorDefineSymbols
|
||||
{
|
||||
public override List<string> GetSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return new List<string>() { "INVECTOR_MELEE" };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bff520e66e218be47ad807dcc619f00b
|
||||
timeCreated: 1529361259
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86d10117a83826041beb463286acd143
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
namespace Invector
|
||||
{
|
||||
public static partial class vAnimatorTags
|
||||
{
|
||||
[Tooltip("Use to identify Attack animations")]
|
||||
public const string Attack = "Attack";
|
||||
[Tooltip("Use to identify Equipping animations")]
|
||||
public const string IsEquipping = "IsEquipping";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ec2a56d2f97ab840838f514d6a89934
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 022e618184c7ac04888deec6962f9930
|
||||
folderAsset: yes
|
||||
timeCreated: 1454458092
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2e3f8cd2ef673047b4fc676d660590b
|
||||
folderAsset: yes
|
||||
timeCreated: 1498604789
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,81 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &126414
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 22467274}
|
||||
- component: {fileID: 22212822}
|
||||
- component: {fileID: 11417396}
|
||||
m_Layer: 5
|
||||
m_Name: lockOnSprite
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &11417396
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 126414}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_Sprite: {fileID: 21300000, guid: b10e654cb30db34489b832dbfbb54370, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
--- !u!222 &22212822
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 126414}
|
||||
--- !u!224 &22467274
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 126414}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 35, y: 35}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 126414}
|
||||
m_IsPrefabParent: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2c21a5084b380e45af41fac8083c307
|
||||
timeCreated: 1498604792
|
||||
licenseType: Store
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50296ec695effaf4482ddb9d93c64826
|
||||
folderAsset: yes
|
||||
timeCreated: 1498606747
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,88 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b10e654cb30db34489b832dbfbb54370
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 9
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 16
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 2
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 42396f0bf693e9c4d90c7ab35295ab9d
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,243 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.vCharacterController
|
||||
{
|
||||
[vClassHeader("MELEE LOCK-ON")]
|
||||
public class vLockOn : vLockOnBehaviour
|
||||
{
|
||||
#region variables
|
||||
[System.Serializable]
|
||||
public class LockOnEvent : UnityEngine.Events.UnityEvent<Transform> { }
|
||||
|
||||
[Tooltip("Make sure to disable or change the StrafeInput to a different key at the Player Input component")]
|
||||
public bool strafeWhileLockOn = true;
|
||||
[Tooltip("Create a Image inside the UI and assign here")]
|
||||
public RectTransform aimImagePrefab;
|
||||
public Canvas aimImageContainer;
|
||||
public Vector2 aimImageSize = new Vector2(30, 30);
|
||||
[Tooltip("True: Hide the sprite when not Lock On, False: Always show the Sprite")]
|
||||
public bool hideSprite = true;
|
||||
[Tooltip("Create a offset for the sprite based at the center of the target")]
|
||||
[Range(-0.5f, 0.5f)]
|
||||
public float spriteHeight = 0.25f;
|
||||
[Tooltip("Offset for the camera height")]
|
||||
public float cameraHeightOffset;
|
||||
[Tooltip("Transition Speed for the Camera")]
|
||||
public float lockSpeed = 0.5f;
|
||||
[Header("LockOn Inputs")]
|
||||
public GenericInput lockOnInput = new GenericInput("Tab", "RightStickClick", "RightStickClick");
|
||||
public GenericInput nexTargetInput = new GenericInput("X", false, false, "RightAnalogHorizontal", true, false, "X", false, false);
|
||||
public GenericInput previousTargetInput = new GenericInput("Z", false, false, "RightAnalogHorizontal", true, true, "Z", false, false);
|
||||
|
||||
internal bool isLockingOn;
|
||||
public LockOnEvent onLockOnTarget;
|
||||
public LockOnEvent onUnLockOnTarget;
|
||||
protected Canvas _aimCanvas;
|
||||
protected RectTransform _aimImage;
|
||||
|
||||
protected bool _inTarget;
|
||||
protected virtual bool inTarget { get { return _inTarget; } set { _inTarget = value; } }
|
||||
protected vThirdPersonInput tpInput;
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
Init();
|
||||
|
||||
tpInput = GetComponent<vThirdPersonInput>();
|
||||
if (tpInput)
|
||||
{
|
||||
tpInput.onUpdate -= UpdateLockOn;
|
||||
tpInput.onUpdate += UpdateLockOn;
|
||||
|
||||
// access the HealthController to Reset the LockOn when Dead
|
||||
GetComponent<vHealthController>().onDead.AddListener((GameObject g) =>
|
||||
{
|
||||
// action to reset lockOn
|
||||
isLockingOn = false;
|
||||
LockOn(false);
|
||||
UpdateLockOn();
|
||||
});
|
||||
}
|
||||
|
||||
if (!aimImageContainer)
|
||||
{
|
||||
aimImageContainer = gameObject.GetComponentInChildren<Canvas>(true);
|
||||
}
|
||||
}
|
||||
|
||||
public RectTransform aimImage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_aimImage) return _aimImage;
|
||||
if (aimImageContainer)
|
||||
{
|
||||
_aimImage = Instantiate(aimImagePrefab, Vector2.zero, Quaternion.identity) as RectTransform;
|
||||
_aimImage.SetParent(aimImageContainer.transform);
|
||||
return _aimImage;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("Missing UI Canvas in the scene, please add one");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateLockOn()
|
||||
{
|
||||
if (this.tpInput == null) return;
|
||||
LockOnInput();
|
||||
SwitchTargetsInput();
|
||||
CheckForTargetDistance();
|
||||
CheckForCharacterAlive();
|
||||
UpdateAimImage();
|
||||
}
|
||||
|
||||
protected virtual void LockOnInput()
|
||||
{
|
||||
if (tpInput.tpCamera == null || tpInput.cc == null) return;
|
||||
|
||||
// lock the camera into a target, if there is any around
|
||||
if (lockOnInput.GetButtonDown() && !tpInput.cc.customAction)
|
||||
{
|
||||
isLockingOn = !isLockingOn;
|
||||
LockOn(isLockingOn);
|
||||
}
|
||||
// unlock the camera if the target is null
|
||||
else if (isLockingOn && (tpInput.tpCamera.lockTarget == null) || LostTargetDistance())
|
||||
{
|
||||
isLockingOn = false;
|
||||
LockOn(false);
|
||||
}
|
||||
// choose to use lock-on with strafe of free movement
|
||||
if (strafeWhileLockOn && !tpInput.cc.locomotionType.Equals(vThirdPersonMotor.LocomotionType.OnlyStrafe))
|
||||
{
|
||||
if (isLockingOn && tpInput.tpCamera.lockTarget != null)
|
||||
{
|
||||
tpInput.cc.lockInStrafe = true;
|
||||
tpInput.cc.isStrafing = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tpInput.cc.lockInStrafe = false;
|
||||
tpInput.cc.isStrafing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool LostTargetDistance()
|
||||
{
|
||||
if (!isLockingOn || currentTarget == null) return false;
|
||||
|
||||
float distance = Vector3.Distance(transform.position, currentTarget.position);
|
||||
|
||||
return distance > rangeToExitLockOn ? true : false;
|
||||
}
|
||||
|
||||
protected override void SetTarget()
|
||||
{
|
||||
if (tpInput.tpCamera != null)
|
||||
{
|
||||
tpInput.tpCamera.SetLockTarget(currentTarget.transform, cameraHeightOffset, lockSpeed);
|
||||
onLockOnTarget.Invoke(currentTarget);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SwitchTargetsInput()
|
||||
{
|
||||
if (tpInput.tpCamera == null) return;
|
||||
|
||||
if (tpInput.tpCamera.lockTarget)
|
||||
{
|
||||
// switch between targets using Keyboard
|
||||
if (previousTargetInput.GetButtonDown()) PreviousTarget();
|
||||
else if (nexTargetInput.GetButtonDown()) NextTarget();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckForTargetDistance()
|
||||
{
|
||||
if (!isLockingOn || currentTarget == null) return;
|
||||
|
||||
float distance = Vector3.Distance(transform.position, currentTarget.position);
|
||||
|
||||
if (distance > rangeToExitLockOn)
|
||||
{
|
||||
isLockingOn = false;
|
||||
LockOn(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CheckForCharacterAlive()
|
||||
{
|
||||
if (currentTarget && !isCharacterAlive() && inTarget || (inTarget && !isCharacterAlive()))
|
||||
{
|
||||
ResetLockOn();
|
||||
inTarget = false;
|
||||
LockOn(true);
|
||||
StopLockOn();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void LockOn(bool value)
|
||||
{
|
||||
base.UpdateLockOn(value);
|
||||
if (!inTarget && currentTarget)
|
||||
{
|
||||
inTarget = true;
|
||||
// send current target if inTarget
|
||||
SetTarget();
|
||||
}
|
||||
else if (inTarget && !currentTarget)
|
||||
{
|
||||
inTarget = false;
|
||||
// send message to clear current target
|
||||
StopLockOn();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateAimImage()
|
||||
{
|
||||
if (!aimImageContainer || !aimImage) return;
|
||||
if (hideSprite)
|
||||
{
|
||||
aimImage.sizeDelta = aimImageSize;
|
||||
if (currentTarget && !aimImage.transform.gameObject.activeSelf && isCharacterAlive())
|
||||
aimImage.transform.gameObject.SetActive(true);
|
||||
else if (!currentTarget && aimImage.transform.gameObject.activeSelf)
|
||||
aimImage.transform.gameObject.SetActive(false);
|
||||
else if (_aimImage.transform.gameObject.activeSelf && !isCharacterAlive())
|
||||
aimImage.transform.gameObject.SetActive(false);
|
||||
}
|
||||
if (currentTarget && aimImage && aimImageContainer)
|
||||
aimImage.anchoredPosition = currentTarget.GetScreenPointOffBoundsCenter(aimImageContainer, tpCamera.targetCamera, spriteHeight);
|
||||
else if (aimImageContainer)
|
||||
aimImage.anchoredPosition = Vector2.zero;
|
||||
}
|
||||
|
||||
public virtual void StopLockOn()
|
||||
{
|
||||
if (currentTarget == null && tpInput.tpCamera != null)
|
||||
{
|
||||
onUnLockOnTarget.Invoke(tpInput.tpCamera.lockTarget);
|
||||
tpInput.tpCamera.RemoveLockTarget();
|
||||
isLockingOn = false;
|
||||
inTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void NextTarget()
|
||||
{
|
||||
base.ChangeTarget(1);
|
||||
}
|
||||
|
||||
public virtual void PreviousTarget()
|
||||
{
|
||||
base.ChangeTarget(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47c91cac344662340bbbedbdbed00328
|
||||
timeCreated: 1498605023
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- aimImagePrefab: {fileID: 22467274, guid: f2c21a5084b380e45af41fac8083c307, type: 2}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,461 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.vCharacterController
|
||||
{
|
||||
[vClassHeader("Lock-On")]
|
||||
public abstract class vLockOnBehaviour : vMonoBehaviour
|
||||
{
|
||||
#region properties
|
||||
|
||||
protected Transform watcher;
|
||||
[Tooltip("Tags of objects that can be found")]
|
||||
public string[] tagsToFind = new string[] { "Enemy" };
|
||||
[Tooltip("Check this option to only Lock into target within the camera field of view")]
|
||||
public bool withinCameraView = true;
|
||||
[vHideInInspector("withinCameraView"), Tooltip("Get only target inside screen margins")]
|
||||
public bool onlyInsideRect = true;
|
||||
[Tooltip("Layer of Obstacle to prevent the find for targets")]
|
||||
public LayerMask layerOfObstacles = 1 << 0;
|
||||
[Range(0, 1)]
|
||||
[Tooltip("Use this to set a margin of Aim point ")]
|
||||
public float screenMarginX = 0.8f;
|
||||
[Range(0, 1)]
|
||||
[Tooltip("Use this to set a margin of Aim point ")]
|
||||
public float screenMarginY = 0.1f;
|
||||
[Tooltip("Range of the search for targets")]
|
||||
public float rangeToEnterLockOn = 10f;
|
||||
[Tooltip("Range to auto exit lock")]
|
||||
public float rangeToExitLockOn = 15f;
|
||||
[Tooltip("Show the Gizmos and helpers")]
|
||||
public bool showDebug;
|
||||
public float timeToChangeTarget = 0.25f;
|
||||
|
||||
protected int index = 0;
|
||||
protected List<Transform> visibles;
|
||||
protected Transform _target;
|
||||
protected virtual Transform target { get { return _target; } set { _target = value; } }
|
||||
protected vCamera.vThirdPersonCamera tpCamera;
|
||||
protected Rect rect;
|
||||
protected bool _inLockOn;
|
||||
protected bool changingTarget;
|
||||
|
||||
#endregion
|
||||
|
||||
#region public methods
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
if (rangeToExitLockOn < rangeToEnterLockOn) rangeToExitLockOn = rangeToEnterLockOn;
|
||||
}
|
||||
/// <summary>
|
||||
/// change the current target to next target of possibles target
|
||||
/// if exist more than 1 target in list
|
||||
/// </summary>
|
||||
public virtual void ChangeTarget(int value)
|
||||
{
|
||||
StartCoroutine(ChangeTargetRoutine(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get current target
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual Transform currentTarget
|
||||
{
|
||||
get { return target; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if Current target(vIHealthController) is Alive
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool isCharacterAlive()
|
||||
{
|
||||
if (currentTarget == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var healthController = currentTarget.GetComponent<vIHealthController>();
|
||||
if (healthController == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//if (ichar.ragdolled) return false;
|
||||
if (healthController.currentHealth > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if target is a vIHealthController Alive
|
||||
/// </summary>
|
||||
/// <param name="other">target</param>
|
||||
/// <returns></returns>
|
||||
public virtual bool isCharacterAlive(Transform other)
|
||||
{
|
||||
var healthController = other.GetComponent<vIHealthController>();
|
||||
if (healthController == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//if (ichar.ragdolled) return false;
|
||||
if (healthController.currentHealth > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset Lock on (removing currentTarget)
|
||||
/// </summary>
|
||||
public virtual void ResetLockOn()
|
||||
{
|
||||
target = null;
|
||||
_inLockOn = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all target possibles
|
||||
/// </summary>
|
||||
public virtual List<Transform> allTargets
|
||||
{
|
||||
get { if (visibles != null && visibles.Count > 0) { return visibles; } return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region protected methods
|
||||
|
||||
protected virtual void UpdateLockOn(bool value)
|
||||
{
|
||||
if (value == true && value != _inLockOn)
|
||||
{
|
||||
_inLockOn = value;
|
||||
visibles = GetPossibleTargets();
|
||||
index = 0;
|
||||
if (visibles != null && visibles.Count > 0)
|
||||
{
|
||||
target = visibles[index];
|
||||
}
|
||||
}
|
||||
else if (value == false && value != _inLockOn)
|
||||
{
|
||||
_inLockOn = value;
|
||||
index = 0;
|
||||
target = null;
|
||||
if (visibles != null)
|
||||
{
|
||||
visibles.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerator ChangeTargetRoutine(int value)
|
||||
{
|
||||
if (!changingTarget)
|
||||
{
|
||||
changingTarget = true;
|
||||
visibles = GetPossibleTargets();
|
||||
if ((_inLockOn == true && visibles != null && visibles.Count > 1))
|
||||
{
|
||||
if (index + value > visibles.Count - 1)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index + value < 0)
|
||||
{
|
||||
index = visibles.Count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
index += value;
|
||||
}
|
||||
|
||||
target = visibles[index];
|
||||
SetTarget();
|
||||
}
|
||||
yield return new WaitForSeconds(timeToChangeTarget);
|
||||
changingTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void SetTarget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw GUI of Rect
|
||||
/// </summary>
|
||||
protected void OnGUI()
|
||||
{
|
||||
if (showDebug)
|
||||
{
|
||||
var width = Screen.width - (Screen.width * screenMarginX);
|
||||
var height = Screen.height - (Screen.height * screenMarginY);
|
||||
var posX = (Screen.width * 0.5f) - (width * 0.5f);
|
||||
var posY = (Screen.height * 0.5f) - (height * 0.5f);
|
||||
rect = new Rect(posX, posY, width, height);
|
||||
GUI.Box(rect, "");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init the properts
|
||||
/// </summary>
|
||||
protected void Init()
|
||||
{
|
||||
if (Camera.main == null)
|
||||
{
|
||||
this.enabled = false;
|
||||
}
|
||||
|
||||
tpCamera = Camera.main.transform.root.GetComponent<vCamera.vThirdPersonCamera>();
|
||||
var width = Screen.width - (Screen.width * screenMarginX);
|
||||
var height = Screen.height - (Screen.height * screenMarginY);
|
||||
var posX = (Screen.width * 0.5f) - (width * 0.5f);
|
||||
var posY = (Screen.height * 0.5f) - (height * 0.5f);
|
||||
rect = new Rect(posX, posY, width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the range gizmo
|
||||
/// </summary>
|
||||
protected void OnDrawGizmos()
|
||||
{
|
||||
if (showDebug && watcher)
|
||||
{
|
||||
Gizmos.color = new Color(0, 1, 0, 0.2f);
|
||||
Gizmos.DrawSphere(watcher.position, rangeToEnterLockOn + 0.1f);
|
||||
if (visibles != null && visibles.Count > 0 && target != null)
|
||||
{
|
||||
visibles.ForEach(delegate (Transform _transform)
|
||||
{
|
||||
Gizmos.color = _transform.Equals(currentTarget) ? Color.red : Color.yellow;
|
||||
Gizmos.DrawSphere(_transform.GetComponent<Collider>().bounds.center, .5f);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// get all possible targets
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual List<Transform> GetPossibleTargets()
|
||||
{
|
||||
if (tpCamera != null && tpCamera.mainTarget != null)
|
||||
{
|
||||
watcher = tpCamera.mainTarget;
|
||||
}
|
||||
else
|
||||
{
|
||||
watcher = transform;
|
||||
}
|
||||
|
||||
var listPrimary = new List<Transform>();
|
||||
var targets = Physics.SphereCastAll(watcher.position, rangeToEnterLockOn, watcher.forward, .01f);
|
||||
for (int i = 0; i < targets.Length; i++)
|
||||
{
|
||||
var hitOther = targets[i];
|
||||
if (tagsToFind.Contains(hitOther.transform.tag))
|
||||
{
|
||||
if (isCharacterAlive(hitOther.transform.GetComponent<Transform>()))
|
||||
{
|
||||
RaycastHit hit;
|
||||
var boundPoints = BoundPoints(hitOther.collider);
|
||||
for (int a = 0; a < boundPoints.Length; a++)
|
||||
{
|
||||
var point = boundPoints[a];
|
||||
if (Physics.Linecast(transform.position, point, out hit, layerOfObstacles))
|
||||
{
|
||||
if (hit.transform == hitOther.transform)
|
||||
{
|
||||
listPrimary.Add(hitOther.transform);
|
||||
|
||||
if (showDebug)
|
||||
{
|
||||
Debug.DrawLine(transform.position, point, Color.green, 2);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (showDebug)
|
||||
{
|
||||
Debug.DrawLine(transform.position, point, Color.red, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
listPrimary.Add(hitOther.transform);
|
||||
|
||||
if (showDebug)
|
||||
{
|
||||
Debug.DrawLine(transform.position, point, Color.green, 2);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SortTargets(ref listPrimary);
|
||||
return listPrimary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort the targets of possible targets by order of priority
|
||||
/// </summary>
|
||||
/// <param name="list"></param>
|
||||
protected void SortTargets(ref List<Transform> list)
|
||||
{
|
||||
if (tpCamera == null || tpCamera.targetCamera)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
var lpriority_01 = new List<Transform>();
|
||||
var lpriority_02 = new List<Transform>();
|
||||
var lpriority_03 = new List<Transform>();
|
||||
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(tpCamera.targetCamera);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
var _transform = list[i];
|
||||
Vector2 screenPoint = tpCamera.targetCamera.WorldToScreenPoint(_transform.transform.position);
|
||||
//Check targets inside camera frustum
|
||||
if (GeometryUtility.TestPlanesAABB(planes, _transform.GetComponent<Collider>().bounds))
|
||||
{
|
||||
//target inside screenRect with margins
|
||||
if (rect.Contains(screenPoint))
|
||||
{
|
||||
lpriority_01.Add(_transform);
|
||||
}
|
||||
//targets only inside camera frustum
|
||||
else if (withinCameraView == false || (withinCameraView && !onlyInsideRect))
|
||||
{
|
||||
lpriority_02.Add(_transform);
|
||||
}
|
||||
}
|
||||
//targets outside camera frustum
|
||||
else if (withinCameraView == false)
|
||||
{
|
||||
lpriority_03.Add(_transform);
|
||||
}
|
||||
}
|
||||
|
||||
//targets only inside camera frustum
|
||||
//Order by screen center distance
|
||||
lpriority_01.Sort(delegate (Transform t1, Transform t2)
|
||||
{
|
||||
Vector2 screenPoint_01 = tpCamera.targetCamera.WorldToScreenPoint(t1.transform.position);
|
||||
Vector2 screenPoint_02 = tpCamera.targetCamera.WorldToScreenPoint(t2.transform.position);
|
||||
return Vector2.Distance(screenPoint_01, rect.center)
|
||||
.CompareTo(Vector2.Distance(screenPoint_02, rect.center));
|
||||
});
|
||||
//targets only inside camera frustum
|
||||
//Order by screen center distance
|
||||
lpriority_02.Sort(delegate (Transform t1, Transform t2)
|
||||
{
|
||||
Vector2 screenPoint_01 = tpCamera.targetCamera.WorldToScreenPoint(t1.transform.position);
|
||||
Vector2 screenPoint_02 = tpCamera.targetCamera.WorldToScreenPoint(t2.transform.position);
|
||||
return Vector2.Distance(screenPoint_01, rect.center)
|
||||
.CompareTo(Vector2.Distance(screenPoint_02, rect.center));
|
||||
});
|
||||
//targets outside camera frustum
|
||||
//Order by character distance
|
||||
lpriority_03.Sort(delegate (Transform t1, Transform t2)
|
||||
{
|
||||
return Vector3.Distance(t1.transform.position, transform.position)
|
||||
.CompareTo(Vector3.Distance(t2.transform.position, transform.position));
|
||||
});
|
||||
|
||||
list = lpriority_01.Union(lpriority_02).Union(lpriority_03).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return 8 bound points
|
||||
/// </summary>
|
||||
/// <param name="collider"></param>
|
||||
/// <returns></returns>
|
||||
protected Vector3[] BoundPoints(Collider collider)
|
||||
{
|
||||
var boundPoint1 = collider.bounds.min;
|
||||
var boundPoint2 = collider.bounds.max;
|
||||
var boundPoint3 = new Vector3(boundPoint1.x, boundPoint1.y, boundPoint2.z);
|
||||
var boundPoint4 = new Vector3(boundPoint1.x, boundPoint2.y, boundPoint1.z);
|
||||
var boundPoint5 = new Vector3(boundPoint2.x, boundPoint1.y, boundPoint1.z);
|
||||
var boundPoint6 = new Vector3(boundPoint1.x, boundPoint2.y, boundPoint2.z);
|
||||
var boundPoint7 = new Vector3(boundPoint2.x, boundPoint1.y, boundPoint2.z);
|
||||
var boundPoint8 = new Vector3(boundPoint2.x, boundPoint2.y, boundPoint1.z);
|
||||
var lineColor = Color.white;
|
||||
if (showDebug)
|
||||
{
|
||||
Debug.DrawLine(boundPoint6, boundPoint2, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint2, boundPoint8, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint8, boundPoint4, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint4, boundPoint6, lineColor, 1);
|
||||
// bottom of rectangular cuboid (3-7-5-1)
|
||||
Debug.DrawLine(boundPoint3, boundPoint7, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint7, boundPoint5, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint5, boundPoint1, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint1, boundPoint3, lineColor, 1);
|
||||
// legs (6-3, 2-7, 8-5, 4-1)
|
||||
Debug.DrawLine(boundPoint6, boundPoint3, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint2, boundPoint7, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint8, boundPoint5, lineColor, 1);
|
||||
Debug.DrawLine(boundPoint4, boundPoint1, lineColor, 1);
|
||||
}
|
||||
return new Vector3[] { boundPoint1, boundPoint2, boundPoint3, boundPoint4, boundPoint5, boundPoint6, boundPoint7, boundPoint8 };
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extencions for Help
|
||||
/// </summary>
|
||||
public static class vLockOnHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Get point of Target relative to Screen
|
||||
/// </summary>
|
||||
/// <param name="canvas"></param>
|
||||
/// <param name="targetPoint"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector2 GetScreenPointOffBoundsCenter(this Transform target, Canvas canvas, Camera cam, float _heightOffset)
|
||||
{
|
||||
var bounds = target.GetComponent<Collider>().bounds;
|
||||
var middle = bounds.center;
|
||||
var height = Vector3.Distance(bounds.min, bounds.max);
|
||||
|
||||
var point = middle + new Vector3(0, height * _heightOffset, 0);
|
||||
var rectTransform = canvas.transform as RectTransform;
|
||||
Vector2 ViewportPosition = cam.WorldToViewportPoint(point);
|
||||
Vector2 WorldObject_ScreenPosition = new Vector2(
|
||||
((ViewportPosition.x * rectTransform.sizeDelta.x) - (rectTransform.sizeDelta.x * 0.5f)),
|
||||
((ViewportPosition.y * rectTransform.sizeDelta.y) - (rectTransform.sizeDelta.y * 0.5f)));
|
||||
return WorldObject_ScreenPosition;
|
||||
}
|
||||
|
||||
public static Vector3 GetPointOffBoundsCenter(this Transform target, float _heightOffset)
|
||||
{
|
||||
var bounds = target.GetComponent<Collider>().bounds;
|
||||
var middle = bounds.center;
|
||||
var height = Vector3.Distance(bounds.min, bounds.max);
|
||||
|
||||
var point = middle + new Vector3(0, height * _heightOffset, 0);
|
||||
return point;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c54e41770d685f6418baa45eb8094332
|
||||
timeCreated: 1449791105
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e77fcb627033384e9c57edab1ab470b
|
||||
folderAsset: yes
|
||||
timeCreated: 1471705431
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d775d620143e8b349bb13648c1a96e29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 179104b96df266e4bb6d05725f7adbfd
|
||||
folderAsset: yes
|
||||
timeCreated: 1470444425
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e791ec4782e265840a301c30985e4b36
|
||||
timeCreated: 1467828935
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92e130449b49ea045beeef72f43fea62
|
||||
timeCreated: 1475778971
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac553591bf57eaf409b797cee1d1e145
|
||||
timeCreated: 1470411358
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f3c392a89026a3409419ffb5d7baa2d
|
||||
timeCreated: 1470947572
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8ba06614993aa3418fcd2e6bc09bd15
|
||||
timeCreated: 1470764862
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 105ebe27587ce1f49b2f0a3abc6e1212
|
||||
timeCreated: 1483988962
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b164d939286a4b429909f275c09452d
|
||||
timeCreated: 1483988962
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f34e1a96446b0d4b9761d0208d6026e
|
||||
timeCreated: 1487018391
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9273a5d06bc34a419fda6f3e81da1e2
|
||||
timeCreated: 1487018582
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b94e6105bcb8ba743ab7041e1b64c593
|
||||
timeCreated: 1529518809
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb97f58541b05b24ab37661346298ff2
|
||||
timeCreated: 1470329607
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00cc2b820c1fe174082aa779f79cb540
|
||||
timeCreated: 1475624836
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Invector.vEventSystems
|
||||
{
|
||||
public interface vIAttackListener
|
||||
{
|
||||
void OnEnableAttack();
|
||||
|
||||
void OnDisableAttack();
|
||||
|
||||
void ResetAttackTriggers();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 226f8db32d72b044cbdb1775783c5958
|
||||
timeCreated: 1529517796
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Invector.vEventSystems
|
||||
{
|
||||
public interface vIAttackReceiver
|
||||
{
|
||||
void OnReceiveAttack(vDamage damage, vIMeleeFighter attacker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 171cab8700dd703409c074ae54f09270
|
||||
timeCreated: 1529517618
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac63b5b29df38024dbb34ba7a5db4483
|
||||
timeCreated: 1529517788
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9058122f6ec699438581f28f117350d
|
||||
timeCreated: 1470332631
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0befb9e9384ab34d9dfc9d3cabf04b3
|
||||
timeCreated: 1470333665
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b02b25f3302cf04fb8e4a1a80f0b12e
|
||||
timeCreated: 1525812721
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c11b181c688f7664aba8ba5b38942ac9
|
||||
timeCreated: 1470329607
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ebe2ea9c9ea0544d84d9c27f7470915
|
||||
timeCreated: 1470329607
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2940e852eb9b874798e470ed9ebf5c3
|
||||
timeCreated: 1495128674
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ec807b121fb8d94e8a2c5d76766cdc4
|
||||
timeCreated: 1535635580
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb97c25f7f28c3d45a20a46d1869b8f5
|
||||
folderAsset: yes
|
||||
timeCreated: 1473464692
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfc844e049912c94fac4a37288ff4c71
|
||||
folderAsset: yes
|
||||
timeCreated: 1457710603
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,560 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Invector.vCharacterController.AI
|
||||
{
|
||||
[CustomEditor(typeof(vWaypointArea))]
|
||||
[CanEditMultipleObjects]
|
||||
[InitializeOnLoad]
|
||||
public class vWaypointAreaEditor : UnityEditor.Editor
|
||||
{
|
||||
public vWaypoint currentNode;
|
||||
public vWaypointArea pathArea;
|
||||
public SerializedObject _wayArea;
|
||||
public int indexOfWaypoint;
|
||||
public SerializedProperty editMode;
|
||||
public GUISkin skin;
|
||||
public int indexOfPatrolPoint;
|
||||
public bool hotKeys;
|
||||
public bool isPlaying;
|
||||
public Tool tool;
|
||||
private Texture2D m_Logo = null;
|
||||
|
||||
#if INVECTOR_AI_TEMPLATE
|
||||
[MenuItem("GameObject/Invector/FSM AI/New Waypoint Area", false, -100)]
|
||||
[MenuItem("Invector/FSM AI/Components/New Waypoint Area")]
|
||||
static void NewWaypointArea()
|
||||
{
|
||||
var wp = new GameObject("WaypointArea", typeof(vWaypointArea));
|
||||
|
||||
SceneView view = SceneView.lastActiveSceneView;
|
||||
if (SceneView.lastActiveSceneView == null)
|
||||
throw new UnityException("The Scene View can't be access");
|
||||
|
||||
Vector3 spawnPos = view.camera.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 10f));
|
||||
wp.transform.position = spawnPos;
|
||||
}
|
||||
#endif
|
||||
[MenuItem("Invector/Melee Combat/Components/New Waypoint Area")]
|
||||
static void MeleeNewWaypointArea()
|
||||
{
|
||||
var wp = new GameObject("WaypointArea", typeof(vWaypointArea));
|
||||
|
||||
SceneView view = SceneView.lastActiveSceneView;
|
||||
if (SceneView.lastActiveSceneView == null)
|
||||
throw new UnityException("The Scene View can't be access");
|
||||
|
||||
Vector3 spawnPos = view.camera.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 10f));
|
||||
wp.transform.position = spawnPos;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Logo = (Texture2D)Resources.Load("icon_v2", typeof(Texture2D));
|
||||
tool = Tools.current;
|
||||
pathArea = (vWaypointArea)target;
|
||||
editMode = serializedObject.FindProperty("editMode");
|
||||
if (pathArea.waypoints == null)
|
||||
pathArea.waypoints = new List<vWaypoint>();
|
||||
if (pathArea.waypoints.Count > 0)
|
||||
currentNode = pathArea.waypoints[0];
|
||||
SetVisiblePoints(editMode.boolValue);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
SetVisiblePoints(editMode.boolValue);
|
||||
}
|
||||
|
||||
void OnSceneGUI()
|
||||
{
|
||||
if (!pathArea) return;
|
||||
CheckNodes(ref pathArea.waypoints);
|
||||
|
||||
Event e = Event.current;
|
||||
if (editMode.boolValue)
|
||||
{
|
||||
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
|
||||
|
||||
if (e.type == EventType.MouseDown && e.button == 0 && e.shift)
|
||||
{
|
||||
Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hitInfo;
|
||||
if (Physics.Raycast(worldRay, out hitInfo, Mathf.Infinity))
|
||||
{
|
||||
CreateNode(pathArea, hitInfo.point);
|
||||
EditorUtility.SetDirty(pathArea);
|
||||
}
|
||||
}
|
||||
else if (e.type == EventType.MouseDown && e.button == 0 && e.control && currentNode)
|
||||
{
|
||||
Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hitInfo;
|
||||
if (Physics.Raycast(worldRay, out hitInfo, Mathf.Infinity))
|
||||
{
|
||||
CreatePatrolPoint(pathArea, hitInfo.point);
|
||||
EditorUtility.SetDirty(pathArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
|
||||
|
||||
if (editMode.boolValue)
|
||||
Handles.color = Color.white;
|
||||
else
|
||||
Handles.color = new Color(1, 1, 1, 0.2f);
|
||||
|
||||
if (pathArea.waypoints.Count > 0)
|
||||
{
|
||||
var node0 = pathArea.waypoints[0];
|
||||
foreach (vWaypoint node in pathArea.waypoints)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
if (editMode.boolValue && currentNode != null)
|
||||
Handles.color = node.isValid ? (currentNode.Equals(node) ? Color.green : Color.white) : Color.red;
|
||||
if (node.rotateTo)
|
||||
{
|
||||
var color = Handles.color;
|
||||
Handles.color = editMode.boolValue && currentNode == node ? Color.blue : new Color(1, 1, 1, 0.2f);
|
||||
Handles.ArrowHandleCap(0, node.transform.position, node.transform.rotation, 1f, EventType.Repaint);
|
||||
Handles.color = color;
|
||||
}
|
||||
if (!editMode.boolValue)
|
||||
Handles.SphereHandleCap(0, node.transform.position, Quaternion.identity, 0.25f, EventType.Repaint);
|
||||
else if (Handles.Button(node.transform.position, Quaternion.identity, currentNode ? (currentNode == node ? .25f : 0.15f) : .25f, currentNode ? (currentNode == node ? .25f : 0.15f) : .25f, Handles.SphereHandleCap))
|
||||
{
|
||||
indexOfWaypoint = pathArea.waypoints.IndexOf(node);
|
||||
currentNode = node;
|
||||
indexOfPatrolPoint = 0;
|
||||
Repaint();
|
||||
}
|
||||
|
||||
if (editMode.boolValue)
|
||||
Handles.color = new Color(0, 0, 1, .2f);
|
||||
|
||||
Handles.DrawLine(node0.transform.position, node.transform.position);
|
||||
node0 = node;
|
||||
var index = pathArea.waypoints.IndexOf(node) + 1;
|
||||
|
||||
if (currentNode == null || !currentNode.Equals(node))
|
||||
{
|
||||
Handles.Label(node.transform.position, new GUIContent("WP-" + index.ToString("00")));
|
||||
if (node.subPoints != null && node.subPoints.Count > 0)
|
||||
{
|
||||
var patrolPoint0 = node.subPoints[0];
|
||||
Handles.DrawLine(node.transform.position, patrolPoint0.position);
|
||||
foreach (vPoint patrolPoint in node.subPoints)
|
||||
{
|
||||
if (patrolPoint != null)
|
||||
{
|
||||
Handles.DrawLine(patrolPoint0.transform.position, patrolPoint.position);
|
||||
patrolPoint0 = patrolPoint;
|
||||
Handles.CubeHandleCap(0, patrolPoint.transform.position, Quaternion.identity, 0.15f, EventType.Repaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Handles.color = Color.white;
|
||||
if (currentNode && editMode.boolValue)
|
||||
{
|
||||
currentNode.transform.position = Handles.DoPositionHandle(currentNode.transform.position, currentNode.transform.rotation);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var position = Handles.Slider(currentNode.transform.position - (currentNode.transform.forward * currentNode.areaRadius), -currentNode.transform.forward, 0.1f, Handles.CubeHandleCap, 0.1f);
|
||||
var dist = Vector3.Distance(currentNode.transform.position, position);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RecordObject(currentNode, "Change Look At Target Position");
|
||||
currentNode.areaRadius = dist;
|
||||
}
|
||||
Handles.Label(currentNode.transform.position - (currentNode.transform.forward * currentNode.areaRadius), dist.ToString("0.00"));
|
||||
|
||||
if (currentNode.rotateTo)
|
||||
{
|
||||
Handles.color = Color.blue;
|
||||
currentNode.transform.rotation = Handles.Disc(currentNode.transform.rotation, currentNode.transform.position, Vector3.up, .9f, true, 0.1f);
|
||||
}
|
||||
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawWireDisc(currentNode.transform.position, Vector3.up, currentNode.areaRadius);
|
||||
e = Event.current;
|
||||
if (e.type == EventType.MouseDown && e.button == 1 && e.shift)
|
||||
{
|
||||
Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hitInfo;
|
||||
if (Physics.Raycast(worldRay, out hitInfo, Mathf.Infinity))
|
||||
{
|
||||
currentNode.transform.position = hitInfo.point;
|
||||
EditorUtility.SetDirty(pathArea);
|
||||
}
|
||||
}
|
||||
if (currentNode.subPoints == null) currentNode.subPoints = new List<vPoint>();
|
||||
if (currentNode.subPoints.Count > 0)
|
||||
{
|
||||
var patrolPoint0 = currentNode.subPoints[0];
|
||||
|
||||
Handles.color = Color.cyan;
|
||||
Handles.DrawLine(currentNode.transform.position, patrolPoint0.position);
|
||||
foreach (vPoint patrolPoint in currentNode.subPoints)
|
||||
{
|
||||
Handles.color = Color.cyan;
|
||||
Handles.DrawLine(patrolPoint0.transform.position, patrolPoint.position);
|
||||
patrolPoint0 = patrolPoint;
|
||||
var index = currentNode.subPoints.IndexOf(patrolPoint);
|
||||
Handles.color = patrolPoint.isValid ? Color.cyan : Color.red;
|
||||
if (patrolPoint != null)
|
||||
{
|
||||
if (Handles.Button(patrolPoint.transform.position, Quaternion.Euler(0, 0, 0), .25f, .25f, Handles.CubeHandleCap))
|
||||
{
|
||||
indexOfPatrolPoint = currentNode.subPoints.IndexOf(patrolPoint);
|
||||
Repaint();
|
||||
}
|
||||
Handles.color = new Color(1, 1, 1, 0.1f);
|
||||
Handles.Label(patrolPoint.position, new GUIContent("P-" + (index + 1).ToString("00")));
|
||||
}
|
||||
}
|
||||
|
||||
Handles.color = Color.green;
|
||||
if (currentNode.subPoints.Count > 0 && indexOfPatrolPoint < currentNode.subPoints.Count)
|
||||
{
|
||||
currentNode.subPoints[indexOfPatrolPoint].position = Handles.DoPositionHandle(currentNode.subPoints[indexOfPatrolPoint].position, currentNode.subPoints[indexOfPatrolPoint].transform.rotation);
|
||||
Handles.DrawWireDisc(currentNode.subPoints[indexOfPatrolPoint].transform.position, Vector3.up, currentNode.subPoints[indexOfPatrolPoint].areaRadius);
|
||||
if (e.type == EventType.MouseDown && e.button == 1 && e.control && currentNode)
|
||||
{
|
||||
Ray worldRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
|
||||
RaycastHit hitInfo;
|
||||
if (Physics.Raycast(worldRay, out hitInfo, Mathf.Infinity))
|
||||
{
|
||||
currentNode.subPoints[indexOfPatrolPoint].position = hitInfo.point;
|
||||
EditorUtility.SetDirty(pathArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (skin == null) skin = Resources.Load("vSkin") as GUISkin;
|
||||
GUI.skin = skin;
|
||||
|
||||
_wayArea = new SerializedObject(target);
|
||||
editMode = _wayArea.FindProperty("editMode");
|
||||
var waypoints = _wayArea.FindProperty("waypoints");
|
||||
_wayArea.Update();
|
||||
pathArea = (vWaypointArea)target;
|
||||
|
||||
GUILayout.BeginVertical("WAYPOINT AREA", "window", GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(true));
|
||||
GUILayout.Label(m_Logo, GUILayout.MaxHeight(25));
|
||||
|
||||
if (GUILayout.Button(editMode.boolValue ? "Exit Edit Mode" : "Enter Edit Mode", GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
editMode.boolValue = !editMode.boolValue;
|
||||
SetVisiblePoints(editMode.boolValue);
|
||||
Repaint();
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
GUI.enabled = editMode.boolValue;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
#if UNITY_2019_1_OR_NEWER
|
||||
EditorGUILayout.HelpBox("Make sure your SceneView Gizmos is enable", MessageType.Warning);
|
||||
#endif
|
||||
|
||||
if (editMode.boolValue && pathArea.waypoints.Count == 0)
|
||||
EditorGUILayout.HelpBox("Starting by holding Shift and Left Click on any surface with a collider.", MessageType.Info);
|
||||
|
||||
if (pathArea.waypoints != null && pathArea.waypoints.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < waypoints.arraySize; i++)
|
||||
{
|
||||
GUI.color = (i.Equals(indexOfWaypoint) ? Color.green : Color.white);
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Waypoint " + (i + 1).ToString("00"), "box", GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
indexOfWaypoint = i;
|
||||
currentNode = pathArea.waypoints[i];
|
||||
Selection.activeGameObject = currentNode.gameObject;
|
||||
SceneView.lastActiveSceneView.FrameSelected();
|
||||
Selection.activeGameObject = pathArea.gameObject;
|
||||
}
|
||||
|
||||
if (pathArea.waypoints[i] != null && !PointIsInNavMesh(pathArea.waypoints[i].transform.position))
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
EditorGUILayout.HelpBox("Out of NavMesh", MessageType.Error);
|
||||
Repaint();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("X", GUILayout.MaxWidth(20), GUILayout.MaxHeight(25)))
|
||||
{
|
||||
RemoveNode(ref waypoints, i);
|
||||
GUILayout.EndVertical();
|
||||
break;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.color = Color.white;
|
||||
if (indexOfWaypoint >= waypoints.arraySize) indexOfWaypoint = waypoints.arraySize - 1;
|
||||
try
|
||||
{
|
||||
if (waypoints != null && waypoints.arraySize > 0)
|
||||
{
|
||||
var vPoint = new SerializedObject(waypoints.GetArrayElementAtIndex(indexOfWaypoint).objectReferenceValue as vWaypoint);
|
||||
DrawWaypoint(vPoint, waypoints);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
GUILayout.EndVertical();
|
||||
GUI.enabled = true;
|
||||
GUILayout.BeginVertical("HOT KEYS", "window");
|
||||
GUILayout.Label(m_Logo, GUILayout.MaxHeight(25));
|
||||
|
||||
hotKeys = GUILayout.Toggle(hotKeys, hotKeys ? "Hide Hot Keys" : "Show Hot Keys", "button", GUILayout.ExpandWidth(true));
|
||||
if (hotKeys)
|
||||
{
|
||||
GUILayout.BeginVertical("box");
|
||||
GUI.color = Color.green;
|
||||
GUILayout.Label("Shift + Left Mouse Click", "box");
|
||||
GUI.color = Color.white;
|
||||
GUILayout.Label("Create New Way Point");
|
||||
GUILayout.EndVertical();
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.BeginVertical("box");
|
||||
GUI.color = Color.green;
|
||||
GUILayout.Label("Ctrl + Left Mouse Click", "box");
|
||||
GUI.color = Color.white;
|
||||
GUILayout.Label("Create New Patrol Point to selected way point");
|
||||
GUILayout.EndVertical();
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.BeginVertical("box");
|
||||
GUI.color = Color.green;
|
||||
GUILayout.Label("Shift + Right Mouse Click", "box");
|
||||
GUI.color = Color.white;
|
||||
GUILayout.Label("Set click point position to way point selected");
|
||||
GUILayout.EndVertical();
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.BeginVertical("box");
|
||||
GUI.color = Color.green;
|
||||
GUILayout.Label("Ctrl + Right Mouse Click", "box");
|
||||
GUI.color = Color.white;
|
||||
GUILayout.Label("Set click point position to patrol point selected");
|
||||
GUILayout.EndVertical();
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
if (Event.current.commandName == "UndoRedoPerformed")
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
if (GUI.changed)
|
||||
{
|
||||
_wayArea.ApplyModifiedProperties();
|
||||
EditorUtility.SetDirty(pathArea);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVisiblePoints(bool value)
|
||||
{
|
||||
if (pathArea == null) return;
|
||||
if (pathArea.waypoints != null && pathArea.waypoints.Count > 0)
|
||||
{
|
||||
foreach (vWaypoint wP in pathArea.waypoints)
|
||||
{
|
||||
if (wP != null)
|
||||
{
|
||||
if (value == true)
|
||||
wP.transform.hideFlags = HideFlags.None;
|
||||
else
|
||||
wP.transform.hideFlags = HideFlags.HideInHierarchy;
|
||||
|
||||
}
|
||||
}
|
||||
if (value) Tools.current = Tool.None;
|
||||
else Tools.current = tool;
|
||||
EditorUtility.SetDirty(pathArea.gameObject);
|
||||
EditorApplication.RepaintHierarchyWindow();
|
||||
}
|
||||
}
|
||||
|
||||
bool PointIsInNavMesh(Vector3 position)
|
||||
{
|
||||
NavMeshHit hit;
|
||||
if (NavMesh.SamplePosition(position, out hit, 0.5f, NavMesh.AllAreas))
|
||||
{
|
||||
if (Vector3.Distance(position, hit.position) > 0.4f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Repaint();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawWaypoint(SerializedObject waypoint, SerializedProperty waypoints)
|
||||
{
|
||||
if (waypoint != null)
|
||||
{
|
||||
GUILayout.BeginVertical("window", GUILayout.ExpandHeight(false));
|
||||
GUI.color = Color.green;
|
||||
GUILayout.BeginHorizontal("box");
|
||||
GUILayout.Label("Selected WP " + (indexOfWaypoint + 1).ToString("00"), GUILayout.ExpandWidth(true));
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("X", GUILayout.MaxWidth(20), GUILayout.MaxHeight(20)))
|
||||
{
|
||||
RemoveNode(ref waypoints, indexOfWaypoint);
|
||||
GUILayout.EndVertical();
|
||||
return;
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
GUI.color = Color.white;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(waypoint.FindProperty("isValid"));
|
||||
EditorGUILayout.PropertyField(waypoint.FindProperty("randomPatrolPoint"));
|
||||
EditorGUILayout.PropertyField(waypoint.FindProperty("timeToStay"));
|
||||
EditorGUILayout.PropertyField(waypoint.FindProperty("maxVisitors"));
|
||||
EditorGUILayout.PropertyField(waypoint.FindProperty("rotateTo"));
|
||||
waypoint.FindProperty("areaRadius").floatValue = EditorGUILayout.Slider("Area Radius", waypoint.FindProperty("areaRadius").floatValue, .1f, 10f);
|
||||
var vPoints = waypoint.FindProperty("subPoints");
|
||||
DrawVPoint(vPoints);
|
||||
GUILayout.EndVertical();
|
||||
if (GUI.changed)
|
||||
{
|
||||
waypoint.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawVPoint(SerializedProperty vPoints)
|
||||
{
|
||||
if (vPoints != null && vPoints.arraySize > 0)
|
||||
{
|
||||
GUILayout.BeginVertical("box");
|
||||
GUILayout.BeginHorizontal("box");
|
||||
GUILayout.Label("Patrol Points", GUILayout.ExpandWidth(true));
|
||||
GUILayout.EndHorizontal();
|
||||
for (int i = 0; i < vPoints.arraySize; i++)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
if (indexOfPatrolPoint.Equals(i))
|
||||
GUI.color = Color.cyan;
|
||||
else
|
||||
GUI.color = Color.white;
|
||||
if (GUILayout.Button("P-" + (i + 1).ToString("00"), "box", GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
indexOfPatrolPoint = i;
|
||||
//Selection.activeGameObject = (vPoints.GetArrayElementAtIndex(i).objectReferenceValue as vPoint).gameObject;
|
||||
SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
if (!PointIsInNavMesh((vPoints.GetArrayElementAtIndex(i).objectReferenceValue as vPoint).transform.position))
|
||||
{
|
||||
GUI.color = Color.white;
|
||||
EditorGUILayout.HelpBox("Out of NavMesh", MessageType.Error);
|
||||
Repaint();
|
||||
}
|
||||
EditorGUILayout.Space();
|
||||
if (GUILayout.Button("-", GUILayout.MaxWidth(20)))
|
||||
{
|
||||
RemoveNode(ref vPoints, i);
|
||||
Repaint();
|
||||
break;
|
||||
}
|
||||
GUILayout.EndHorizontal();
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
GUI.color = Color.white;
|
||||
if (indexOfPatrolPoint >= vPoints.arraySize) indexOfPatrolPoint = vPoints.arraySize - 1;
|
||||
var prop = vPoints.GetArrayElementAtIndex(indexOfPatrolPoint);
|
||||
if (prop != null)
|
||||
{
|
||||
var vPoint = new SerializedObject(prop.objectReferenceValue);
|
||||
GUILayout.BeginVertical("box");
|
||||
GUI.color = Color.cyan;
|
||||
GUILayout.Box("P-" + (indexOfPatrolPoint + 1).ToString("00"), GUILayout.ExpandWidth(true));
|
||||
GUI.color = Color.white;
|
||||
EditorGUILayout.PropertyField(vPoint.FindProperty("isValid"));
|
||||
EditorGUILayout.PropertyField(vPoint.FindProperty("timeToStay"));
|
||||
EditorGUILayout.PropertyField(vPoint.FindProperty("maxVisitors"));
|
||||
vPoint.FindProperty("areaRadius").floatValue = EditorGUILayout.Slider("Area Radius", vPoint.FindProperty("areaRadius").floatValue, 1f, 10f);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
EditorGUILayout.Space();
|
||||
GUILayout.EndVertical();
|
||||
|
||||
if (GUI.changed)
|
||||
{
|
||||
vPoint.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveNode(ref SerializedProperty waypoints, int index)
|
||||
{
|
||||
var obj = (waypoints.GetArrayElementAtIndex(index).objectReferenceValue as vPoint).gameObject;
|
||||
waypoints.DeleteArrayElementAtIndex(index);
|
||||
|
||||
DestroyImmediate(obj);
|
||||
}
|
||||
|
||||
void CreateNode(vWaypointArea wayArea, Vector3 position)
|
||||
{
|
||||
var nodeObj = new GameObject("node");
|
||||
var node = nodeObj.AddComponent<vWaypoint>();
|
||||
node.subPoints = new List<vPoint>();
|
||||
nodeObj.transform.position = position;
|
||||
nodeObj.transform.parent = wayArea.transform;
|
||||
wayArea.waypoints.Add(node);
|
||||
currentNode = node;
|
||||
indexOfWaypoint = wayArea.waypoints.IndexOf(currentNode);
|
||||
}
|
||||
|
||||
void CreatePatrolPoint(vWaypointArea wayArea, Vector3 position)
|
||||
{
|
||||
if (currentNode)
|
||||
{
|
||||
if (currentNode.subPoints == null) currentNode.subPoints = new List<vPoint>();
|
||||
var nodeObj = new GameObject("patrolPoint");
|
||||
var node = nodeObj.AddComponent<vPoint>();
|
||||
nodeObj.transform.position = position;
|
||||
nodeObj.transform.parent = currentNode.transform;
|
||||
currentNode.subPoints.Add(node);
|
||||
indexOfPatrolPoint = currentNode.subPoints.IndexOf(node);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckNodes(ref List<vWaypoint> waypoints)
|
||||
{
|
||||
var wP = ((vWaypointArea)target).transform.GetComponentsInChildren<vWaypoint>();
|
||||
|
||||
if (waypoints.Count != wP.Length)
|
||||
waypoints = wP.ToList();
|
||||
foreach (vWaypoint waypoint in waypoints)
|
||||
{
|
||||
var vP = waypoint.transform.GetComponentsInChildren<vPoint>();
|
||||
var _vp = vP.ToList().FindAll(p => p.transform != waypoint.transform);
|
||||
if (waypoint.subPoints.Count != _vp.Count)
|
||||
waypoint.subPoints = _vp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f1cc0f245d4fa74b8b0a1afb105120d
|
||||
timeCreated: 1457710593
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
namespace Invector
|
||||
{
|
||||
[System.Serializable]
|
||||
public class vPoint : MonoBehaviour
|
||||
{
|
||||
public float timeToStay = 0f;
|
||||
public int maxVisitors = 1;
|
||||
public bool isValid = true;
|
||||
public List<Transform> visitors;
|
||||
public float areaRadius = 1f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
visitors = new List<Transform>();
|
||||
}
|
||||
|
||||
public Vector3 position
|
||||
{
|
||||
get { return transform.position; }
|
||||
set { transform.position = value; }
|
||||
}
|
||||
|
||||
public virtual void Enter(Transform visitor)
|
||||
{
|
||||
if (!visitors.Contains(visitor))
|
||||
visitors.Add(visitor);
|
||||
}
|
||||
|
||||
public virtual void Exit(Transform visitor)
|
||||
{
|
||||
if (visitors.Contains(visitor))
|
||||
visitors.Remove(visitor);
|
||||
}
|
||||
|
||||
public virtual bool IsOnWay(Transform visitor)
|
||||
{
|
||||
return visitors.Contains(visitor);
|
||||
}
|
||||
|
||||
public virtual bool CanEnter(Transform visitor)
|
||||
{
|
||||
if (visitors.Contains(visitor)) return true;
|
||||
if (!isValid) return false;
|
||||
if (visitors.Count == maxVisitors) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 30a2cef9d5c509446954e56cd2b87ddd
|
||||
timeCreated: 1457790416
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
namespace Invector.vCharacterController.AI
|
||||
{
|
||||
[System.Serializable]
|
||||
public class vWaypoint : vPoint
|
||||
{
|
||||
public List<vPoint> subPoints;
|
||||
public bool randomPatrolPoint;
|
||||
public bool rotateTo = true;
|
||||
|
||||
public Vector3 GetRandomSubPoint()
|
||||
{
|
||||
System.Random random = new System.Random(100);
|
||||
var index = random.Next(0, subPoints.Count - 1);
|
||||
return GetSubPoint(index);
|
||||
}
|
||||
|
||||
public Vector3 GetSubPoint(int index)
|
||||
{
|
||||
if (subPoints != null && subPoints.Count > 0 && index < subPoints.Count) return subPoints[index].position;
|
||||
|
||||
return transform.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36a5a844de6a6df419bd8fb9e1079117
|
||||
timeCreated: 1457706489
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Invector.vCharacterController.AI
|
||||
{
|
||||
public class vWaypointArea : MonoBehaviour
|
||||
{
|
||||
public List<vWaypoint> waypoints;
|
||||
public bool randomWayPoint;
|
||||
#if UNITY_EDITOR
|
||||
[SerializeField,HideInInspector]
|
||||
private bool editMode;
|
||||
#endif
|
||||
public vWaypoint GetRandomWayPoint()
|
||||
{
|
||||
System.Random random = new System.Random(100);
|
||||
var _nodes = GetValidPoints();
|
||||
var index = random.Next(0, waypoints.Count - 1);
|
||||
if (_nodes != null && _nodes.Count > 0 && index < _nodes.Count)
|
||||
return _nodes[index];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<vWaypoint> GetValidPoints(bool reverse = false)
|
||||
{
|
||||
var _nodes = waypoints.FindAll(node => node.isValid);
|
||||
if (reverse) _nodes.Reverse();
|
||||
return _nodes;
|
||||
}
|
||||
|
||||
public List<vPoint> GetValidSubPoints(vWaypoint waipoint,bool reverse = false)
|
||||
{
|
||||
var _nodes = waipoint.subPoints.FindAll(node => node.isValid);
|
||||
if (reverse) _nodes.Reverse();
|
||||
return _nodes;
|
||||
}
|
||||
|
||||
public vWaypoint GetWayPoint(int index)
|
||||
{
|
||||
var _nodes = GetValidPoints();
|
||||
if (_nodes != null && _nodes.Count > 0 && index < _nodes.Count) return _nodes[index];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38a6efba93686334cbc6b7186c9acee3
|
||||
timeCreated: 1457709108
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user