// Copyright (C) 2023 Nicholas Maltbie // // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and // associated documentation files (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, publish, distribute, // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or // substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using nickmaltbie.OpenKCC.Environment.MovingGround; using UnityEngine; namespace nickmaltbie.OpenKCC.Character.Config { /// /// Relative parent configuration for saving /// the position of an object relative to a given parent object. /// public class RelativeParentConfig { /// /// Relative position in local space. /// public Vector3 RelativePos { get; internal set; } /// /// Relative rotation in local space. /// TODO: Adjust this configuration to work as expected. /// public Quaternion RelativeRotation { get; internal set; } /// /// Previous parent for saving relative transform position. /// public Transform PreviousParent { get; internal set; } /// /// Check if the player is standing on moving ground. /// public bool OnMovingGround => PreviousParent != null; /// /// Reset the relative parent transform. /// public void Reset() { RelativePos = Vector3.zero; RelativeRotation = Quaternion.identity; PreviousParent = null; } /// /// Update the moving ground state for a given /// relative parent for some given movement. /// /// Position of object before moving. /// Rotation of object before moving. /// Current grounded state of the object. /// Delta that the object has moved. /// Delta time for update. /// The distance the player should be moved based /// on moving ground. Will only be more than Vector3.zero if the ground /// is moving and should not attach. public virtual Vector3 UpdateMovingGround(Vector3 position, Quaternion rotation, IKCCGrounded groundedState, Vector3 delta, float deltaTime) { if (groundedState.StandingOnGround && groundedState.Floor != null) { Transform parent = groundedState.Floor?.transform; IMovingGround ground = parent.GetComponent(); if (ground == null || ground.ShouldAttach()) { RelativeRotation = rotation * Quaternion.Inverse(parent.rotation); if (parent != PreviousParent) { RelativePos = position + delta - parent.position; RelativePos = Quaternion.Inverse(parent.rotation) * RelativePos; } else { RelativePos += Quaternion.Inverse(parent.rotation) * delta; } PreviousParent = parent; } else { PreviousParent = null; return ground.GetVelocityAtPoint(groundedState.GroundHitPosition) * deltaTime; } } else { Reset(); } return Vector3.zero; } /// /// Move the transform's position /// to be the same relative position to parent as the saved position. /// /// Transform to move. public virtual void FollowGround(Transform transform) { transform.position += DeltaPosition(transform.position); } /// /// Compute the delta in rotation required to move the /// object with the moving ground for this update. /// /// Rotation fo the object in world space. /// public Quaternion DeltaRotation(Quaternion rotation) { if (OnMovingGround) { return PreviousParent.rotation * Quaternion.Inverse(RelativeRotation); } return Quaternion.identity; } /// /// Compute the delta in position required to move the character /// with the moving ground for this update. /// /// Position of the object in world space. /// Delta in world space to move the player. public Vector3 DeltaPosition(Vector3 position) { if (OnMovingGround) { return (PreviousParent.position + PreviousParent.rotation * RelativePos) - position; } return Vector3.zero; } } }