Moving sphere to a 2D waypoint on terrain in a 3D space Unity

60 Views Asked by At

Im trying to create an animation using Unity3D where I have a world which is created by converting a heightmap into a terrain. Using a python program I am calculating a route for this sphere and am then transferring the x and y values. I also want to note that in Unity my plane for the terrain is the x,z one, so the x,y values from the python program are really x,z values. I am now trying to move a sphere along waypoints I created (basically x,y tuples) traversing said terrain.

The function I am using is MoveTowards. Here is my code so far:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class WaypointMover : MonoBehaviour
{
    [SerializeField]
    private float _WaypointDistance = 0.01f;    //DISTANCE REQUIRED TO MOVE TO NEXT WAYPOINT
    [SerializeField]
    private float _MovementSpeed = 6f;          //TRAVEL SPEED

    private List<Vector2> _Waypoints;           //COLLECTION OF WAYPOINTS
    private int _CurrentWaypointIndex;          //TRACKS WAYPOINT INDEX
    private Vector2 _CurrentWaypoint;           //TRACKS CURRENT WAYPOINT TO MOVE TO

    void Start()
    {
        _Waypoints = new List<Vector2>();
        _CurrentWaypointIndex = 0;                               //Initial Waypoint Index
        _CurrentWaypoint = _Waypoints[_CurrentWaypointIndex];    //Initial Waypoint

        transform.position = new Vector3(_CurrentWaypoint.x, Terrain.activeTerrain.SampleHeight(new Vector3(_CurrentWaypoint.x, 0, _CurrentWaypoint.y)), _CurrentWaypoint.y); //Moving Sphere to start location
        _CurrentWaypointIndex++;
    }

    // Update is called once per frame
    void Update()
    {
        if (Vector2.Distance(_CurrentWaypoint, new Vector2(transform.position.x, transform.position.z)) < _WaypointDistance)
        {
            _CurrentWaypointIndex++;
            if (_CurrentWaypointIndex < 0)
                _CurrentWaypointIndex = 0;
            _CurrentWaypoint = _Waypoints[_CurrentWaypointIndex % _Waypoints.Count];
        }
        else
        {
            transform.position = Vector3.MoveTowards(transform.position, new Vector3(_CurrentWaypoint.x, Terrain.activeTerrain.SampleHeight(transform.position) + 2f, _CurrentWaypoint.y), _MovementSpeed * Time.deltaTime);
        }

        transform.LookAt(_Waypoints[_CurrentWaypointIndex]);
    }
}

Note: I deleted parts of my code that import the data from python and everything else that is not relevant to my problem.

The problem I am facing now is that the sphere often times clips into the Terrain even though I am doing Terrain.activeTerrain.SampleHeight(transform.position) + 2f, which should move my sphere exactly onto the terrain. The 2 at the end is an offset I tried to solve this issue with but the sphere still keeps clipping.

I also tried adding a rigidbody onto my sphere, but no matter how much I decrease the sphere's mass I wont move after being transported to its starting position.

Ideally I want to make the sphere 'stick' to the ground. Any help is appreciated.

Ive also added some pictures showing the sphere inside the terrain and floating above it.

Sphere floating above the terrain

Sphere inside the terrain

1

There are 1 best solutions below

1
Jonathan On

I think the issue lies with the Vector3.MoveTowards function. when the function moves the sphere, will it also account for the terrain or will it disregard it and just move the item as if nothing is in the way? I'm fairly certain it's the latter. In that case, you might want to reconsider your movement method.

I would suggest using instead the RigidBody.Velocity and transform.Forward to move the ball as it would be much smoother and would not go through solid objects. first face the desired location then add speed so you would move forward. there are already many answers on this site that offer a code for this solution but if you will have trouble finding or implementing them feel free to ask me for it.

FYI, hard coding '+2' to the position is less than optimal, try this instead: position.y + Player.transform.scale.y / 2

Hope I helped (;