问题
I've been trying to make gun plugin for Bukkit, and I'm trying to build a burst fire feature. I have a for loop that contains a delayed task, and inside that delayed task is the code to create a bullet and all that. Theoretically, the code would add some bullets, wait one tick, and add some more bullets, wait one tick, etc until the for loop is done.
public void fire(final Player p, final Gun g) {
for(int i=0; i<shotsPerBurst; i++) {
Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
public void run() {
for(int i=0; i<bulletsPerShot; i++) {
Bullet b = new Bullet(p, g);
GunsV1.bullets.add(b);
}
}
}, 1L);
}
}
Eclipse demands that Player p and Gun g both be final, I don't know why, and when I try to run fire(p, g), nothing happens. How can I set up my code so the for loop will run with a delay of 1 tick between cycles?
回答1:
To resolve one question:
Eclipse demands that Player p and Gun g both be final, I don't know why
You are passing the Player p
and the Gun g
to an new Thread
/new Runnable
and Eclipse tells you that those 2 Object
's shouldn't be modified or changed because the Thread
/Runnable
also uses these 2 Object's inside the run method (as you can see).
I would suggest you to write your issue directly in here: http://bukkit.org/forums/plugin-development.5/ because there are also developer which know more and in detail about the Bukkit Server for Minecraft.
I will try to find a solution that fit's your needs now - but maybe you already try to find a solution in the forum.
Found this link for you - it may help you a little bit: http://www.programcreek.com/java-api-examples/index.php?api=org.bukkit.scheduler.BukkitScheduler
回答2:
There's no easy way to run the for
loop with a delay without freezing Bukkit's main thread. The best thing to do in this case is to use plugin.getServer().getScheduler().runTaskLater():
plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
public void run(){
//shoot the gun
}
},1L);//run after 1 tick
But, if you use this, the gun will only fire one shot. To fix this, you should keep running the scheduler:
public static void runTask(){
plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
public void run(){
//shoot the gun
runTask(); //run the task again
}
},1L);//run after 1 tick
}
But this way, the gun will keep firing every tick, and never stop. So, you should count the number of times it has ran, and stop running the task once the number is reached:
public static void runTask(final int timesLeft){
plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
public void run(){
//shoot the gun
if(timesLeft > 0){
runTask(timesLeft - 1); //run the task again after removing from the times left
}
}
},1L);//run after 1 tick
}
So, in the end, your loop method could look something like this:
public static void fire(final Player player, final Gun gun, final int timesLeft){
plugin.getServer().getScheduler().runTaskLater(plugin, new Runnable(){
public void run(){
Bullet bullet = new Bullet(player, gun);
GunsV1.bullets.add(bullet);
if(timesLeft > 0){
fire(player, gun, timesLeft - 1); //run the task again after removing from the times left
}
}
},1L);//run after 1 tick
}
and you could call it by using:
fire(player, gun, shotsPerBurst);
回答3:
After experimenting with some longer delays and looking at the spigot reference, I realized that the ticks of delay are not ticks until the next task, but until the runnable runs. Knowing this, I was able to use the for loop to increase the ticks of delay proportionally:
public void fire(final Player p, final Gun g) {
for(int i=0; i<shotsPerBurst; i++) {
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
public void run() {
for(int i=0; i<bulletsPerShot; i++) {
Bullet b = new Bullet(p, g);
GunsV1.bullets.add(b);
}
}
}, i*3);
}
}
Now it runs each task three ticks after the previous one, and fires in a burst
来源:https://stackoverflow.com/questions/29463608/bukkit-delayed-task-inside-a-for-loop