Just wanted to say this is the best character controller tut that I've seen, and all the character controllers I've made since watching this have been based off of this.
Awesome explanation and solutions, thank you for sharing! I've been developing a similar physics based character controller by trying to combine my favorite parts of a responsive platformer controller and a raycast vehicle controller so this is all super helpful!
This is so exciting! I am pumped for the game, and thanks for talking in depth about your physics based movement and even showing code. I will for sure give this a go in my next game!
Wow, very impressed. The game I'm working on uses (mostly) hover vehicles, so I was already using a setup similar to yours (floating "characters" with continually calculated strength and dampening forces). But you guys have really taken it to the next level with improvements that I hadn't thought of at all. Thanks!
I've been looking for an explanation, a hint on physics based movement for the past 3 months. This has really helped figure out how to do it, at least gave me a starting point. Thanks for the explanation!
The hovering capsule mechanic is really clever. Finally found something that works for my project. Thanks for sharing. Amazing video. Great Explanation !!!
Hey, just created this Git repository with the assets I've created based on your tutorial. Just wanted to say thanks as this is EXACTLY what I was looking for.
Hey guys, thanks for this video! I just completed our first full playthrough with my family. We all love this game, so thank you so much for your hardwork! 🙏 In this breakdown, you get goalvel by multiplying the normalized relative input vector by the maxspeed and speedfactor. Can you briefly explain what speedfactor is and why you need it? To everyone else reading this, if you haven't purchased this game yet, I encourage you to do so! Let's support game devs who do great work and care about their craft!
My guess is that speedFactor is just used so they can apply movement effects (slow down and speed up) based on game mechanics. So its not really important to the system as a whole.
really not gonna lie, im gonna use this method of applying torque to remain upright. It's super fun to mess around with the spring strength and damper values to get wacky reactions! I can get some really wobbly bois that way. Thank you so much for the video!
Some things maybe a little over-complicated but considering this is a console game, everything had to be just right, console ppl are pretty strict I really liked how you made this (maybe you guys, this game and controller is way too good for one person) I also like making physics based systems since they basically handel everything themselves if you make it right, but everyone either mixes rb based movement with normal movement or just go with normal movement Earned a sub!
Hi! Great video and blog! I was looking at the Character Animation blog post and I'm really confused about the "use an animation curve that defined how to move between single frame poses." I get the idea that you're blending between the poses, but I'm not sure how you can apply the animation curve to a pose.
Thanks so much for sharing, this is a very interesting approach! Would reeeeeally love to see your vehicle configuration! It looks like you're using Unity's vehicle/wheel physics, but it's more responsive and snappy than any controller using those Ive ever seen
I don't really get the spring math. I wrote exactly what you have for the float mechanic and the capsule either plops to the ground, or starts bouncing infinitely high. What are the values you have set for the rigidbody weight, what are the values for the spring force and damper? they are just off screen and you don't explain how to play around with the values to get this right.
looking at the project now, the player's rigid body is average human sized (~2 units tall), and the mass is 10. the Ride Spring Strength is 2000, Ride Spring Damper is 100. Upright (torque) spring strength is also 2000, damper on that one is 30. Ride height is 1, but the raycast length is 1.5 (so 0.5 buffer)
I don't quite understand how the sticky to slope is implemented. My character, when walking upwards on an inclined surface, sticks too much to the surface, and when it descends, it stays too high, causing the character to make small falls. This is my code that implements the ground hover: public void GroundHover(float hoverHeight, float frequency, float dampFactor) { Vector3 origin = transform.TransformPoint(_capsuleCollider.center); bool rayDidHit = Physics.Raycast(origin, Vector3.down, out RaycastHit hit, Data.rayLength); if (rayDidHit) { float mass = _rigidbody.mass; Vector3 vel = _rigidbody.velocity; Vector3 rayDir = transform.TransformDirection(Vector3.down); float springDelta = hit.distance - hoverHeight; float springStrength = frequency * frequency * mass; float dampStrength = 2 * mass * frequency * dampFactor; // spring speed Vector3 otherVel = Vector3.zero; Rigidbody hitBody = hit.rigidbody; if (hitBody) { otherVel = hitBody.velocity; } float rayDirVel = Vector3.Dot(rayDir, vel); float otherDirVel = Vector3.Dot(rayDir, otherVel); float relVel = rayDirVel - otherDirVel; // add force float tension = springDelta * springStrength; float damp = relVel * dampStrength; float springForce = tension - damp; _rigidbody.AddForce(rayDir * springForce, ForceMode.Force); if (hitBody) { hitBody.AddForceAtPosition(rayDir * -springForce, hit.point, ForceMode.Force); } } } My parameter values are: - hoverHeight = 1.2f - frequency = 15f - dampFactor = 0.55f
What is the UtilsMath.ShortestRotation function doing? I was thinking it is just a Slerp from the current to desired rotation, but then why not just use the built-in Slerp.
here's a look at the code for that function. we need it it to make sure that turning the resulting Quaternion into a torque (angle axis essentially) would consistently be a torque that results in the shortest rotation. pastecode.io/s/o7O0y2PKNo
it was pointed out to us that we hadn't included the full code for this, the "Multiply" method in the snippet wasn't shown. updated code snippet: pastecode.io/s/5eo0fr5zak
@@ToyfulGames Oh my god thank you for providing that. I was tearing my hair out trying to reverse engineer it. I was just missing the dot product, instead I was trying to be fancy negating the angles and axis and it was NOT working out.
That's amazing, I searched for days until finally found this, and it's by far the best and most intelligent solution I found, can you tell me how did you make your character jump? I manage to make him float in the air just, but I can't make he jump, because he keeps being attracted to the floating point.
I love the idea of the floating capsule and am trying to implement it into a test of my own. That spring function is a double edge sword of sorts, as it like to pull down my character at the start of my jumps :V curious as to how you guys solved this problem!
we basically turn off the raycast and the forces to float the capsule when jumping, and then once in the air, turn them back on and wait for the raycast to "see" the ground again.
The stuff ya'll have shared lately has been phenomenal. Excited to peeps the full release on the 25th. I have a specific question on how your base controller works with your actual model asset. In the case of the Uprighting feature, is this just applied to the underlying rigidbody/collider and then that's taken into account on the actual mesh/skeleton by way of IK/FK effectors? Between the head/legs/body the way these all move is really impressive but it's got me rather flabbergasted. And weirdly as much as I want to throw in the towel and just go for a kinematic CC, I can't help but think the project I'm working on would be more fun with just an obsessively tuned physically based controller. This is so rare with most other things in comparison leaning more on unresponsive/active ragdoll variants, and while that's fine, it doesn't have that same tight game-feel that makes projects like this harken back to a wonderful era of platforming. Kudos :) feel free to ignore this question if it's too specific, and good luck on the release!
Thanks! yes, the upright force is happening on the root (rigid body) object. The visual mesh is a bit farther down in the heirarchy, and we ended up with a fair bit of code to orient the visual mesh beyond just what the rigid body is doing. when the ground is detected, for example, we are placing the character on the ground and the height comes from the animation state, not from the "bounce" of the physics levitation force for example. Hopefully that helps a bit.
@@ToyfulGames This is exactly what I've been hoping to have answered. Stuff like approach and clear definitions of "what-handles-what"; I can't thank ya'll enough.
if you look at 4:11 in the video, you can see we have a value called "groundVel", this is the velocity of the object you're standing on, so we just take it into account in calculating the target velocity for the character. so if there is no input from the joystick, then the character will move at the speed of the object it's standing on. works pretty well and is very simple.
The collider getting stuck likely has to do with friction. By setting the default physics material to frictionless should remove most issues of getting stuck. Also if you have any issues with the raycast detecting things for jumping (like its too precise and thus u dont have enough padding) experiment with using a sphere or box cast instead!
the force when the character reach the top reduce to 0, then the gravity will push it down again, making the character just bobbing up and down. what did I miss ? turn gravity off wont do, cause the character then will just float around and other funky sh1 t.
Hi, this is a great tutorial, I just have one question: When creating the floating capsule, how do you balance the spring so that it eventually stops moving when standing still? So far, my player character is always vibrating a little bit since it's always applying force trying to balance. Any tips would be great, I'll check the game out too for sure! Thanks!
That's what the "damping" does. basically, it's a factor that takes the velocity into account, and can stop the spring from oscillating forever. You then have 2 variables to tune: the overall strength of the spring, and the damping factor. With physics-based springs I usually find that a damping factor about 1/100th of the spring strength is a pretty good place to start. so if your spring strength is 1500, maybe start at a damping value of 15 and tweak from there.
HI there, such an interesting video and a great looking game. I was curious about the character movement mechanic for the floating. I'm new to coding and unity and just trying to understand how it works. It would be great to see the full snipping of the movement code, as I think it isn't shown entirely in the video? Thanks!
Thanks for the feedback... the code is kind of messy in the full game (for the purpose of understanding the core movement), because many other mechanics and visual aspects are in there as well... that's why we chose to describe the approach in more detail, as opposed to the specific, exact code. Hopefully that makes sense.
@@ToyfulGames I am trying to implement a system similar to what you show in the video. However, no matter how I tweak the values, the character still bobs up and down pretty aggressively... like a spring. I cannot get the player to maintain a solid distance to the ground without bobbing. How did you avoid the bobbing?
At 3:56 you say to "adjust it based on the camera angle" How can I do this? In your script it seems Rewired has some built in function, but I can't really figure out what it does, or how I would replicate it.
if anyone gets the same issue as me, this worked for me: Vector2 moveInput = playerControls.Player.Move.ReadValue(); Quaternion lookQuaternion = Quaternion.Euler(0, cameraLookTransform.rotation.y, 0); m_UnitGoal = cameraLookTransform.rotation * new Vector3(moveInput.x, 0, moveInput.y); (the cameraLookTransform only rotates around its y axis)
this controller is awesome!! how did you implement jumping? since the controller applies force to make the player also stick to the floor the the only solution to jump is to temporarily disable the springforce to with a ienumerator. i feel like there must be a better solution.
that's pretty much exactly what we do. we give the palyer an upwards velocity, and disable the check for the floating spring force for a brief period / or until the character's y velocity becomes negative.
This video was super informative!! Well-written code + great visual examples and explaination. BTW are you using the google C# naming conventions? Noticed the _ before private fields
we have our own code style we use that's just come from experience and working on various projects. not sure if it's the same as google or others tbh :)
@@ToyfulGames :) Good stuff! I'm working on a character controller in a game im making in Godot 4 Beta and it feels super smooth and responsive! Floating capsules are the way 🙏
Awesome video! I would love to know how the cars were done! I can make pushable objects, or objects with joints that react correctly to jumping on them, but can't find a setup for movable objects that would react correctly with the joints.
we will definitely consider making a similar video about the car physics in the future. but in our case, the characters controller is essentially disabled when the valets are in a car, and a separate system gives them some secondary motion and IK when driving a car.
toy bro can u do an in depth cine machine anti collision camera or when u get near walls how to prevent ur camera from going inside objects. Another thing is why some people think rb.velocity is better to move characters instead of rb.addforce. Im having troubles to make a decent controller to move my character around terrains in a smooth way. I dont use transform.position that cause so many problems.
Question: what did you do to get player input into the desired orientation? My guess is you did some kind of math, probably converting cartesian 2D input coordinates into polar coords to get an angle, and then somehow converting that into a quaternion?
although there are many methods for this, the easiest method is to "project" the player input into world space. in general, you need two world-space vectors: one that represents left/right input direction, and one that represents up/down input direction. usually this is the camera's "right" vector, and "forward" vector (perhaps with the Y component removed to "flatten it out" with the ground). you can create a world-space vector pointing in the direction of player input by essentially taking (world_right * input_x) + (world_fwd * input_y), assuming world_right and world_fwd are both normalized. that's the basic idea anyway!
Thanks a lot for this. I've bought the game, gameplay feels like a dream. I am trying to implement this upright force to the car controller I am trying to create, because it flips when turning. Hovewer, I can't see a UtilsMath or shortestRotation method. Can you help me?
That's a great video, I really like the floating capsule idea! But I wonder about the movement implementation, it gives no control over customizing deacceleration, or friction, without touching acceleration and maxacceleration themselves. How would one do to get control over that as well?
yeah that's a good point! you would need to make the code a bit more sophisticated if you wanted a different rate of "coasting" to a stop vs acceleration when running, and also for things like different surface types with different friction. But you're right, ultimately it would be a step on top where you perform a lookup to determine the correct acceleration and maxAcceleration values based on the situation.