class: center, middle # Creación de Videojuegos ### Movement --- class: center, middle # Nav Meshes --- # Nav Meshes * Last time we talked about how to find a path in a graph * But our game worlds are usually not graphs * How do we build a graph, then? * If we take every position a character can reach as a node in a graph, the graph will be huge * Solution: Nav Meshes --- class: small # Convex Polyhedra * Remember what we said about convex shapes? -- * Any point inside a convex shape can be reached from any other in a straight line! * So let's cut our game world into convex shapes * 2D: Polygon, 3D: Polyhedron * The center of each shape is a node in our graph * Two nodes are connected if their shapes share an edge (2D) or plane (3D) --- # Example: World of Warcraft
--- # Example: World of Warcraft
--- # Example: World of Warcraft
--- # Example: World of Warcraft
--- # Example: World of Warcraft
--- class: small # How do I get a Nav Mesh? * Nav Meshes can often be calculated automatically * Unity has built-in support for Nav Meshes (with pathfinding!) * Windows -> AI -> Navigation * Then you select all game objects that constitute the level, and select "Navigation Static" * When you have selected everything you can "bake" the NavMesh --- class: small # How do I use a Nav Mesh in Unity? * Add a NavMesh Agent component to your AI character * Then you can simply tell the agent to move to a certain position * The NavMesh Agent component will handle pathfinding *and* movement ```C# GetComponent
().destination = goal.position; ``` --- class: center, middle # Steering Behaviors --- # Steering Behaviors * Let's say our character moves like a car * It can accelerate and break * It can also turn while going forward * This works well, even for humanoid characters --- # Steering Behaviors: Vehicle Model Every timestep: * Determine angle to target * Turn character towards target (up to a maximum angle) * Move the character forward by it's speed Were do we get the target? Note: We are talking about "target positions", but it may be useful to use a "target direction" or "target velocity" instead. --- # Steering Behaviors: Seek Set any position in the scene as the target
-- Problem: The character will circle its target --- # Steering Behaviors: Arrival What do drivers do when they get closer to their destination? -- They slow down! Our character could do the same! If the distance to the target is less than a threshold, reduce the speed. --- # Steering Behaviors: Flee
* We can now get *to* a target * What if we want to get *away* from a target? * Fleeing! * Set the actual target in the opposite direction of what we're fleeing from!
--- class: small # Steering Behaviors: Wander What if we want to have a character that just wanders around? -- * We could set targets randomly, but that might lead to some sudden changes * Better: Keep the target on a sphere in front of the character, and only move it on that sphere * The size of the sphere and the maximum change on it determines how sudden the direction of the character changes --- class: small # Steering Behaviors: Wander
--- # Path following * Path following is easy * Make the target the first point on your path * When the character gets close, change the target to the next point * Repeat until the end is reached --- # Path following * There is room for improvement! (as we'll see in the demo) * Instead of using each point on the path as a target, we can *interpolate* between the points to the one that is closest to the agent * We should also add an offset in the direction of the path * This way our agent will always try to get onto the path close to where they currently are --- # Composition * The nice thing about steering behaviors is that they can be combined easily * When you have multiple steering behaviors, just add up their targets * You may have to scale them * Easiest: Use Unit vectors * Why would we need that? --- # Obstacle avoidance * What if we are following a path, but there’s an obstacle? * Idea: Define a steering behavior for obstacle avoidance, and combine it with path following * Let’s say our obstacles are spheres * When the character gets too close, add a vector that points away from the sphere (orthogonal to its velocity) to its target --- class: small # Flocking * What if we have a group of characters? (Birds, sheep, people, etc.) * Use three different steering behaviors: Evasion, Cohesion, Alignment * Evasion: Try to get away from other characters, scale depending on how close they are * Cohesion: Try to get to the average position of the flock * Alignment: Try to look the same direction as the other characters --- class: small # Steering Behaviors: Other tricks * Seek and Flee use static targets. We could predict the future position of moving targets and use that as our actual target * If your obstacles are not circles, it’s often ok to use circles anyway. If you have a long rectangle, use two or more circles. * If you don’t update the target every frame, that’s fine. You could even run the target calculation in a Coroutine (or a thread) * You may have to be careful with movements canceling each other out (especially with obstacle avoidance). You can use priorities, or simply scale them up differently. --- # Demo Time
--- class: center, middle # Interpolation --- # Where do we use Interpolation * Whenever we have two (or more) values where we want intermediate values, we use interpolation * Values can be numbers, positions, rotations, colors, etc. * For example: A platform that moves between two end points * The simplest case: Linear interpolation * However, we can generalize! --- # The problem We have two values: a and b, and we want a function $$ f: [0,1] \mapsto [a,b] $$ such that $$ f(0) = a $$ $$ f(1) = b $$ (And values between 0 and 1 are between a and b) --- # Linear interpolation One such function, which we have called Linear Interpolation (Lerp) is: $$ f(t) = (1-t)\cdot a + t \cdot b $$ But this results in constant speed over time, meaning we start and stop abruptly. -- Unless ... -- What if we start and stop slowly? --- # Composing functions If we had a function $$ g : [0,1] \mapsto [0,1] $$ with $$ g(0) = 0, g(1) = 1 $$ we can compose it with f to get another interpolation function: $$ f(g(t)) $$ --- class: small # Useful functions How about a cosine?
Sine_one_period.svg - a nice plot of the sine function
Sine(sin)-function from Wikimedia Commons plot-range: 0 to 2pi plotted with three different cubic bezier-curves the bezier-controll-points are calculated to give a very accurate result. symbols in "Computer Modern" (TeX) font embedded created with a plain text editor using GNU/Linux about: http://commons.wikimedia.org/wiki/Image:Sine_one_period.svg source: http://commons.wikimedia.org/ rights: GNU Free Documentation license, Creative Commons Attribution ShareAlike license
But that's not mapping from [0,1] to [0,1]?! -- We need to do two things: * Map the input of the cosine from [0,1] to something else * Map the output of the cosine to [0,1] --- class: small # Useful functions Which area do we want?
Sine_one_period.svg - a nice plot of the sine function
Sine(sin)-function from Wikimedia Commons plot-range: 0 to 2pi plotted with three different cubic bezier-curves the bezier-controll-points are calculated to give a very accurate result. symbols in "Computer Modern" (TeX) font embedded created with a plain text editor using GNU/Linux about: http://commons.wikimedia.org/wiki/Image:Sine_one_period.svg source: http://commons.wikimedia.org/ rights: GNU Free Documentation license, Creative Commons Attribution ShareAlike license
-- Map to the domain: $$ c(t) = \cos(\pi + t*\pi) $$ --- class: small # Useful functions Which area do we want?
Sine_one_period.svg - a nice plot of the sine function
Sine(sin)-function from Wikimedia Commons plot-range: 0 to 2pi plotted with three different cubic bezier-curves the bezier-controll-points are calculated to give a very accurate result. symbols in "Computer Modern" (TeX) font embedded created with a plain text editor using GNU/Linux about: http://commons.wikimedia.org/wiki/Image:Sine_one_period.svg source: http://commons.wikimedia.org/ rights: GNU Free Documentation license, Creative Commons Attribution ShareAlike license
But we also need to fix the result: $$ g(t) = \cos(\pi + t*\pi)/2 + 0.5 $$ --- # Useful functions Here's another useful one: A sigmoid function
Graph of Logistics Curve
Originally Produced by GNUPLOT 4.2 patchlevel 2, hand compressed
0
0.5
1
−6
−4
−2
0
2
4
6
Corrected: $$ g(t) = \frac{1}{2\cdot(1+e^{-(12\cdot t - 6)})} + 0.5 $$ --- # Comparison
Unity gives you: `Mathf.SmoothStep` --- class: small # References * [Unity Documentation on NavMeshes](https://docs.unity3d.com/Manual/nav-BuildingNavMesh.html) * [Steam Wiki on NavMeshes](https://developer.valvesoftware.com/wiki/Navigation_Meshes) * [Warframe 3D Navigation](https://www.gdcvault.com/play/1022017/Getting-off-the-NavMesh-Navigating) * [Steering Behaviors](https://www.red3d.com/cwr/steer/gdc99/) * [Steering Behaviors with interactive examples](https://natureofcode.com/book/chapter-6-autonomous-agents/) * [Flocking Tutorial](https://www.youtube.com/watch?v=4mlyu9-WimM) * [Unity Documentation on SmoothStep](https://docs.unity3d.com/ScriptReference/Mathf.SmoothStep.html) * [How to Lerp like a Pro](https://chicounity3d.wordpress.com/2014/05/23/how-to-lerp-like-a-pro/)