Right now I'm working on a sort of space-invaders style game. You move the character to the y coordinate where the enemy is, and shoot.
There is four windows that the player will shoot at. There will ALWAYS be an enemy in one of them.
So here is how the code would work:
enemylocation = 1;
*CHANGE VALUE EVERY X SECONDS
if(enemylocation==1){
enemy.draw(x, y, size);
}
if(enemylocation==2){
enemy.draw(x, y, size);
}
if(enemylocation==3){
enemy.draw(x, y, size);
}
if(enemylocation==4){
enemy.draw(x, y, size);
}
What would the timing code/method be?
Thanks
You would want to use something like this:
public static void main(String[] args) throws InterruptedException
{
while(true) //Makes the code run forever
{
enemylocation++; // increments 1
Thread.sleep(1000); // Waits one second
}
}
Most people would use a Swing timer to update code over a given time interval. I would use the java.Math.Random Class to change the number to 1-4.
public class game implements ActionListener{
Timer enemyUpdate;
int enemylocation;
public game(){
enemyUpdate = new Timer(1000, this); //1000ms = 1s
enemyUpdate.start();
}
public void actionPerformed(){
//utilize math.random to change enemylocation every second
}
}
Related
I'm having a bit of trouble with using a bukkit runnable. I've tried to get it to work, but it just throws errors at me. Here's what I'd like
public class FlyE implements Listener {
#EventHandler
public void onPlayerMovement(PlayerMoveEvent e) {
Player p = e.getPlayer();
double y1 = p.getLocation().getY();
// wait 1 second
double y2 = p.getLocation().getY();
double yf = y1 - y2;
Bukkit.broadcastMessage(p + " Increase = " + yf);
}
}
This code is intended to get a users Y coords, wait a second, get it again, and then work out the increase. However, no matter how I attempt to use the BukkitRunnable, it just confuses me. I was hoping somebody could walk me through how to convert the below into a Bukkit Runnable that gathers y1, waits 20 ticks, then gathers y2.
The player move event is called every time the player moves. You only need to start a Bukkit scheduler once and then it will run continuously. I'm not sure how you want to select your player so this might not be exactly what you want to achieve, but to start a scheduler once put it in the onEnable() method.
public class MyPlugin extends JavaPlugin implements Listener {
private HashMap<String, Integer> lastY = new HashMap<>(); //Stores the last y location for an arbitrary number of users. The map key (String) is the user's name and the value (Integer) is the user's last Y coord
#Override
public void onEnable(){
//Start the timer asynchronously because it doesn't need to run on the main thread and the time will also be more accurate
Bukkit.getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
#Override
public void run() {
for (Player player : Bukkit.getOnlinePlayers()) { //Loop through all the players on the server
int y = player.getLocation().getBlockX();
player.sendMessage("Increase = " + (y - lastY.getOrDefault(player.getName(), 0))); //Display the increase in height using the stored value or 0 if none exists
lastY.put(player.getName(), y); //Replace their previous y coordinate with the new one
}
}
}, 0, 20L);
}
#EventHandler
public void onPlayerQuit(PlayerQuitEvent e){
lastY.remove(e.getPlayer().getName()); //Remove stored data for player
}
}
The HashMap here allows you to store the y coordinate for all the players on the server and access them in an efficient way. However, remember to remove the stored data when it is no longer needed (i.e. the player quits the game)
I'm trying to make a simple action in a Java FX "game" in which an image of a pig 'jumps' upwards every time the spacebar is pressed. Here is the code for the key event handlers and the Animation Timer that I'm using to actually carry out the action.
Key Handlers:
ArrayList<String> in = new ArrayList<String>();
s.setOnKeyPressed(
new EventHandler<KeyEvent>()
{
public void handle(KeyEvent e)
{
String code = e.getCode().toString();
if ( !in.contains(code) ){
in.add( code );
}
}
});
s.setOnKeyReleased(
new EventHandler<KeyEvent>()
{
public void handle(KeyEvent e)
{
String code = e.getCode().toString();
in.remove( code );
}
});
Animation timer:
new AnimationTimer()
{
double q = 200;
public void handle(long currentNanoTime)
{
double t = (currentNanoTime - startNanoTime) / 4000000.0;
if(in.contains("SPACE")){
q -= 20;
}
double y = q + t;
if(y >= 520){
gc.drawImage(background1, 0, 0, 1160, 740);
gc.drawImage(pig, 90, 520, 125, 100);
}else{
gc.drawImage(background1, 0, 0, 1160, 740);
gc.drawImage(pig, 90, y, 125, 100);
}
}
}.start();
So as you can see I'm having the animation timer simply cause the 'pig' to gradually fall down the y-axis, and when the spacebar is pressed, it is given a slight boost upwards.
The problem is that if the spacebar is held down, the pig just flies continuously upwards without stopping. I want this to be prevented so that the spacebar must be repeatedly tapped and not just held down. So I want only one 'jump' per spacebar press. Nothing that I've tried to workaround it has worked. How can I do this?
EDIT: I reworked the answer. The original solution used a counter which prevented the pressed key from having any impact for a certain period of time. Unfortunately, this was not what this question was about. :) The current solution is more straight forward and uses only a simple boolean lock.
Before answering the question, here are some annoying tips: I would suggest to use Map<KeyCode, Boolean> instead of List<String> to store information about what keys are currently pressed. It will simplify your code in terms of readability and give it a performance boost at the same time. Next, creating a dedicated object to store information about the pig (haha!) might be a good idea. Finally, using constants instead of hard coded literal values is a good practice.
Also, note that you don't actually need to store information about whether the spacebar is pressed or not and then refer to it from the timer thread. This would only be necessary if you WANTED the pig to be controlled by HOLDING the spacebar. But since you want it to jump only when the spacebar is pressed, you could tell the pig to switch into "jump" state directly from the handler. Of course, this won't solve your problem, because the onKeyPressed handler is invoked repeatedly when holding a key for a longer period of time. But I thought it was worth mentioning. :)
Now, to answer the question. If you want to quickfix your current solution and ignore all the "good practice" crap, focus only on the jumpLock field of the Pig class. The trick is to keep telling the pig to jump repeatedly as you are currently doing, BUT making sure that the pig will obey only when the jumpLock allows it to do so.
NOTE: The following solution assumes you will update the state of your game using a fixed interval like every 30 milliseconds. But as noted at the end, this solution can be easily modified to use FPS based timer.
The following class contains constants which you may want to change when tweaking your game in the future:
public final class Settings {
private Settings() {
}
public static final double BOOST_VELOCITY = 10.0;
public static final double GRAVITY = 0.3;
}
This class represents the pig. The x and y fields store information about current position of the pig. velocityX and velocityY are vectors containing information about the direction and "speed" of the pig in X and Y axis, respectively. jumpLock is a simple boolean flag which is actually a solution to your problem. Whenever user makes a jump, this lock is set to true. And it will remain so until it will be told to release the lock, which will happen when user releases the spacebar.
public final class Pig {
private double x;
private double y;
private double velocityX;
private double velocityY;
private boolean jumpLock;
public Pig() {
// ...
}
public void timeChanged() {
x += velocityX;
y += velocityY;
velocityY -= Settings.GRAVITY;
}
public void jumpBoost() {
if (!jumpLock) {
velocityY = Settings.BOOST_VELOCITY;
jumpLock = true;
}
}
public void releaseLock() {
jumpLock = false;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
}
Your handlers could look like this. Notice that Map<KeyCode, Boolean> is used to store information about currently pressed keys. It performs better than List<String> in this situation. Also adding the #Override annotation is a good practice even when overriding methods which are abstract:
final Map<KeyCode, Boolean> keyboard = new HashMap<>();
keyboard.put(KeyCode.SPACE, false);
scene.setOnKeyPressed(
new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.SPACE) {
keyboard.put(e.getCode(), true);
// You could alternately call pig.jumpBoost()
// directly from this handler and not having to
// deal with the 'keyboard' map at all
// as illustrated with by pig.releaseLock()
// in the next handler
}
}
});
scene.setOnKeyReleased(
new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
if (e.getCode() == KeyCode.SPACE) {
keyboard.put(e.getCode(), false);
pig.releaseLock(); // IMPORTANT!!!
}
}
});
Finally, the following snippet of code must be executed repeatedly. This solution assumes this code will be executed in a fixed interval like every 30 milliseconds. If you are using FPS based timer (meaning there will be irregular interval between executions), you should pass the time which elapsed from the previous update as a parameter to the timeChanged() method, and multiply with it whatever necessary inside that method.
pig.timeChanged();
if (keyboard.get(KeyCode.SPACE)) {
pig.jumpBoost();
}
// Note that pig.releaseLock() could be called in else
// branch here and not in the onKeyReleased handler.
// Choose whatever solution suits you best.
// + draw image of the pig on pig.getX() and pig.getY() coordinates
Hope I got this right. I was almost asleep when writing this post and misunderstood the question at first. But I really need to earn some reputation points to be allowed to comment on an issue which is currently important to me. Haha! :D:D
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?
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
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);
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
Ok so i'm going to try to explain this, well I created a shoot method in a class that contains my bluespell, and all of it's constructors, well the problem is when I press space once it constantly shoots without me pressing it again, and if I press it twice the speed at which it fires doubles and it starts to contain more than one x and y position on my grid I just want the spell to fire when fired and I only need one item because I don't want there to be more than one instance of it on the grid I want it to be that the player cannot fire until the spell has left the grid, here's my code thanks oh and I only have it called in my key released seeing as it should only do it once the key has been released, but if that should change please let me know thanks :)
public void shootSpell(){
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
ActionListener taskPerformed = new ActionListener(){
public void actionPerformed(ActionEvent e){
if(b.gety() != 19){
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety()+1)].setIcon(b.getIcon());
}
else{
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() +1);
}
}
};
new Timer(delay, taskPerformed).start();
else if(key == KeyEvent.VK_SPACE){
GoodSpell.shootSpell();
}
Do not use a Timer! Your task should not repeat every 100 milliseconds. If I understand your code, you should run the code from your ActionListener in a new thread.
// Something like this,
new Thread(new Runnable() {
public void run() {
if (b.gety() != 19) {
WizardCells[b.getx()][b.gety()].setIcon(null);
WizardCells[b.getx()][b.changey(b.gety() + 1)].setIcon(b
.getIcon());
} else {
WizardCells[b.getx()][b.gety()].setIcon(null);
b.changex(GoodGuy.getx());
b.changey(GoodGuy.gety() + 1);
}
}
}).start();
You also need to do a check if the spell is currently in view/activate prior to initiating a new spell in the shoot() method...
public void shootSpell(){
//do a check here if a spell is already running!
final BlueSpell b = new BlueSpell(GoodGuy.getx(), GoodGuy.gety() +1, BlueSpellWizard());
int delay = 100;
//......
So in your method that is updating the spell going accross the screen you either need to have a flag in there if its still active, or if you are running it in a new thread, save that thread to a global var and check to see if the thread is running prior instantiating a new BlueSpell()
I am making a Conway's Game of Life program in java, and am trying to change it from the command line version to a GUI. From the command line I just printed an array which showed the generations (the objects such as blocks and blinkers are shown as a series of 1's and 0's where it is blank, and in the GUI I'm showing it as squares (white squares as blank and blue squares where it isn't). But where I'm getting stuck is when I make another method (which replaces the method which prints the array) which checks the grid array, if there is a zero then the square changes from white to blue, and vice-versa. The Conway's Life rules are dealt with in a separate class which is independent, and all this method does is after the rules have changed the array this method checks it.
The rules are done in methods in one class and the GUI components are done in another. But since I need instance of both how would I go about doing it?, merge the two classes (all the GUI classes into the Life one, embed them some how, I am completely stuck on what to do
public void runGUI() {
int x = getX(), y = getY();
x /= squareSize;
y /= squareSize;
for (int i = 0; i < LifeData.grid.length; i++) {
for (int j = 0; j < LifeData.grid[i].length; j++) {
if (LifeData.grid[i][j] == 0)
l.setCell(x, y, l.getCell(x, y) + 1);
else
l.setCell(x, y, l.getCell(x, y) - 1);
this.repaint();
}
}
}
That is what I have changed it to now but when compiling it is saying "non-static variable grid cannot be referenced from a static context" and "non-static method runGUI() cannot be referenced from a static context". When trying to run the method.
Make a separate thread that will execute the game of life and update the GUI.
Something like this
public class GameExecutor implements Runnable {
private static final int DELAY = 1000;
private GameOfLife game;
private boolean stop = false;
private Gui gui;
public GameExecutor(Gui gui, GameOfLife game) {
this.gui = gui;
this.game = game;
};
public void run(){
game.start();
while (!stop) {
game.step(); //execute a step
gui.update(game.getState());
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {}
}
}
}
Launch this in a thread at startup and pass it your gui. Don't forget to update the gui in the correct Swing thread.
Obviously you'll need to add some code to stop it, too :)