Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Why when setting high speed moving of the player in waypoints he fall out of the terrain area ?

Discussion in 'Scripting' started by Chocolade, Feb 27, 2017.

  1. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    932
    What i mean is that if i set the speed to 10 he will walk between the waypoints without a problem. In this case i clone some random positions cubes and set them as waypoints.

    If there is a cube(waypoint) near the terrain edge and the player moving speed is 20 or 30 he will get to the waypoint but then will continue and will fall out of the terrain area instead rotating to the next waypoint. In speed 10 it's working fine.

    How can i make that also in high speeds like 20-30 or more he will move fine between the waypoints ?

    Another problem is if the cubes small it will walk to next waypoint even if there is a cube in the middle. Like a path find. But if i put huge cubes very big cubes if there is a cube in the middle he will stuck and will not continue to the next waypoint. how can i make when the waypoints objects are big very big the player will turn/rotate left or right and will go around to the next waypoint ?

    The script is attached to a ThirdPersonController.

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEditor;
    5. using UnityEngine;
    6. using UnityStandardAssets.Characters.ThirdPerson;
    7.  
    8. public class WayPoints : MonoBehaviour {
    9.  
    10.     public GameObject[] waypoints;
    11.     public Transform target;
    12.     public float moveSpeed = 1f;
    13.     public float rotationSpeed = 1f;
    14.     private Transform myTransform;
    15.     private int targetsIndex = 0;
    16.     private Vector3 originalPosition;
    17.  
    18.     public float walkSpeed = 15f;
    19.  
    20.     void Awake()
    21.     {
    22.         myTransform = transform;
    23.     }
    24.     // Use this for initialization
    25.     void Start()
    26.     {
    27.         waypoints = GameObject.FindGameObjectsWithTag("ClonedObject");
    28.  
    29.         originalPosition = myTransform.position;
    30.     }
    31.  
    32.     // Update is called once per frame
    33.     void Update()
    34.     {
    35.         if (MyCommands.walkbetweenwaypoints == true)
    36.         {
    37.             WayPointsAI();
    38.         }
    39.  
    40.         DrawLinesInScene();
    41.     }
    42.  
    43.     private void WayPointsAI()
    44.     {
    45.         if (targetsIndex == waypoints.Length)
    46.             targetsIndex = 0;
    47.         target = waypoints[targetsIndex].transform;
    48.         float distance = Vector3.Distance(myTransform.position, target.transform.position);
    49.         myTransform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed * Time.deltaTime);
    50.  
    51.         //move towards the player
    52.         myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
    53.         if (distance < 2f)
    54.             targetsIndex++;
    55.     }
    56.  
    57.     void DrawLinesInScene()
    58.     {
    59.         // draw lines between each checkpoint //
    60.         for (int i = 0; i < waypoints.Length - 1; i++)
    61.         {
    62.             Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
    63.         }
    64.  
    65.         // draw a line between the original transform start position
    66.         // and the current transform position //
    67.         Debug.DrawLine(originalPosition, transform.position, Color.red);
    68.  
    69.         // draw a line between current transform position and the next waypoint target
    70.         // each time reached a waypoint.
    71.         if (target != null)
    72.             Debug.DrawLine(target.transform.position, myTransform.position, Color.green);
    73.     }
    74. }
    75.  
     
  2. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    One thing you can look into is the NavAgent system of Unity it might help you out.
    The problem with edge waypoints is simply he get close to the edge waypoint.. say 2.1f from it. Then next update he moves past it and he's going so fast he runs right off the edge.

    You have two options:
    1)Each time the agent is moving. CHeck where the move will end up, and if its off the grid make it a shorter move
    2) Create a waypoint just before the edge waypoint, mark it special someway. When an agent reaches one of these waypoints he slows down to 1/2 speed. Walks to the next "normal" waypoint at the edge and then resumes full speed.

    He's getting stuck because your big cube is bigger than 2f. Your only checking if they get within 2f of the center of that cube. Change 2f to the bigger than the radius of the cubes you make.
     
  3. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    932

    About the speed slow down before and speed up after:
    Its at a good way to do it ? The problem is that the user might change the speed while the game is running.
    And also i think it's better to slow down before not sure what distance before a way point and speed up back after the player/enemy/bot did the rotation to the next way point ?

    Code (csharp):
    1.  
    2. var distanceCheckpoint = Vector3.Distance(checpoint_1.position, checpoint_2.position);
    3. var distance = Vector3.Distance(myTransform.position, target.transform.position);
    4. var thresholdSpeed = distance / distanceCheckpoint * moveSpeed;
    5.  
    And about the radius i didn't find a real answer how to find a cube radius and if it's not a cube maybe a sphere or another gameobject ? How do i find the radius then ? And what side bigger then the radius to change to ?
     
  4. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Well aren't you making these cubes? You should know how big they are..? How are you generating them.
     
  5. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    932
    This is how i create the cubes or any other GameObject. For now they are in same size but maybe in the future i will make also the size to be random.

    Code (csharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using Random = UnityEngine.Random;
    5. using System.Collections;
    6. using System.Collections.Generic;
    7. using System.Linq;
    8.  
    9. public class CloneObjects : MonoBehaviour
    10. {
    11.     public GameObject ObjectToCreate;
    12.     public int objectsHeight = 3;
    13.     [HideInInspector]
    14.     public GameObject[] objects;
    15.  
    16.     // for tracking properties change
    17.     private Vector3 _extents;
    18.     private int _objectCount;
    19.     private float _objectSize;
    20.  
    21.     /// <summary>
    22.     ///     How far to place spheres randomly.
    23.     /// </summary>
    24.     public Vector3 Extents;
    25.  
    26.     /// <summary>
    27.     ///     How many spheres wanted.
    28.     /// </summary>
    29.     public int ObjectCount;
    30.     public float ObjectSize;
    31.  
    32.     // Use this for initialization
    33.     void Awake()
    34.     {
    35.         Clone();
    36.         objects = GameObject.FindGameObjectsWithTag("ClonedObject");
    37.     }
    38.  
    39.     private void OnValidate()
    40.     {
    41.         // prevent wrong values to be entered
    42.         Extents = new Vector3(Mathf.Max(0.0f, Extents.x), Mathf.Max(0.0f, Extents.y), Mathf.Max(0.0f, Extents.z));
    43.         ObjectCount = Mathf.Max(0, ObjectCount);
    44.         ObjectSize = Mathf.Max(0.0f, ObjectSize);
    45.     }
    46.  
    47.     private void Reset()
    48.     {
    49.         Extents = new Vector3(250.0f, 20.0f, 250.0f);
    50.         ObjectCount = 100;
    51.         ObjectSize = 20.0f;
    52.     }
    53.  
    54.     // Update is called once per frame
    55.     void Update()
    56.     {
    57.  
    58.     }
    59.  
    60.     private void Clone()
    61.     {
    62.         if (Extents == _extents && ObjectCount == _objectCount && Mathf.Approximately(ObjectSize, _objectSize))
    63.             return;
    64.  
    65.         // cleanup
    66.         var ObjectsToDestroy = GameObject.FindGameObjectsWithTag("ClonedObject");
    67.         foreach (var t in ObjectsToDestroy)
    68.         {
    69.             if (Application.isEditor)
    70.             {
    71.                 DestroyImmediate(t);
    72.             }
    73.             else
    74.             {
    75.                 Destroy(t);
    76.             }
    77.         }
    78.  
    79.         var withTag = GameObject.FindWithTag("Terrain");
    80.         if (withTag == null)
    81.             throw new InvalidOperationException("Terrain not found");
    82.  
    83.         for (var i = 0; i < ObjectCount; i++)
    84.         {
    85.             var o = Instantiate(ObjectToCreate);
    86.             o.tag = "ClonedObject";
    87.             o.transform.SetParent(base.gameObject.transform);
    88.             o.transform.localScale = new Vector3(ObjectSize, ObjectSize, ObjectSize);
    89.  
    90.             // get random position
    91.             var x = Random.Range(-Extents.x, Extents.x);
    92.             var y = Extents.y; // sphere altitude relative to terrain below
    93.             var z = Random.Range(-Extents.z, Extents.z);
    94.  
    95.             // now send a ray down terrain to adjust Y according terrain below
    96.             var height = 10000.0f; // should be higher than highest terrain altitude
    97.             var origin = new Vector3(x, height, z);
    98.             var ray = new Ray(origin, Vector3.down);
    99.             RaycastHit hit;
    100.             var maxDistance = 20000.0f;
    101.             //var nameToLayer = LayerMask.NameToLayer("Terrain");
    102.             var nameToLayer = LayerMask.GetMask("Terrain");
    103.             var layerMask = 1 << nameToLayer;
    104.             if (Physics.Raycast(ray, out hit, maxDistance, layerMask))
    105.             {
    106.                 var distance = hit.distance;
    107.                 y = height - distance + y; // adjust
    108.             }
    109.             else
    110.             {
    111.                 Debug.LogWarning("Terrain not hit, using default height !");
    112.             }
    113.  
    114.             // place !
    115.             o.transform.position = new Vector3(x, y + objectsHeight, z);
    116.         }
    117.         _extents = Extents;
    118.         _objectCount = ObjectCount;
    119.         _objectSize = ObjectSize;
    120.     }
    121. }
    122.  
    Then in the WayPoints script i'm getting all the cloned objects:

    Code (csharp):
    1. waypoints = GameObject.FindGameObjectsWithTag("ClonedObject");
     
  6. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Your setting your cubes to objectSize. That means their radius will be ObjectSize/2. You either need to find the biggest cube and say if you get within ObjectSize/2 of a waypoint go to the next one. Or keep track of which size goes with which waypoint and check if you are close enough.
     
  7. Chocolade

    Chocolade

    Joined:
    Jun 19, 2013
    Posts:
    932
    I tried but it's not working.
    In CloneObjects script i added to the Awake function

    Code (csharp):
    1.  
    2. void Awake()
    3.     {
    4.         Clone();
    5.         objects = GameObject.FindGameObjectsWithTag("ClonedObject");
    6.  
    7.         foreach (var element in objects)
    8.         {
    9.             float Size = element.transform.localScale.x;
    10.             if (Size > LargestSize)
    11.                 LargestSize = Size;
    12.         }
    13.     }
    14.  
    But this loop for now is not relevant since all the cloned objects are in the same size.
    But anyway i did that the variable LargeSize will be public static.

    Then in the WayPoints script i did:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEditor;
    5. using UnityEngine;
    6. using UnityStandardAssets.Characters.ThirdPerson;
    7.  
    8. public class WayPoints : MonoBehaviour {
    9.  
    10.     public GameObject[] waypoints;
    11.     public Transform target;
    12.     public float moveSpeed = 1f;
    13.     public float rotationSpeed = 1f;
    14.     private Transform myTransform;
    15.     private int targetsIndex = 0;
    16.     private Vector3 originalPosition;
    17.     private GameObject[] robots;
    18.  
    19.     public Transform reverseTarget;
    20.     private int reverseTargetsIndex = 0;
    21.     private Vector3 reverseOriginalPosition;
    22.  
    23.     private float radius;
    24.  
    25.     void Awake()
    26.     {
    27.         myTransform = transform;
    28.     }
    29.     // Use this for initialization
    30.     void Start()
    31.     {
    32.         waypoints = GameObject.FindGameObjectsWithTag("ClonedObject");
    33.  
    34.         radius = CloneObjects.LargestSize / 2;
    35.  
    36.         robots = GameObject.FindGameObjectsWithTag("Robots");
    37.        
    38.         AddColliderToWaypoints();
    39.  
    40.         originalPosition = robots[0].transform.position;
    41.         reverseOriginalPosition = robots[1].transform.position;
    42.     }
    43.  
    44.     // Update is called once per frame
    45.     void Update()
    46.     {
    47.         if (MyCommands.walkbetweenwaypoints == true)
    48.         {
    49.             WayPointsAI();
    50.             ReverseWayPointsAI();
    51.         }
    52.  
    53.         DrawLinesInScene();
    54.     }
    55.  
    56.     private void WayPointsAI()
    57.     {
    58.         if (targetsIndex == waypoints.Length)
    59.             targetsIndex = 0;
    60.         target = waypoints[targetsIndex].transform;
    61.         float distance = Vector3.Distance(robots[0].transform.position, target.transform.position);
    62.         robots[0].transform.rotation = Quaternion.Slerp(robots[0].transform.rotation, Quaternion.LookRotation(target.position - robots[0].transform.position), rotationSpeed * Time.deltaTime);
    63.  
    64.         //move towards the player
    65.         robots[0].transform.position += robots[0].transform.forward * moveSpeed * Time.deltaTime;
    66.         if (distance < radius)
    67.             targetsIndex++;
    68.  
    69.        
    70.     }
    71.  
    72.     private void ReverseWayPointsAI()
    73.     {
    74.         if (reverseTargetsIndex == 0)
    75.             reverseTargetsIndex = waypoints.Length -1;
    76.         reverseTarget = waypoints[reverseTargetsIndex].transform;
    77.         float distance = Vector3.Distance(robots[1].transform.position, reverseTarget.transform.position);
    78.         robots[1].transform.rotation = Quaternion.Slerp(robots[1].transform.rotation, Quaternion.LookRotation(reverseTarget.position - robots[1].transform.position), rotationSpeed * Time.deltaTime);
    79.  
    80.         //move towards the player
    81.         robots[1].transform.position += robots[1].transform.forward * moveSpeed * Time.deltaTime;
    82.         if (distance < radius)
    83.             reverseTargetsIndex--;
    84.  
    85.        
    86.     }
    87.  
    88.     void RandomWayPointsAI()
    89.     {
    90.        
    91.     }
    92.  
    93.     void DrawLinesInScene()
    94.     {
    95.         // draw lines between each checkpoint //
    96.         for (int i = 0; i < waypoints.Length - 1; i++)
    97.         {
    98.             Debug.DrawLine(waypoints[i].transform.position, waypoints[i + 1].transform.position, Color.blue);
    99.         }
    100.  
    101.         // draw a line between the original transform start position
    102.         // and the current transform position //
    103.         Debug.DrawLine(originalPosition, robots[0].transform.position, Color.red);
    104.         Debug.DrawLine(originalPosition, robots[1].transform.position, Color.red);
    105.  
    106.         // draw a line between current transform position and the next waypoint target
    107.         // each time reached a waypoint.
    108.         if (target != null)
    109.             Debug.DrawLine(target.transform.position, robots[0].transform.position, Color.green);
    110.         if (reverseTarget != null)
    111.             Debug.DrawLine(reverseTarget.transform.position, robots[1].transform.position, Color.green);
    112.     }
    113.  
    114.     void AddColliderToWaypoints()
    115.     {
    116.         foreach (GameObject go in waypoints)
    117.         {
    118.             SphereCollider sc = go.AddComponent<SphereCollider>() as SphereCollider;
    119.             sc.isTrigger = true;
    120.         }
    121.     }
    122. }
    123.  
    In both WayPoints functions i changed the < 2 to < radius

    But when running the game when the character is reaching to the first waypoint he continue and fall out of the terrain then make some turn in some degrees and keep falling.