Tutorial Creating basic shapes

Discussion in 'Resources' started by Sandertv, Jan 19, 2017.

  1. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    Hello everyone! I've lately been working on a worldedit plugin, and noticed there have been a lot of questions about how to make shapes properly, and settings those for example to a given block. This tutorial is to clear that up for you. This tutorial is also aimed to make the process as mathematically easy as possible, and efficient, due to the scanning in for example a sphere not processing the same block additional times.

    This tutorial is made for people who already know at least a decent amount of PocketMine API.

    Now, let's start shall we? Let's begin by making the most basic shape: A cube.

    We first start by introducing a new function. There are a couple required things to make a cube. In our case, this is a center Vector3, and a radius.
    PHP:
    public function createCube(Position $centerfloat $radius) {
      for(
    $x $center->$radius$x <= $center->$radius$x++) {
        for(
    $y $center->$radius$y <= $center->$radius$y++) {
          for(
    $z $center->$radius$z <= $center->$radius$z++) {
            
    $center->getLevel()->setBlock(new Vector3($x$y$z), Block::get(Block::STONE), falsefalse); // Set block update to false to decrease lag with big areas.
          
    }
        }
      }
    }

    Now that we know how to make a cube, it is time to move on to the sphere. A sphere is the shape most coders have problems with. Spheres can be made using a lot of math, but there is a way easier way to do it without a big amount of math knowledge.

    PHP:
    public function createSphere(Position $centerfloat $radius) {
      
    $radiusSquared $radius $radius;
      for(
    $x $center->$radius$x <= $center->$radius$x++) {
        
    $xsquared = ($center->$x) * ($center->$x);
        for(
    $y $center->$radius$y <= $center->$radius$y++) {
          
    $ysquared = ($center->$y) * ($center->$y);
          for(
    $z $center->$radius$z <= $center->$radius$z++) {
            
    $zsquared = ($center->$z) * ($center->$z);
            if(
    $xsquared $ysquared $zsquared $radiusSquared) {
              
    $center->getLevel()->setBlock(new Vector3($x$y$z), Block::get(Block::STONE), falsefalse);
            }
          }
        }
      }
    }

    The code to make a sphere may look quite complicated at first, but if you look at it a couple times, you should slowly start to understand what it does. As soon as you understand how the sphere works, we can continue to the cylinder. Creating a cylinder is basically a combination between the creating of a cube, and the creating of a sphere.

    PHP:
    // A cylinder is super similar to a sphere. Just change one for loop, and you're set!
    public function createCylinder(Position $centerfloat $radius) {
      
    $radiusSquared $radius $radius;
      for(
    $x $center->$radius$x <= $center->$radius$x++) {
        
    $xsquared = ($center->$x) * ($center->$x);
        for(
    $y $center->$radius$y <= $center->$radius$y++) {
          for(
    $z $center->$radius$z <= $center->$radius$z++) {
            
    $zsquared = ($center->$z) * ($center->$z);
            if(
    $xsquared $zsquared $radiusSquared) {
              
    $center->getLevel()->setBlock(new Vector3($x$y$z), Block::get(Block::STONE), falsefalse);
            }
          }
        }
      }
    }

    I made this in the hope that it'll be helpful, so please make sure to tell me if something is wrong or doesn't work, or if you need more help. I hope this tutorial helped some of you!

    This method CAN be used for particles too. To make a good looking sphere though, you would have to replace for example $x++ with $x += 0.05 for a higher density.

    Please note that setting blocks on this way is not very efficient when setting a huge amount of blocks. This tutorial is mainly for the part of showing how to do it, and could, when not handled with care, freeze the server.
     
    Last edited: Jan 29, 2017
  2. Muqsit

    Muqsit Chicken

    Messages:
    1,549
    GitHub:
    muqsit
    Using setBlockIdAt, is pretty fast. I don't know what the cons are tho.
     
    0x15f likes this.
  3. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    That's the only thing I didn't look into for optimizing. Thanks for the suggestion :)
     
    Skullex and Muqsit like this.
  4. PocketKiller

    PocketKiller Slime

    Messages:
    83
    GitHub:
    iPocket
    wat.
    that makes me get more confusion... TOO MANY MATHS! (I don't understand a single thing of it) (Whats an SPhere?)
     
  5. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    The math required is honestly really little. Just try to visualize what you're doing with the code. Once you get that, it's really easy to understand :)
     
    TestDevelopment and Skullex like this.
  6. 0x15f

    0x15f Baby Zombie

    Messages:
    145
    GitHub:
    0x15f
    Don't use a 'for' loop in the completed WE plug, setting large amounts of blocks would cause the Main thread to be "frozen" for too long.
     
    Muqsit and Sandertv like this.
  7. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    True. I'll add a warning. What do you suggest otherwise next to setting it in a repeating task or an async?

    My world edit plugin doesn't allow to set big amounts of blocks anyways. It limits a radius bigger than 10.
     
  8. 0x15f

    0x15f Baby Zombie

    Messages:
    145
    GitHub:
    0x15f
    In my WE plug (not public) I used one of the tasks shown here: http://blog.falkirks.com/setting-huge-areas-of-blocks/ the tick separated would work allowing the server to respond to players in-between block sets.
     
    Thunder33345 likes this.
  9. Muqsit

    Muqsit Chicken

    Messages:
    1,549
    GitHub:
    muqsit
    If you replace $i++ with ++$i you can save some time as pre incrementing doesn't make a copy of the var. Idk how much time you can actually save with that though, but your's is the farthest in optimization already.

    Except for... (I could be wrong), setBlock outside a for loop might be better.
    PHP:
    public function createCube(Vector3 $centerfloat $radius) {
      
    $blockdata = [];
      for(
    $x $center->$radius$x <= $center->$radius$x++) {
        for(
    $y $center->$radius$y <= $center->$radius$y++) {
          for(
    $z $center->$radius$z <= $center->$radius$z++) {
            
    $blockdata[] = [$x$y$z];
          }
        }
      }
      foreach(
    $blockdata as $coord) {
        
    //I think Location and Position have getLevel(), not sure about Vector3 having one.
        
    $center->getLevel()->setBlockIdAt($coord[0], $coord[1], $coord[2], Block::get(Block::STONE)); //no updates are sent.
      
    }
    }
    Nice work btw xd
     
    Sandertv likes this.
  10. Thunder33345

    Thunder33345 Moderator Staff Member

    Messages:
    2,137
    GitHub:
    Thunder33345
    isnt looping for the same thing better then merging the loop
    since now you just run x2 amounts of loops + array access + array storing
    also recommend reading up http://blog.falkirks.com/setting-huge-areas-of-blocks/ like imagical gamer said
    it is defenitly a good read if you want to make plugin that sets huge amount of date

    why doe?
    why not just let them do it, it is not like it will break the internal machanism
    if i really have to do that, that will be my last resort i will also add a limit overwrite config for users who know what they are doing
     
  11. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    Lol this thread was never meant to be a subject of optimizing block placement. It was just to show people how to make basic shapes. Of course there's ways to optimize it, but I leave that to the others.
     
    Muqsit likes this.
  12. gistrec

    gistrec Witch

    Messages:
    68
    GitHub:
    gistrec
    How long does it take to create sphere with radius = 30?
     
  13. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    With the basic setBlock method in the main thread, not that fast for sure.
     
  14. gistrec

    gistrec Witch

    Messages:
    68
    GitHub:
    gistrec
    Also this code http://pastebin.com/Lta2E2U0 is work's too :)
    And it create sphere with radius = 30 for 1-2 sec
     
  15. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin

    Messages:
    1,968
    GitHub:
    sof3
    Add ellipsoid, elliptical cylinder, rotated cylinder, distorted cylinder, distorted sphere, parallelepiped and elliptical frustum!
    How long it takes primarily depends on the machine and extra actions executed. "1-2 sec" is meaningless in this situation.
     
  16. Hipster

    Hipster Zombie

    Messages:
    214
    Call to undefined method pocketmine\math\Vector3::getLevel() @Sandertv
     
    Last edited: Jan 28, 2017
  17. Thunder33345

    Thunder33345 Moderator Staff Member

    Messages:
    2,137
    GitHub:
    Thunder33345
    that is unrelated to this thread
     
  18. Hipster

    Hipster Zombie

    Messages:
    214
    Call to undefined method pocketmine\math\Vector3::getLevel() @Sandertv
    nope
     
  19. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    786
    GitHub:
    Sandertv
    I made this with $center as Position object in my head, for example a block. A basic Vector3 won't work, you'll have to make at least a new Position object for it, or get the block at that location.
     
  20. Hipster

    Hipster Zombie

    Messages:
    214
    How to make getBlock() as Position object?
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.