I understand what Fluzing is getting at. But, although pathfinding can be a little complicated when you’re new to AI, it’s largely a solved and standardized problem: use A* or waypoints with some basic steering behavior. The only thing that varies game-to-game is world-specific information (How do I recognize obstacles? Do I use stairs? Are there any doors or elevators? etc.)
Make sure you’ve set up your Physics collision layers correctly so that NPCs can’t pass through walls. Then, if the AI can’t find a good path, it will stop at the wall instead of passing through.
Waypoints are a very easy way to implement pathfinding, since you can specify at design-time how to move between areas of the map. The AI computation is much simpler than A* and often more reliable than writing your own A* from scratch if don’t have a lot of time to fine-tune it. (Technically they’re both graph analysis problems, but basic waypoints use simpler algorithms and data structures.)
If pathfinding determines where to go, steering controls how the NPC gets there. It handles acceleration and deceleration, smooths out the path, and avoids dynamic obstacles. You can use the same steering behavior to maintain a minimum distance from your FPcontroller, which should control the bug you described.
Google “steering behavior” and either “waypoints” or “A* pathfinding”.
The topics of perception and decision-making are much more at the forefront of modern AI. (What targets are here? Which one should I attack? What kind of attack should I use?) There are many approaches, but the old standby for decision-making is the finite state machine (FSM). Unity Gems has a tutorial here: http://unitygems.com/fsm1/
For perception, you can leverage the Physics engine. If you have CPU to spare, just call Physics.OverlapSphere() every Update() and see what’s in range. A more efficient option (perhaps as an enhancement once you get it working with OverlapSphere) would be to add a trigger collider to the NPC. Then use OnTriggerEnter and OnTriggerExit to record whenever something enters or exits the NPC’s perception range.
If you make everything modular, then you can swap out waypoints for A* pathfinding, or behavior trees for FSMs, without affecting anything else. Many people who are starting out couple their AI algorithms too tightly to the game they’re writing. Then, when they determine they need to use a different steering behavior, for example, they can’t do it without breaking everything. My #1 tip is to google “loose coupling”. In the big picture, this will probably save you more time than anything else, which will leave you more time to write an interesting AI! 