Solved Particle circle that faces player

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

1. Ward1246

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) {

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) {
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) {
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;
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
Last edited: Aug 10, 2018
2. AndreTheGamer

It'd be useful if you're able to provide previous examples of attempts you've done.

3. Ward1246

Sorting through what I have now.

4. StarTux

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