This is related to my last question but I thought it was different enough to make a new thread… (I’m making a platformer, X is in front of the player);
This is the code I have in there right now, but I want it to not get the object closest to the player, but instead the object closest in front of the player. Is there a simple way to do that?
public PlayerController player;
public SB_Checkpoint[] checkpoints;
public Vector3 closestCheckpoint;
void Start()
{
closestCheckpoint = checkpoints[0].transform.position; //this is so it doesn't get set to (0,0,0) right away
}
void checkClosestCheckpoint(Vector3 check)
{
if (Vector3.Distance(check, player.transform.position) < Vector3.Distance(closestCheckpoint, player.transform.position))
{
closestCheckpoint = check;
}
}
void Update()
{
foreach(SB_Checkpoint checkpoint in checkpoints)
{
checkClosestCheckpoint(checkpoint.transform.position);
}
}
Hi!
you would have to add a criteria for the check position, and only consider the check´s that are in front of the player.
If the player can move freely you need to do some calculations to figure out what the criteria would be.
if you have a fps approach you might get lucky by just using renderer.isvisible() that way you would only consider the
checks that are actually visible (in any camera). Beware that this will, in editmode, return true if your check is visible in any editor camera
You can use the dot product to determine if something is in front of a transform or behind, so do this check first and then yours maybe?
I got it to only run a check for checkpoints in front of the player, but if the checkpoint in front of the player it’s checking is further away than the current closestCheckpoint, it won’t change.
Is there a way to make a second private array that only lists the checkpoints that have an X value larger than the player?
please provide your current code
If i understand your problem correctly i think this would be your solution:
public PlayerController player;
public SB_Checkpoint[] checkpoints;
public Vector3 closestCheckpoint;
void Start()
{
closestCheckpoint = checkpoints[0].transform.position; //this is so it doesn't get set to (0,0,0) right away
}
void checkClosestCheckpoint(Vector3 check)
{
if (Vector3.Distance(check, player.transform.position) < Vector3.Distance(closestCheckpoint, player.transform.position))
{
closestCheckpoint = check;
}
}
void Update()
{
var forward:Vector3 = player.transform.TransformDirection(Vector3.forward);
foreach(SB_Checkpoint checkpoint in checkpoints)
{
var toOther: Vector3 = checkpoint.transform.position - player.transform.position;
// check if it's in front of the player based on the transform forward vector
if(Vector3.Dot(forward, toOther) > 0)
{
Debug.Log(checkpoint.name + " IS IN FRONT OF ME!");
checkClosestCheckpoint(checkpoint.transform.position);
}
}
}
Thanks for your response…
This works for making sure it only selects the checkpoint if it’s in front of the player, but also the easier way I’d say over vector.Dot would be to just check if the X value of the checkpoint is greater than the players, as it’s a sidescroller. Now, I put something similar to what you wrote in, but, while it only checks checkpoints in front of the player, it won’t switch the checkpoint if the current value of closestCheckpoint is closer to the player than the checkpoint it’s checking, regardless of whether or not it’s in front of the player. I need a way to go to the next checkpoint the moment the player passes one checkpoint.
As I said before, I had an idea of making a second private array that only is populated with checkpoints that are above the player’s X position, but I don’t know how to change the length of an array in code, or add checkpoints to the array
Sorry I misread your platformer part :). Well I can’t really tell you much about that as I always script in C# which allows dynamic arrays thus dynamic sizes.
If you want to check the distance over just the X value you can simply subtract player.position.x from check.position.x. If the result is > 0 then it’s “in front”, smaller it’s “behind”. If it’s in front, you can compare that value to the stored check point. Something like this:
void checkClosestCheckpoint(Vector3 check)
{
var distance: float = check.x - player.transform.position.x;
if (distance > 0 distance < closestCheckpoint.x - player.transform.position.x)
{
// we are in front AND the closest!
closestCheckpoint = check;
}
}
Sorry I should have said before… I’m using C# so you could give me a C# example. Thanks 
Haha no probs, I will work you a sample just a minute, in the meantime did my code work?
I must say I still think my previous code should work and would be more efficient but maybe I just don’t get what you want
The following code should somewhat work but I can’t test it so be prepared for some possible errors? 
// important!! with the other usings
using System.Collections.Generic;
private Dictionary<float, SB_Checkpoint> checkPointsLarger = new Dictionary<float, SB_Checkpoint>();
public PlayerController player;
public SB_Checkpoint[] checkpoints;
public Vector3 closestCheckpoint;
public float closest;
void Start()
{
closestCheckpoint = checkpoints[0].transform.position; //this is so it doesn't get set to (0,0,0) right away
}
void Update()
{
// clear the list
closestCheckpoint.Clear();
// reset closest
closest = 0f;
foreach(SB_Checkpoint checkpoint in checkpoints)
{
float distance = checkpoint.transform.position.x - player.transform.position.x;
if (distance > 0)
{
closestCheckpoint.add(distance, checkpoint);
}
}
foreach (KeyValuePair<float, SB_Checkpoint> pair in closestCheckpoint)
{
if(pair.Key > closest)
{
closest = pair.Key;
closestCheckpoint = pair.Value.transform.position;
}
}
// do something usefull with ClosestCheckpoint
}
Hey, thanks for all your help but I just figured out a way to do it with only adding a few lines from my original script…
public PlayerController player;
public SB_Checkpoint[] checkpoints;
public Vector3 closestCheckpoint;
void Start()
{
closestCheckpoint = checkpoints[0].transform.position;
}
void checkClosestCheckpoint(Vector3 check)
{
if (Vector3.Distance(check, player.transform.position) < Vector3.Distance(closestCheckpoint, player.transform.position))
{
closestCheckpoint = check;
}
}
void Update()
{
foreach(SB_Checkpoint checkpoint in checkpoints)
{
if (checkpoint.transform.position.x > player.transform.position.x)
{
checkClosestCheckpoint(checkpoint.transform.position);
}
}
if (closestCheckpoint.x < player.transform.position.x)
{
closestCheckpoint = new Vector3(10000,0,0);
}
}
in a nutshell the second you pass a checkpoint, it throws the closest checkpoint vector way off to the right, and so it find the closest one to you on the right afterwards. If I didn’t throw the vector to the right, it would just stay as the checkpoint behind you
Yea thats very good, it’s sort of a longer version then i posted before:
void checkClosestCheckpoint(Vector3 check)
{
var distance: float = check.x - player.transform.position.x;
if (distance > 0 distance < closestCheckpoint.x - player.transform.position.x)
{
// we are in front AND the closest!
closestCheckpoint = check;
}
}