1
\$\begingroup\$

I'm making an endless runner game.

I have the script that make coins and walls appear at the same time in front of the player.

The problem is that sometimes the coin and wall appear in the same place/position.

How can I ensure that coins and walls do not appear in the same place/position?

public class Instantiate : MonoBehaviour
{
public float betweenSpawn = 1.05f;
public float angle;
public Vector3 spawnValues; //Range of appearing 
public GameObject coinPrefab;
public GameObject wallPrefab;

public Transform coinInstantiate;
public Transform wallInstantiate;

void Start()
{
    InvokeRepeating("Spawn", 0f, betweenSpawn);
}

void Spawn()
{
    Vector3 coinPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), 1, Random.Range(-spawnValues.z, spawnValues.z));
    Vector3 wallPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), 1, Random.Range(-spawnValues.z, spawnValues.z));

    Instantiate(coinPrefab, coinPosition + coinInstantiate.TransformPoint(0, 0, 0), Quaternion.AngleAxis(angle, Vector3.forward));
    Instantiate(wallPrefab, wallPosition + wallInstantiate.TransformPoint(0, 0, 0), Quaternion.AngleAxis(angle, Vector3.forward));    
}

}

\$\endgroup\$
1
\$\begingroup\$

Two approaches you can try:

A) Guess and Check (simple, usually works well enough, but a little wasteful)

void Spawn() {
    // First, we place the wall (assuming it's the bigger / more complicated obstacle)
    Vector3 wallPosition = GetRandomSpawnPositionNear(platformPosition);

    Instantiate(wallPrefab, wallPosition, Quaternion.Euler(0, 0, angle);

    // Next, we try to place the coin in some non-intersecting position.
    // We make sure to limit how many tries we take, so we don't stall unduly.
    for(int i = 0; i < maxSpawnAttempts; i++) {
        Vector3 coinPosition = GetRandomSpawnPositionNear(pathPointPosition);

        // Check for overlaps near this position.
        // (Assuming your wall has a 2D collider attached)
        if(Physics2D.OverlapCircle(coinPosition, coinRadius) == null) {
             // We found a non-overlapping spot! Slap it down & call it done. :D
             Instantiate(coinPrefab, coinPosition, Quaternion.Euler(0, 0, angle));
             return;
        }
        // Otherwise, loop and try again with a new random point.
    }
}

// In case you need it, here's the point-randomizing logic - same as you're using now.
Vector3 GetRandomSpawnPositionNear(Vector3 center) {
    Vector3 spawnOffset = spawnRange;

    spawnOffset.x *= Random.Range(-1f, 1f);
    spawnOffset.z *= Random.Range(-1f, 1f);

    return center + spawnOffset;
}

This has a chance to fail and give up before it finds a place to put the coin. In practice, it usually succeeds with just a few tries, unless you've put it in an over-constrained situation (colliders too densely packed in the spawning space to hit a non-overlapping spot by chance)

B) Correct by Construction

For this strategy we need to exploit some knowledge of the structure of your level, which unfortunately isn't included in your question so I can only guess. So I'll describe the overall approach rather than explicit code.

Let's say, for example, that we always want the coin to spawn to the left, above, or to the right of the wall. Once we've placed the wall, we can choose one of these three zones randomly, then choose a random place within the selected zone.

By offsetting the zones' positions and sizes using our knowledge of the shape & size of the wall, we can ensure that any point we choose in these zones will be non-overlapping, without needing to check for overlaps using physics queries.

\$\endgroup\$
  • \$\begingroup\$ Wall BoxCollider size is x=2 y=0.78 z=2, and Coin BoxCollider size is x=0.58 y=0.78 z= 1.5 \$\endgroup\$ – FELIX_SKI Jul 14 '18 at 18:19
0
\$\begingroup\$

I don't know what you are trying to do exactly, but it seems that either your Vector3 position and the Random.Range producing too much similiar numbers (maybe not a high enough range in your spawnvalues?) or that the addition of your pathposition is zero or very low.

Here's how i would do it:

Add an empty gameobject to your player, call it spawnPosition. Simply change the position in front of the player.

then:

public class Instantiate : MonoBehaviour
{

public GameObject coinPrefab;
public GameObject wallPrefab;

public Transform attachedGameObject;


void Start()
{

}

void Update(){
 Instantiate(coinPrefab, attachedGameObject.postion, Quaternion.Identity);

}

You can change the position also by simply adding a Random.Range to the position.

\$\endgroup\$
  • \$\begingroup\$ This answer shows how to spawn one object, but not the second object. Do you have a recommendation for how to spawn both without the two overlapping one another? \$\endgroup\$ – DMGregory Jul 14 '18 at 12:52
  • \$\begingroup\$ Simply add another spawn point, adjust position either via editor or via code and spawn obj1 at pos1, obj2 at pos2. \$\endgroup\$ – Prometheus Jul 14 '18 at 14:28
  • \$\begingroup\$ And given that the two positions are randomized, how do you ensure the randomized positions don't overlap? \$\endgroup\$ – DMGregory Jul 14 '18 at 14:32
  • \$\begingroup\$ OP said: "I have the script that make coins and walls appear at the same time in front of the player.". He also stated that he: "I'm making an endless runner game.".So high randomized position wouldnt make sense at all, otherwise it would be probably impossible to catch them? I think OP wants most likely to randomize the x position and maybe slightly the z, this can be done very easily and he simply needs to make sure that the randomized position are never higher than the distance between both spawning points, which is quite easy to do with this method since both points are static. \$\endgroup\$ – Prometheus Jul 14 '18 at 14:51
  • \$\begingroup\$ OP included randomization in their code example. This is not at all unusual for endless runner games. What I'm getting at is I don't think this answer as written fully addresses the question that was asked, and I'd recommend editing it to give a more complete description of how you propose to solve the overlap problem with randomly selected spawn positions. \$\endgroup\$ – DMGregory Jul 14 '18 at 14:58
0
\$\begingroup\$

There are literally infinite approaches to this problem.

One of it could be, for example, Worley noise + Voronoi diagram. You could create that diagram then choose 1 area on it, remove that area from possible samples. Then pick another one and you have 2 non-overlapping points. -

This is harder approach than the next one. But it was just to show you an example of how this can be achieved to support theory of multiple(infinite) ways.

Everything depends on your game, its needs, how it should work... without enough context, I doubt that there will be a perfect enough solution for your game.

The easiest/fast-forward option in my opinion would be to pick point 1 at random. Then pick another one at random. Check the distance/collision between points -

  1. No collision - good, it worked.
  2. They overlap - move the second point from other point until(by distance) they don't overlap (opposite direction or whatever suits your game).
  3. There is no place for the second point in the direction its choosing - move 2 points simultaneously. 1 away from another till they don't overlap. First on both axis, then separately. - it will always work as far as I understand, unless there is really no space for them to fit at all.
  4. Nothing worked - choose second point at random again. Max attempts. Usually it won't get here because of (3). So you will just need to increase the spawn area for points.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.