-
-
Save hugmanrique/1bd273e3b20b419f625c437db61b7ff9 to your computer and use it in GitHub Desktop.
public class SwordAnimation { | |
// Config variables | |
private static final float SEPARATOR = 2; | |
private static final float RAD_PER_SEC = 1.5F; | |
private static final float RAD_PER_TICK = RAD_PER_SEC / 20F; | |
private Location center; | |
private double radius; | |
private List<ArmorStand> swords; | |
public SwordAnimation(Location center, double radius) { | |
this.center = center; | |
this.radius = radius; | |
swords = Lists.newArrayList(); | |
} | |
public void start(JavaPlugin plugin) { | |
for (double angle = 0; angle < Math.PI * 2; angle += SEPARATOR) { | |
spawnStand(angle); | |
} | |
new BukkitRunnable(){ | |
int tick = 0; | |
public void run() { | |
++tick; | |
for (int i = 0; i < swords.size(); i++) { | |
ArmorStand stand = swords.get(i); | |
Location loc = getLocationInCircle(RAD_PER_TICK * tick + SEPARATOR * i); | |
// Entity falling bug | |
stand.setVelocity(new Vector(1, 0, 0)); | |
stand.teleport(loc); | |
} | |
} | |
}.runTaskTimer(plugin, 0L, 1L); | |
} | |
private void spawnStand(double angle) { | |
Location loc = getLocationInCircle(angle); | |
ArmorStand stand = loc.getWorld().spawn(loc, ArmorStand.class); | |
// TODO Customize by hiding, adding items, rotation... | |
swords.add(stand); | |
} | |
private Location getLocationInCircle(double angle) { | |
double x = center.getX() + radius * Math.cos(angle); | |
double z = center.getZ() + radius * Math.sin(angle); | |
return new Location(center.getWorld(), x, center.getY(), z); | |
} | |
} |
If you have two locations, is it possible to calculate the locations between the given locations?
Considering the context of this gist, I don't know whether "between" means (1) the location whose distance to two other locations is equal, or, (2) given two angles in a circle, the location in the circle whose argument is the mean of both angles.
For (1), we can compute the arithmetic mean of both locations (say a, b
) as
final var midpoint = a.add(b).multiply(0.5);
Note that this method doesn't account for overflow; this is unlikely to happen in a Minecraft world and is left as an exercise.
For (2), given the center c
and the two locations a, b
, find the midpoint as above, obtain the segment from the center to the midpoint, and scale it by the radius
of the circle:
final var center = c.toVector();
final var diff = midpoint.toVector().subtract(center);
final var vect = center.add(diff.normalize().multiply(radius));
final var location = vect.toLocation(c.getWorld());
This method throws if the two points are antipodal (the normalize call divides by zero).
I wrote this on the fly and it isn't optimized, but it should work fine. If performance is a huge concern, avoid Location
and Vector
objects and handle the math on double
s yourself.
The
start
method callsspawnStand
in a loop, which calls the Bukkit methodWorld#spawn(Location, Class<? extends Entity>)
. That tells Bukkit you want to spawn an entity of the given type (in this case an ArmorStand) at the given location. Next, the start method creates a repeating task that will move the stands around a circle. You could save the return value of the task (aBukkitRunnable
) in a field so you can later cancel it to stop the animation (you would also need to despawn the stands by callingEntity#remove()
).To start the whole thing, your plugin needs to create an instance of
SwordAnimation
with the appropriate parameters.