[Решено] Заполнить территорию определённым блоком

  • Автор темы Автор темы CoolBoy
  • Дата начала Дата начала
Статус
Закрыто для дальнейших ответов.
Попробуйте заполнить 5 блоков вокруг игрока. В вашем случае вв заполните лишь секцию 2 и 3, потому что во 2 - x и z положительные, а в 3 - x и z отрицательные.

С "y" пока не работайте - он не нужен.
Код:
x= player.getLocation().getX-2;//тут два по причине того что при делении 5 на 2 без остатка будет 2
y= player.getLocation().getY-2;
z= player.getLocation().getZ-2;

x2= player.getLocation().getX+2;
y2= player.getLocation().getY+2;
z2= player.getLocation().getZ+2;

for(;y<y2;y++){
for(;x<x2;x++){
   for(;z<z2;z++){
    //здесь устанавливаем блок по полученным координатам при выполнении нужных условий
    }
   }
}

Теперь тыкните меня лицом в место где я не прав.
 
Код:
x= player.getLocation().getX-2;//тут два по причине того что при делении 5 на 2 без остатка будет 2
y= player.getLocation().getY-2;
z= player.getLocation().getZ-2;

x2= player.getLocation().getX+2;
y2= player.getLocation().getY+2;
z2= player.getLocation().getZ+2;

for(y=0;y<y2;y++){
for(x=0;x<x2;x++){
   for(for(z=0;z<z2;z++){
    //здесь устанавливаем блок по полученным координатам при выполнении нужных условий
    }
   }
}

Теперь тыкните меня лицом в место где я не прав.
Проверьте код и убедитесь в моих словах :)
 
Ты про что?Я исправил код в своём ответе,страничку обнови.
Проверьте этот код в майнкрафте. Он будет работать не совсем так как нужно :)
Также, хочу заметить, что getZ(), getY() и getX() - это методы. Поэтому нужны скобки.
 
Заполнили всё пространство вокруг игрока на радиус 3 блока?
P.S.Мне как показалось мы не вокруг игрока заполняли, а относительно его кубоид.
Проверьте этот код в майнкрафте. Он будет работать не совсем так как нужно :)
P.S.Мне как показалось мы не вокруг игрока заполняли, а относительно его кубоид.Это разные вещи.Если хотите круг,то вам нужно каждый блок этого кубоида при постановке проверять принадлежит ли он окружности.
У меня уже 3 часа ночи,не обращай внимания на повтор фраз.
 
P.S.Мне как показалось мы не вокруг игрока заполняли, а относительно его кубоид.

P.S.Мне как показалось мы не вокруг игрока заполняли, а относительно его кубоид.Это разные вещи.Если хотите круг,то вам нужно каждый блок этого кубоида при постановке проверять принадлежит ли он окружности.
У меня уже 3 часа ночи,не обращай внимания на повтор фраз.
Именно в этом и дело. С кубойдом я бы, надеюсь, и один справился :)
А тут задачка посложнее.

Я уже писал, что можно решить мою задачу в 4 цикла, в каждом из которых будет ещё 2. Но это не лучшее решение, как по мне.
 
Именно в этом и дело. С кубойдом я бы, надеюсь и один справился :)
А тут задачка посложнее.
Ну как я и сказал,просто проверь каждый блок на принадлежность к окружности,ну и чтобы всё было нормально,то лучше получать целочисленные координаты от игрока.
 
