Flying Pickups

ahh, yup. That did indeed fix the problem, thank you for the precise instructions Brian :slight_smile:

before we end it though, any idea how to work with this?

See above quote from all the way at the top of the thread…

no other solution? If I place another huge bridge later down the line, this might be a bit of a problem

Do I just tag that bridges’ layer mask as “terrain” as well instead?

You could edit the bridge’s prefab and put that on the terrain layer so then any time you add a bridge it will be on the terrain layer, but yes, this is the solution.

and… that did work, but I don’t think Malbers properly set his horse up to want to be on a Terrain Layer, because I think it considers that as a free-falling state (it’s a messy problem, and I reached out to him about it…)

However, whilst this definitely solves the problem for the pickups, the enemy drops and anything the player drops out of his inventory can still float. I’m guessing the same ‘HandleToRaycast’ function needs to go to new locations as well, right? (I promise we’re almost done with this topic :slight_smile:)

Interestingly enough, that should be covered by the GetDropLocation() function already within the RandomDropper method.

        protected override Vector3 GetDropLocation()
        {
            // We might need to try more than once to get on the NavMesh
            for (int i = 0; i < ATTEMPTS; i++)
            {
                Vector3 randomPoint = transform.position + Random.insideUnitSphere * scatterDistance;
                NavMeshHit hit;
                if (NavMesh.SamplePosition(randomPoint, out hit, 0.1f, NavMesh.AllAreas))
                {
                    return hit.position;
                }
            }
            return transform.position;
        }

If that lands in the air then the NavMesh is likely not up to date.

here’s mine, from ‘RandomDropper.cs’:

        protected override Vector3 GetDropLocation()
        {

            // generate 'attempts' number of random points for our loot to drop on (everytime loot hits the ground):
            for (int i = 0; i < Attempts; i++) {
            
            // The random Point should be within the Unit Sphere of the killed Enemy/Player
            Vector3 randomPoint = transform.position + (Random.insideUnitSphere * scatterDistance);

            // Ensuring our loot does not fall in the air, off the cliff or somewhere inaccessible by the player:
            NavMeshHit hit;

            if (NavMesh.SamplePosition(randomPoint, out hit, 0.1f, NavMesh.AllAreas)) {

                return hit.position;

            }
            
            }

            // if we can't drop it on the ground, just drop it at the players' location:
            return transform.position;

        }

so we just… bake it again?

If it helps as well, I once asked for a system that drops equipment and inventory stuff on death. Not sure if that’s helpful, but this is what we coded back then:

public void DropIDroppableItems() {

            // This function replaces the 'DropInventoryItems()' function above, because now we're not just dropping the inventory
            // items and keeping the most valuable items, but we are also dropping the EQUIPMENT ITEMS on the player in this new function:

            int keep = -1;

            // Sorting items from most to least expensive:
            foreach (DroppableItem droppableItem in GetAllDroppableItems().OrderByDescending(d => d.number * d.relativeValue)) {

                keep++;
                // if (keep >= numberToKeep) continue;
                Debug.Log($"Item #{keep} = {droppableItem.item.GetDisplayName()}, qty {droppableItem.number}, value = {droppableItem.item.GetPrice() * droppableItem.number} will keep = {keep < numberToKeep}");
                if (keep < numberToKeep) continue; // if you have more than 3 items kept, just break out of this loop to the rest of the function
                droppableItem.dropItemCallback?.Invoke();   // remove the LESS VALUABLE items from the equipment slot
                DropItem(droppableItem.item, droppableItem.number); // Drop the stuff you got into your inventory on the Players' death, a combination of both Equipment and Inventory items

            }

            TriggerDroppableUpdates();

        }

Yes, bake again.
I’m going to have to leave this here. At least for tonight. I’m running out of time and still have a LOT of other questions to answer.

I can tell you that the method in RandomDropper is bulletproof. It’s been tried and tested by thousands of students, we know it works.

With the other method you added, assuming that’s in RandomDropper, it still has to get the location from GetDropLocation(), which means it will be cast to the NavMesh, so should be glued to the ground.

no worries. If I get stuck somewhere, I’ll leave my doubts as is until you’re available again (or I can solve them prior :slight_smile:)

the NavMeshAgent was properly baked though, and considering the amount of trees that are invisible (because they’re under respawners), baking is no easy job at this moment… I’ll need to figure out a solution for that soon (apart from adding experimental NavMeshAgents… I know they work, but… it’s a nightmare for me personally), so there should be some other way to get the terrain height integrated into ‘GetDropLocation()’)

You could copy the method over to RandomDropper. Once you’ve got the location from the NavMeshSurface, apply the RaycastToTerrain on it, then return that as the result of GetDropLocation()

I got in contact with one of the supporters of GAIA, and… this was a problem with me installing one of their systems and not using it (Flora). We uninstalled it (from the game scene, can’t do that otherwise), all went well again :stuck_out_tongue:

Anyway, time to see what I was missing here

