Introduction I've often seen threads about wings left unsolved because people claimed you'd have to be an expert at math for it, or simply because people lacked the knowledge. I'll attempt to teach you how to do this very easily today using the player direction vector. This has a lot more usages than you'd initially expect. Before starting this tutorial, you should have basic knowledge about how to create a repeating task. If you do not have this knowledge, you should take a look here: https://forums.pmmp.io/threads/creating-a-timer-with-tasks.136/ Preparation I won't be covering the creation of the entire plugin, so make sure you have a plugin.yml, a main plugin class and a repeating task ready to execute. For this tutorial, I'll be using functions from the GD PHP extension. Make sure you have this extension installed. For windows, you simply have to add it in the php.ini, for Linux you'll have to compile a version yourself with the GD (-g) option. Tutorial Okay, so we have our repeating task right here, which should look somewhat like this: PHP: <?phpnamespace MyNamespace;use pocketmine\Player;use pocketmine\plugin\Plugin;use pocketmine\scheduler\PluginTask;class WingDrawTask extends PluginTask{ public function __construct(Plugin $owner){ parent::__construct($owner); } public function onRun(int $currentTick) : void{ }} For this tutorial I'm going to use a wing PNG image with the dimensions 32x16. This can of course be changed to your likes, but for the sake of clarity I used these dimensions. First of all, for this example, make sure you have your wing image in the data folder of this plugin. You could make your image with some pixel editor, I personally use Piskel. (It's an online pixel editor) In the constructor of this task, we'll add the following: PHP: private $image;public function __construct(Plugin $owner){ parent::__construct($owner); $this->image = imagecreatefrompng($owner->getDataFolder() . "your_image_file.png");} We now have an `image` property, that we'll use further on to read the shape and colours from the wings from. We'll start with adding a foreach loop to get all players in the level onRun. Of course you probably don't want that, but you'll have to add permission checks as an example for that yourself. We'll also be defining some variables. PHP: public function onRun(int $currentTick) : void{ foreach($this->getOwner()->getServer()->getOnlinePlayers() as $player){ $directionVector = $player->getDirectionVector(); $sub = $directionVector()->multiply(0.5); // Because the direction vector is 1 block away from the player, we need to get a point closer to the player so the wings don't have a gap between the player. $base = $player->subtract($sub)->add(0, 1.8); // We try to get the base on a proper location here. First subtract the sub to get it at the right distance from the player, then make it higher. $particleDistance = 0.13; // This is the distance between the particles. You have to use a value you like. $imageHeight = 16; $halfImageWidth = 16; }} These are all variables we need to define for our wings. We'll now have to do the actual calculation part. This might sound harder than it really is. The actual position calculating is just one line. We'll first add some for loops using our image dimensions. PHP: public function onRun(int $currentTick) : void{ foreach($this->getOwner()->getServer()->getOnlinePlayers() as $player){ $directionVector = $player->getDirectionVector(); $sub = $directionVector()->multiply(0.5); // Because the direction vector is 1 block away from the player, we need to get a point closer to the player so the wings don't have a gap between the player. $base = $player->subtract($sub)->add(0, 1.8); // We try to get the base on a proper location here. First subtract the sub to get it at the right distance from the player, then make it higher. $particleDistance = 0.13; // This is the distance between the particles. You have to use a value you like. $imageHeight = 16; $halfImageWidth = 16; for($x = -$halfImageWidth; $x < $halfImageWidth; $x++){ // We use the half negative + half positive width to center the wings correctly. for($y = 0; $y < $imageHeight; $y++){ } } }} We'll now do the position calculating. We'll be using mostly common sense to calculate those positions. First, say we have a player standing on a spot looking straight to one direction. The player's direction vector X is 1, while the Z is 0. If we want to get the position on the right of a player, we'll have to swap the X and Z values. We use this logic to calculate the position. We have to make sure to multiply the x value with the particle distance however, to make sure we get that correct space in between. PHP: public function onRun(int $currentTick) : void{ foreach($this->getOwner()->getServer()->getOnlinePlayers() as $player){ $directionVector = $player->getDirectionVector(); $sub = $directionVector()->multiply(0.5); // Because the direction vector is 1 block away from the player, we need to get a point closer to the player so the wings don't have a gap between the player. $base = $player->subtract($sub)->add(0, 1.8); // We try to get the base on a proper location here. First subtract the sub to get it at the right distance from the player, then make it higher. $particleDistance = 0.13; // This is the distance between the particles. You have to use a value you like. $imageHeight = 16; $halfImageWidth = 16; for($x = -$halfImageWidth; $x < $halfImageWidth; $x++){ // We use the half negative + half positive width to center the wings correctly. for($y = 0; $y < $imageHeight; $y++){ $pos = $base->add($directionVector->z * $x * $particleDistance, -$y * $particleDistance, -$directionVector->x * $x * $particleDistance); } } }} That's all! You've now calculated all positions for wings on the back of a player. We're not done yet though, because this is no wing yet! This is where we start using our image class property. PHP: public function onRun(int $currentTick) : void{ foreach($this->getOwner()->getServer()->getOnlinePlayers() as $player){ $directionVector = $player->getDirectionVector(); $sub = $directionVector()->multiply(0.5); // Because the direction vector is 1 block away from the player, we need to get a point closer to the player so the wings don't have a gap between the player. $base = $player->subtract($sub)->add(0, 1.8); // We try to get the base on a proper location here. First subtract the sub to get it at the right distance from the player, then make it higher. $particleDistance = 0.13; // This is the distance between the particles. You have to use a value you like. $imageHeight = 16; $halfImageWidth = 16; for($x = -$halfImageWidth; $x < $halfImageWidth; $x++){ // We use the half negative + half positive width to center the wings correctly. for($y = 0; $y < $imageHeight; $y++){ $pos = $base->add($directionVector->z * $x * $particleDistance, -$y * $particleDistance, -$directionVector->x * $x * $particleDistance); $rgba = imagecolorsforindex($this->image, imagecolorat($this->image, $x + 16, $y)); // First we translate the colors on the X and Y position to a readable colour array. $alpha = $rgba["alpha"]; if($alpha >= 95){ // We check if the alpha value is reasonably high, as alpha particles do not actually show their alpha value. continue; } $player->level->addParticle(new pocketmine\level\particle\DustParticle($pos, $rgba["red"], $rgba["green"], $rgba["blue"], $rgba["alpha"])); // We'll now add the particle with the colours of the original image. } } }} That's all! Everybody who joins now gets wings coloured and shaped according to the image specified! To further improve this, you could of course add checks for who can or can't use the wings, and you could make the wings slightly hanging over by multiplying the direction vector X and Z with the Y value. That is up to you to mess around with however. I hope this tutorial was helpful. Don't hesitate to ask questions below.
I wish I could do this, seems like you need the GD PHP Extensions though and im on phone. If anyone can help me out on how I can do this on mobile let me know thanks.
You only need GD if you are reading the wing data from a PNG file. If you can read it into code in another format, or just generate it with code, you don't need GD at all.
Very interesting approach. I always used sin cos and tan to figure them out. Your approach is probably faster (?) https://github.com/robske110/Player...PlayerParticles/Render/Renderer.php#L122-L158
Actually, in this kind of programming, 99% of the time you can do every without involving any angles at all. Most useful things that require using trigonometric relationships can be replaced by vector manipulation, e.g. resolving a component can be done by a vector dot product instead of using cos. If vectors don't work well, you could even just write down the whole algorithm on paper and try to optimize it; usually you'd end up finding out that you don't need any trigonometric functions (at most some sqrt() calls). Trigonometric conversion are usually only required in the input and output of a program.
yes, it is quite interesting. I actually just started to do PP because in school I learned sin, cos and tan. Vectors are still coming up (I think in half a year).
https://raw.githubusercontent.com/TWRRR/useless/master/fairywings.png PHP: This is dirty, but this is for people who need to be spoonfed```php<?phpnamespace Taco\Wings;use pocketmine\plugin\PluginBase;use pocketmine\scheduler\Task;use pocketmine\plugin\Plugin;use pocketmine\Server;use pocketmine\math\Vector3;use pocketmine\level\particle\DustParticle;class Main extends PluginBase {public function onEnable() {$this->getScheduler()->scheduleRepeatingTask(new WingsTask($this), 8);}}class WingsTask extends Task {private $image;public function __construct($plugin) {$this->plugin = $plugin;$this->image = imagecreatefrompng($plugin->getDataFolder() . "fairywings.png");}public function onRun(int $currentTick): void {foreach($this->plugin->getServer()->getOnlinePlayers() as $player){$directionVector = $player->getDirectionVector();$sub = $directionVector->multiply(0.5); // Because the direction vector is 1 block away from the player, we need to get a point closer to the player so the wings don't have a gap between the player.$base = $player->subtract($sub)->add(0, 1.8); // We try to get the base on a proper location here. First subtract the sub to get it at the right distance from the player, then make it higher.$particleDistance = 0.13; // This is the distance between the particles. You have to use a value you like.$imageHeight = 16;$halfImageWidth = 16;for($x = -$halfImageWidth; $x < $halfImageWidth; $x++){ // We use the half negative + half positive width to center the wings correctly.for($y = 0; $y < $imageHeight; $y++){$pos = $base->add($directionVector->z * $x * $particleDistance, -$y * $particleDistance, -$directionVector->x * $x * $particleDistance);$rgba = imagecolorsforindex($this->image, imagecolorat($this->image, $x + 16, $y)); // First we translate the colors on the X and Y position to a readable colour array.$alpha = $rgba["alpha"];if($alpha >= 95){ // We check if the alpha value is reasonably high, as alpha particles do not actually show their alpha value.continue;}$player->level->addParticle(new DustParticle($pos, $rgba["red"], $rgba["green"], $rgba["blue"], $rgba["alpha"])); // We'll now add the particle with the colours of the original image.}}}}} This is a working method, all you need it a plugin .yml Code: name: Wings api: "3.0.0" version: 1.0.0 main: Taco\Wings\Main And then wings to use link for working wings Put the wings in the resources folder, and then join ur server