Tutorial Using the Direction Vector to create wings

Discussion in 'Resources' started by Sandertv, Oct 27, 2017.

  1. Sandertv

    Sandertv Zombie Pigman Poggit Reviewer

    Messages:
    799
    GitHub:
    Sandertv
    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:
    <?php

    namespace 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(01.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(01.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(01.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->$x $particleDistance, -$y $particleDistance, -$directionVector->$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(01.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->$x $particleDistance, -$y $particleDistance, -$directionVector->$x $particleDistance);

            
    $rgba imagecolorsforindex($this->imageimagecolorat($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.
     
    Last edited: Jul 29, 2018
  2. Remarkabless

    Remarkabless Slime

    Messages:
    83
    GitHub:
    Remakem
    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.
     
  3. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin Noobiest member in the PMMP Team

    Messages:
    1,796
    GitHub:
    sof3
    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.
     
  4. robske_110 (Tim)

    robske_110 (Tim) Wither Skeleton Poggit Reviewer Verified

    Messages:
    1,374
    GitHub:
    robske110
  5. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin Noobiest member in the PMMP Team

    Messages:
    1,796
    GitHub:
    sof3
    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.
     
    HimbeersaftLP and jasonwynn10 like this.
  6. robske_110 (Tim)

    robske_110 (Tim) Wither Skeleton Poggit Reviewer Verified

    Messages:
    1,374
    GitHub:
    robske110
    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).
     
  7. SOFe

    SOFe Administrator Staff Member PMMP Team Poggit Admin Noobiest member in the PMMP Team

    Messages:
    1,796
    GitHub:
    sof3
    Vectors are not necessary. Just try to optimize your algorithm on paper ;)
     
  8. Marabou

    Marabou Baby Zombie

    Messages:
    122

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.