I followed the code created by Sam for getting a random drop location, with some modifications, that are explained here.
In my case, I changed the ClickablePickUp
as follow:
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player") && pickup.CanBePickedUp() && isAvailable)
PickUpItem();
}
public bool HandleRaycast(PlayerController callingController)
{
if (Vector3.Distance(transform.position, callingController.transform.position) > maxDistanceToPickUp)
return false;
if (Input.GetMouseButtonDown(0))
PickUpItem();
return true;
}
private void PickUpItem()
{
isAvailable = false;
pickup.PickupItem();
}
This means that if the player is not on a maxDistanceToPickUp
, I will not allow him to click on the pickup and get it automatically. If you want the pick up that is on the other side of the river, you need to go there! And I made all Clickable Pickups to work with the “run over” behaviour too, using the OnTriggerEnter
.
Because of that, I needed to have a small change in the RandomDropper.GetDropLocation
method: I can’t make it drop the item on the transform.position
, as this would make the OnTriggerEnter
fire and the player get the pickup again. I needed to add a check about the distance to see that.
Because of this check, most of the times it will not accept the attemps to create a random position.
So, my idea was: if none of the NavMesh.SamplePosition
worked, I can “drop” the item in front of the player, using the scatter distance (that in my case is higher).
But this generates a case where the we would drop the item “on the water”. To avoid that, I made a new check: is the position “reachable”? In case it is not, I am dropping the item “behind” the player.
This made my GetDropLocation
looks like this:
protected override Vector3 GetDropLocation()
{
for (var i = 0; i < ATTEMPTS; i++)
{
var randomPoint = transform.position + Random.insideUnitSphere * scatterDistance;
print($"{i}: {randomPoint}");
if (!NavMesh.SamplePosition(randomPoint, out var hit, 0.1f, NavMesh.AllAreas) ||
Vector3.Distance(transform.position, randomPoint) < scatterDistance / 2)
continue;
return hit.position;
}
var inFront = transform.position + transform.forward * scatterDistance;
var path = new NavMeshPath();
var isReachable = NavMesh.CalculatePath(transform.position, inFront, NavMesh.AllAreas, path)
&& path.status == NavMeshPathStatus.PathComplete;
if (isReachable)
return inFront;
return transform.position - transform.forward * scatterDistance;
}
I just would like to hear some opinions if there is any way better to do that. Any comment is highly appreciated
The fact that it is not generating a “valid” random position is something that is making me annoyed…
And there is the problem that if the player is near a “mountain”, it can drop the item “inside” the mountain…