Interact Modification ValitadeObject Question

nathanj

Active member
Edit: You can find a working version of this here: https://www.opsive.com/forum/index.php?threads/swim-height-detection-ability.4934/


Hi,

I'm using a stripped down mod of an interact ablilty to detect water height (to set the water height of the swim ability) but I'm a little confused about how the ValitadeObject is called.

At the moment the ability works if my player walks up to the water source (it gets the water height ans applies it to the swim Ability) but once the player is swimming the ValidateObject stops detecting. Can you tell me how to have the ValidateObject continue to run while the player is swimming?

Thanks as always,
Nathan

Code:
 /// <summary>
    /// Interacts with another object within the scene. The object that the ability interacts with must have the Interact component added to it.
    /// </summary>
    [DefaultStartType(AbilityStartType.Automatic)]
    [DefaultInputName("Action")]
    [DefaultAbilityIndex(9)]
    [DefaultAllowPositionalInput(false)]
    [DefaultAllowRotationalInput(false)]
    [AllowDuplicateTypes]
    public class InteractSD : DetectObjectAbilityBase
    {
        private Swim m_SwimAbility;
        public override void Awake()
        {
            base.Awake();
            m_SwimAbility = m_CharacterLocomotion.GetAbility<Swim>();
        }
    
        /// <summary>
        /// Called when the ablity is tried to be started. If false is returned then the ability will not be started.
        /// </summary>
        /// <returns>True if the ability can be started.</returns>
        public override bool CanStartAbility()
        {
            // The base class may prevent the ability from starting.
            if (!base.CanStartAbility())
            {
                return false;
            }
            return false;
        }

  
        /// <summary>
        /// Validates the object to ensure it is valid for the current ability.
        /// </summary>
        /// <param name="obj">The object being validated.</param>
        /// <param name="raycastHit">The raycast hit of the detected object. Will be null for trigger detections.</param>
        /// <returns>True if the object is valid. The object may not be valid if it doesn't have an ability-specific component attached.</returns>
        protected override bool ValidateObject(GameObject obj, RaycastHit? raycastHit)
        {
            if (!base.ValidateObject(obj, raycastHit)) {
                return false;
            }
        
            if (obj.layer == 4) {
                m_SwimAbility.SetWaterSurfacePosition(raycastHit.Value.point.y);
                Debug.Log(raycastHit.Value.point.y + "  water height");
                return false;
            }
            return false;
        }


        /// <summary>
        /// The object has been destroyed.
        /// </summary>
        public override void OnDestroy()
        {
            base.OnDestroy();

        }
    }


InteractSD.PNG
 
Last edited:
k, this seems to be working. Add this script to your Swim scripts folder. Water objects are set to layer 4 in my project, and this script is looking for that value.

Code:
 [DefaultStartType(AbilityStartType.Automatic)]
    [DefaultAbilityIndex(-1)]
    [DefaultAllowPositionalInput(false)]
    [DefaultAllowRotationalInput(false)]

    public class InteractSD : DetectObjectAbilityBase
    {
        private Swim m_SwimAbility;
        private GameObject _gameObj;
        private bool setWaterTo0 = false;
    
        public override void Awake()
        {
            base.Awake();
            m_SwimAbility = m_CharacterLocomotion.GetAbility<Swim>();
        }
    
    
        public override bool CanStartAbility()
        {
           // The base class may prevent the ability from starting.
            if (!base.CanStartAbility())
            {
                if (setWaterTo0)
                {
                    if (_gameObj == null && !m_SwimAbility.IsActive)
                    {
                        m_SwimAbility.SetWaterSurfacePosition(0f);
                        setWaterTo0 = false;
                    }
                    _gameObj = null;
                    return false;
                }
            }
            return false;
        }

    

      
        protected override bool ValidateObject(GameObject obj, RaycastHit? raycastHit)
        {
            if (!base.ValidateObject(obj, raycastHit))
            {
                return false;
            }
            _gameObj = obj;
            if (obj.layer == 4)
            {
                m_SwimAbility.SetWaterSurfacePosition(raycastHit.Value.point.y);
                Debug.Log(raycastHit.Value.point.y + "  water height");
                if (!setWaterTo0) setWaterTo0 = true;
                return true;
              
            }
                return false;
        }
      

        public override void OnDestroy()
        {
            base.OnDestroy();

        }
    }

@Justin Is there any reason why something like this isn't included in the swimming package? I have no doubt that this can be written much cleaner ;) but still, this functionality really opens up a lot of possibilities with multiple water sources.

Edit: K, there is still one issue I just found. If the camera is on the ground or looking up to the character when the player enters the water it only registers if the collider is set to convex, but it doesn't get the proper height of the water, it's a bit below (say 1 unit) the actual water height. Is there a different detection method that might work better? I've tried and Raycast seems to be the only one that I can get to work with the above script. Maybe this is why you haven't included this type of script before :rolleyes:

Anyways, thanks
Nathan
 
Last edited:
Top