- Home /
Character that Climbs Everything Including On Ceiling
We have been collectively banging our heads against this particular problem for a month or two now. We get results that are almost there but nothing is working perfectly.
The goal is to get our character to scramble over and around any surface at any angle in the level, much like a spider is able to do. This includes over uneven surfaces and around protruding cliff edges.
The main problem is keeping the guy grounded:
We can't seem to keep the rigidbody glued to the ground--addForce isn't controlled enough for ground hugging. CharacterControllers are awesome for ground hugging, but unfortunatly world Y up seems to be very important to it--any time we rotate our CharacterController, it wigs out. So we sigh and go back trying to get the rigid body to work.
Our main approach with the rigid body character is to use raycasting to detect ground/cliff normal's angle and orient our character to the angle. We then apply fake gravity on the local y axis to keep him on the surface, and lerp between any change in angle as our character moves over terrain.
The main problem we've encountered is that a rigidbody moved by addForce is very prone to leaving the ground because our character likes to ramp off of bumps. This leads to grounded state issues and a character with weird floating behavior when on a cliff face. We've attempted to add more local downward force when he leaves the ground to push him back to the surface, the results have been uneven motion and a bit of a jitter and he still leaves the ground a little bit, which means its not really accomplishing the goal anyway.
We have also tried the Locomotion System which has a planet walking demo where the character(rigid body) walks on all angles. For performance reasons(we are launching on iOS), and for the sake of simplicity, we'd prefer not to go this route. At any rate, the character flys off the planet when you round any sharp corners because of the local y down gravity they use to keep it stuck to the surface.
We've experimented with translate to move our character about, but the rigid body tended to ignore the terrain and go through the mesh. I've heard movePosition has been used, but it sounds like it would have the same collider ignoring problems of translate. Perhaps by directly manipulating velocity we could gain a bit more control, but regardless none of those solutions alone would solve our need to hug a bumpy ground--please correct me if I'm wrong there.
Perhaps there is a way of using velocity to move forward while using ray casts to translate my character to the surface, kind of like a match target?
I wish unity had a stick-to-any-surface-like-glue-while-moving-forward function :).
Any suggestions would be greatly appreciated. Thanks.
Just FYI you can't rotate a character controller.
Just an idea: is it possible for you to rotate the world ins$$anonymous$$d of the player? It's just a way around rotation a character controller :)
I wish that were a possibility, but unfortunately the world is far too complex. Thanks for the suggestion though:)
Well, you could write your own character controller, I think thats your only option. Using inbuilt physics is to inaccurate for what your looking for
How do you know what the "down" direction is? Is it when the character touch a surface, then that is the new ground, or you have set up alot of trigger boxes? And, is it 2D game or 3D game?
@$$anonymous$$r. JWolf, Down is the characters local Y axis as opposed to world Y. We ray cast to the surface, grab the hit normal angle and orient our character to the angle. We then apply fake gravity down characters local y axis, effectively making the new angle "Down" as far as he is concerned.
Answer by dl_studios · Jun 05, 2013 at 05:01 AM
Well as luck would have it we found the answer. By directly controlling the rigid body velocity to move our character and using a downward local y velocity to keep him on the surface we oriented him to our character sticks like glue. This worked much better than addForce.
Modified this slightly. Controls velocity. http://answers.unity3d.com/questions/61089/how-to-properly-move-a-rigidbodycollider.html
We got the character orienting code from another forum thread that I can't find anymore. We put it in our series of ray casts to orient character to normal face should raycast hit.
private Vector3 curNormal = Vector3.zero;
private Vector3 usedNormal = Vector3.zero;
private Quaternion tiltToNormal;
public float turnSpeed = 2f;
public float MoveSpeed = 20f
moveDirection = transform.TransformDirection (moveDirection);
//rotates character
rotationAmount = Input.GetAxis ("Horizontal") * turnSpeed * Time.deltaTime;
transform.RotateAround (transform.up, rotationAmount);
//set up a variable to manipulate velocity directly.
Vector3 velocityAllAxis = transform.rigidbody.velocity;
velocityAllAxis.x = moveDirection.x;
velocityAllAxis.z = moveDirection.z;
velocityAllAxis.y = moveDirection.y;
transform.rigidbody.velocity = velocityAllAxis;
//now for detection and orientation.
RaycastHit outhit;
if (Physics.Raycast (transform.position, transform.forward, out outhit, 3f)) {
Debug.DrawRay (transform.position, transform.forward, Color.blue, 2f);
usedNormal = outhit.normal;
curNormal = Vector3.Lerp (curNormal, usedNormal, 6.0f * Time.deltaTime);
tiltToNormal = Quaternion.FromToRotation (transform.up, curNormal) * transform.rotation;
transform.rotation = tiltToNormal;
} else {
if (Physics.Raycast (transform.position, -transform.up, out outhit, 3f)) {
Debug.DrawRay (transform.position, -transform.up, Color.green, 2f);
usedNormal = outhit.normal;
curNormal = Vector3.Lerp (curNormal, usedNormal, 6.0f * Time.deltaTime);
tiltToNormal = Quaternion.FromToRotation (transform.up, curNormal) * transform.rotation;
transform.rotation = tiltToNormal;
} else {
if (Physics.Raycast (transform.position + (-transform.up), -transform.forward + new Vector3 (0, .3f, 0), out outhit, 3f)) {
Debug.DrawRay (transform.position + (-transform.up), -transform.forward + new Vector3 (0, .3f, 0), Color.green, 2f);
usedNormal = outhit.normal;
curNormal = Vector3.Lerp (curNormal, usedNormal, 6.0f * Time.deltaTime);
tiltToNormal = Quaternion.FromToRotation (transform.up, curNormal) * transform.rotation;
transform.rotation = tiltToNormal;
} else {
curNormal = Vector3.Lerp (curNormal, Vector3.up, 6.0f * Time.deltaTime);
tiltToNormal = Quaternion.FromToRotation (transform.up, curNormal) * transform.rotation;
transform.rotation = tiltToNormal;
}
}
}
Good job. Could you post the code that solved the problem? So others with the same problem might get some ideas :3
Good job solving this. I have a very similar problem, so I for one would very much appreciate seeing the code snippet that did the trick for you!
Personally I think @dl_studios has supplied sufficient explanation for someone to get the right idea of what to do :)
Thanks for updating with example code dl_studios - much appreciated.
Hello I know this topic is closed but I'm in a ditch here... So I have no idea what you did in the first half of this code. The commands mentioned here aren't even showing up in $$anonymous$$onodevelop.. total noob here ... I got the raycasting part but don't understand how to implement the gravity. Any help appreciated.
Your answer
Follow this Question
Related Questions
Best climbing system! 1 Answer
Using Vector3.lerp to climb 0 Answers
climbing ladders script, help 0 Answers
MatchTarget Help 1 Answer
Can the Locomotion System be adapted to climb vertical surfaces? 2 Answers