A
A
Arkady Baganin2020-08-22 10:42:37
C++ / C#
Arkady Baganin, 2020-08-22 10:42:37

How to find empty space on water in 2d?

Good day!
I need to make a ship and bird spawner. I didn't come up with anything better than to create a variable "Dir", which stores the direction of the path of each monster (for ships y = 0, for birds = 3)... When 0, then we calculate the top point of the water and move the object there... But I have another problem, how to make the mobs not spawn on top of each other, I will attach the code below, the function that is responsible for the x position of the ships is called poolObj ()

shitcode

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

public class EnemyController : MonoBehaviour
{
    private Rigidbody2D _rb;
    private GameCamera _gc;
    private EnemyData _data;

    private GameObject _water;

    private int _minX;
    private int _maxX;

    public EnemyData Data
    {
        get
        {
            return _data;
        }

        set
        {
            _data = value;
        }
    }

    public void Start()
    {
        _rb = GetComponent<Rigidbody2D>();
        _gc = Camera.main.GetComponent<GameCamera>();

        _water = GameObject.FindGameObjectWithTag("Water");
        _minX = (int)Mathf.RoundToInt(1 - _gc.OffsetCamX) - 5;
        _maxX = (int)Mathf.RoundToInt(Camera.main.ScreenToWorldPoint(_water.transform.position).x + Camera.main.ScreenToWorldPoint(_water.GetComponent<BoxCollider2D>().size * _water.transform.localScale).x);
        _maxX = (int)Mathf.RoundToInt((1 - (_maxX + Camera.main.ScreenToWorldPoint(this.GetComponent<BoxCollider2D>().size * this.transform.localScale).x)) * 2) + 10;

        float _waterY = Camera.main.ScreenToWorldPoint(_water.transform.position).y - (Camera.main.ScreenToWorldPoint(_water.GetComponent<BoxCollider2D>().size * _water.transform.localScale).y / 2);
        float _yPos = _data.Dir.y > 0 ? _data.Dir.y : _waterY;
        transform.position = new Vector3(transform.position.x, _data.Dir.y, transform.position.z);

        GetComponent<Animator>().runtimeAnimatorController = _data.AnimController;
        GetComponent<AudioSource>().clip = _data.WalkSound;
        GetComponent<AudioSource>().loop = true;

        GetComponent<SpriteRenderer>().sprite = _data.Skin;

        transform.localScale = _data.ScaleEnemy;

        if (_data.IsBird)
        {
            GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezePositionY;
            transform.Rotate(0, 180, 0);
        }

        _poolObj();
    }

    private void FixedUpdate()
    {
        _rb.velocity += _data.Dir * _data.SpeedEnemy * Time.fixedDeltaTime;

        if (transform.position.x < _minX)
        {
            _poolObj();
        }
    }

    private void _poolObj()
    {
        int x = Random.Range(1 - _minX, _maxX);
        List<int> _usedCoordX = new List<int>();
        GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");

        foreach (GameObject enemy in enemies)
        {
            int _cx = (int)Mathf.RoundToInt(enemy.transform.position.x);

            if (_cx != (int)Mathf.RoundToInt(transform.position.x))
            {
                _usedCoordX.Add(_cx);
                _usedCoordX.Add(_cx - (int)Mathf.RoundToInt(Camera.main.ScreenToWorldPoint(enemy.GetComponent<BoxCollider2D>().size * enemy.transform.localScale).x));
                _usedCoordX.Add(_cx + (int)Mathf.RoundToInt(Camera.main.ScreenToWorldPoint(enemy.GetComponent<BoxCollider2D>().size * enemy.transform.localScale).x));
            }
        }

        int _checkX = (int)Mathf.RoundToInt(Camera.main.ScreenToWorldPoint(GetComponent<BoxCollider2D>().size * transform.localScale).x);

        if (_usedCoordX.Equals(x) || _usedCoordX.Equals(x + _checkX) || _usedCoordX.Equals(x - _checkX))
        {
            x = Random.Range(1 - _minX, _maxX);
        } else
        {
   <b></b>         transform.position = new Vector3(x, transform.position.y, transform.position.z);
        }
    }
}



Game screenshot

5f40cc5ab2bc3385930278.png


How to fix the bug so that they do not spawn on top of each other, i.e. how to find an empty space? And how it is possible to issue the code more beautifully ?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
AlexHell, 2020-08-28
@ark_yt

simple solution - loop through random variant X

// ВНЕ цикла подбора рандомного X для оптимизации
  foreach (GameObject enemy in enemies)
  {
    // заполнить _usedCoordX
  }
// цикл подбора рандомного X
while (true)
{
  int x = Random.Range(1 - _minX, _maxX);
  if (!_usedCoordX.Contains(x)) break;
}

(NOT performance-efficient, can be optimized - with Spatial structures or filled areas - I will not give implementations)
___
UPDATE:
where _usedCoordX is filled
, it would be nice to beat the field on the GRID uniform, analogue of the hash
______
|__|__|
|__|__|
for example
, if the position of object.X >= 10 && object.X < 20 then newX=1
if the position of object.X >= 20 && object.X < 30 then newX=2
, etc. with a step of 10
then with an already existing object with X = 15, an object with X = 16 or 17 will not be generated, etc. because they are in the same grid cell
and Random, of course, throw in the same dimension (_maxX should not be the full pixel / object size, but the grid size)
UPD2: on this topichttps://gamedev.stackexchange.com/questions/69310/...
and there is also a
UPD3 picture: instead of uniform GRID - you can use true Collision Detection, i.e. after generating Random X - check all enemies around, and if there are - generate a new one, so it will probably be better
.. but again, you can check by GRID for everyone in the same cell (i.e. if X is 15, then check all enemies - are they in X from 10 to 19, and if no - exit from the loop
.. plus check in neighboring cells (otherwise they will be generated right next to

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question