Minecraft Flat Ride "Delirium" Plugin

Discussion in 'Plugin Requests' started by FilthyCasual, Jun 12, 2016.

Thread Status:
Not open for further replies.
  1. Offline

    FilthyCasual

    I co-own a theme park server that currently is building Kings Dominion in Richmond VA

    We need a plugin for free, that will do this task...

    We could like minecarts to spin in this motion and have it last around 2 mins or so.

    If anyone would like to help us please let me know! We really need help with this! Here is our current Delirium recreation without minecarts to give you guys a basic idea of what we are going for.
    [​IMG]
     
  2. Offline

    MrGeneralQ

    And how exactly are we supposed to make every single block move like that? That's not so easy. Nearly impossible actually. But still possible. However, way too hard for me.
     
  3. Offline

    FilthyCasual

    Minecarts moving
     
  4. Offline

    I Al Istannen

    @MrGeneralQ
    It will look a bit glitchy, as working with falling sand is every time. You also have to account, that falling sand will disappear after I think 300 ticks. But apart from that I guess you could use spherical coordinates and then just move the angle in the x2-x3 plane (in normal? coordinates, minecraft has x3 and x2 flipped). That should rotate it from left to right, like a pendulum. I am not really advanced in this topic in general either, so there might be a better, easier solution. Maybe I will find one, maybe not.

    @FilthyCasual
    I actually quite like the idea, and I will maybe make this. I won't promise anything, as I am sadly quite fond of dismissing projects that turned out to be more boring or generally different than I expected :p. If things are unclear it either lowers the chance of me making the plugin or it will turn out differently from what you imagined. I can't read your mind, and words are often not that descriptive. Pictures are really nice most of the time. Screenshots from the game for example.

    But your current post is by no means extensive enough to create this plugin:
    1. Which minecraft version?
    2. Which Java version? Okay, this is not a question, I will make it for Java 8. Just for you to know though :p
    3. How would you create one?
    4. What do you want to be customizable? This point is really important. If you want to have anything changed later on, I might dismiss it, if it isn't feasible with the way I designed threw together the plugin. Things like when does it end, how high up does it go and stuff fall under this category. If you want to have them customizable, write them here.
    5. Should it also move back and forth and back and forth, gaining height in every period?
    6. Should it also spin, like the one in the video does? I mean around the vertical axis.
    7. How should obstacles be handled? What if there is a block in the way? I may end up changing the velocity of the falling sand or at least the minecarts, making it stop at every obstacle it encounters. Just like a real one would :p You will have to account for that in your building.
    8. How should the minecarts be attached to the middle pole? Design ideas? Otheriwse I will make it as I think it is the easiest and it will look terrible.
    9. How should the middle pole look like? If it should move, using falling sand is the only option to make it smooth. You should look some creations with falling sand up, if you don't know how they look like. They have the tendency to randomly glitch and often have lightning bugs. Again, if you have no idea, it will probably just be a pile of wood.
    10. Pictures on the two above are REALLY appreciated.
    I would appreciate you answering all the above questions.
     
    Last edited: Jun 13, 2016
  5. Offline

    FilthyCasual

    1. 1.8.8 at the moment. It might need to be upgraded soon though.
    3. /delirium create (radius) (amount of cars) (height) (max vertical angle) (horizontal angle) (speed) <the command would be typed while standing at the lowest point of the ride>
    4. see above
    5. yes, usually with the max vertical angle reached a few times in the middle of the ride cycle
    6. yes
    7. just go right through the obstacle. possibly if it is an entity make it go flying off.
    8. nothing special. probably just something like this: (by the way, if you can, try to make the middle pole colors customizable)
    9. see above :p
    If you need me to explain it more. I will be glad to.
    Once again thank you for helping us! We really need this plugin and it will be very nice if someone could make it for us.
     
  6. Offline

    I Al Istannen

    @FilthyCasual
    3. What is "radius"? What is "horizontal angle"? From where is it measured? The (I think) Yaw, minecraft shows you? What is "speed"? What is it measured in? Just some arbitrary number between two limits I decide?
    7. Might be hard, I will see how it will work out.
    8. "Nothing special" :p The minecarts look damn good there, I will see how close I can come ;)

    It will take some time, first because it isn't something I have done before and I don't know if my math and programming knowledge will be enough and second because I have a whole lot of class tests coming up. But I will try to finish it soon.
     
  7. Offline

    FilthyCasual

    The radius is basically the radius of the circle that the cars go in.
    And by horizontal angle, sorry that was a little unclear. I meant the angle that it is on if you are looking at it from an aerial view. Since we are making 1:1 parks we can not make all of them on a 90 degree angle sadly.
    Also, now that I think about it, speed isn't all that important, it can just have one speed depending on the length of the pole in the middle. (That reminds me, we would also need to specify the height that the pole goes to!
    Also, if making entities in the way go flying is too hard for you, don't do it, it really isn't needed.
    Anyways, thanks so much! Even if you can't do it then thanks for trying at least. It will really help us, and we really appreciate it!
     
  8. Offline

    MrGeneralQ

    Well I'm impressed. I know it was possibe, but I didn't knew that anyone actually succeeded in such thing. I hope the @I Al Istannen will succeed.
     
  9. Offline

    I Al Istannen

    @FilthyCasual
    I am currently outlining the way it should move with particles, just to see if the math is correct, as that is the part that needs to be done first. The pole motion is relatively easy and done, what I am struggeling with now is the rotation of the minecarts. It is also easy if the plane is fixed, but it isn't. It constantly changes, so you would need a way to draw an orthogonal circle around a location with a direction (the end of the particle ray). I have absolutly no idea how to do this and I can't find anything nice on the internet (not requiring some math I have never seen in my life, without any explanation), so I will annoy my maths teacher tomorrow. Don't know how that will work out :p

    The particles are really not that interesting, but whatever (real game footage, totally not edited... :p):
    Particles.png


    I will need to replace them with entities if I work the rotation out, which will be the next interesting thing :p
    So, as of now I can't say if I am able to finish it. I sincerly hope so, but I don't know if my Math knowledge is able to cover me.
    Being a student and not doing a whole lot of math outside of school has it's drawbacks :D

    Anyways I already learned some nice things about spherical coordinates, so it was worth it even it if it doesn't (for me at least, sorry to be egocentric).

    But let's stay optimistic (at least for the next few days :D)

    Have a nice day :)
     
  10. Offline

    FilthyCasual

    Thanks for helping our staff team! We thank you so much for working on this :)
     
  11. Offline

    I Al Istannen

    @FilthyCasual
    Thank me if I can finish it ;) I probably won't be able to do anything till friday, so I hope you got some time.

    If anybody else wants to do this plugin, feel free to do so. I would love to see a working plugin, so that I can annoy you with questions :p Maybe I can finish it, I am not able to tell right now.

    Have a nice few days ;)
     
  12. Offline

    I Al Istannen

    @FilthyCasual
    Okay, I had a chat with my math teacher ;) She had absolutly no idea, but luckily another math and physics teacher walked by. His way of solving it involved either solving a differential equation, while I don't event know what that is or introducing a forth dimension or some things about overlaying forces. Sadly, I couldn't follow any of the ways he suggested and we didn't exactly have that much time. I may ask him to bear with me for a little longer, but I don't know if he will have time or is even willing to help.

    Which means, that I probably won't finish this, as I am just not advanced enough in geometry and (pre)calculus. Which is sad and maybe embarrassing, I don't know.
    It is also a shame, since the pole motion looks really nice and smooth, which actually surprised me.

    May be able to solve it in a few years :D
     
  13. Offline

    CeramicTitan

    @I Al Istannen
    I have no idea how this plugin would be made, but what I can tell you is that in the video, they don't use falling blocks - this is because it doesn't look glitchy when it runs. I think they use a similar method to that of a plugin called TimeLapse(super outdated) but its open source, so you could check it out here: https://github.com/Nightgunner5/TimeLapse
     
  14. Offline

    I Al Istannen

    @CeramicTitan
    Either I am dumb or this doesn't work with entities. But just with blocks isn't smooth enough.
    I put the falling sand as a passenger of armorstands (and needed to use NMS, as the setAge or how it is called doesn't work...), which is smooth enough:
    delirium pole.gif

    The reason why I can't complete this request is, that I have no clue how to make a circle rotate orthogonal(perpendicular?) to the pole at the poles's end.

    The timelapse plugin looks quite nice though, thanks for the intersting link!
     
  15. Offline

    CeramicTitan

    Can you post the code for this?
     
  16. Offline

    I Al Istannen

    @CeramicTitan
    You don't want to see it. It is quite messy at the moment, as I tested left and right :p
    The whole class is a test, as you can probably tell from the name:
    Code:
    package me.ialistannen.delirium_fun_ride.delirium_standard_implementation;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.World;
    import org.bukkit.entity.ArmorStand;
    import org.bukkit.entity.Entity;
    import org.bukkit.entity.EntityType;
    import org.bukkit.entity.FallingBlock;
    
    import me.ialistannen.delirium_fun_ride.SphericalCoords;
    import me.ialistannen.delirium_fun_ride.delirium.DeliriumPole;
    import me.ialistannen.delirium_fun_ride.util.Util;
    
    /**
    * A cool pole
    */
    public class CoolPole extends DeliriumPole {
    
        private List<Entity> fallingSands = new ArrayList<>();
        private Location currentHeadCenter;
    
        /**
         * @param height The height of the pole
         */
        public CoolPole(int height) {
            super(height);
        }
    
        @Override
        public void remove() {
            if(isSpawned()) {
                fallingSands.stream().forEach(entity -> {
                    if(entity.getPassenger() != null) {
                        entity.getPassenger().remove();
                    }
                    entity.remove();
                });
            }
        }
    
        @Override
        public void spawn(SphericalCoords direction, Location topCenterLocation) {
            remove();
            fallingSands.clear();
            World world = topCenterLocation.getWorld();
    
            for (Location location : Util.getBlocksInDirection(direction.clone(), topCenterLocation, getHeight(), 1)) {
                @SuppressWarnings("deprecation")
                FallingBlock fallingBlock = world.spawnFallingBlock(location, Material.WOOD, (byte) 3);
                fallingBlock.setDropItem(false);
                ArmorStand armorStand = (ArmorStand) world.spawnEntity(location, EntityType.ARMOR_STAND);
                armorStand.setVisible(false);
                armorStand.setPassenger(fallingBlock);
                fallingSands.add(armorStand);
            }
        }
    
        @Override
        public boolean isSpawned() {
            return fallingSands.size() > 0 && fallingSands.stream().anyMatch(Entity::isValid);
        }
    
        @Override
        public void move(SphericalCoords direction, Location topCenterLocation) {
            SphericalCoords tmpCoords = (SphericalCoords) direction.clone();
            for(int i = 0; i < getHeight(); i += 1) {
                tmpCoords.setRho(i);
                Location loopLoc = topCenterLocation.clone().add(tmpCoords.toBukkitVector());
                Entity fallingSandEntry = fallingSands.get(i);
                // .multiply 0.5 to prevent spasming
                fallingSandEntry.setVelocity(loopLoc.toVector().subtract(fallingSandEntry.getLocation().toVector()).multiply(0.5));
               
                Optional.ofNullable(fallingSandEntry.getPassenger()).ifPresent(entity -> {
                    FallingBlock falling = (FallingBlock) entity;
                    Util.resetTimeLived(falling);
                });
            }
            currentHeadCenter = topCenterLocation.clone().add(tmpCoords.toBukkitVector());
        }
    
        @Override
        public Location getCurrentHeadCenter() {
            return currentHeadCenter.clone();
        }
    }
    getBlocksInDirection was just a try to combine this part of the code in one place, as it is often needed:
    Code:
        /**
         * @param direction The direction to get blocks in
         * @param start The start Location
         * @param maxDistance The maximum distance to check
         * @param step The increase in rho at every step
         * @return An iterable to get all the blocks in the direction
         */
        public static Iterable<Location> getBlocksInDirection(SphericalCoords direction, Location start, double maxDistance, double step) {
            // create a new direction, to not modify the passed one.
            final SphericalCoords myDirection = direction.clone();
            return new Iterable<Location>() {
               
                @Override
                public Iterator<Location> iterator() {
                    return new Iterator<Location>() {
                        private int counter = 0;
                        @Override
                        public boolean hasNext() {
                            return counter < maxDistance;
                        }
    
                        @Override
                        public Location next() {
                            myDirection.setRho(counter * step);
                            counter++;
                            return start.clone().add(myDirection.toBukkitVector());
                        }
                    };
                }
            };
        }
    The move method is called here:
    Code:
    package me.ialistannen.delirium_fun_ride.delirium;
    
    import java.util.Optional;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.scheduler.BukkitRunnable;
    
    import me.ialistannen.delirium_fun_ride.DeliriumFunRide;
    import me.ialistannen.delirium_fun_ride.SphericalCoords;
    
    /**
     * A single delirium instance
     */
    public class Delirium {
       
       private Location topCenter;
       
       private DeliriumPole pole;
       private DeliriumHead head;
       
       private DeliriumPathPlotter pathPlotter;
       
       private BukkitRunnable runner;
       
       /**
        * @param topCenter The center of the delirium. Is in the air!
        * @param head The head of this delirium
        * @param pole The pole of this delirium
        * @param pathPlotter The path plotter
        */
       public Delirium(Location topCenter, DeliriumHead head, DeliriumPole pole, DeliriumPathPlotter pathPlotter) {     
         this.topCenter = topCenter.clone();
         this.head = head;
         this.pole = pole;
         this.pathPlotter = pathPlotter;
       }
       
       /**
        * Moves this Delirium.
        * <br>Correctly calls the move methods for the {@link DeliriumPole} and {@link DeliriumHead}
        *
        * @param direction The direction to move in
        */
       public void move(SphericalCoords direction) {
         if(!pole.isSpawned()) {
           pole.spawn(direction, topCenter);
         }
         pole.move(direction, getTopCenter());
         head.onCenterChange(pole.getCurrentHeadCenter());
       }
       
       /**
        * Starts the delirium. //TODO: May need revision
        */
       public void start() {
         if(isRunning()) {
           runner.cancel();
         }
         runner = new BukkitRunnable() {
           
           @Override
           public void run() {
             Optional<SphericalCoords> optLoc = pathPlotter.getNextLocation();
             if(!optLoc.isPresent()) {
               System.out.println("bye, gracefully");
               stop();
               return;
             }
             else {
               move(optLoc.get());
             }
           }
         };
         runner.runTaskTimer(DeliriumFunRide.getInstance(), 0, 1);
       }
       
       /**
        * Stops this if it is running
        */
       public void stop() {
         if(isRunning()) {
           runner.cancel();
           pole.remove();
         }
       }
       
       /**
        * @return True if this is running
        */
       public boolean isRunning() {
         return runner != null && (Bukkit.getScheduler().isCurrentlyRunning(runner.getTaskId()) || Bukkit.getScheduler().isQueued(runner.getTaskId()));
       }
       
       /**
        * @return The center of this delirium
        */
       public Location getTopCenter() {
         return topCenter.clone();
       }
    }
    
    It isn't that pretty, but criticism is always welcome!
     
    CeramicTitan likes this.
  17. Offline

    I Al Istannen

    @FilthyCasual
    Although he will probably never come back to look at this, I might be actually able to finish this :p
    Don't know if I will do it though. But the math is pretty much sorted, thanks to some rotation matrixes ;)
    What is left is making it use minecarts and stuff and optimizing it. I will probably stop here and be happy I sorted out the math though, except somebody actually wants this. I see no reason to finish it :p

    better ride.gif
     
  18. @I Al Istannen That looks really look! Would you mind PMing me the code that went into making that?
     
  19. Offline

    ArsenArsen

    @bwfcwalshy y spoonz? Just kidding. Better off, take the matrices.
     
  20. Offline

    CeramicTitan

  21. Offline

    I Al Istannen

    @CeramicTitan
    Not much to see there and it is by no means "optimized". I think by now I will just repost what I write to bwfcwalshy (got, get a new name xD) and ArsenArsen (don't know how the formatting will come, so I will probably edit this post a few times):
    Hey,

    you asked me if I could send you the code for the particle thingy :p

    Well, the answer is of course yes. I will only post the relevant parts, there is more to it, logically:
    Code:
        @Override
        public void onCenterChange(Location newCenter) {
            for(double t = 0; t <= 2 * Math.PI; t += Math.PI / 32) {
                 double x = Math.cos(t);
                 double y = Math.sin(t);
                 double z = 0;
              
                 Vector v = new Vector(x, y, z);
                 v = MathUtil.rotate(v, newCenter);
              
                 newCenter.add(v);
                 newCenter.getWorld().playEffect(newCenter, Effect.SMALL_SMOKE, Effect.SMALL_SMOKE.getData());
                 newCenter.subtract(v);
            }
        }
    This draws the head, which is the circle at the end. The newCenter is the ending location of the beam, pointing in the right direction (from the middle outwards).
    What t does is just looping from 0 to 2 * Math.PI ==> 0° - 360° ==> Enough for a circle

    x and y are just defined with the parametric equation for a circle. z is the distance on the z axis, which is 0, so that it directly connects with the beams.
    It constructs a circle on the z axis, and then rotates this circle, so that it fits the direction of the location.

    I will come to the MathUtils later.

    The pole is the particle beam. It is made using spherical coordinates:
    Code:
        @Override
        public void move(SphericalCoords direction, Location topCenterLocation) {
            World world = topCenterLocation.getWorld();
            SphericalCoords tmpCoords = (SphericalCoords) direction.clone();
            for(double i = 0; i < getHeight(); i += 0.1) {
                tmpCoords.setRho(i);
                Location loopLoc = topCenterLocation.clone().add(tmpCoords.toBukkitVector());
                world.playEffect(loopLoc, Effect.SMALL_SMOKE, Effect.SMALL_SMOKE.getData());
            }
            currentHeadCenter = topCenterLocation.clone().add(tmpCoords.toBukkitVector());
            currentHeadCenter.setDirection(direction.toBukkitVector());
        }
    The topCenterLocation is the origin of the whole thing, the center.
    The direction is the direction the beam should go in.

    The logic is done in the for loop. "direction" is cloned to prevent a modification, as we need it later.
    Then the "rho" of the direction is increased by one every time. Rho depicts the radius. So, if we increase it, the point will move further and further outside. This is used to make a continuous beam and not just a point somewhere.

    It then sets the currentHeadCenter to the last particle laocation it draw. This is where the head should move around.
    At the end the correct direction is set to the currentHeadCenter, as it is later passed to the onCenterChange method above.

    Spherical Coords is a class I made some time ago, just implementing spherical coordinates. I don't really know how to explain them, maybe youtube can help you :/ I made this writing to visualize it for myself, maybe it helps you too. At least it has all the formulas you need.
    The class is this:
    Code:
    package me.ialistannen.delirium_fun_ride.util;
    
    import java.text.NumberFormat;
    import java.util.concurrent.ThreadLocalRandom;
    
    import org.bukkit.util.Vector;
    
    /**
    * Spherical coordinates
    */
    public class SphericalCoords implements Cloneable {
    
        private double theta, phi, rho;
     
        /**
         * @param rho The length of the vector
         * @param theta The angle on the x - y plane
         * @param phi The angle between the z and the direct line
         */
        public SphericalCoords(double rho, double theta, double phi) {
            this.rho = rho;
            this.theta = theta;
            this.phi = phi;
        }
     
        /**
         * @return Rho
         */
        public double getRho() {
            return rho;
        }
     
        /**
         * @param rho The new rho
         */
        public void setRho(double rho) {
            this.rho = rho;
        }
     
        /**
         * @return Theta in radian
         */
        public double getTheta() {
            return theta;
        }
    
        /**
         * @return Theta in degrees
         */
        public double getThetaDegrees() {
            return Math.toDegrees(theta);
        }
     
        /**
         * @param theta Theta in radians
         */
        public void setTheta(double theta) {
            this.theta = theta;
        }
     
        /**
         * @return Phi in radian
         */
        public double getPhi() {
            return phi;
        }
     
        /**
         * @return Phi in degrees
         */
        public double getPhiDegree() {
            return Math.toDegrees(phi);
        }
     
        /**
         * @param phi Phi in radian
         */
        public void setPhi(double phi) {
            this.phi = phi;
        }
     
        /**
         * @param x The cartesian x
         * @param y The cartesian y
         * @param z The cartesian z
         * @return The Spherical coords
         */
        public static SphericalCoords fromCartesian(double x, double y, double z) {
            double rho = Math.sqrt( x * x + y * y + z * z);
            double phi = Math.acos(z / rho);
            double theta = Math.atan2(y, x);
    
            return new SphericalCoords(rho, theta, phi);
        }
     
        /**
         * @param rho The rho
         * @param theta The theta
         * @param phi The phi
         * @return The cartesian coords
         */
        public static double[] toCartesian(double rho, double theta, double phi) {
            double x = Math.cos(theta) * Math.sin(phi) * rho;
            double y = Math.sin(theta) * Math.sin(phi) * rho;
            double z = Math.cos(phi) * rho;
         
            return new double[] {x, y, z};
        }
     
        /**
         * @param coords The Spherical coordinates
         * @return The cartesian coords
         */
        public static double[] toCartesian(SphericalCoords coords) {
            return toCartesian(coords.getRho(), coords.getTheta(), coords.getPhi());
        }
    
        /**
         * @param rho rho
         * @param thetaDeg theta in degrees
         * @param phiDeg phi in degrees
         * @return The cartesian coords
         */
        public static double[] toCartesianDegree(double rho, double thetaDeg, double phiDeg) {
            double theta = Math.toRadians(thetaDeg);
            double phi = Math.toRadians(phiDeg);
            double x = Math.cos(theta) * Math.sin(phi) * rho;
            double y = Math.sin(theta) * Math.sin(phi) * rho;
            double z = Math.cos(phi) * rho;
         
            return new double[] {x, y, z};
        }
     
        /**
         * @return The vector. Does account for the x-y swap.
         */
        public Vector toBukkitVector() {
            double[] values = toCartesian(this);
            return new Vector(values[0], values[2], values[1]);
        }
     
        @Override
        public SphericalCoords clone() {
            return new SphericalCoords(getRho(), getTheta(), getPhi());
        }
     
     
        /* (non-Javadoc)
         * @see java.lang.Object#hashCode()
         */
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            long temp;
            temp = Double.doubleToLongBits(phi);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            temp = Double.doubleToLongBits(rho);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            temp = Double.doubleToLongBits(theta);
            result = prime * result + (int) (temp ^ (temp >>> 32));
            return result;
        }
    
        /* (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            SphericalCoords other = (SphericalCoords) obj;
            if (Double.doubleToLongBits(phi) != Double.doubleToLongBits(other.phi))
                return false;
            if (Double.doubleToLongBits(rho) != Double.doubleToLongBits(other.rho))
                return false;
            if (Double.doubleToLongBits(theta) != Double.doubleToLongBits(other.theta))
                return false;
            return true;
        }
    
    
        /**
         * Just for testing purposes!
         *
         * @param args The args passed.
         */
        public static void main(String[] args) {
            // theta , phi, rho
    /*        SphericalCoords coords = fromCartesian(0, 2 * Math.sqrt(3), -2);
            print(coords);
         
            System.out.println();
         
            double[] sphere = toCartesian(2, Math.PI / 4, Math.PI / 3);
            print(sphere);
         
            System.out.println();
            print(toCartesianDegree(5, 60, 30));
         
            System.out.println();
            print(fromCartesian(3, 4, 5));
    */     
            for(int i = 0 ; i < 20; i++) {
                double x = ThreadLocalRandom.current().nextDouble(200), y = ThreadLocalRandom.current().nextDouble(200), z = ThreadLocalRandom.current().nextDouble(200);
                x = ThreadLocalRandom.current().nextBoolean() ? -1 : x;
                y = ThreadLocalRandom.current().nextBoolean() ? -1 : y;
                z = ThreadLocalRandom.current().nextBoolean() ? -1 : z;
             
                SphericalCoords coor = fromCartesian(x, y, z);
                double[] cart = toCartesian(coor);
             
                if(!format(x).equals(format(cart[0]))) {
                    System.out.println("Error! X is: " + format(cart[0]) + " expected " + format(x));
                    break;
                }
                if(!format(y).equals(format(cart[1]))) {
                    System.out.println("Error! Y is: " + format(cart[1]) + " expected " + format(y));
                    System.out.println("X: " + x + " Y: " + y + " Z: " + z);
                    System.out.println();
                    print(coor);
                    System.out.println();
                    print(cart);
                    break;
                }
                if(!format(z).equals(format(cart[2]))) {
                    System.out.println("Error! Z is: " + format(cart[2]) + " expected " + format(z));
                    break;
                }
            }
        }
     
        private static void print(SphericalCoords coords) {
            System.out.println("Rho: " + format(coords.rho) + " (4)");
            System.out.println("Theta: " + format(coords.theta) + " (1,571)");
            System.out.println("Phi: " + format(coords.phi) + " (2,094)");
        }
    
        private static void print(double[] cartesian) {
            System.out.println("X: " + format(cartesian[0]) + " (1,225)");
            System.out.println("Y: " + format(cartesian[1]) + " (1,225)");
            System.out.println("Z: " + format(cartesian[2]) + " (1)");
        }
     
        private static String format(double d) {
            return NumberFormat.getInstance().format(d);
        }
    }
    
    Delete the last few methods :p

    The math util class:
    Code:
    package me.ialistannen.delirium_fun_ride.util;
    
    import org.bukkit.Location;
    import org.bukkit.util.Vector;
    
    /**
    * Some math functions
    */
    public class MathUtil {
    
     
        /**
         * Rotates a vector in the looking direction
         *
         * @param v The vector to rotate
         * @param loc The location to get the direction from
         *
         * @return The rotated vector
         */
        public static Vector rotate(Vector v, Location loc) {
            return rotate(v, loc.getYaw(), loc.getPitch());
        }
    
        /**
         * Rotates a vector in the looking direction
         *
         * @param v The vector to rotate
         * @param yaw The yaw to use
         * @param pitch The pitch to use
         *
         * @return The rotated vector
         */
        public static Vector rotate(Vector v, double yaw, double pitch) {
            double yawRad = Math.toRadians(yaw);
            double pitchRad = Math.toRadians(pitch);
         
            v = rotX(v, pitchRad);
            v = rotY(v, -yawRad); // - because minecraft...
         
            return v;
        }
    
        /**
         * Rotates a vector in the looking direction
         *
         * @param v The vector to rotate
         * @param direction The direction vector to use
         *
         * @return The rotated vector
         */
        public static Vector rotate(Vector v, Vector direction) {
            SphericalCoords coords = SphericalCoords.fromCartesian(direction.getX(), direction.getY(), direction.getZ());
            return rotate(v, coords.getPhi(), -coords.getTheta()); // TODO: Check the minus here
        }
     
        /**
         * Rotates around the x axis
         *
         * @param in The input vector
         * @param alpha The angle to rotate around
         * @return A clone with the new coordinates
         */
        public static Vector rotX(Vector in, double alpha) {
            double y = in.getY() * Math.cos(alpha) + in.getZ() * - Math.sin(alpha);
            double z = in.getY() * Math.sin(alpha) + in.getZ() * Math.cos(alpha);
         
            return new Vector(in.getX(), y, z);
        }
    
        /**
         * Rotates around the y axis
         *
         * @param in The input vector
         * @param beta The angle to rotate around
         * @return A clone with the new coordinates
         */
        public static Vector rotY(Vector in, double beta) {
            double x = in.getX() * Math.cos(beta) + in.getZ() * Math.sin(beta);
            double z = in.getX() * -Math.sin(beta) + in.getZ() * Math.cos(beta);
         
            return new Vector(x, in.getY(), z);
        }
    }
    It just implements the rotation matrices around the x and y axis, and then rotates it according to the location yaw and pitch. I don't know how they work sadly, but they do :p

    Then I just run this through a bukkit runnable loop, which changes the angle phi of the direction SphericalLocation. This makes the whole thing animate.
    Code:
            runner = new BukkitRunnable() {
             
                @Override
                public void run() {
                    Optional<SphericalCoords> optLoc = pathPlotter.getNextLocation();
                    if(!optLoc.isPresent()) {
                        System.out.println("bye, gracefully");
                        stop();
                        return;
                    }
                    else {
                        move(optLoc.get());
                    }
                }
            };
            runner.runTaskTimer(DeliriumFunRide.getInstance(), 0, 1);
    The pathPlotter#getNextLocation() has some quirks, as it makes this thing animate between bounds, which get larger every rotation. But this is nothing you will need to worry about :p


    If I explained that badly and/or you have any questions, feel free to ask them. I will try to answer them to by best knowledge. I can also post a SSCCE if you want.

    Good luck! :)

    EDIT: It was inspired (by a good part) by this.
     
    CeramicTitan likes this.
  22. @I Al Istannen And now that conversation has 34 replies 90% of which are offtopic :p
     
    I Al Istannen likes this.
  23. Offline

    PixelMemo

    Is there a chance that I could have this plugin? I really need it and it would be very useful.
     
Thread Status:
Not open for further replies.

Share This Page