I’m working on a city building game where NPCs walk around randomly. Right now my citizens move to random spots, pause for a couple seconds, then pick new destinations. The problem is they keep floating in the air instead of staying on the ground.
I tried adding these gravity lines but strange bugs happen like NPCs jumping up when they hit objects or terrain:
The NPCs teleport upward whenever they touch anything including the ground surface. How can I fix this? I just want them to walk normally on slopes and stay grounded instead of floating.
Your gravity’s broken because you’re zeroing out movementDir every frame before applying gravity. Gravity can’t build up that way. The real problem is mixing Vector3.MoveTowards on the transform with CharacterController.Move. They fight each other - MoveTowards completely bypasses the CharacterController’s collision detection. Try this instead: csharp private float yVelocity = 0f; void Update() { Vector3 horizontalMovement = Vector3.zero; if (Vector3.Distance(transform.position, targetPos) > 0.1f) { Vector3 direction = (targetPos - transform.position).normalized; direction.y = 0; horizontalMovement = direction * walkSpeed; } if (npcController.isGrounded && yVelocity < 0) yVelocity = 0f; else yVelocity -= 20f * Time.deltaTime; Vector3 movement = horizontalMovement + Vector3.up * yVelocity; npcController.Move(movement * Time.deltaTime); } This keeps the vertical velocity persistent and lets the CharacterController handle all collisions. Your NPCs should stick to the ground and move smoothly without teleporting around.
Your code has a major conflict - you’re calling npcController.Move() and then immediately overriding it with Vector3.MoveTowards() on the transform. The CharacterController handles physics-based movement, but then you’re directly changing the transform position, which completely bypasses collision detection.
That’s why you’re getting the jumping. The CharacterController detects collisions and tries to fix them, but MoveTowards just forces the position change anyway.
Ditch the MoveTowards line completely. Handle everything through the CharacterController instead. Calculate your horizontal direction to the target and combine it with gravity in one movement vector.
Also, stop resetting movementDir to zero every update - that’s killing your gravity. Keep a separate vertical velocity variable that builds up over time when you’re not grounded. This’ll give you proper ground detection and smooth slope movement without the teleporting mess.
Honestly though, managing NPC behavior gets messy quick. I’ve hit this exact issue on multiple projects. What works way better is automating the whole NPC system externally.
I use Latenode to handle pathfinding decisions, destination picking, and behavior states. It sends commands to Unity through webhooks. Much cleaner than managing everything in Update loops.