Ahhh. I was curious as to why my Collider size and Collider height changed every time I played.
@JanOtt can explain better Iâm sure, but what Iâve noticed is that I can ignore the actual collider settings and change the ones on mover which will adjust the size of the collider as needed.
@toddkc Thanks for the input.
@JanOtt Not that you need any help with a crouch system but Easy Character Movement [ https://assetstore.unity.com/packages/templates/systems/easy-character-movement-57985 ] does a good job. Granted, I prefer your system since itâs more accurate on difficult terrains.
Thatâs exactly right, toddkc. The âMoverâ component overrides the colliderâs height and offset, based on the values set in its inspector (step height, collider height, collider thickness and collider offset).
Thanks! Iâm familiar with âEasy Character Movementâ, really nice package.
I am using the First person view and was wondering if there was any way to mimic a head bob while walking?
Generally speaking, youâd have to generate a heab bob animation for the camera (either through Unityâs built-in animation tools, an external program like Blender or procedurally creating it through code), then link that animation to the characterâs current state (for example, only play the head bob when the character is grounded and its movement speed exceeds a certain threshold).
The controller component of âCharacter Movement Fundmentalsâ offers two functions you can use for this purpose:
- GetVelocity() â Returns the characterâs current movement velocity.
- IsGrounded() â Returns âtrueâ if the character is currently grounded.
You might also want to check out chapter 4.6 of the manual, which has a short code example on this as well.
@JanOtt Iâm loving the controllers. Great work.
Just sharing a bit of todayâs work.
The goal: Iâm working on a test of some RPG mechanics in which the player can switch characters and/or possess other characters. So, I wanted to implement a system in which both the player and npcs use the mover system so the core movement mechanics are the same for both, so when you possess an NPC that was previously AI controlled, we just change the controller to one of the basic walker controllers. So, to make all entities use the mover system, I implemented a simple bridge script for controlling movers with NavMesh agents which will have their destinations set through behavior trees when not possessed by the player.
Hierarchy:
- The base Gameobject has all the character stats and the like and also includes the bridge component.
- Navmesh Agent: This must be a separate sibling of the gameobject with the Mover component as the Navmesh agent and non-kinematic rigidbody will push eachother otherwise!
- Controller: This Gameobject contains the modified controller, collider, rigidbody and Mover (Note: the Mover step and slope should be set equal to those of the NavMesh agent type used to keep them in sync).
- Model: With smoothtransform component.
Root: Mesh, animators, etc.
So what I built first is the Bridge:
public class NMAgentControllerBridge : MonoBehaviour
{
[SerializeField]
Mover mover; //Mover component on the child
[SerializeField]
NavMeshAgent agent;//NavMeshAgent on the sibling of the child with the Mover component
[SerializeField]
float leash = 1f;//Acceptable distance between the NavmeshAgent and the Mover before the NavmeshAgent is stopped and waits for the Mover to catch up.
bool hasAgent = false;
bool hasMover = false;
private void Awake()
{
if (agent == null)
{
agent = GetComponentInChildren<NavMeshAgent>();
}
if (mover == null)
{
mover = GetComponentInChildren<Mover>();
}
if(agent == null)
{ hasAgent = false; }
else
{ hasAgent = true; }
if(mover == null)
{
hasMover = false;
}
else
{ hasMover = true; }
}
private void Update()
{
if(!hasAgent || !hasMover)//If we're missing and agent or mover, we return to avoid null reference errors.
{ return; }
if(agent.pathPending)//Don't do anything if the agent is calculating a path
{
return;
}
if(agent.hasPath)
{
[INDENT][INDENT]//If the distance between the simulated position of the agent on the x and z axis (agent.nextposition) and Mover position is greater than the length of the leash, stop the NavmeshAgent. When the Mover catches up, let the NavMeshAgent resume along the path.[/INDENT][/INDENT]
if(Vector3.Distance(new Vector3(agent.nextPosition.x, 0f, agent.nextPosition.z), new Vector3(mover.transform.position.x, 0f, mover.transform.position.z)) > leash)
{
agent.isStopped = true;
}
else
{
agent.isStopped = false;//Resume
}
}
}
}
Then, on the child that contains the Mover component (sibling of the NavMeshAgent), I put this Controller:
public class AIWalkerController : BasicWalkerController
{
public NavMeshAgent agent;
bool hasAgent = false;
[SerializeField]
float leash = 1f;
protected override void Setup()
{
base.Setup();
if(agent == null)
{
GameObject parent = transform.parent.gameObject;
agent = parent.GetComponentInChildren<NavMeshAgent>();
}
else { hasAgent = true; }
if (!hasAgent)
{
if (agent == null)
{
hasAgent = false;
}
else { hasAgent = true; }
}
if(hasAgent)
{
agent.updatePosition = false;
agent.updateRotation = false;
}
}
protected override Vector3 CalculateMovementDirection()
{
Vector3 _movementDirection = Vector3.zero;
bool isMoving = false;
if(!hasAgent)
{
return _movementDirection;
}
if(agent.hasPath && agent.remainingDistance > agent.stoppingDistance)
{
isMoving = true;
}
//If the NavMeshAgent is Moving, the Movement Vector to send to the Mover component is the vector from the our Transform position to the agent's simulated position.
if(isMoving)
{
var heading = agent.nextPosition - transform.position;
_movementDirection = heading.normalized;
}
return _movementDirection;
}
//May implement jumping later
protected override bool IsJumpKeyPressed()
{
return false;
}
}
Navmesh Agent setup: For optimal results, I set the the Navmesh agentâs speed to about double the Moverâs speed (so the Mover will never be ahead of the agent) and the agentâs acceleration to the movement speed (so it wonât jitter when it stop and resumes waiting for the Mover).
Now the Mover follows smoothly behind the NavMeshAgent (keeping the leash short has the Mover follow closely as the agent avoids obstacles). If anyone else is looking for something similar, I hope it helps. Thanks again for the great system!
@JanOtt Great work on the Character Controller package. Really impressed with the general feel and how robust it is. Iâve been using it for a few weeks and keep running into some issues I was hoping you could help me with.
In general Iâm having a lot of problems with manual overrides, like wanting to control the camera rotation manually or
move the character in scripting.
Is it possible to change the facing direction of the character without it being overriden by the previous velocity? I am using topdown with âTurnTowardControllerVelocityâ but sometimes I just want to teleport the character to a new location and rotation.
Using the top-down control, is there any way to manually tween the camera rotation between different rotations? I explicitly want to rotate 45 degrees at a time to look around, but I couldnât figure out a way to make the camera rotate smoothly without it fighting the controls.
Finally, Iâd love to see some âhold jump to jump higherâ control options.
Thanks for the great work. Iâm looking forward to the next update.
Hi @dock !
[USER=3008380][/user]The easiest way to implement something like this would be to add add a simple function to the âTurnTowardControllerVelocityâ script that you can call to manually set the charactersâ rotation, whenever you want to teleport.
The specifics depend a bit on your individual game though, so itâd probably be best if you contacted me via the support mail (support@j-ott.com) with a more-detailed description of how your teleportation works and Iâll try my best to help!
[USER=3008380][/user]With a bit of custom code, thatâs definitely possible! Thereâs just a few things to consider here first, though:
Do you want the player to only be able to rotate the camera in 45° increments, or should these 45° rotations happen on top of the normal camera rotation? And do you need the camera angle to âsnapâ to certain angles (0, 45, 90, 135, 180 âŚ)?
Just like before, please feel free to contact me via the support mail with more details and Iâm sure weâll find a good solution!
[USER=3008380][/user]Thanks! A âhold to jump higherâ option is actually part of the next update. I just have a few minor code improvements to do, but after that, the update should be released shortly.
If you try to edit certain prefabs with unity 2019.2.5 and have the root of the prefab with the mover component selected, the prefab will try to save 10 times per second!
I found a fix for it.
Go into the MoverInspector.cs Editor script and change the last line to this:
//EditorUtility.SetDirty(mover);
Undo.RecordObject(mover,"mover updated");
Thanks for the suggestion! Iâve already implemented a fix for this bug (which will be part of the next update), but maybe your approach is an even better solution? If thatâs the case, Iâll definitely include it in the next update instead!
Thanks again!
@MrJohnWeez Great fix! Thanks for sharing!!
Thank-you, this helped a lot. I was able to write a new version with an override that allowed the new rotation to be manually set.
At the moment my game starts at 0 and I can rotate 45 degrees at a time only. My soluton at the moment is a CameraController hack which specifies a new RotateCamera, but I wasnât able to allow any sort of smooth movement, such as âRotateTowardsVelocityâ
Mostly I would love an option to have more freedom to rotate the camera and have the movement input cope with it.
Sounds great! Looking forward to it!!
For smooth camera rotation, the best way would probably be to rotate the camera over a short period of time using coroutines - that way, you could even use custom curves to ease in/out the rotation for a more âorganicâ game feel.
If the player should only be able to rotate the camera in increments of 45° and shouldnât be able to move the camera âmanuallyâ using the mouse, a camera system like that should be very straightforward to implement.
If thatâs what youâre after, feel free to contact me via email and Iâll walk you through the specifics!
So if I understood you correctly, you would prefer a controller system that doesnât require a âCameraControllerâ component to work?
Iâm asking because I wrote a modified controller script a few weeks ago for a different customer who needed something very similar for their project.
Essentially, instead of a âCamera Controllerâ component, the modified controller only requires a reference to (any) camera in the scene and will use that cameraâs view axes to calculate the characterâs movement direction.
As a result, youâre free to move and rotate the camera around as you like (it doesnât even have to be parented to the character).
If that sounds interesting to you, just contact me via email and Iâll send you the script along with some instructions on how to import it into your project.
Hope that helps!
I was able to find a nice solution for my camera control woes. I separated the ability to Reset the camera into a public function on CameraController.cs. These were all taken from Awake()
// This resets relative controls
public void ResetFromWorldPosition()
{
lastPosition = tr.position;
//Set angle variables to current rotation angles of this transform;
currentXAngle = tr.localRotation.eulerAngles.x;
currentYAngle = tr.localRotation.eulerAngles.y;
//Execute camera rotation code once to calculate facing and upwards direction;
RotateCamera(0f, 0f);
}
Meanwhile Iâm using âDoTweenâ for rotating the camera, on a class which inherits from CameraController. It calls ResetFromWorldPosition() while the rotation happens.
IEnumerator RotateCameraSequence(float offsetAngle)
{
Tween myTween = transform.DOBlendableRotateBy(new Vector3(0, offsetAngle, 0), 0.25f);
while (myTween != null)
{
yield return null;
ResetFromWorldPosition();
}
}
Hello! Iâm loving the look of this package. Before I pick it up, Iâd like to know a little more about how well it plays alongside Unityâs own AI nav agents. Can the two co-exist in a space quite happily? What happens if the player tries to move their character through a crowd of agents, for example? Or jump on their heads?
Just wanted to quickly announce that version 1.2 has just been approved by Unity. Hereâs the changelog:
Version 1.2
- Fixed a bug that caused visual glitching when viewing controller prefabs in the inspector in newer versions of Unity (2018 and up).
- Added a public âAdd Momentumâ function to âBasicWalkerControllerâ, which can be used to add a force to the controller (useful for jump pads, dashing, [âŚ]).
- Added an option for more responsive jumping: By holding the âjumpâ key longer, the character will jump higher.
- Added two public functions to âCameraControllerâ. By calling them from an external script, the camera can be rotated either toward a direction or a specific position (see manual for more details).
- âSideScrollerâ controller prefab has been streamlined (code-wise) and is now compatible with the âGravityFlipperâ prefabs.
- Various minor changes to some of the code to improve readability.
If thereâs any questions about some of the new features, please feel free to ask in this thread or directly by email (support@j-ott.com).
Hi! In allmost all situations, the controllers included in 'Character Movement Fundamentalsâ behave very similarly to regular rigidbodies. So when it comes to the interaction between navmesh agents and controllers, it all depends on how youâve set up the agents.
For example:
- If your navmesh agents have no collider and rigidbody attached, there wonât be any collision between agents and controllers (since navmesh agents by themselves are not physics objects).
- If your navmesh agents do have colliders and (kinematic) rigidbodies attached, then the controller will get pushed around by the agents.
I havenât tested this yet, but Iâm fairly sure that if you attach a âNav Mesh Obstacleâ component to a (player) controller, the agents will try to walk around it (which is probably the best solution for crowds).
I hope that helps!
Great, makes perfect sense. Thanks for the quick reply!
I have used NavMeshObstacles in the past and yeah thatâs exactly how Iâd expect it to work.
Iâm going to buy the plugin now
Thanks for the update!
Unfortunately Iâm having lots of problems.
Firstly, the gravity tunnel is broken in all camera modes.
Secondly, I wasnât able to get the camera rotation controls working at all, and itâs not clear what the function expects.
Could you show a working code example to press Q and E to rotate the camera in 45 degree steps around the Y axis?
Even when I got it partially working, the movement input wasnât updating for up/down controls, but the left/right controls were correctly aligned.
I was usually getting the following error when I added camera keys to the Topdown demo:
Hi Hayden!
Iâm very sorry for the confusion, I should have explained the two new camera controller functions in more detail in the change log.
Anyway, to clear things up:
The new âRotateTowardPosition/Directionâ functions that have been added to the camera controller component are intended for making the camera look at a specific object in the scene (or in a specific direction).
They are really not suited for directly controlling the cameraâs angles in a precise way (which is what you need in your project).
Are you still using the âGlobalCameraWalkerControllerâ script I sent you? Because that script currently canât handle a rotating controller (which is whatâs happening in the gravity tunnel and the gravity flippers).
To make the script compatible with controller rotation, youâll need to replace the code in line 33/34:
Vector3 _cameraForwardVector = Vector3.ProjectOnPlane(globalCameraTransform.forward, Vector3.up).normalized;
Vector3 _cameraRightVector = Vector3.ProjectOnPlane(globalCameraTransform.right, Vector3.up).normalized;
⌠with this code:
Vector3 _cameraForwardVector = Vector3.ProjectOnPlane(globalCameraTransform.forward, tr.up).normalized;
Vector3 _cameraRightVector = Vector3.ProjectOnPlane(globalCameraTransform.right, tr.up).normalized;
That way, the script will take the current rotation of the controller into account when calculating the new input direction.
Sure!
Please take a look at the script I attached to this post called âRotateAroundYAxisInIncrementsâ.
Try importing it into your project and attach it to the âCameraControlsâ gameobject in the characterâs hierarchy (and make sure to delete/disable the camera controller script, if necessary).
By pressing âQâ and âEâ, this script will rotate any gameobject in adjustable increments (âAngle Incrementâ) over time (âRotation Durationâ).
You can also change the âfeelâ of the rotation by adjusting the âRotation Curveâ or enable âClamp Angleâ to make sure that floating point imprecision wonât affect the rotation results (over time).
I hope that fixes all (or at least most) of the problems youâve described. If somethingâs still not working or if anythingâs unclear, please contact me via the support mail so we can continue there!
5102399â503225âRotateAroundYAxisInIncrements.cs (2.47 KB)