OK so… I’m not sure of the solution, but is this correct? (My changes were highlighted by the ‘// ← changed the above line for this one’ in the comments below):

        protected override Vector3 GetDropLocation()
        {

            // generate 'attempts' number of random points for our loot to drop on (everytime loot hits the ground):
            for (int i = 0; i < Attempts; i++) {
            
            // The random Point should be within the Unit Sphere of the killed Enemy/Player
            Vector3 randomPoint = transform.position + (Random.insideUnitSphere * scatterDistance);

            // Ensuring our loot does not fall in the air, off the cliff or somewhere inaccessible by the player:
            NavMeshHit hit;

            if (NavMesh.SamplePosition(randomPoint, out hit, 0.1f, NavMesh.AllAreas)) {
                // return hit.position;
                return RaycastToTerrain(); // <-- changed the line above for this one
            }
            
            }

            // if we can't drop it on the ground, just drop it at the players' location:
            // return transform.position;
            return RaycastToTerrain(); // <-- changed the line above for this one

        }

and this is the ‘RaycastToTerrain()’ function that I copy-pasted:

Vector3 RaycastToTerrain()
        {
            Ray ray = new Ray(transform.position + Vector3.up * 2, Vector3.down);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit, 10, LayerMask.GetMask("Terrain")))
            {
                return hit.point;
            }

            else return transform.position;
        }

I can’t tell if it’s right or wrong because it’s getting a little hard for me to get to the point of having flying drops as we speak… it happens occasionally I believe

The only problem here is that we’re trying to get some randomness in the drop point…

  • Add a Vector3 position to the RaycastToTerrain() method in RandomDropper
  • Pass hit.point to the function within the if(NavMesh.SamplePosition()) block
  • pass transform.position in the default (couldnt’ find a spot)'s call to RaycastToTerrain.

3rd party tools can be a source of great… bugmaking… glad they were able to help you on that one.

I mean… it was either I adapt to this system, or risk having to deal with World Streaming down the line :stuck_out_tongue: (and frankly speaking, I’d rather not risk my project this way ever again, but I had zero idea what World Streaming would be like, so I took the easy way out :sweat_smile:)

Anyway, back to bug-fixing, I go

OK so… assuming I followed the correct steps, this is how ‘GetDropLocation()’ and ‘RaycastToTerrain()’ will look like in ‘RandomDropper.cs’, just double checking:

        // protected, because that's the type it is in 'ItemDropper.cs' (this entire class inherits from 'ItemDropper.cs)
        // override because it overrides 'GetDropLocation()' in 'ItemDropper.cs'
        protected override Vector3 GetDropLocation()
        {

            // generate 'attempts' number of random points for our loot to drop on (everytime loot hits the ground):
            for (int i = 0; i < Attempts; i++) {
            
            // The random Point should be within the Unit Sphere of the killed Enemy/Player
            Vector3 randomPoint = transform.position + (Random.insideUnitSphere * scatterDistance);

            // Ensuring our loot does not fall in the air, off the cliff or somewhere inaccessible by the player:
            NavMeshHit hit;

            if (NavMesh.SamplePosition(randomPoint, out hit, 0.1f, NavMesh.AllAreas)) {
                // return hit.position;
                return RaycastToTerrain(hit.position);
            }
            
            }

            // if we can't drop it on the ground, just drop it at the players' location:
            // return transform.position;
            return RaycastToTerrain(transform.position);

        }

        Vector3 RaycastToTerrain(Vector3 position)
        {
            Ray ray = new Ray(position + Vector3.up * 2, Vector3.down);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit, 10, LayerMask.GetMask("Terrain")))
            {
                return hit.point;
            }

            else return position;
        }

correct?

Looks right!

1 Like

quick question on the fly, since we’re all into flying obstacles right now. If I want to slam some of my environment prefabs to the floor lower than a Widebody Kit Lamborghini (search that up if you don’t know what it is :stuck_out_tongue: - no Ferraris mentioned though, their lawsuits are annoying), but not below the terrain, can we use this algorithm? (all I’m trying to do is to not make my environment seem like it’s floating off the game’s terrain)

using UnityEngine;

public class SnapToTerrain : MonoBehaviour
{

    void Start() 
    {
        RaycastToTerrain(transform.position);
    }

    Vector3 RaycastToTerrain(Vector3 position)
    {
        Ray ray = new Ray(position + Vector3.up * 2, Vector3.down);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, 10, LayerMask.GetMask("Terrain")))
        {
            return hit.point;
        }

        else return position;
    }
}

I tried, it didn’t work, so I was asking if we can (on the fly) get that to work?

You didn’t do anything with the result.

void Start()
{
    transform.position = RaycastToTerrain(transform.position);
}

that didn’t work… Alls good though, in the morning I’ll put some supports to make it look like there’s something holding the bridge :stuck_out_tongue: (not like I will die if it doesn’t work)

and both layers (the terrain and the prefab) had Terrain set up on them, if that helps

Privacy & Terms