First thing i want to do is to apologize for my english, i will try to write as understanable as possible.
Also, i have already tried to search the solution for this problem, but i didnt find one until now..
The problematic part of the code is the following:
//eventmanagement for the bat
scene.setOnKeyPressed (new EventHandler <KeyEvent> () {
public void moveBat(double speed) {
if ((speed > 0) && ((bat.getLayoutX() + bat.getWidth())<scene.getWidth())){
bat.setLayoutX(bat.getLayoutX() + speed);
}
if ((speed < 0) && ((bat.getLayoutX() > 0))){
bat.setLayoutX(bat.getLayoutX() + speed);
}
};
#Override
public void handle(KeyEvent event){
if (event.getCode().toString() == "RIGHT"){
this.moveBat(batVelocity);
}
if (event.getCode().toString() == "LEFT"){
this.moveBat(-batVelocity);
}
}
});
This thing works, but if i press the LEFT key for example, and i dont unpress it, so just let it remain pressed, then the "bat" will move left once, then delay for about 1 second, and then continue moving in the left direction.
I want to have a continuos movement in the left direction for the time the LEFT button remains pressed. Anyone has an idea how to fix this??
Thank you very much for your time and answers!!
Crutz
So, OnKeyPressed fires when a key is first pressed and then every second or so after. If you want something to happen continuously, instead of having it happen when the OnKeyPressed event fires, consider having OnKeyPressed and OnKeyReleased control some sort of boolean keyIsPressed, and using that in a while loop of some sort. So OnKeyPressed would set keyIsPressed=true and OnKeyReleased would do the opposite
So what you wanna do is save your KeyCode to a List and check it in your AnimationTimer:
Fields:
private List<KeyCode> input = new ArrayList<>();
and your listeners:
scene.setOnKeyPressed((KeyEvent event) -> {
input.add(event.getCode());
});
scene.setOnKeyReleased((KeyEvent event) -> {
input.remove(event.getCode());
});
And in your AnimationTimer:
if (input.contains(KeyCode.RIGHT)) {
//do something
}
if (input.contains(KeyCode.LEFT)) {
//do something else
}
Related
I am creating a 2D tank game and I want my tank to be able to shoot immediately once the fire button is pressed and then again every half second, while the fire button is held. Currently In my game, my first bullet shoots immediately after the fire button is pressed, then there is a delay (I presume half second) until my tank starts shooting a stream of bullets. I'm wondering why the initial delay after the first bullet works, but the successive ones fail. Below I have included the method which creates bullets which is called every frame in my 144Hz main game loop:
public void addBullets(ArrayList<Animate> animates, ArrayList<Drawable> drawables){
if (this.ShootPressed) {
if( firstShot || (System.currentTimeMillis() - timeSinceLastShot) >= 500) {
Bullet newBullet = this.addBullet();
animates.add(newBullet);
drawables.add(newBullet);
firstShot = false;
timeSinceLastShot = System.currentTimeMillis();
}
}
}
Here are the associated methods in my KeyListener class:
public void keyPressed(KeyEvent key) {
int keyPressed = key.getKeyCode();
if (keyPressed == up) {
this.t1.toggleUpPressed();
}
if (keyPressed == down) {
this.t1.toggleDownPressed();
}
if (keyPressed == left) {
this.t1.toggleLeftPressed();
}
if (keyPressed == right) {
this.t1.toggleRightPressed();
}
if(keyPressed == shoot) {
this.t1.toggleShootPressed();
this.t1.setFirstShot(true);
}
I am including this for additional information even though the bug happens before the key is released:
public void keyReleased(KeyEvent ke) {
int keyReleased = ke.getKeyCode();
if (keyReleased == up) {
this.t1.unToggleUpPressed();
}
if (keyReleased == down) {
this.t1.unToggleDownPressed();
}
if (keyReleased == left) {
this.t1.unToggleLeftPressed();
}
if (keyReleased == right) {
this.t1.unToggleRightPressed();
}
if (keyReleased == shoot) {
this.t1.unToggleShootPressed();
}
}
I suspect it's an issue with key-repeats which will repeatedly call KeyPressed while the key is held. It is usually setup to behave as you describe. Consequently, "firstShot" will be repeatedly set to true and a shot will be fired.
I advise restricting your event code, mainly as it's continuous in nature, to only toggling actions, rather than performing any logic. You can determine whether a shot is first or not in your game loop, with the help of some messages from your events.
However, the firstShot variable is not really necessary at all as the time delta will account for it. Removing it would also prevent firing faster than every 500ms by pressing the fire key rapidly, which you may or may not want.
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()
This is a follow up to a previous question I had. I have a Battleships game with two boards. When the user clicks on the computer board an action occurs, along these lines:
public void mouseClicked(MouseEvent e)
// Get coordinates of mouse click
if (//Set contains cell) {
/add Cell to set of attacked cells
//Determine if set contains attacked cell.
// If yes, hit, if no, miss.
checkForWinner();
The checkForWinner method determines if the game has been won yet. If it hasn't it calls a nextTurn method which changes the current turn. If the currentTurn is set to Computer, a ComputerMove() method is automatically called.
When that method finishes, it again checksforWinner, changes turn and waits for the user to click on the grid to start the cycle again.
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
If I use a simple Thread.sleep(500) in the CheckforWinner method, or in the ComputerMove method, all that happens is the human's go is delayed for the set amount of time. As soon as his move is executed the computer's move is completed immediately.
I know very little about threads but I assume this is because all the initiation of the bouncing back and forth between methods begins with a method in the mouse listener.
Given the set up of my system, is there a way to implement a delay without radically changing things?
Edit: May as well include the classes:
public void checkForWinner() {
if (human.isDefeated())
JOptionPane.showMessageDialog(null, computer.getName() + " wins!");
else if (computer.isDefeated())
JOptionPane.showMessageDialog(null, human.getName() + " wins!");
else
nextTurn();
}
public void nextTurn() {
if (currentTurn == computer) {
currentTurn = human;
} else {
currentTurn = computer;
computerMove();
}
}
public void computerMove() {
if (UI.currentDifficulty == battleships.UI.difficulty.EASY)
computerEasyMove();
else
computerHardMove();
}
public void computerEasyMove() {
// Bunch of code to pick a square and determine if its a hit or not.
checkForWinner();
}
Ideally, I'd like to have sound effects, or at the very least a pause between moves. However, no matter how I use Thread.sleep, or TimerTask, or anything else, I can't get it to function correctly.
You should be using a Swing Timer. Something like:
Timer timer = new Timer(1000, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
currentTurn = computer;
computerMove();
}
});
timer.setRepeats(false);
timer.start();
I have a program in LWJGL where I have a series of buttons. I'm trying to use Mouse.getEventButton() and Mouse.getEventButtonState() in order to figure out when the mouse is released, but neither seem to be working. After adding a few print statements for debugging, it seems that getEventButton() always returns 0 regardless of what the mouse is doing, and getEventButtonState() always returns false. All other mouse methods I've used so far have behaved normally. Any idea what might be going on?
It can be done by analogy with keyboard as described in this tutorial.
while (Mouse.next()){
if (Mouse.getEventButtonState()) {
if (Mouse.getEventButton() == 0) {
System.out.println("Left button pressed");
}
}else {
if (Mouse.getEventButton() == 0) {
System.out.println("Left button released");
}
}
}
By default MouseClicked event starts with one click. I have one in a JTextPane but I want to start with double click. Is it possible?
I believe you can extract the click count from the MouseEvent (assuming its called e)
Try this
if (e.getClickCount() == 2 && !e.isConsumed()) {
e.consume();
//handle double click event.
}
I don't think there will be a solution to this, since Java can run on non-pc devices.
Most portable devices don't support double-click.
You may keep track of the moment of each mouse click and fire your own "double-click" event. But I don't think this is a good idea.
private void jEditorPane3MouseClicked(java.awt.event.MouseEvent evt) {
if (evt.getClickCount() == 2 && !evt.isConsumed()) {
evt.consume();
System.out.println("Double Click");
}
}
You can override the mousePressed() or mouseReleased() methods and asking if e.getClickCount() == 2 , I recommend using the mousePressed() or mouseReleased() instead of mouseClicked() method since using those will give the user more time to perform the clicks.
You can compute the time lapsed between consecutive clicks. Compare it with a threshold value and decide yourself whether it is a double click or not.