Rotate Players Around a Sphere

Discussion in 'Spigot Plugin Development' started by SirCodalot, May 12, 2018.

  1. Hello.
    I am trying to make a player rotate around a sphere when he is falling down as if he is swinging on a rope that is connected to the middle of the sphere.
    [​IMG]

    (Jump to 4:40)
    I already did the part of throwing the hook, I just need to figure out how to do the swinging part.
     
  2. Just a random suggestion, but maybe summon a pig on a lead and set the player as a passenger to that pig. The lead is connected to your grapple location ;)
     
  3. I already thought about doing that, but I want to have control over the distance of the player from the center of the sphere. In addition, If I use leads, the pigs will stop when they reach the same x and z of the center of the sphere instead of swinging until they lose their velocity.
     
  4. I don't work with a ton of math in Bukkit, but two places I can recommend starting with UCM [1] and looking into how air strafing [2] is implemented. In general, I think UCM describes a curve well enough once you have the player's position and length of the grapple, but it would work better if you also computed the player's velocity. You can use this to set the player's velocity every tick interval or so depending on how smooth you want the curve to be.

    1: http://www.physicsclassroom.com/class/circles/Lesson-1/Mathematics-of-Circular-Motion
    2: https://steamcommunity.com/sharedfiles/filedetails/?id=184184420
     
  5. Well, you can try to use vectors. The problem is that if there's a wall the player may glitch
     
    • Funny Funny x 1
  6. Thanks but I already figured that part out, I'm trying to find a way to calculate the vectors.

    Thanks, I was planning to do something like that so these links are very helpful, but I still need to calculate the vectors.
     
  7. Than you should create a different type of vector for every type of movement that your player will need in order to create a circle. Us ethis immage:
    [​IMG]
     
  8. The problem is that I don't know how to get the vectors.
     
  9. Just use the player's direction to get the vertical plane of motion, the vector normal to the player's acceleration vector (that is, the vector pointing from the player towards the point of rotation) would describe the horizontal plane of motion. Just subtract the coordinates of the player and the center of rotation to get the acceleration vector components, and you can use the cross product of the vertical component and the acceleration vector to get the velocity (i.e. the one "normal" to the acceleration vector and tangent to the curve) and apply this vector every X ticks
     
  10. After some thinking and sketching on paper, I think I know of a solution.

    First, you would want to draw a circle and get all it's points so you know how to make the vectors you need. You can do this by using my favorite and go-to option, the unit circle. Just get the midpoint of the circle, then start with an angle of 0, then increase it until you get to 2pi (full circle rotation) and fill a list with these locations.

    Code (Java):
    Location origin=something;
    for(float i=0;i<Math.PI*2;i+=scalar factor, make bigger or smaller for determining how fine-tuned/laggy your animation is)
    list.add(origin.clone().add(Math.cos(i)*radius,0,Math.sin(i)*radius);
     
    At this point, I was thinking of something like the dot product or some other complex equation I probably don't know, but then it occurred to me. We stored those locations in order, so we can just subtract one from the other to find a direction that goes around.

    You would want to make a bukkit runnable that stores the index of this list and gets the location it's up to in that list and the element before it in the list, subtract the two to get a vector from one to the other and just set the player's velocity. I recommend putting them on a vehicle like an armor stand and set that thing's velocity instead since players as MC's advanced flying 'anti-cheat' would probably kick you. This would also make the animation smoother.

    Let me know how this goes.
     
  11. It would work, but it is not what I want. Just like in the examples, I want the player to keep the same distance from the center while he swings, and not getting pushed towards it.

    It sounds a little inefficient, especially since I need to do this with a sphere and not with a 2D circle so it will be very hard to work with indexes.
     
  12. That's not how UCM works, and in fact, the player will actually start to move away from the center of the circle because of the delay in updating the player velocity. Once you have the motion dynamics down, it's easy to just clamp on a fixed distance.
     
  13. This is the code that I used:
    Code (Java):
            Vector vertical = new Vector(lastVelocity.getX(), 0, lastVelocity.getZ()).multiply(Math.abs(lastVelocity.getY())*15);
            Vector horizontal = hookLocation.toVector().subtract(player.getLocation().toVector());

            player.setVelocity(player.getVelocity().add(horizontal.add(vertical).normalize().multiply(0.1)));
    And this is the result:
    [​IMG]
    (https://i.imgur.com/XorgNY5.gif)

    It's not the result that I was hoping for. I want to make something similar to the grappling hook from this video.
     
    #13 SirCodalot, May 14, 2018
    Last edited: May 14, 2018
  14. I tried to use the acceleration and this is what I got:
    Code (Java):
        private double acceleration(double radius) {
            return (4 * Math.pow(Math.PI, 2) * radius) / Math.pow(ticks, 2);
        }

            Vector accVel = new Vector(
                    hookLocation.getX() - player.getLocation().getX(),
                    acceleration(hookLocation.getY() - player.getLocation().getY()),
                    hookLocation.getZ() - player.getLocation().getZ()
            );

            player.setVelocity(accVel.normalize());

            ticks++;
    [​IMG]
    (https://i.imgur.com/4KvbK4Y.gif)
     
  15. You gotta keep in mind that this will, in whatever way, look buggy when done with a plugin. Due to latency and all that, it won't look as smooth as in the mod Crayfish reviewed.

    I haven't really done anything like this myself before, however I'd recommend to start by trying to get it on a 2d plane first (as in, don't allow the player to go sideways just yet). As for in which direction the player should fly, I'd say you gotta use the vector perpendicular to the vector from the player to the pivot point/where the hook hit the surface.

    Then you can use the Y value of that created vector to see how far the player should fly. Obviously, if the vector points straight up, you don't want them to make a looping, so you'll cancel that out. And if it's pointing straight down, you'll want to apply some more force to make sure they make a good swing. If I have the time I'll try to write something up after work. :)
     
  16. I tried a few things but none of them worked. I'm out of ideas :confused:

    EDIT: I just found the mod's source on GitHub, I'll try to translate it to Bukkit. It shouldn't be very hard since most of it is math.
    EDIT2: The source didn't help. If any of you have any ideas please share them.
     
    #16 SirCodalot, May 17, 2018
    Last edited: May 17, 2018
  17. Crazy idea but maybe you could make the player ride an invisible bat and then make the bat fly using pathfinders. This would probably be less buggy when teleporting the player itsself.
     
  18. Can you share the link to the source? I'd love to take a look at that.
     
  19. Making the custom PathfinderGoal will be just as hard as what I'm trying to do now.

    https://www.curseforge.com/minecraft/mc-mods/grappling-hook-mod
    https://github.com/yyon/grapplemod

    I tried to copy a few things from the mod and this is the result:

    Code (Java):
            Vector oldSphere = player.getLocation().clone().subtract(hookLocation).toVector();
            Vector sphere = VectorUtils.changeLength(oldSphere.clone(), distance);
            Vector change = sphere.clone().subtract(oldSphere.clone());

            Vector motion;
            if (hookLocation.distance(player.getLocation()) < distance)
                motion = new Vector(0, 0, 0);
            else
                motion = change;
            player.setVelocity(player.getVelocity().add(motion.multiply(0.25)));
    Code (Java):
        public static Vector changeLength(Vector vector, double newLength) {
            vector = vector.clone();
            double oldLength = length(vector);
            if (oldLength != 0) {
                double changeFactor = newLength / oldLength;
                vector = vector.multiply(changeFactor);
                return vector;
            } else {
                return vector;
            }
        }
    It's still not working properly, but its an improvement.
     

Share This Page