Random location within a radius (Not a square area)

Discussion in 'Plugin Development' started by the_merciless, Feb 24, 2013.

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


    I want to make it so when a player dies they spawn in a random location within a certain radius. I have found ways to get random ints but from what i have found i can only get random locations within a square/rectangular area. Any ideas?
  2. Offline


    You could try generating a random x, a random y and a random z and then check if the difference between x, y, and z from the center squared added together are equal to the radius squared, but I might have my math wrong...
  3. Set a min and max number for x, y, z and generate random number imbetween them then create a new Location.
  4. Offline


    Thats a square again!
  5. the_merciless
    The best way to do it would be to use a random generator to generate coordinates within a rectangular area, and just re-run the check if the distance is greater than some distance you specify. This way the areas on the corners of the area will not be valid.
  6. Offline


    That's what I said... (But I might have gotten the distance incorrectly)
  7. Offline


    Im using a square area at the moment just to test my code but im getting an error with negative numbers,

    2013-02-24 20:12:52 [SEVERE] Could not pass event PlayerRespawnEvent to MercilessPvp v1.0.0[1.4.7]
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:427)
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62)
        at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:477)
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:462)
        at net.minecraft.server.v1_4_R1.PlayerList.moveToWorld(PlayerList.java:368)
        at net.minecraft.server.v1_4_R1.PlayerList.moveToWorld(PlayerList.java:325)
        at net.minecraft.server.v1_4_R1.PlayerConnection.a(PlayerConnection.java:1147)
        at net.minecraft.server.v1_4_R1.Packet205ClientCommand.handle(SourceFile:30)
        at net.minecraft.server.v1_4_R1.NetworkManager.b(NetworkManager.java:290)
        at net.minecraft.server.v1_4_R1.PlayerConnection.d(PlayerConnection.java:113)
        at net.minecraft.server.v1_4_R1.ServerConnection.b(SourceFile:39)
        at net.minecraft.server.v1_4_R1.DedicatedServerConnection.b(SourceFile:30)
        at net.minecraft.server.v1_4_R1.MinecraftServer.r(MinecraftServer.java:598)
        at net.minecraft.server.v1_4_R1.DedicatedServer.r(DedicatedServer.java:224)
        at net.minecraft.server.v1_4_R1.MinecraftServer.q(MinecraftServer.java:494)
        at net.minecraft.server.v1_4_R1.MinecraftServer.run(MinecraftServer.java:427)
        at net.minecraft.server.v1_4_R1.ThreadServerApplication.run(SourceFile:849)
    Caused by: java.lang.IllegalArgumentException: n must be positive
        at java.util.Random.nextInt(Unknown Source)
        at me.merci.MercilessPvp.Pvplistener.getRandom(Pvplistener.java:88)
        at me.merci.MercilessPvp.Pvplistener.onrespawn(Pvplistener.java:76)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
        at java.lang.reflect.Method.invoke(Unknown Source)
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:425)
        ... 16 more
    Why am i getting this?
  8. Offline


    Are you trying to use a negative number as an argument in Random.nextInt?
  9. Offline


    Yes, can i not do that. If so how do i get around it. Heres my code so far:

    @EventHandler (priority = EventPriority.HIGHEST)
        public void onrespawn(PlayerRespawnEvent e ){
            Player p = e.getPlayer();
            String pname = p.getName();
            int ranx = getRandom(-678,-878);
            int ranz = getRandom(-428,-628);
            Location ranl = new Location(Bukkit.getServer().getWorld("merci"), ranx, 64, ranz);
            ItemStack[] inv = inventories.get(pname);
            ItemStack[] arm = armour.get(pname);
        public int getRandom(int lower, int upper) {
            Random random = new Random();
            return random.nextInt((upper - lower) + 1) + lower;
  10. Offline


    a math cycle is defined like: r² = x² + y²
    (because minecrafts y is the hight a cycle on the ground is: r² = x² + z²)
    each pair of numbers who fit that, are part of the cycle
    next step is to get a random position on the edge of a cycle for a constant r (distance from the center):
    so create a new random generator

    Random rndGen = new Random();

    and get a random number ... this is ur x coordinate.

    int x = rndGen.nextInt(r);

    now u can calc the z = (r² - x²)

    int z = Math.sqrt(Math.pow(r,2) - Math.pow(x,2));

    now u got a random position on the edge of a cycle with the radius r

    because u dont want ur player alway spawn on the border of the cycle, u need another random for the radius, lower than the maximum distance:

    int r = rndGen.nextInt(maxDistance);

    put all thogether:
    1. Random rndGen = new Random();
    2. int r = rndGen.nextInt(maxDistance);
    3. int x = rndGen.nextInt(r);
    4. int z = Math.sqrt(Math.pow(r,2) - Math.pow(x,2));

    now u may realize that x and z always are positive, but they should also be able to get negative values. An easy fix is to add:

    if(rndGen.nextBoolean()) x *= -1;
    if(rndGen.nextBoolean()) z *= -1;

    the completed code:
    1. Random rndGen = new Random();
    2. int r = rndGen.nextInt(maxDistance);
    3. int x = rndGen.nextInt(r);
    4. int z = Math.sqrt(Math.pow(r,2) - Math.pow(x,2));
    5. if(rndGen.nextBoolean()) x *= -1;
    6. if(rndGen.nextBoolean()) z *= -1;

    thats all :D

    x and z are somewhere in a cycle with the radius "maxDistance"


    now get the players position oldPx, oldPy, oldPz

    and add the calculated values...

    newPx = oldPx + x;
    newPz = oldPz + z;

    and make sure they dont spawn in solid blocks xD
  11. Offline


    I know a really random way to do it. Generate a double using Random.nextDouble, multiply it by the diameter, and then subtract it by the radius, and then add it to the center of the circle. Randomizing the y is probably not a good idea as the players could possibly spawn into a wall. Grabbing the height of the highest block at the randomized x and z coordinates would be a nice y.

    Here's an example if you have no idea what to do:
    double diameter = radius*2;
    Location center = //Center of the circle
    Random rand = new Random();
    double x = center.getX() + (rand.nextDouble()*diameter - radius);
    double z = center.getY() + (rand.nextDouble()*diameter - radius);
    Location spawn = new Location(world, x, y, z);
    Edit: This is a square. Scroll down to my post below for a circle.
  12. Offline


    Will this work with negatives?
  13. Offline


    It will work with negative coordinates. The coordinates of the center of the circle square is added to the randomly generated coordinates.

    Random.nextDouble() generates a random double from 0.o to 1.0, which is pretty nice.
  14. Offline


    this is not a cycle ...

    f.e.(lets say "rand.nextDouble()" is generating 1 both times and we want a radius of 10 blocks):

    diameter = 10 * 2 = 20
    center = 0, 0, 0
    x = 0 + (1*20 - 10) = 10
    z = 0 + (1*20 - 10) = 10
    spawn = 10, 0, 10

    to make a cycle check:
    r² = x² + z²
    10² = 10² + 10²
    100 = 200 -> false , not part of the cycle

    also ur solution always produces a positive value

    here i finished a correct solution

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: May 31, 2016
  15. Offline


    // given loc as the centre of the area you want, r as the max radius...
    Random rnd = new Random();
    double a = rnd.nextDouble() * 2 * Math.PI;
    double dist = rnd.nextDouble() * r;
    Location wanted = loc.clone().add(dist * Math.sin(a), 0, dist * Math.cos(a));
    If the terrain is isn't flat,you might also want to use World.getHighestBlockYAt() to ensure the location is on the surface.
  16. Offline


    Do you mean a circle?

    You're right, it is a square. I'll make it a circle by using trig.

    Location center = // Center of the circle
    Random rand = new Random();
    double angle = rand.nextDouble()*360; //Generate a random angle
    double x = center.getX() + (rand.nextDouble()*radius*Math.cos(Math.toRadians(angle))); // x
    double z = center.getZ() + (rand.nextDouble()*radius*Math.sin(Math.toRadians(angle))); // z
    Location newloc = new Location(world, x, y, z);
    All theory here and it's untested.

    Edit: desht ninja'd me!
    Edit 2: desht's solution has the same x and z offsets though...

    Actually, it can produce a negative value.

    center = {5,5,0}
    radius = 5
    genx = 0.3
    genz = 0.0
    x = 5 + (3 - 5) = 2
    z = 0 + (0 - 5) = -5

    But it's a square.
  17. Offline


    oh yeah circle ... nah english is not my mother tongue xD
Thread Status:
Not open for further replies.

Share This Page