Пока на ум пришла лишь следующая конструкция:
Java:
//Его использование
for (Block blocks : this.getBlocksInRadius(player.getLocation(), 5) {
    blocks.setType(Material.<MY_VALUE>);
}

//Метод
public static List<Block> getBlocksInRadius(Location location, int radius) {
    List<Block> blocks = new ArrayList<>();

    int bX = location.getBlockX(),
            bY = location.getBlockY(),
            bZ = location.getBlockZ();

    for (int x = bX - radius; x <= bX + radius; x++) {
        for (int y = bY - radius; y <= bY + radius; y++) {
            for (int z = bZ - radius; z <= bZ + radius; z++) {
                double distance = ((bX - x) * (bX - x) + (bY - y) * (bY - y) + (bZ - z) * (bZ - z));

                if (distance < radius * radius
                            && !(distance < ((radius - 1) * (radius - 1)))) {
                    Location l = new Location(location.getWorld(), x, y, z);

                    if (l.getBlock().getType() != Material.BARRIER) {
                        blocks.add(l.getBlock());
                    }
                }
            }
        }
    }

    return blocks;
}
 
Последнее редактирование:
Пока на ум пришла лишь следующая конструкция:
Java:
//Его использование
for (Block blocks : this.getBlocksInRadius(player.getLocation(), 5) {
    blocks.setType(Material.<MY_VALUE>);
}

//Метод
public static List<Block> getBlocksInRadius(Location location, int radius) {
    List<Block> blocks = new ArrayList<>();

    int bX = location.getBlockX(),
            bY = location.getBlockY(),
            bZ = location.getBlockZ();

    for (int x = bX - radius; x <= bX + radius; x++) {
        for (int y = bY - radius; y <= bY + radius; y++) {
            for (int z = bZ - radius; z <= bZ + radius; z++) {
                double distance = ((bX - x) * (bX - x) + (bY - y) * (bY - y) + (bZ - z) * (bZ - z));

                 if (distance < radius * radius
                            && !(distance < ((radius - 1) * (radius - 1)))) {
                    Location l = new Location(location.getWorld(), x, y, z);

                    if (l.getBlock().getType() != Material.BARRIER) {
                        blocks.add(l.getBlock());
                    }
                }
            }
        }
    }

    return blocks;
}
Вроде как всё верно,но с 14 по 16 строку не всё ясно(может быть я плохо знаю геометрию).Но мне кажется,что запись стоит сократить вот так: r==Math.sqrt((x-xp)*(x-xp)+(z-zp)*(z-zp)) ,где r-радиус,x,z - координаты центра окражности; xp и zp - координаты проверяемой точки.
Мне кажется или тут все ненавидят "Math.pow(число, степень);"
 
@CoolBoy, я не очень внимательно читал посты в теме, вопрос: тебе нужен алгоритм floodfill?
То, как это работает в WorldEdit (/fillr ...)?
Например, первое с гугла. Ну там тебе надо только вставить проверку на принадлежность твоему радиусу.
P.S. Ну и плюс переделать чтобы не было рекурсии, если ты хочешь иметь возможность указывать действительно большие радиусы без переполнения стека.
 
@CoolBoy, я не очень внимательно читал посты в теме, вопрос: тебе нужен алгоритм floodfill?
То, как это работает в WorldEdit (/fillr ...)?
Например, первое с гугла. Ну там тебе надо только вставить проверку на принадлежность твоему радиусу.
P.S. Ну и плюс переделать чтобы не было рекурсии, если ты хочешь иметь возможность указывать действительно большие радиусы без переполнения стека.
Именно. Проблема в том, что заполняю я пространство из центральной точки.
UP, не решено!
 
1. Получаешь начальную точку, пусть это будет loc.
2. Рекурсивно бегаешь по соседним координатам (6 блоков вокруг текущего), если это не воздух или он выше loc.getY() или он дальше, чем нужный тебе радиус, то просто return.
Иначе заменяешь его на что-то нужное тебе и вызываешь этот же метод для 6 блоков соседей уже этого блока-соседа.
 
1. Получаешь начальную точку, пусть это будет loc.
2. Рекурсивно бегаешь по соседним координатам (6 блоков вокруг текущего), если это не воздух или он выше loc.getY() или он дальше, чем нужный тебе радиус, то просто return.
Иначе заменяешь его на что-то нужное тебе и вызываешь этот же метод для 6 блоков соседей уже этого блока-соседа.
Можно код? :)
 
Естественно, не проверял, только доверился интуиции.
Java:
public void doFloodFill(Player p, Material m, double radius)
{
    Location loc = p.getLocation().clone().add(0.0, -1.0, 0.0);
    recursive(loc, loc, m, radius * radius);
}
private final Vector[] vs = new Vector[]
{
    new Vector(+1, 0, 0), new Vector(0, +1, 0), new Vector(0, 0, +1),
    new Vector(-1, 0, 0), new Vector(0, -1, 0), new Vector(0, 0, -1),
};
private void recursive(Location src, Location loc, Material m, double r2)
{
    Block block = loc.getBlock();
    if(block == null)
        return;
    boolean isUnder  = block.getY() >= 0 && block.getY() <= src.getBlockY();
    boolean isInside = loc.distanceSquared(src) <= r2;
    boolean isEmpty  = block.getType().equals(Material.AIR);
    if(isUnder && isInside && isEmpty)
    {
        block.setType(m);
        for(Vector v : vs)
        {
            recursive(src, loc.clone().add(v), m, r2);
        }
    }
}
Смотри, чтобы были импортированы правильные вектора (org.bukkit.vector).
Снаружи нужно вызывать doFloodFill. Ну и там может быть когда у игрока берется положение, может быть его ещё ниже надо утащить.
P.S. Предполагается, что внизу мир перекрыт блоками (бедрок тот же), иначе надо добавить ограничение по y вниз. Я сейчас его допишу в код.
.
 
Последнее редактирование:
Естественно, не проверял, только доверился интуиции.
Java:
public void doFloodFill(Player p, Material m, double radius)
{
    Location loc = p.getLocation().clone().add(0.0, -1.0, 0.0);
    recursive(loc, loc, m, radius * radius);
}
private final Vector[] vs = new Vector[]
{
    new Vector(+1, 0, 0), new Vector(0, +1, 0), new Vector(0, 0, +1),
    new Vector(-1, 0, 0), new Vector(0, -1, 0), new Vector(0, 0, -1),
};
private void recursive(Location src, Location loc, Material m, double r2)
{
    Block block = loc.getBlock();
    if(block == null)
        return;
    boolean isUnder  = block.getY() >= 0 && block.getY() <= src.getBlockY();
    boolean isInside = loc.distanceSquared(src) <= r2;
    boolean isEmpty  = block.getType().equals(Material.AIR);
    if(isUnder && isInside && isEmpty)
    {
        block.setType(m);
        for(Vector v : vs)
        {
            recursive(src, loc.clone().add(v), m, r2);
        }
    }
}
Смотри, чтобы были импортированы правильные вектора (org.bukkit.vector).
Снаружи нужно вызывать doFloodFill. Ну и там может быть когда у игрока берется положение, может быть его ещё ниже надо утащить.
P.S. Предполагается, что внизу мир перекрыт блоками (бедрок тот же), иначе надо добавить ограничение по y вниз. Я сейчас его допишу в код.
.
Огромное вам спасибо, уже не в первый раз выручаете. Метод работает как раз так, как нужно.

Решено. Закрыто.

Спасибо @Reality_SC
 
Статус
Закрыто для дальнейших ответов.
Назад
Верх