# Math: Circumference Teleportation

Discussion in 'Spigot Plugin Development' started by Bladian, Jun 20, 2015.

I'm basically wanting to make a scatter plugin which will scatter players around an X and Z radius.

I'm not sure how I want to do it though.

2. ### clip Benefactor

Get the max X and max Z

Create a random which gets a number from minimum to max for both x and z.

Teleport to the location for that x and z

3. ### SubSide

You could use the /spreadplayers command in minecraft. xP

4. ### Absentee23

Use Math.random() (an explanation) to generate two coordinates (x, z), then use World.getHighestBlockYAt() (javadoc) to get the Y coordinate (add 1 to it, so they aren't IN the block), then teleport them there.

5. ### SubSide

I feel like he's trying to spread them out consistently, where all players are scattered from each other with a certain distance. So this might not be the best solution for him.

But ofcourse I can also be completely wrong ;P

• Like x 1
6. ### Absentee23

If thats the case, Math.sin(), Math.cos(), Math.PI() are the relevant java methods that would be needed, but my math is wayyy to rusty to figure out the formula.

https://en.wikipedia.org/wiki/Circle#Equations

7. ### SubSide

I still think it's best if you used minecrafts own /spreadplayers, or at least code that gets close to it.
Just using Math.sin could still result in players being to close to each other so you need to loop, and keep testing if all players are far enough.

My guess is that over at Mojang, they thought this one through.

• Agree x 1

Sorry for the late messages. Yeah I do know that Mojang's is great but it takes a long time and doesn't reach the desired shape I want to do this basically.

-------x------
- zzzzzzzzzzzz -
x zzzzzzzzzzzz x
- zzzzzzzzzzzz -
-------x------

(Imagine it's a circle)

And I need to teleport each one to the x. Having the equal distance between each other.

What are the sin and cos functions int his case. We've only done sin and cos with triangles so far .

9. ### blablubbabc

2*pi is representing going once around the whole circle (360°). If you divide that by the amount of spawn points you want to have on the circle you get the angle between the different spawn locations. You can then get the x and z coordinates of the different spawn locations by starting somewhere on the circle (example at angle zero) and then going those steps on the circle to get to the next spawn location:

Pseudo code:
Code (Text):

delta = (2 * pi) / amountOfSpawns
// start somewhere on the circle:
angle = 0
for (amountOfSpawns )
// spawn point:
x = centerX + radius * sin(angle)
z = centerZ + radius * cos(angle)
// go 1 step further on the circle, to get to the next spawn point:
angle += delta

10. ### sothatsit Patron

sin and cos are from the unit circle. I suggest reading up on it, it will help you a lot with trig. Basicly, the functions are used to get relative x and y values for a given angle. In trig this is used for triangle side lengths but it can be just as easily used to get points evenly distributed on a circle.

@blablubbabc's post shows how it would be implemented.

The unit circle: https://www.mathsisfun.com/geometry/unit-circle.html

11. ### 1Rogue

It's a lot easier to simply wrap it in a class for the results though, especially when you can just do the math extremely quick in the constructor:

Code (Java):
double angle = Math.random() * Math.PI * 2; //Random position, use division for spacing
}

Why are you using a Math.Random in your example.

If someone could lead me to a quick trigonometry tutorial i would be grateful.

Wait I'm starting to see the logic!

Okay 2 * pi which is the base.
Divided by the amount of spawns, gives you a part of the circumference or the Angle.

The East/West or right/west is equal to the X coordinates.

Therefore I multiply by sin.

The North/South is the Z coordinates.

Therefore I multiple it by cos. Which gives me the coordinates.

X and Z.

14. ### 1Rogue

Because it generates a random coordinate along the circle, as the comment stated, you would just use division to determine even spacing.

Thanks just looked at a few trig tutorials and I now fully understand it.

New question. If I wanted the chunks to which they are being teleported at to be fully loaded, so it doesn't cause lag. How would I do it?

This is what I came up with.

Code (Text):
package me.uhc.scatter;

import me.uhc.core.Core;
import org.bukkit.*;
import org.bukkit.entity.Player;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

/**
* Created by maxmigliorini on 20/06/15.
*/
public class MethodScatter {

private String scatter = "§9[§eScatter§9]§e";

List<Location> locations = new ArrayList<Location>();

public void chooseLocations(int x, int z, World world) {

Random random = new Random();

for (Player all : Bukkit.getOnlinePlayers()) {

int pX = random.nextInt(x - 0 + 1) + 1;
int pZ = random.nextInt(z - 0 + 1) + 1;
int pY = world.getHighestBlockYAt(pX, pZ);

Location location = new Location(world, pX, pY, pZ);

}

Bukkit.broadcastMessage(scatter + "Chunks have been chosen");

}

final int size = locations.size();

int i = 0;

@Override
public void run() {

if (i < size) {

Location location = locations.get(i);
Chunk chunk = location.getChunk();

}
}

}
}, 0L, 40L);

}

public void scatterPlayers() {

int i = 0;

for(Player p : Bukkit.getOnlinePlayers()) {
if(!locations.isEmpty()) {
Location location = locations.get(i);
i++;
if(location.getBlock().getType() == Material.WATER) {
location.getBlock().setType(Material.DIRT);
}
p.teleport(location);
Bukkit.broadcastMessage(scatter + p.getName() + " has been scattered");
}
else {
break;
}

}
Bukkit.broadcastMessage(scatter + "All players have been scattered");
}
}
Code (Text):
package me.uhc.scatter;

import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

import java.util.List;

/**
* Created by maxmigliorini on 21/06/15.
*/
public class EventScatter implements Listener {

List<Location> locations = CommandScatter.getInstance().getMethodScatter().locations;

@EventHandler

Chunk chunk = e.getChunk();

if(locations.contains(chunk)) {
e.setCancelled(true);
}

}
}

Code (Text):
package me.uhc.scatter;

import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

/**
* Created by maxmigliorini on 20/06/15.
*/
public class CommandScatter implements CommandExecutor {

private static CommandScatter instance;

public static CommandScatter getInstance() {
if (instance == null) {
instance = new CommandScatter();
}
return instance;
}

public CommandScatter() {
instance = this;

}

private String scatter = "§9[§eScatter§9]§e";

public MethodScatter getMethodScatter() {
return methodScatter;
}

MethodScatter methodScatter = new MethodScatter();

@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {

if (command.getName().equalsIgnoreCase("scatter")) {

if (commandSender.hasPermission("galaxy.scatter")) {

if (strings.length < 3 || strings.length > 3) {

commandSender.sendMessage(scatter + "The command does not have enough §4arguments");

} else {

World world = Bukkit.getWorld(strings[2]);

methodScatter.chooseLocations(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), world);
methodScatter.scatterPlayers();

}
}else {
commandSender.sendMessage(scatter + "You do not have the §4permissions  §eto use this command");

}
}
return false;
}
}

16. ### sothatsit Patron

Just Loop through the Locations and add their chunks to a list if the chunk is not already in there.

Something like:
Code (Text):
List<Chunk> chunks = new ArrayList<Chunk>();
for(Location loc : locations) {
Chunk chunk = loc.getChunk();
if(!chunks.contains(chunk)) {
}
}
chunks.clear();
* Written in browser so might not be completely working.

17. ### 1Rogue

Or... y'know... use a Set

18. ### sothatsit Patron

What is the advantage of using a Set in this situation?

19. ### 1Rogue

Well, it's guarunteed to only have a single instance of each equivalent object, so you don't need to manually put a constraint on your Collection:

Code (Java):
Set<Chunk> chunks = new HashSet<>();
for (Location l : locations) {