# Tutorial Creating basic shapes

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

1. ### SandertvZombie PigmanPoggit 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 \$center, float \$radius) {  for(\$x = \$center->x - \$radius; \$x <= \$center->x + \$radius; \$x++) {    for(\$y = \$center->y - \$radius; \$y <= \$center->y + \$radius; \$y++) {      for(\$z = \$center->z - \$radius; \$z <= \$center->z + \$radius; \$z++) {        \$center->getLevel()->setBlock(new Vector3(\$x, \$y, \$z), Block::get(Block::STONE), false, false); // 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 \$center, float \$radius) {  \$radiusSquared = \$radius * \$radius;  for(\$x = \$center->x - \$radius; \$x <= \$center->x + \$radius; \$x++) {    \$xsquared = (\$center->x - \$x) * (\$center->x - \$x);    for(\$y = \$center->y - \$radius; \$y <= \$center->y + \$radius; \$y++) {      \$ysquared = (\$center->y - \$y) * (\$center->y - \$y);      for(\$z = \$center->z - \$radius; \$z <= \$center->z + \$radius; \$z++) {        \$zsquared = (\$center->z = \$z) * (\$center->z - \$z);        if(\$xsquared + \$ysquared + \$zsquared < \$radiusSquared) {          \$center->getLevel()->setBlock(new Vector3(\$x, \$y, \$z), Block::get(Block::STONE), false, false);        }      }    }  }} ```

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 \$center, float \$radius) {  \$radiusSquared = \$radius * \$radius;  for(\$x = \$center->x - \$radius; \$x <= \$center->x + \$radius; \$x++) {    \$xsquared = (\$center->x - \$x) * (\$center->x - \$x);    for(\$y = \$center->y - \$radius; \$y <= \$center->y + \$radius; \$y++) {      for(\$z = \$center->z - \$radius; \$z <= \$center->z + \$radius; \$z++) {        \$zsquared = (\$center->z = \$z) * (\$center->z - \$z);        if(\$xsquared + \$zsquared < \$radiusSquared) {          \$center->getLevel()->setBlock(new Vector3(\$x, \$y, \$z), Block::get(Block::STONE), false, false);        }      }    }  }} ```

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. ### MuqsitChicken

Messages:
1,549
GitHub:
muqsit
Using setBlockIdAt, is pretty fast. I don't know what the cons are tho.

0x15f likes this.
3. ### SandertvZombie PigmanPoggit 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. ### PocketKillerSlime

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. ### SandertvZombie PigmanPoggit 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. ### 0x15fBaby 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. ### SandertvZombie PigmanPoggit 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. ### 0x15fBaby 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. ### MuqsitChicken

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 \$center, float \$radius) {  \$blockdata = [];  for(\$x = \$center->x - \$radius; \$x <= \$center->x + \$radius; \$x++) {    for(\$y = \$center->y - \$radius; \$y <= \$center->y + \$radius; \$y++) {      for(\$z = \$center->z - \$radius; \$z <= \$center->z + \$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, \$coord, \$coord, Block::get(Block::STONE)); //no updates are sent.  }} ```
Nice work btw xd

Sandertv likes this.
10. ### Thunder33345ModeratorStaff 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. ### SandertvZombie PigmanPoggit 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. ### gistrecWitch

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

13. ### SandertvZombie PigmanPoggit Reviewer

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

14. ### gistrecWitch

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

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. Call to undefined method pocketmine\math\Vector3::getLevel() @Sandertv

Last edited: Jan 28, 2017
17. ### Thunder33345ModeratorStaff Member

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

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

19. ### SandertvZombie PigmanPoggit 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. How to make getBlock() as Position object?