update
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the location that the ability should use when determining where to move the limb to. This component should be attached to the target limb location.
|
||||
/// </summary>
|
||||
public class AbilityIKTarget : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The IK limb that should be positioned.")]
|
||||
[SerializeField] protected CharacterIKBase.IKGoal m_Goal;
|
||||
[Tooltip("The amount of time that the ability should wait before setting the IK goal.")]
|
||||
[SerializeField] protected float m_Delay = 0;
|
||||
[Tooltip("The time it takes for the limb to reach the target. A positive value is required.")]
|
||||
[SerializeField] protected float m_InterpolationDuration = 0.2f;
|
||||
[Tooltip("The amount of time after the IK goal is set that the limb should be in the IK location. This value should be greater than the interpolation duration.")]
|
||||
[SerializeField] protected float m_Duration = 1f;
|
||||
|
||||
public CharacterIKBase.IKGoal Goal { get { return m_Goal; } }
|
||||
public float Delay { get { return m_Delay; } }
|
||||
public float InterpolationDuration { get { return m_InterpolationDuration; } }
|
||||
public float Duration { get { return m_Duration; } }
|
||||
|
||||
private Transform m_Transform;
|
||||
public Transform Transform { get { return m_Transform; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
m_Transform = transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 627fb43e464c809458459585500fad4d
|
||||
timeCreated: 1520365325
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,152 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Audio;
|
||||
using Opsive.UltimateCharacterController.Traits;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a bool parameter value when interacted with (implements IInteractableTarget).
|
||||
/// </summary>
|
||||
public class AnimatedInteractable : MonoBehaviour, IInteractableTarget, IInteractableMessage
|
||||
{
|
||||
[Tooltip("Can the interactable be interacted with only once?")]
|
||||
[SerializeField] protected bool m_SingleInteract;
|
||||
[Tooltip("The bool parameter name that should be changed when interacted with. Can be empty.")]
|
||||
[SerializeField] protected string m_BoolParameter;
|
||||
[Tooltip("The value to set the bool to when interacted with. Only used if the bool parameter is not empty.")]
|
||||
[SerializeField] protected bool m_BoolInteractValue = true;
|
||||
[Tooltip("The UI message that should be displayed when the bool is enabled.")]
|
||||
[SerializeField] protected string m_BoolEnabledMessage;
|
||||
[Tooltip("The UI message that should be displayed when the bool is disabled.")]
|
||||
[SerializeField] protected string m_BoolDisabledMessage;
|
||||
[Tooltip("Should the bool interact value be toggled after an interact?")]
|
||||
[SerializeField] protected bool m_ToggleBoolInteractValue = true;
|
||||
[Tooltip("The trigger parameter name that should be set when interacted with. Can be empty.")]
|
||||
[SerializeField] protected string m_TriggerParameter;
|
||||
[Tooltip("An array of audio clips that can be played when the interaction starts.")]
|
||||
[SerializeField] protected AudioClip[] m_InteractAudioClips;
|
||||
|
||||
private GameObject m_GameObject;
|
||||
private Animator m_Animator;
|
||||
private AnimatedInteractable[] m_AnimatedInteractables;
|
||||
protected bool m_HasInteracted;
|
||||
private int m_BoolParameterHash;
|
||||
private int m_TriggerParameterHash;
|
||||
private int m_AudioClipIndex = -1;
|
||||
private bool m_ActiveBoolInteractable;
|
||||
|
||||
public bool ActiveBoolInteractable { get { return m_ActiveBoolInteractable; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
protected virtual void Awake()
|
||||
{
|
||||
m_GameObject = gameObject;
|
||||
m_Animator = GetComponent<Animator>();
|
||||
if (!string.IsNullOrEmpty(m_BoolParameter)) {
|
||||
m_BoolParameterHash = Animator.StringToHash(m_BoolParameter);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(m_TriggerParameter)) {
|
||||
m_TriggerParameterHash = Animator.StringToHash(m_TriggerParameter);
|
||||
}
|
||||
var animatedInteractables = GetComponents<AnimatedInteractable>();
|
||||
if (animatedInteractables.Length > 1) {
|
||||
m_AnimatedInteractables = new AnimatedInteractable[animatedInteractables.Length - 1];
|
||||
var count = 0;
|
||||
for (int i = 0; i < animatedInteractables.Length; ++i) {
|
||||
if (animatedInteractables[i] == this) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_AnimatedInteractables[count] = animatedInteractables[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the target be interacted with?
|
||||
/// </summary>
|
||||
/// <param name="character">The character that wants to interactact with the target.</param>
|
||||
/// <returns>True if the target can be interacted with.</returns>
|
||||
public bool CanInteract(GameObject character)
|
||||
{
|
||||
return !m_HasInteracted || !m_SingleInteract;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interact with the target.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that wants to interactact with the target.</param>
|
||||
public void Interact(GameObject character)
|
||||
{
|
||||
if (m_BoolParameterHash != 0) {
|
||||
// If the bool value can be toggled then there's a chance that another AnimatedInteractable is currently active. In that case the original
|
||||
// AnimatedInteractable should respond to the interact event.
|
||||
if (m_AnimatedInteractables != null) {
|
||||
for (int i = 0; i < m_AnimatedInteractables.Length; ++i) {
|
||||
if (m_AnimatedInteractables[i].ActiveBoolInteractable) {
|
||||
m_AnimatedInteractables[i].Interact(character);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Animator.SetBool(m_BoolParameterHash, m_BoolInteractValue);
|
||||
if (m_ToggleBoolInteractValue) {
|
||||
m_BoolInteractValue = !m_BoolInteractValue;
|
||||
m_ActiveBoolInteractable = !m_ActiveBoolInteractable;
|
||||
}
|
||||
}
|
||||
if (m_TriggerParameterHash != 0) {
|
||||
m_Animator.SetTrigger(m_TriggerParameterHash);
|
||||
}
|
||||
|
||||
if (m_InteractAudioClips.Length > 0) {
|
||||
// Sequentually switch between audio clips.
|
||||
m_AudioClipIndex = (m_AudioClipIndex + 1) % m_InteractAudioClips.Length;
|
||||
AudioManager.Play(m_GameObject, m_InteractAudioClips[m_AudioClipIndex]);
|
||||
}
|
||||
m_HasInteracted = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the interact variables.
|
||||
/// </summary>
|
||||
public void ResetInteract()
|
||||
{
|
||||
m_HasInteracted = false;
|
||||
m_AudioClipIndex = -1;
|
||||
m_Animator.Rebind();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the message that should be displayed when the object can be interacted with.
|
||||
/// </summary>
|
||||
/// <returns>The message that should be displayed when the object can be interacted with.</returns>
|
||||
public string AbilityMessage()
|
||||
{
|
||||
if (m_BoolParameterHash != 0) {
|
||||
// If the bool value can be toggled then there's a chance that another AnimatedInteractable is currently active. In that case the original
|
||||
// AnimatedInteractable should respond to the message.
|
||||
if (m_AnimatedInteractables != null) {
|
||||
for (int i = 0; i < m_AnimatedInteractables.Length; ++i) {
|
||||
if (m_AnimatedInteractables[i].ActiveBoolInteractable) {
|
||||
return m_AnimatedInteractables[i].AbilityMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_BoolInteractValue ? m_BoolEnabledMessage : m_BoolDisabledMessage;
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f54cf0812fcc9d6458c6102e4df6be2b
|
||||
timeCreated: 1520793857
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Character.Abilities;
|
||||
using Opsive.UltimateCharacterController.Game;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A Gravity Zone represents a trigger area that adjusts the character's gravity direction when the character is within the trigger.
|
||||
/// </summary>
|
||||
public abstract class GravityZone : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the direction of gravity that should be applied.
|
||||
/// </summary>
|
||||
/// <param name="position">The position of the character.</param>
|
||||
/// <returns>The direction of gravity that should be applied.</returns>
|
||||
public abstract Vector3 DetermineGravityDirection(Vector3 position);
|
||||
|
||||
/// <summary>
|
||||
/// An object has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The object that entered the trigger.</param>
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// A main character collider is required.
|
||||
if (!MathUtility.InLayerMask(other.gameObject.layer, 1 << LayerManager.Character)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The object must be a character.
|
||||
var characterLocomotion = other.GetComponentInParent<UltimateCharacterLocomotion>();
|
||||
if (characterLocomotion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// With the Align To Gravity Zone ability.
|
||||
var alignToGravity = characterLocomotion.GetAbility<AlignToGravityZone>();
|
||||
if (alignToGravity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
alignToGravity.RegisterGravityZone(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object has exited the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The collider that exited the trigger.</param>
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
// A main character collider is required.
|
||||
if (!MathUtility.InLayerMask(other.gameObject.layer, 1 << LayerManager.Character)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// The object must be a character.
|
||||
var characterLocomotion = other.GetComponentInParent<UltimateCharacterLocomotion>();
|
||||
if (characterLocomotion == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// With the Align To Gravity Zone ability.
|
||||
var alignToGravity = characterLocomotion.GetAbility<AlignToGravityZone>();
|
||||
if (alignToGravity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
alignToGravity.UnregisterGravityZone(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82bf2d12f02310144aabbb3f7f06e6ec
|
||||
timeCreated: 1543955724
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Traits;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Heals the object that has the Health component.
|
||||
/// </summary>
|
||||
public class HealthPickup : ObjectPickup
|
||||
{
|
||||
[Tooltip("The amount of health to replenish.")]
|
||||
[SerializeField] private float m_HealthAmount = 40;
|
||||
[Tooltip("Should the object be picked up even if the object has full health?")]
|
||||
[SerializeField] private bool m_AlwaysPickup;
|
||||
|
||||
public float HealthAmount { get { return m_HealthAmount; } set { m_HealthAmount = value; } }
|
||||
public bool AlwaysPickup { get { return m_AlwaysPickup; } set { m_AlwaysPickup = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// A GameObject has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The GameObject that entered the trigger.</param>
|
||||
public override void TriggerEnter(GameObject other)
|
||||
{
|
||||
var health = other.GetCachedParentComponent<Health>();
|
||||
if (health != null && health.IsAlive()) {
|
||||
if (health.Heal(m_HealthAmount) || m_AlwaysPickup) {
|
||||
ObjectPickedUp(health.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50af1f3344f80c64dbd40bdbc4d9df5e
|
||||
timeCreated: 1500999042
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Interface for any object that can be driven.
|
||||
/// </summary>
|
||||
public interface IDriveSource
|
||||
{
|
||||
/// <summary>
|
||||
/// The GameObject of the vehicle.
|
||||
/// </summary>
|
||||
GameObject GameObject { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Transform of the vehicle.
|
||||
/// </summary>
|
||||
Transform Transform { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The location that the character drives the vehicle from.
|
||||
/// </summary>
|
||||
Transform DriverLocation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique identifier of the object. This value is used within the AbilityIntData parameter of the character's animator.
|
||||
/// </summary>
|
||||
int AnimatorID { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The character has started to enter the vehicle.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that is entering the vehicle.</param>
|
||||
void EnterVehicle(GameObject character);
|
||||
|
||||
/// <summary>
|
||||
/// The character has entered the vehicle.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that entered the vehicle.</param>
|
||||
void EnteredVehicle(GameObject character);
|
||||
|
||||
/// <summary>
|
||||
/// The character has started to exit the vehicle.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that is exiting the vehicle.</param>
|
||||
void ExitVehicle(GameObject character);
|
||||
|
||||
/// <summary>
|
||||
/// The character has exited the vehicle.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that exited the vehicle.</param>
|
||||
void ExitedVehicle(GameObject character);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b364593e2dde534a93176a932934cf6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,62 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Inventory;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Extends ItemPickupBase to allow for ItemIdentifier pickups.
|
||||
/// </summary>
|
||||
public class ItemPickup : ItemPickupBase
|
||||
{
|
||||
[Tooltip("An array of ItemIdentifiers to be picked up.")]
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("m_ItemTypeCounts")]
|
||||
[SerializeField] protected ItemDefinitionAmount[] m_ItemDefinitionAmounts;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ItemDefinitionAmount that the ItemPickup contains.
|
||||
/// </summary>
|
||||
/// <returns>The ItemDefinitionAmount that the ItemPickup contains.</returns>
|
||||
public override ItemDefinitionAmount[] GetItemDefinitionAmounts()
|
||||
{
|
||||
return m_ItemDefinitionAmounts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ItemPickup ItemDefinitionAmounts value.
|
||||
/// </summary>
|
||||
/// <param name="itemDefinitionAmounts">The ItemDefinitionAmount that should be set.</param>
|
||||
public override void SetItemDefinitionAmounts(ItemDefinitionAmount[] itemDefinitionAmounts)
|
||||
{
|
||||
m_ItemDefinitionAmounts = itemDefinitionAmounts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method which picks up the ItemIdentifier.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that should pick up the ItemIdentifier.</param>
|
||||
/// <param name="inventory">The inventory belonging to the character.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
/// <param name="immediatePickup">Should the item be picked up immediately?</param>
|
||||
/// <param name="forceEquip">Should the item be force equipped?</param>
|
||||
/// <returns>True if an ItemIdentifier was picked up.</returns>
|
||||
protected override bool DoItemIdentifierPickupInternal(GameObject character, InventoryBase inventory, int slotID, bool immediatePickup, bool forceEquip)
|
||||
{
|
||||
// Add the ItemIdentifiers to the Inventory. This allows the character to pick up the actual item and any consumable ItemIdentifier (such as ammo).
|
||||
var pickedUp = false;
|
||||
if (m_ItemDefinitionAmounts != null) {
|
||||
for (int i = 0; i < m_ItemDefinitionAmounts.Length; ++i) {
|
||||
if (inventory.Pickup(m_ItemDefinitionAmounts[i].ItemIdentifier, m_ItemDefinitionAmounts[i].Amount, slotID, immediatePickup, forceEquip)) {
|
||||
pickedUp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pickedUp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e704e820a055af41b5a98fa3a79f767
|
||||
timeCreated: 1500999042
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,280 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.Shared.Inventory;
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Inventory;
|
||||
using Opsive.UltimateCharacterController.Items;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Base class which allows an object with the Inventory component to pickup items when a character enters the trigger.
|
||||
/// </summary>
|
||||
public abstract class ItemPickupBase : ObjectPickup
|
||||
{
|
||||
/// <summary>
|
||||
/// Class which allows the specified item to be collected by the character at runtime.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class PickupSet
|
||||
{
|
||||
[Tooltip("The item prefab that can be picked up.")]
|
||||
[SerializeField] protected GameObject m_Item;
|
||||
[Tooltip("The ID of the category that the ItemSet should be added to.")]
|
||||
[SerializeField] protected uint m_CategoryID;
|
||||
[Tooltip("The ItemSet to load when the item is picked up.")]
|
||||
[SerializeField] protected ItemSet m_ItemSet;
|
||||
[Tooltip("Is the ItemSet the default ItemSet within the category?")]
|
||||
[SerializeField] protected bool m_Default;
|
||||
|
||||
public GameObject Item { get { return m_Item; } set { m_Item = value; } }
|
||||
public uint CategoryID { get { return m_CategoryID; } set { m_CategoryID = value; } }
|
||||
public ItemSet ItemSet { get { return m_ItemSet; } set { m_ItemSet = value; } }
|
||||
public bool Default { get { return m_Default; } set { m_Default = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Default PickupSet constructor.
|
||||
/// </summary>
|
||||
public PickupSet() { m_ItemSet = new ItemSet(); }
|
||||
}
|
||||
|
||||
[Tooltip("An array of items and ItemSets to pick up.")]
|
||||
[SerializeField] protected PickupSet[] m_ItemPickupSet;
|
||||
[Tooltip("Should the object be picked up even if the inventory cannot hold any more of the ItemIdentifier?")]
|
||||
[SerializeField] protected bool m_AlwaysPickup;
|
||||
|
||||
public PickupSet[] ItemPickupSet { get { return m_ItemPickupSet; } set { m_ItemPickupSet = value; } }
|
||||
public bool AlwaysPickup { get { return m_AlwaysPickup; } set { m_AlwaysPickup = value; } }
|
||||
|
||||
private bool m_PickedUp;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (m_ItemPickupSet != null) {
|
||||
for (int i = 0; i < m_ItemPickupSet.Length; ++i) {
|
||||
// The item GameObject must contain the Item component.
|
||||
if (m_ItemPickupSet[i].Item != null && m_ItemPickupSet[i].Item.GetComponent<Item>() == null) {
|
||||
Debug.LogError($"Error: {m_ItemPickupSet[i].Item.name} doesn't contain the Item component.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A GameObject has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The GameObject that entered the trigger.</param>
|
||||
public override void TriggerEnter(GameObject other)
|
||||
{
|
||||
TriggerEnter(other, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A GameObject has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The other GameObject which is trying to do the pickup.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
public void TriggerEnter(GameObject other, int slotID)
|
||||
{
|
||||
// The object must have an enabled inventory in order for the item to be picked up.
|
||||
var inventory = other.GetCachedParentComponent<InventoryBase>();
|
||||
if (inventory == null || !inventory.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The collider must be a main character collider. Items or ragdoll colliders don't count.
|
||||
var layerManager = inventory.gameObject.GetCachedComponent<CharacterLayerManager>();
|
||||
if (layerManager == null || !MathUtility.InLayerMask(other.gameObject.layer, layerManager.CharacterLayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TryItemPickup(inventory, slotID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to pickup the item.
|
||||
/// </summary>
|
||||
/// <param name="inventory">The inventory belonging to the character.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
private void TryItemPickup(InventoryBase inventory, int slotID)
|
||||
{
|
||||
if (m_PickupOnTriggerEnter) {
|
||||
DoItemPickup(inventory.gameObject, inventory, slotID, false, true);
|
||||
} else {
|
||||
// If the object is a character that has a disabled pickup item ability then the item should be picked up immediately,
|
||||
// even if the pickup on trigger enter is disabled.
|
||||
var character = inventory.gameObject.GetCachedComponent<Character.UltimateCharacterLocomotion>();
|
||||
if (character != null) {
|
||||
var pickupItem = character.GetAbility<Character.Abilities.PickupItem>();
|
||||
if (pickupItem != null && pickupItem.CanItemPickup()) {
|
||||
DoItemPickup(inventory.gameObject, inventory, slotID, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Picks up the item.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that should pick up the item.</param>
|
||||
/// <param name="inventory">The inventory belonging to the character.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
/// <param name="immediatePickup">Should the item be picked up immediately?</param>
|
||||
/// <param name="pickupItemIdentifier">Should the ItemIdentifier be picked up? This should be false if the ItemIdentifier will later be picked up.</param>
|
||||
public void DoItemPickup(GameObject character, InventoryBase inventory, int slotID, bool immediatePickup, bool pickupItemIdentifier)
|
||||
{
|
||||
// Add any items to the character.
|
||||
if (m_ItemPickupSet != null && m_ItemPickupSet.Length > 0) {
|
||||
// Spawn the item under the character's ItemPlacement GameObject.
|
||||
var itemPlacement = character.GetComponentInChildren<ItemPlacement>(true);
|
||||
if (itemPlacement == null) {
|
||||
Debug.LogError($"Error: ItemPlacement doesn't exist under the character {character.name}.");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < m_ItemPickupSet.Length; ++i) {
|
||||
// If the Item is null then only the ItemSet should be added.
|
||||
if (m_ItemPickupSet[i].Item == null) {
|
||||
var itemSetManager = character.GetCachedComponent<ItemSetManagerBase>();
|
||||
if (itemSetManager == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IItemCategoryIdentifier category = null;
|
||||
var addItemSetParents = true;
|
||||
// If no item is specified then the category should be retrieved from the Item Definition.
|
||||
if (m_ItemPickupSet[i].CategoryID == 0) {
|
||||
for (int j = 0; j < m_ItemPickupSet[i].ItemSet.Slots.Length; ++j) {
|
||||
var itemDefinition = m_ItemPickupSet[i].ItemSet.Slots[j];
|
||||
if (itemDefinition != null) {
|
||||
category = itemDefinition.GetItemCategory();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// A specific category was specified.
|
||||
if (itemSetManager.CategoryItemSets != null) {
|
||||
for (int j = 0; j < itemSetManager.CategoryItemSets.Length; ++j) {
|
||||
if (itemSetManager.CategoryItemSets[j].CategoryID == m_ItemPickupSet[i].CategoryID) {
|
||||
category = itemSetManager.CategoryItemSets[j].ItemCategory;
|
||||
addItemSetParents = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (category != null) {
|
||||
itemSetManager.AddItemSet(m_ItemPickupSet[i].ItemSet, m_ItemPickupSet[i].Default, category, addItemSetParents);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slotID != -1 && (slotID >= m_ItemPickupSet[i].ItemSet.Slots.Length || m_ItemPickupSet[i].ItemSet.Slots[slotID] == null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = m_ItemPickupSet[i].Item.GetCachedComponent<Item>();
|
||||
if (inventory.HasItem(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Instantiate the item that will be added to the character.
|
||||
item = Item.SpawnItem(character, item);
|
||||
|
||||
// Add the ItemSet before the item so the item can use the added ItemSet.
|
||||
if (m_ItemPickupSet[i].ItemSet != null) {
|
||||
var itemSetManager = character.GetCachedComponent<ItemSetManager>();
|
||||
if (itemSetManager != null) {
|
||||
m_ItemPickupSet[i].ItemSet.ItemIdentifiers = new Shared.Inventory.IItemIdentifier[m_ItemPickupSet[i].ItemSet.Slots.Length];
|
||||
m_ItemPickupSet[i].ItemSet.ItemIdentifiers[item.SlotID] = item.ItemIdentifier;
|
||||
itemSetManager.AddItemSet(item, m_ItemPickupSet[i].ItemSet, m_ItemPickupSet[i].Default);
|
||||
}
|
||||
}
|
||||
|
||||
// All of the setup is complete - add the item to the inventory.
|
||||
inventory.AddItem(item, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
m_PickedUp = m_AlwaysPickup;
|
||||
if (pickupItemIdentifier) {
|
||||
// Even if the ItemIdentifier doesn't have space it may be equipped by the inventory. The object should be considered as picked up in this situation.
|
||||
EventHandler.RegisterEvent<Item, int>(character, "OnAbilityWillEquipItem", OnWillEquipItem);
|
||||
if (DoItemIdentifierPickup(character, inventory, slotID, immediatePickup, true)) {
|
||||
m_PickedUp = true;
|
||||
}
|
||||
EventHandler.UnregisterEvent<Item, int>(character, "OnAbilityWillEquipItem", OnWillEquipItem);
|
||||
} else {
|
||||
// If pickup ItemIdentifier is false then the PickupItem ability will pick up the ItemIdentifier.
|
||||
m_PickedUp = true;
|
||||
}
|
||||
|
||||
if (m_PickedUp) {
|
||||
ObjectPickedUp(character);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ItemDefinitionAmount that the ItemPickup contains.
|
||||
/// </summary>
|
||||
/// <returns>The ItemDefinitionAmount that the ItemPickup contains.</returns>
|
||||
public abstract ItemDefinitionAmount[] GetItemDefinitionAmounts();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ItemPickup ItemDefinitionAmounts value.
|
||||
/// </summary>
|
||||
/// <param name="itemDefinitionAmounts">The ItemDefinitionAmount that should be set.</param>
|
||||
public abstract void SetItemDefinitionAmounts(ItemDefinitionAmount[] itemDefinitionAmounts);
|
||||
|
||||
/// <summary>
|
||||
/// Picks up the ItemIdentifier.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that should pick up the ItemIdentifier.</param>
|
||||
/// <param name="inventory">The inventory belonging to the character.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
/// <param name="immediatePickup">Should the item be picked up immediately?</param>
|
||||
/// <param name="forceEquip">Should the item be force equipped?</param>
|
||||
/// <returns>True if an ItemIdentifier was picked up.</returns>
|
||||
public bool DoItemIdentifierPickup(GameObject character, InventoryBase inventory, int slotID, bool immediatePickup, bool forceEquip)
|
||||
{
|
||||
EventHandler.ExecuteEvent(character, "OnItemPickupStartPickup");
|
||||
var result = DoItemIdentifierPickupInternal(character, inventory, slotID, immediatePickup, forceEquip);
|
||||
EventHandler.ExecuteEvent(character, "OnItemPickupStopPickup");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal method which picks up the ItemIdentifier.
|
||||
/// </summary>
|
||||
/// <param name="character">The character that should pick up the ItemIdentifier.</param>
|
||||
/// <param name="inventory">The inventory belonging to the character.</param>
|
||||
/// <param name="slotID">The slot ID that picked up the item. A -1 value will indicate no specified slot.</param>
|
||||
/// <param name="immediatePickup">Should the item be picked up immediately?</param>
|
||||
/// <param name="forceEquip">Should the item be force equipped?</param>
|
||||
/// <returns>True if an ItemIdentifier was picked up.</returns>
|
||||
protected abstract bool DoItemIdentifierPickupInternal(GameObject character, InventoryBase inventory, int slotID, bool immediatePickup, bool forceEquip);
|
||||
|
||||
/// <summary>
|
||||
/// The specified item will be equipped.
|
||||
/// </summary>
|
||||
/// <param name="item">The item that will be equipped.</param>
|
||||
/// <param name="slotID">The slot that the item will occupy.</param>
|
||||
private void OnWillEquipItem(Item item, int slotID)
|
||||
{
|
||||
m_PickedUp = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75b4a0fd8e4a0b14bb9cac502a77aa37
|
||||
timeCreated: 1500999042
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the location that the character should move to when the Move Towards ability is started.
|
||||
/// </summary>
|
||||
public class MoveTowardsLocation : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The offset relative to the transform that the character should move towards.")]
|
||||
[SerializeField] protected Vector3 m_Offset = new Vector3(0, 0, 1);
|
||||
[Tooltip("The yaw offset relative to the transform that the character should rotate towards.")]
|
||||
[SerializeField] protected float m_YawOffset = 180;
|
||||
[Tooltip("The size of the area that the character can start the ability at. A zero value indicates that the character must land on the exact offset.")]
|
||||
[SerializeField] protected Vector3 m_Size;
|
||||
[Tooltip("The ability can start when the distance between the start location and character is less than the specified value.")]
|
||||
[Range(0.0001f, 100)] [SerializeField] protected float m_Distance = 0.01f;
|
||||
[Tooltip("The ability can start when the angle threshold between the start location and character is less than the specified value.")]
|
||||
[Range(0, 360)] [SerializeField] protected float m_Angle = 0.5f;
|
||||
[Tooltip("Is the character required to be on the ground?")]
|
||||
[SerializeField] protected bool m_RequireGrounded = true;
|
||||
[Tooltip("Should the ability wait to start until all transitions are complete?")]
|
||||
[SerializeField] protected bool m_PrecisionStart = true;
|
||||
[Tooltip("The multiplier to apply to the character's speed when moving to the start location.")]
|
||||
[SerializeField] protected float m_MovementMultiplier = 1;
|
||||
|
||||
public Vector3 Offset { get { return m_Offset; } set { m_Offset = value; } }
|
||||
public float YawOffset { get { return m_YawOffset; } set { m_YawOffset = value; } }
|
||||
public Vector3 Size { get { return m_Size; } set { m_Size = value; } }
|
||||
public float Distance { get { return m_Distance; } set { m_Distance = value; } }
|
||||
public float Angle { get { return m_Angle; } set { m_Angle = value; } }
|
||||
public bool RequireGrounded { get { return m_RequireGrounded; } set { m_RequireGrounded = value; } }
|
||||
public bool PrecisionStart { get { return m_PrecisionStart; } set { m_PrecisionStart = value; } }
|
||||
public float MovementMultiplier { get { return m_MovementMultiplier; } set { m_MovementMultiplier = value; } }
|
||||
|
||||
private Transform m_Transform;
|
||||
private float m_StartYawOffset;
|
||||
private Vector3 m_StartOffset;
|
||||
|
||||
public Vector3 TargetPosition { get { return m_Transform.TransformPoint(m_Offset); } }
|
||||
public Quaternion TargetRotation { get { return m_Transform.rotation * Quaternion.Euler(0, m_YawOffset, 0); } }
|
||||
public float StartYawOffset { get { return m_StartYawOffset; } }
|
||||
public Vector3 StartOffset { get { return m_StartOffset; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
m_Transform = transform;
|
||||
m_StartYawOffset = m_YawOffset;
|
||||
m_StartOffset = m_Offset;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the direction that the character should move towards.
|
||||
/// </summary>
|
||||
/// <param name="position">The position of the character.</param>
|
||||
/// <param name="rotation">The rotation of the character.</param>
|
||||
/// <returns>The direction that the character should move towards.</returns>
|
||||
public Vector3 GetTargetDirection(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
var direction = m_Transform.TransformPoint(m_Offset) - position;
|
||||
if (m_Size.sqrMagnitude == 0) {
|
||||
return MathUtility.InverseTransformDirection(direction, rotation);
|
||||
}
|
||||
|
||||
var size = m_Transform.TransformDirection(m_Size);
|
||||
if (Mathf.Abs(direction.x) < Mathf.Abs(size.x / 2)) { direction.x = 0; }
|
||||
if (Mathf.Abs(direction.y) < Mathf.Abs(size.y / 2)) { direction.y = 0; }
|
||||
if (Mathf.Abs(direction.z) < Mathf.Abs(size.z / 2)) { direction.z = 0; }
|
||||
return MathUtility.InverseTransformDirection(direction, rotation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the character in a valid position?
|
||||
/// </summary>
|
||||
/// <param name="position">The position of the character.</param>
|
||||
/// <param name="rotation">The rotation of the character.</param>
|
||||
/// <param name="grounded">Is the character grounded?</param>
|
||||
/// <returns>True if the position is valid.</returns>
|
||||
public bool IsPositionValid(Vector3 position, Quaternion rotation, bool grounded)
|
||||
{
|
||||
var direction = GetTargetDirection(position, rotation);
|
||||
if (Mathf.Abs(direction.x) <= m_Distance &&
|
||||
((m_RequireGrounded && grounded) || (!m_RequireGrounded && (Mathf.Abs(direction.y) <= m_Distance))) &&
|
||||
Mathf.Abs(direction.z) <= m_Distance) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the character in a valid rotation?
|
||||
/// </summary>
|
||||
/// <param name="rotation">The rotation of the character.</param>
|
||||
/// <returns>True if the rotation is valid.</returns>
|
||||
public bool IsRotationValid(Quaternion rotation)
|
||||
{
|
||||
Vector3 forwardDirection;
|
||||
if (m_RequireGrounded) {
|
||||
forwardDirection = Vector3.ProjectOnPlane(m_Transform.forward, rotation * Vector3.up);
|
||||
} else {
|
||||
forwardDirection = m_Transform.forward;
|
||||
}
|
||||
return Vector3.Angle(Quaternion.Euler(0, m_YawOffset, 0) * forwardDirection, rotation * Vector3.forward) <= m_Angle / 2 + 0.001f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e1740b57cc4f204399681ca7a2edd2f
|
||||
timeCreated: 1520365325
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects
|
||||
{
|
||||
using Opsive.UltimateCharacterController.StateSystem;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Activates or deactivates the GameObject based on the state.
|
||||
/// </summary>
|
||||
public class ObjectActivator : StateBehavior
|
||||
{
|
||||
[Tooltip("Should the GameObject be activated?")]
|
||||
[SerializeField] protected bool m_Active = true;
|
||||
|
||||
public bool Active { get { return m_Active; } set { m_Active = value; } }
|
||||
|
||||
private GameObject m_GameObject;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
m_GameObject = gameObject;
|
||||
|
||||
base.Awake();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The StateManager has changed the active state on the current object.
|
||||
/// </summary>
|
||||
public override void StateChange()
|
||||
{
|
||||
base.StateChange();
|
||||
|
||||
m_GameObject.SetActive(m_Active);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0b2f510676cc504cacc3fdbce05b906
|
||||
timeCreated: 1512934167
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the number of forward faces the object has, used by the Detect Object Ability Base ability.
|
||||
/// </summary>
|
||||
public class ObjectForwardFaces : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The number of forward facing sides the object has.")]
|
||||
[SerializeField] protected int m_ForwardFaceCount = 1;
|
||||
|
||||
public int ForwardFaceCount { get { return m_ForwardFaceCount; } set { m_ForwardFaceCount = value; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 330bb3e76868731429949dcb8df426b3
|
||||
timeCreated: 1527000257
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a unique identifier for the object that this component is attached to, used by the Detect Object Ability Base ability.
|
||||
/// </summary>
|
||||
public class ObjectIdentifier : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The value of the identifier.")]
|
||||
[SerializeField] protected uint m_ID;
|
||||
|
||||
public uint ID { get { return m_ID; } set { m_ID = value; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3ebcf42a9d8f9145a73c60c46c60bc2
|
||||
timeCreated: 1527000257
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,211 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Audio;
|
||||
using Opsive.UltimateCharacterController.Game;
|
||||
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
|
||||
using Opsive.UltimateCharacterController.Networking.Game;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for any object that can be picked up.
|
||||
/// </summary>
|
||||
public abstract class ObjectPickup : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The amount of time to enable the trigger after the object has been enabled and the rigidbody has stopped moving.")]
|
||||
[SerializeField] protected float m_TriggerEnableDelay = 4;
|
||||
[Tooltip("Should the item be picked up when the character enters the trigger?")]
|
||||
[SerializeField] protected bool m_PickupOnTriggerEnter = true;
|
||||
[Tooltip("The amount that the object should rotate while waiting to be picked up.")]
|
||||
[SerializeField] protected Vector3 m_RotationSpeed;
|
||||
[Tooltip("A set of AudioClips that can be played when the object is picked up.")]
|
||||
[SerializeField] protected AudioClipSet m_PickupAudioClipSet = new AudioClipSet();
|
||||
[Tooltip("The text that should be shown by the message monitor when the object is picked up.")]
|
||||
[SerializeField] protected string m_PickupMessageText;
|
||||
[Tooltip("The sprite that should be drawn by the message monitor when the object is picked up.")]
|
||||
[SerializeField] protected Sprite m_PickupMessageIcon;
|
||||
|
||||
public float TriggerEnableDelay { get { return m_TriggerEnableDelay; } set { m_TriggerEnableDelay = value; } }
|
||||
public bool PickupOnTriggerEnter { get { return m_PickupOnTriggerEnter; } set { m_PickupOnTriggerEnter = value; } }
|
||||
public Vector3 RotationSpeed { get { return m_RotationSpeed; } set { m_RotationSpeed = value; enabled = m_RotationSpeed.sqrMagnitude > 0; } }
|
||||
public AudioClipSet PickupAudioClipSet { get { return m_PickupAudioClipSet; } set { m_PickupAudioClipSet = value; } }
|
||||
public string PickupMessageText { get { return m_PickupMessageText; } set { m_PickupMessageText = value; } }
|
||||
public Sprite PickupMessageIcon { get { return m_PickupMessageIcon; } set { m_PickupMessageIcon = value; } }
|
||||
|
||||
private GameObject m_GameObject;
|
||||
private Transform m_Transform;
|
||||
private Rigidbody m_Rigidbody;
|
||||
private Collider m_Trigger;
|
||||
|
||||
private int m_StartLayer;
|
||||
private bool m_IsDepleted = true;
|
||||
private ScheduledEventBase m_TriggerEnableEvent;
|
||||
private bool m_Initialized;
|
||||
|
||||
public bool IsDepleted { get { return m_IsDepleted; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
protected virtual void Awake()
|
||||
{
|
||||
m_GameObject = gameObject;
|
||||
m_Transform = transform;
|
||||
m_Rigidbody = GetComponent<Rigidbody>();
|
||||
m_StartLayer = m_GameObject.layer;
|
||||
|
||||
// Get a reference to the trigger and non-trigger collider. The collider will be disabled when the Rigidbody has stopped moving. The trigger will be enabled
|
||||
// when the Rigidbody has stopped moving.
|
||||
var colliders = GetComponents<Collider>();
|
||||
for (int i = 0; i < colliders.Length; ++i) {
|
||||
if (colliders[i].isTrigger) {
|
||||
m_Trigger = colliders[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Trigger == null) {
|
||||
Debug.LogError("Error: A trigger must exist on the ObjectPickup component on the GameObject " + name + ".");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The object has been enabled.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
Initialize(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the object.
|
||||
/// </summary>
|
||||
/// <param name="forceInitialization">Should the object be initialized even if it isn't depleted?</param>
|
||||
public void Initialize(bool forceInitialization)
|
||||
{
|
||||
// If the item isn't depleted then it has already been initialized.
|
||||
if (!m_IsDepleted && !forceInitialization) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsDepleted = false;
|
||||
if (m_TriggerEnableDelay > 0) {
|
||||
m_Trigger.enabled = false;
|
||||
m_GameObject.layer = LayerManager.IgnoreRaycast;
|
||||
if (m_Initialized || forceInitialization) {
|
||||
// If a rigidbody exists then the trigger event should be scheduled after the rigidbody has settled. If a rigidbody does not exist then
|
||||
// the event should be scheduled immediately.
|
||||
if (m_Rigidbody != null) {
|
||||
if (m_TriggerEnableEvent != null) {
|
||||
Scheduler.Cancel(m_TriggerEnableEvent);
|
||||
m_TriggerEnableEvent = null;
|
||||
}
|
||||
Scheduler.Schedule(0.2f, CheckVelocity);
|
||||
} else {
|
||||
m_TriggerEnableEvent = Scheduler.Schedule(m_TriggerEnableDelay, EnableTrigger);
|
||||
}
|
||||
} else {
|
||||
// If the object isn't initialized yet then this is the first time the object has spawned.
|
||||
EnableTrigger();
|
||||
}
|
||||
}
|
||||
m_Initialized = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disable the component when the Rigidbody has settled.
|
||||
/// </summary>
|
||||
private void CheckVelocity()
|
||||
{
|
||||
if (m_Rigidbody.linearVelocity.sqrMagnitude < 0.01f) {
|
||||
m_TriggerEnableEvent = Scheduler.Schedule(m_TriggerEnableDelay, EnableTrigger);
|
||||
return;
|
||||
}
|
||||
// The Rigidbody hasn't settled yet - check the velocity again in the future.
|
||||
Scheduler.Schedule(0.2f, CheckVelocity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the trigger.
|
||||
/// </summary>
|
||||
private void EnableTrigger()
|
||||
{
|
||||
m_Trigger.enabled = true;
|
||||
m_TriggerEnableEvent = null;
|
||||
m_GameObject.layer = m_StartLayer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optionally rotates the object.
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
m_Transform.rotation *= Quaternion.Euler(m_RotationSpeed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An object has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The object which entered the trigger.</param>
|
||||
public virtual void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// The object can't be picked up if it is depleted.
|
||||
if (m_IsDepleted) {
|
||||
return;
|
||||
}
|
||||
|
||||
TriggerEnter(other.gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A GameObject has entered the trigger.
|
||||
/// </summary>
|
||||
/// <param name="other">The GameObject that entered the trigger.</param>
|
||||
public abstract void TriggerEnter(GameObject other);
|
||||
|
||||
/// <summary>
|
||||
/// The object has been picked up.
|
||||
/// </summary>
|
||||
/// <param name="pickedUpBy">A reference to the object that picked up the object.</param>
|
||||
protected virtual void ObjectPickedUp(GameObject pickedUpBy)
|
||||
{
|
||||
// The object may not have been instantiated within the scene.
|
||||
if (m_GameObject == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_IsDepleted = true;
|
||||
|
||||
// Send an event notifying of the pickup.
|
||||
EventHandler.ExecuteEvent(pickedUpBy, "OnObjectPickedUp", this);
|
||||
|
||||
// Optionally play a pickup sound if the object picking up the item is attached to a camera.
|
||||
// A null GameObject indicates that the clip will play from the AudioManager.
|
||||
var camera = Utility.UnityEngineUtility.FindCamera(pickedUpBy);
|
||||
if (camera != null) {
|
||||
m_PickupAudioClipSet.PlayAudioClip(null);
|
||||
}
|
||||
|
||||
if (ObjectPool.InstantiatedWithPool(m_GameObject)) {
|
||||
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
|
||||
if (NetworkObjectPool.IsNetworkActive()) {
|
||||
NetworkObjectPool.Destroy(m_GameObject);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ObjectPool.Destroy(m_GameObject);
|
||||
} else {
|
||||
// Deactivate the pickup for now. It can appear again if a Respawner component is attached to the GameObject.
|
||||
m_GameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2ab038298fafd84cb7c13303f9fe91c
|
||||
timeCreated: 1505262312
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,47 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.Objects.CharacterAssist
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The Spherical Gravity Zone extends the Gravity Zone component by implementing a gravity force that is affected by spherical directions.
|
||||
/// </summary>
|
||||
public class SphericalGravityZone : GravityZone
|
||||
{
|
||||
[Tooltip("The amount of influence that the gravity force has. An x value of 0 represents the further point away from the sphere (at the distance of the radius), " +
|
||||
"while an x value of 1 represents the cloest point (the center of the sphere). The y value represents the amount of force that should be applied at that distance (0-1).")]
|
||||
[SerializeField] protected AnimationCurve m_Influence = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
||||
[Tooltip("The value to multiply the influence by. A larger value can be used for larger spheres.")]
|
||||
[SerializeField] protected float m_InfluenceMultiplier = 1;
|
||||
|
||||
private Transform m_Transform;
|
||||
private SphereCollider m_SphereCollider;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
private void Awake()
|
||||
{
|
||||
m_Transform = transform;
|
||||
m_SphereCollider = GetComponent<SphereCollider>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the direction of gravity that should be applied.
|
||||
/// </summary>
|
||||
/// <param name="position">The position of the character.</param>
|
||||
/// <returns>The direction of gravity that should be applied.</returns>
|
||||
public override Vector3 DetermineGravityDirection(Vector3 position)
|
||||
{
|
||||
var direction = (position - m_Transform.position);
|
||||
var influenceFactor = m_Influence.Evaluate(1 - (direction.magnitude / (m_SphereCollider.radius * MathUtility.ColliderRadiusMultiplier(m_SphereCollider)))) * m_InfluenceMultiplier;
|
||||
return direction.normalized * influenceFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33f9f41519105e741b84fe36d514ef71
|
||||
timeCreated: 1543955762
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user