Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Rblain · Feb 07, 2010 at 11:32 PM · physicscharactermathvectormove-with-moving-platform

CharacterController on Moving Surface

The CharacterController needs to get on and off translating and rotating surfaces without parenting, which does not work without messing with the hierarchy. I can get a collided objects hit point, the offset of that from its axis and the position and rotation of the controller. It updates on FixedUpdate(). However, I cannot figure out the proper use or combination of Vector3 or Quaternion or transform.rotation.eulerAngles to get the controller to behave like it is on a moving (translating) object that may be turning, tilting or rotating as well. It would seem to e to be a very useful piece of code for most game style and should probably be integrated wherever it is best (console kept telling me it didn't like where I was putting these vars) as a built in method "RideOnObject". I would post the code I am playing with but it will change ten minutes from now. If I strike it rich I will post the javascript.

edit:I checked the scripts out from answer 694. The last one threw too many errors in the console to even start debugging and rearranging the code. I have set up the first simpler script with appropriate inputs but am looking at the var calculatedMove which I have yet to assign a value to because I am wondering if I can retrieve that value somehow from the CharacterController script or the FPSWalker script and whether the MouseLook value should be incorporated. Or should I write my own move calculation? As well, I noted that when you add a script it automatically goes underneath the ones there and you cannot change order. If they fire off from top to bottom the does the bottom script translation and rotation of the CharacterController override the values from the script higher up the Inspector list?

Thanks for the meat of the answer.I was doing very similar routines but the quaternion versus Vector3 and how to get them to play together flipping from world to local and translating that back to world after updating the tracked local point position of collision was kicking my butt. I now have all that and am digging into how to control the Move. I then assign that value to calculatedMove and I can then test on any number of tagged objects. What's the trick here?

Best Regards and TIA

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Rblain · Feb 09, 2010 at 12:04 AM

Here is my script I can drop on a CharacterController or select one from the dropdown list in the inspector. I have done rudimentary testing on a rotating platform as I figured that was more of a trick than just a translating platform. To use it tag those surfaces with a "MovingSurface" tag so the OnCharacterColliderHit can find the name of the tag and implement the algorithm if the hitObject tag == "MovingSurface". Thanks to those I stood on the shoulders of to finally get this. Now for coffee.

var myCharacterController : CharacterController; private var activePlatform : Transform; private var hit : ControllerColliderHit; private var activeGlobalPlatformPoint : Vector3; private var activeLocalPlatformPoint : Vector3; private var activeGlobalPlatformRotation : Quaternion; private var activeLocalPlatformRotation : Quaternion; var tagName : String; private var moveDirection = Vector3.zero; private var grounded : boolean = false;

function FixedUpdate () { if (tagName != "MovingSurface") { activePlatform = null; lastPlatformVelocity = Vector3.zero; } if (tagName == "MovingSurface") { if (grounded) { // We are grounded on a Moving Surface, so recalculate move direction directly from axes moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); moveDirection = transform.TransformDirection(moveDirection);// Move the controller var controller : CharacterController = GetComponent(CharacterController); var flags = controller.Move(moveDirection Time.deltaTime); grounded = (flags & CollisionFlags.CollidedBelow) != 0; //Keep moving (?) by getting the spped var from the FPSWalker CC script or whatever you are using moveDirection = FPSWalker.speed;

     }
 var calculatedMovement = moveDirection * Time.deltaTime;
     // Moving platform support
     if (activePlatform != null) {
         var newGlobalPlatformPoint = activePlatform.TransformPoint(activeLocalPlatformPoint);
         var moveDistance = (newGlobalPlatformPoint - activeGlobalPlatformPoint);
         transform.position = transform.position + moveDistance;
         lastPlatformVelocity = (newGlobalPlatformPoint - activeGlobalPlatformPoint) / Time.deltaTime;
         // If you want to support moving platform rotation as well:
         var newGlobalPlatformRotation = activePlatform.rotation * activeLocalPlatformRotation;
         var rotationDiff = newGlobalPlatformRotation * Quaternion.Inverse(activeGlobalPlatformRotation);
         transform.rotation = rotationDiff * transform.rotation;
         }
         else
         {
             lastPlatformVelocity = Vector3.zero;
         }
         //Controller Move  takes place here 
         collisionFlags = myCharacterController.Move (calculatedMovement);
         // Moving platforms support
     if (activePlatform != null) {
         activeGlobalPlatformPoint = transform.position;
         activeLocalPlatformPoint = activePlatform.InverseTransformPoint (transform.position);
         // If you want to support moving platform rotation as well:
         activeGlobalPlatformRotation = transform.rotation;
         activeLocalPlatformRotation = Quaternion.Inverse(activePlatform.rotation) * transform.rotation;
         }
 }

}

function OnControllerColliderHit (hit : ControllerColliderHit) { // Make sure we are really standing on a straight platform // Not on the underside of one and not falling down from it either! if (hit.moveDirection.y < -0.9 && hit.normal.y > 0.5) { activePlatform = hit.collider.transform; tagName = hit.collider.tag; } }

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Rblain · Feb 14, 2010 at 01:17 PM 0
Share

It works fabulousy xcept one item. How do I get the CharacterControler to follow the rotation of a merry-go-round for instance. The CC can get on and is dragged around but the view from their camera does not rotate with the platform and looks in the same absolute direction as prior to boarding.

avatar image CracksisT · Feb 25, 2010 at 07:44 PM 0
Share

i'm getting this error:

Assets/CharStickPlatform.js(26,44): BCE0020: An instance of type 'FPSWalker' is required to access non static member 'speed'.

I'll probably have to refer to my own script for moving around but that gives the same error.

What should I do?

avatar image Braian Correa · Nov 03, 2013 at 07:18 PM 0
Share

Cracksis, that's because you need to set the variable speed on your FPSWalker (or whatever you named your movement script)to static, os you can access its value from a different script! declair it like:

static var speed : float;

avatar image Kachupi · Feb 20, 2014 at 01:11 PM 0
Share

getting the error $$anonymous$$ identifier: 'lastPlatformVelocity'. not sure why doesnt seem like anyone else is o.o

avatar image d-pav · Apr 25, 2014 at 04:56 AM 0
Share

Same with me, $$anonymous$$ identifier: 'lastPlatformVelocity'. Is there a solution for this? Thanks in advance!

avatar image
2

Answer by Jaap Kreijkamp · Feb 08, 2010 at 05:18 AM

See Question 694 for several solutions.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by $$anonymous$$ · Dec 31, 2015 at 12:56 AM

Your solution work but it's quite illisible... here is my solution in C# my CharacterController is in multiple modules so I will just expose the code for my module PlayerGround

 [System.Serializable]
 public class PlayerGround : PlayerAttribute {
 
     private bool    m_grounded;
     private bool    m_prevGrounded;
     private Vector3 m_groundNormal;
 
     public bool    Grounded     { get { return m_grounded;     } }
     public bool    PrevGrounded { get { return m_prevGrounded; } }
     public Vector3 GroundNormal { get { return m_groundNormal; } }
 
     // attributes to check the platform
     private Transform m_platform;
 
     private Vector3 m_globalPoint;
     private Vector3 m_localPoint;
 
     private Quaternion m_globalRotation;
     private Quaternion m_localRotation;
 
     /* INIT METHOD */
     //public override void Init(PlayerController controller) { base.Init(controller); }
 
     /* UPDATE METHOD */
     public override void Update() {
         // we update the state of the player
         GroundCheck();
 
         //Vector3 lastVelocity = Vector3.zero;
 
         // if we are on a platform
         if ( m_platform != null ) {
             // we calculate the movement of the platform since the last update
             Vector3 newGlobalPoint = m_platform.TransformPoint(m_localPoint);
             Vector3 moveDistance = newGlobalPoint - m_globalPoint;
             // we apply the movement to the player
             m_ctrl.transform.position += moveDistance;
 
             // we calculate the rotation of the platform since the last update
             Quaternion newGlobalRotation = m_platform.rotation * m_localRotation;
             Quaternion rotationDiff = newGlobalRotation * Quaternion.Inverse(m_globalRotation);
             // we apply the rotation to the player
             m_ctrl.transform.rotation = rotationDiff * m_ctrl.transform.rotation;
             // Quaternion multiplication is not commutative !
         }
     }
 
     // allow to keep track of the position and rotation of the platform
     public void UpdatePlatform() {
         if ( m_platform != null ) {
             // we recover the position of the platform for the next update
             m_globalPoint = m_ctrl.transform.position;
             m_localPoint = m_platform.InverseTransformPoint(m_ctrl.transform.position);
             // we recover the rotation of the platform for the next update
             m_globalRotation = m_ctrl.transform.rotation;
             m_localRotation = Quaternion.Inverse(m_platform.rotation) * m_ctrl.transform.rotation;
         }
     }
 
     // we check if the player is on the ground
     public void GroundCheck() {
         RaycastHit hitInfo;
         m_prevGrounded = m_grounded;
         // if the player has a ground beneath his feet
         if (Physics.SphereCast(
             m_ctrl.transform.position,
             m_ctrl.Collider.radius,
             Vector3.down,
             out hitInfo,
             ((m_ctrl.Collider.height / 2f) - m_ctrl.Collider.radius) + 0.01f)
         ) {
             // he is grounded
             m_grounded = true;
             m_groundNormal = hitInfo.normal;
             
             // we check if we changed of platform
             bool platformChange = m_platform != hitInfo.transform;
             // we recover the platform on which the player is standing
             m_platform = hitInfo.transform;
             // if we just changed of platform
             if ( platformChange ) {
                 // we update the position of the platform once
                 UpdatePlatform();
             }
         } else {
             // he is not grounded
             m_grounded = false;
             m_groundNormal = Vector3.up;
             // the player is not on a platform
             m_platform = null;
         }
         // if the player just leave the ground without jumping
         if (!m_prevGrounded && m_grounded && m_ctrl.Move.Jumping) {
             // he is not jumping
             m_ctrl.Move.Jumping = false;
         }
     }
 
     // we fix the player to the ground
     public void StickToGround() {
         // if the ground under the feet of the player is not too much steep
         if (Mathf.Abs(Vector3.Angle(m_groundNormal, Vector3.up)) < 85f) {
             // we stick the player to the ground
             m_ctrl.Body.velocity = Vector3.ProjectOnPlane(m_ctrl.Body.velocity, m_groundNormal);
         }
     }
 }

Then in my the update function of my PlayerController, I call PlayerGround.Update(); then I move the character based on player's inputs then I call PlayerGround.UpdatePlatform();

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by BDX777 · Oct 23, 2015 at 01:48 AM

A real naive yet effective and convincing approach is to re-parent the transform of your character to the platform below you using a simple raycast firing straight down. This works, but may need optimizations.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image $$anonymous$$ · Jan 01, 2016 at 05:06 PM 1
Share

This solution doesn't work for rotation or when the platform has a non-normalized scale.

avatar image BDX777 $$anonymous$$ · Jan 01, 2016 at 11:32 PM 0
Share

Very very true, but still a somewhat working naive approach.

As for another approach, you could calculate difference in position from a platform below your feet using some sort of raycast and two Vector3s for the platform's current and last position, calculate direction and speed based off that, and apply those values to your worldspace movement vector that you feed to CharacterController.$$anonymous$$ove(); and see if that works, and make sure that it's additive and not forcing those values, that way you can move about while you're on the platform.

Also make sure that it is your designated worldspace vector, the one you feed a localspace vector which handles your inputs and then calculate movement based on relative rotation in worldspace.

World Space $$anonymous$$ovement Vector = gameObject.transform.rotation * Local Space Input Vector;

Oh and you could even try using another vector and use interpolation ($$anonymous$$athf.Lerp) to smooth out player movement, and then feed that Smoothed World Space $$anonymous$$ovement vector to CharacterController.$$anonymous$$ove(); ins$$anonymous$$d.

Just more ideas of $$anonymous$$e.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

How to get the tangent and normal of a collision? 1 Answer

How to get a Character to move with a moving platform ? 6 Answers

Trying to move an object towards another's axis. 1 Answer

Make rigidbody walk like character controller 6 Answers

How to calculate the angle of a trajectory to hit the target 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges