Solved Particle circle that faces player

Discussion in 'Spigot Plugin Development' started by Ward1246, Aug 10, 2018.

  1. Hello! Using methods that can rotate vectors, I tried creating a particle circle that always faces the player. I was unable to do so, as I was unable to find the correct values to run the angles on. I could rotate it along the Y axis to always match the player's Yaw, but rotating on the X and Z to match the pitch I could not do. I could match it on one axis, but not the other. It's hard for me to explain this, but I am essentially trying to create a particle circle that always faces a specific player. Any help is appreciated!

    Edit: A good analogy for this would be as if the circle was a camera lens, that tracks the player.

    Edit2: I origionally didn't post my attempts, as the methods I used could be better found here: https://www.spigotmc.org/threads/rotating-particle-effects.166854/
    Code (Java):
        public void circleparticles(Entity player, double size) {
     
            //player is the player this circle will be around

            double points = size * 20;
            for (int i = 0; i < 360; i += 360 / points) {
                        double angle = (i * Math.PI / 180);
                        double x = size * Math.cos(angle);
                        double z = size * Math.sin(angle);
             
                        Vector v = new Vector(x, 0, z);
                        rotateAroundAxisZ1(v, 90, player, z);

                        rotateAroundAxisZ1(v, player.getLocation().getPitch(), player, z);//this makes the circle follow my pitch. It does not follow the Yaw still.
             
                        Location loc = player.getLocation().add(new Vector(v.getX(), v.getY(), v.getZ()));

                        PacketPlayOutWorldParticles packet1 = new PacketPlayOutWorldParticles(EnumParticle.SMOKE_NORMAL, isEnabled(), (float) (loc.getX()), (float) loc.getY(), (float) (loc.getZ()), (float) 0, (float) 0, 0, (float) 0, 0);
                        for(Player online : Bukkit.getOnlinePlayers()) {
                        ((CraftPlayer)online).getHandle().playerConnection.sendPacket(packet1);
                        }
             
            }}
     
        private Vector rotateAroundAxisZ1(Vector v, double angle, Entity e, double z) {
     
            angle = Math.toRadians(angle);
            double x, y, cos, sin;
            cos = Math.cos(angle);
            sin = Math.sin(angle);
            x = v.getX() * cos - v.getY() * sin;
            y = v.getX() * sin + v.getY() * cos;

           //I multiply by half of it's value to make it an oval, and not a circle.

            y = y * 0.5;
     
     
            return v.setX(x).setY(y);
    //Currently, this generated a circle, and make it face upright. I actually
        //wanted an Oval at first, but could settle with a circle. I need to do this to make generating the oval
        //easier, as I do not have a method to generate one otherwise.
        }
    Final Edit:
    Edit of an Edit: Turns out, you can still make an oval! I just didn't seem to see I didn't need to use Z axis rotation at all.

    Got fresh copies of this method to quickly test. Just needed to use X and Y rotation methods, I was always using Z with them (likely due to how I was originally going to use an oval)
    pointed out by @StarTux
    Code (Text):

     private Vector rotateAroundAxisX(Vector v, double angle) {
                angle = Math.toRadians(angle);
                double y, z, cos, sin;
                cos = Math.cos(angle);
                sin = Math.sin(angle);
                y = v.getY() * cos - v.getZ() * sin;
                z = v.getY() * sin + v.getZ() * cos;
                return v.setY(y).setZ(z);
            }
       
        private Vector rotateAroundAxisX1(Vector v, double angle) {
                angle = Math.toRadians(angle);
                double y, z, cos, sin;
                cos = Math.cos(angle);
                sin = Math.sin(angle);
                y = v.getY() * cos - v.getZ() * sin;
                z = v.getY() * sin + v.getZ() * cos;
             
                y = y * 0.5;
             
                return v.setY(y).setZ(z);
            }

            private Vector rotateAroundAxisY(Vector v, double angle) {
                angle = -angle;
                angle = Math.toRadians(angle);
                double x, z, cos, sin;
                cos = Math.cos(angle);
                sin = Math.sin(angle);
                x = v.getX() * cos + v.getZ() * sin;
                z = v.getX() * -sin + v.getZ() * cos;
                return v.setX(x).setZ(z);
            }
         
            public void ovalparticles(Entity player, double f) {
             
                double points = f * 20; //amount of points to be generated
                for (int i = 0; i < 360; i += 360 / points) {
                            double angle = (i * Math.PI / 180);
                            double x = f * Math.cos(angle);
                            double z = f * Math.sin(angle);
                         
                            Vector v0 = new Vector(x, 0, z);
                            rotateAroundAxisX1(v0, 90);
                            Vector v01 = new Vector(v0.getX(), v0.getY(), v0.getZ());
                            rotateAroundAxisX(v01, -90);
                         
                            Vector v = new Vector(v01.getX(), v01.getY(), v01.getZ());
                            rotateAroundAxisX(v, player.getLocation().getPitch() - 90);
                            Vector v2 = new Vector(v.getX(), v.getY(), v.getZ());
                            rotateAroundAxisY(v2, player.getLocation().getYaw());
                         
                            Location loc = player.getLocation().add(v2.getX(), v2.getY(), v2.getZ());
                         
                            PacketPlayOutWorldParticles packet1 = new PacketPlayOutWorldParticles(EnumParticle.SMOKE_NORMAL, isEnabled(), (float) (loc.getX()), (float) loc.getY(), (float) (loc.getZ()), (float) 0, (float) 0, 0, (float) 0, 0);
                            for(Player online : Bukkit.getOnlinePlayers()) {  
                            ((CraftPlayer)online).getHandle().playerConnection.sendPacket(packet1);
                            }
                }}
     
     
    #1 Ward1246, Aug 10, 2018
    Last edited: Aug 10, 2018
  2. It'd be useful if you're able to provide previous examples of attempts you've done.
     
  3. Sorting through what I have now.
     
  4. So essentially you want to transform 2d coordinates to the player's viewpoint, in order to billboard a circle. You wouldn't rotate anything around the Z axis as that would roll your circle. I believe that for any given point x, y of your circle, you would
    • Build a 3d vector (x, y, z) with z being the negative distance to the viewer.
    • Do a 2d rotation of the y and z to adjust for the pitch
    • Do a 2d rotation of the x and z to adjust for the yaw
    • Add the player's location
    • Spawn the particle.
    I could be wrong, of course. One could take a different route and find two orthogonal vectors which span the normal plane of the player's view vector, then go from there. I'm sure that someone more apt at math than I could figure this one out. ;)
     
    • Agree Agree x 1
  5. Face-palming hard right now... Yup! I was meaning to do that. For some reason I never thought of not using Z (likely due to originally using an oval) so I never tried Just X and Y. Thank you both for being there to try to help!