I'm writing a dungeon style game, the dungeon is basically a GridPane. I want to allow the player move for one grid for every 0.5 seconds if he keeping holding the control keys. But I'm not sure how to accomplish this. I have read JavaFX : How to detect if a key is being held down? . But this question is not particularly related to my problem (except for I can track how many key event happens and perhaps do more based on that). So I follow this post and try to use Thread.sleep() to solve my problem, but it turns out the player just get stoped for a few seconds and then suddenly move a few grid.
Does anyone know how to solve this?
#FXML
public void handleKeyPress(KeyEvent event) {
switch (event.getCode()) {
case UP:
System.out.println("Up");
player.moveUp();
break;
case DOWN:
System.out.println("Down");
player.moveDown();
break;
case LEFT:
System.out.println("Left");
player.moveLeft();
break;
case RIGHT:
System.out.println("Right");
player.moveRight();
break;
default:
break;
}
}
Basically, you'll have to keep track of when you last allowed a move and only move again if a specified amount of time has passed. Here's a proof-of-concept:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
private static final long THRESHOLD = 500_000_000L; // 500 ms
private long lastMoveNanos;
private Rectangle rect;
#Override
public void start(Stage primaryStage) {
rect = new Rectangle(25, 25, Color.DODGERBLUE);
rect.setStroke(Color.BLACK);
rect.setStrokeWidth(1);
var root = new Group(rect);
root.setOnKeyPressed(this::handleKeyPressed);
var scene = new Scene(root, 600, 400);
rect.setX(scene.getWidth() / 2 - rect.getWidth() / 2);
rect.setY(scene.getHeight() / 2 - rect.getHeight() / 2);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
root.requestFocus();
}
private void handleKeyPressed(KeyEvent event) {
if (event.getCode().isArrowKey()) {
event.consume();
long now = System.nanoTime();
if (lastMoveNanos <= 0L || now - lastMoveNanos >= THRESHOLD) {
switch (event.getCode()) {
case UP:
rect.setY(rect.getY() - rect.getHeight());
break;
case DOWN:
rect.setY(rect.getY() + rect.getHeight());
break;
case LEFT:
rect.setX(rect.getX() - rect.getWidth());
break;
case RIGHT:
rect.setX(rect.getX() + rect.getWidth());
break;
default:
throw new AssertionError();
}
lastMoveNanos = now;
}
}
}
}
The above moves the Rectangle an amount equal to its width/height (to simulate a "grid") at a maximum speed of 1 move per 500 milliseconds. If the change-in-position should be continuous you can use an animation for the movement (e.g. a TranslateTransition with its byX and byY properties set). When using an animation, if the duration is as long as the desired throttle time you could use the animation itself to track when the next move is allowed.
A more robust example might use AnimationTimer and may keep track of all movement keys that have been pressed but not yet released (e.g. to pick up the last still-pressed key when the "current" key is released, if any). Here's another proof-of-concept:
import java.util.ArrayDeque;
import java.util.Deque;
import javafx.animation.AnimationTimer;
import javafx.scene.input.KeyCode;
import javafx.scene.shape.Rectangle;
class MoveAnimationTimer extends AnimationTimer {
private static final long THRESHOLD = 500_000_000L; // 500 ms
private final Rectangle node;
private final Deque<KeyCode> keyStack = new ArrayDeque<>(4);
private long then;
MoveAnimationTimer(Rectangle node) {
this.node = node;
}
void pushKeyIfAbsent(KeyCode code) {
if (code.isArrowKey() && !keyStack.contains(code)) {
keyStack.push(code);
start();
}
}
void removeKey(KeyCode code) {
if (code.isArrowKey()) {
keyStack.remove(code);
if (keyStack.isEmpty()) {
stop();
}
}
}
#Override
public void handle(long now) {
if (then <= 0L || now - then >= THRESHOLD) {
switch (keyStack.getFirst()) {
case UP:
node.setY(node.getY() - node.getHeight());
break;
case DOWN:
node.setY(node.getY() + node.getHeight());
break;
case LEFT:
node.setX(node.getX() - node.getWidth());
break;
case RIGHT:
node.setX(node.getX() + node.getWidth());
break;
default:
throw new AssertionError();
}
then = now;
}
}
}
Related
I'm testing this code when I'm making a game with Java 8.
public void keyReleased(KeyEvent e) {
int keycode = e.getKeyCode();
switch( keycode ) {
case 37:
System.out.println("left");
break;
case 39:
System.out.println("right");
break;
case 38:
System.out.println("up");
break;
case 40:
System.out.println("down");
break;
}
}
I found out that when I press an arrow key and hold it, it will print out that key name many times until I release it. If I want it to print the key name only once even if I'm holding the key (and print it again until I release and press it again), what should I do?
I've look at the docs but it says:
Because of how operating systems handle key repeats, holding down a
key may cause multiple calls to keyPressed() (and keyReleased() as
well). The rate of repeat is set by the operating system and how each
computer is configured. ( end auto-generated )
Call method getWhen to find how much time elapsed between consecutive calls to method keyReleased. If the elapsed time is less than a particular amount (say half a second, i.e. 500 milliseconds) then you know that the key is being held down. By the way, with Java 11 on Windows 10 I don't get this behavior. The key name prints only once.
Try the below example app.
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class GetsWhen implements KeyListener {
/** Maximum elapsed time to consider key held down. */
private static final long THRESHOLD = 500L;
/** Timestamp of last invocation of method 'keyReleased'. */
private long lastWhen;
#Override // java.awt.event.KeyListener
public void keyTyped(KeyEvent e) {
// Not implemented.
}
#Override // java.awt.event.KeyListener
public void keyPressed(KeyEvent e) {
// Not implemented.
}
#Override // java.awt.event.KeyListener
public void keyReleased(KeyEvent e) {
long when = e.getWhen();
long diff = when - lastWhen;
if (diff > THRESHOLD) {
int keycode = e.getKeyCode();
switch (keycode) {
case 37:
System.out.println("left");
break;
case 39:
System.out.println("right");
break;
case 38:
System.out.println("up");
break;
case 40:
System.out.println("down");
break;
}
}
lastWhen = when;
}
private void createAndDisplayGui() {
JFrame frame = new JFrame("When");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField textField = new JTextField(10);
textField.addKeyListener(this);
frame.add(textField);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> new GetsWhen().createAndDisplayGui());
}
}
I am writing a code that is a program that has a user create circles on the screen, based on where they click. What I have tried is to put the create new circle method in the first event handler but all it did was give me problems. As of now, I am trying to approach the problem differently. I am now using an ArrayList to group all the shapes together and display them on the pane. But the circles are not displaying when I run the code.
This is my code:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
import java.util.ArrayList;
public class Main extends Application {
private Pane root;
private Circle circle;
private Line line;
private boolean isClicked = false;
private ArrayList<Circle> circleList;
#Override
public void start(Stage primaryStage) {
root = new Pane();
circle = new Circle();
line = new Line();
circleList = new ArrayList<Circle>();
root.getChildren().addAll(line);
//root.getChildren().addAll(circle); //when this is uncommented the program runs just fine but there is only one circle there at a time
root.getChildren().addAll(circleList); //I feel like the problem could be here?
root.setOnMousePressed(new mouseClick());
root.setOnMouseMoved(new moveMouse());
Scene scene = new Scene(root, 600, 600);
primaryStage.setTitle("blank");
primaryStage.setScene(scene);
primaryStage.show();
}
private double getRadius(double pointOnRadiusX, double pointOnRadiusY, double circleCenterX, double circleCenterY) {
return Math.sqrt(Math.pow(Math.abs(pointOnRadiusX) - Math.abs(circleCenterX), 2) + Math.pow(Math.abs(pointOnRadiusY) - Math.abs(circleCenterY), 2));
}
private class mouseClick implements EventHandler<MouseEvent> {
#Override
public void handle(MouseEvent e) {
if (!isClicked) {
if(e.getEventType() == MouseEvent.MOUSE_PRESSED){
circle.setRadius(0);
circle.setCenterX(e.getSceneX());
circle.setCenterY(e.getSceneY());
circle.setStroke(Color.RED);
circle.setFill(Color.TRANSPARENT);
line.setStartX(e.getSceneX());
line.setStartY(e.getSceneY());
line.setStroke(Color.RED);
isClicked = true;
circleList.add(circle);
}
}
else {
circle.setRadius(getRadius(e.getSceneX(),e.getSceneY(),circle.getCenterX(), circle.getCenterY()));
circle.setStroke(Color.GREEN);
line.setStroke(Color.TRANSPARENT);
isClicked = false;
}
}
}
private class moveMouse implements EventHandler <MouseEvent>{
#Override
public void handle(MouseEvent e) {
{
if (isClicked) {
circle.setRadius(getRadius(e.getSceneX(),e.getSceneY(),circle.getCenterX(), circle.getCenterY()));
line.setEndX(e.getSceneX());
line.setEndY(e.getSceneY());
}
}
}
}
public static void main(String[] args) {
Application.launch(args);
} }
When this code is executed:
root.getChildren().addAll(circleList);
The circleList is empty. Given that you later add to the circleList I'm going to assume you're under the impression that the addAll method somehow "links" the two lists together. It does not. All that method does is copy all the elements from one list and append them to the other. And note by "copy" I don't mean each element is duplicated; the elements added to the one list are the same instances as in the given list. But the lists themselves remain separate.
You also must make sure not to add the same Circle instance to the root more than once. A Node can only appear in the scene graph at most once. When the processes for adding a new circle is started you should be creating a new Circle object. The same goes for your Line if you plan to have multiple lines displayed.
Here's a working example (without your Line):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class App extends Application {
private Pane root;
private Circle circle;
#Override
public void start(Stage primaryStage) {
root = new Pane();
root.setOnMousePressed(this::handleMousePressed);
root.setOnMouseMoved(this::handleMouseMoved);
primaryStage.setScene(new Scene(root, 1000.0, 650.0));
primaryStage.show();
}
private void handleMousePressed(MouseEvent e) {
if (e.getButton() == MouseButton.PRIMARY && e.getClickCount() == 1) {
if (circle == null) {
// start drawing a new circle
circle = new Circle(e.getX(), e.getY(), 0.0, Color.TRANSPARENT);
circle.setStroke(Color.RED);
circle.setStrokeWidth(2.0);
root.getChildren().add(circle);
} else {
// "lock" the circle in place
circle.setStroke(Color.GREEN);
circle = null;
}
}
}
private void handleMouseMoved(MouseEvent e) {
// if 'circle' is null then there's no circle being drawn
if (circle != null) {
double x1 = circle.getCenterX();
double y1 = circle.getCenterY();
double x2 = e.getX();
double y2 = e.getY();
double r = Math.sqrt(Math.pow(x2 - x1, 2.0) + Math.pow(y2 - y1, 2.0));
circle.setRadius(r);
}
}
}
Note I used private methods and method references to implement the mouse handlers. It's more concise that way but is behaviorally the same as your inner classes.
Also note that I don't use Math.abs when computing the radius. Using abs is actually wrong and can give you the wrong results (|x2| - |x1| != x2 - x1). For example, what if you had -3 - 2? That gives you |-3| - |2| = 1 which is not the same as -3 - 2 = -5.
I'm trying to recreate the game Pong in Javafx, but i ran into a problem with the movement of the platforms.
I'm using the keylisteners and switch statements to move the platforms up and down. The left one with W and S and the right one with Up and Down.
It works fine when i press them seperatly, but not when I want to move them at the same time.
package application;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,700,400);
primaryStage.setScene(scene);
primaryStage.show();
scene.setFill(Color.BLACK);
Rectangle player1 = new Rectangle();
player1.setWidth(10);
player1.setHeight(50);
player1.setY(175);
player1.setX(10);
player1.setFill(Color.WHITE);
root.getChildren().add(player1);
Rectangle player2 = new Rectangle();
player2.setWidth(10);
player2.setHeight(50);
player2.setY(175);
player2.setX(680);
player2.setFill(Color.WHITE);
root.getChildren().add(player2);
scene.setOnKeyPressed(new EventHandler<KeyEvent>(){
public void handle(KeyEvent event) {
switch(event.getCode()) {
case W: if(player1.getY() -3 >= 0) {player1.setY(player1.getY()- 4);} break;
case S: if(player1.getY() +53 <= 400) {player1.setY(player1.getY()+4);} break;
case UP: if(player2.getY() -3 >= 0) {player2.setY(player2.getY()- 4);} break;
case DOWN: if(player2.getY() +53 <= 400) {player2.setY(player2.getY()+4);} break;
}
}
});
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
JavaFX processes only one KeyCode in an event handler. So there is no way to check for multiple key codes from a keyevent object. However it do processes all KeyCodes that are pressed in a sequential manner. So if you press A & B at a time, it processes events for A & B in the order they are pressed. So taking advantage of this feature we can tweak a bit and handle multi key press event handling.
Considering for your example, keep registering all the key codes(in a set) that come through pressed event handler and perform your logic accordingly. And ensure to clear the set on key released. This way we can know which keys are pressed together.
Below is the code that demonstrates my above explanation. And it worked in your example :)
final List<KeyCode> acceptedCodes = Arrays.asList(KeyCode.S, KeyCode.W, KeyCode.UP, KeyCode.DOWN);
final Set<KeyCode> codes = new HashSet<>();
scene.setOnKeyReleased(e -> codes.clear());
scene.setOnKeyPressed(e -> {
if (acceptedCodes.contains(e.getCode())) {
codes.add(e.getCode());
if (codes.contains(KeyCode.W)) {
if (player1.getY() - 3 >= 0) {
player1.setY(player1.getY() - 4);
}
} else if (codes.contains(KeyCode.S)) {
if (player1.getY() + 53 <= 400) {
player1.setY(player1.getY() + 4);
}
}
if (codes.contains(KeyCode.UP)) {
if (player2.getY() - 3 >= 0) {
player2.setY(player2.getY() - 4);
}
} else if (codes.contains(KeyCode.DOWN)) {
if (player2.getY() + 53 <= 400) {
player2.setY(player2.getY() + 4);
}
}
}
});
I want to write a little game where I can move a ball on a JavaFX Panel using the W, A, S, D keys.
I have a getPosX() and setPosX() but I don't know how to write a KeyListener which will e.g. calculate setPosX(getPosX()+1) if I press D.
What do I have to do?
From a JavaRanch Forum post.
Key press and release handlers are added on the scene and update movement state variables recorded in the application. An animation timer hooks into the JavaFX pulse mechanism (which by default will be capped to fire an event 60 times a second) - so that is a kind of game "loop". In the timer the movement state variables are checked and their delta actions applied to the character position - which in effect moves the character around the screen in response to key presses.
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.image.*;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Hold down an arrow key to have your hero move around the screen.
* Hold down the shift key to have the hero run.
*/
public class Runner extends Application {
private static final double W = 600, H = 400;
private static final String HERO_IMAGE_LOC =
"http://icons.iconarchive.com/icons/raindropmemory/legendora/64/Hero-icon.png";
private Image heroImage;
private Node hero;
boolean running, goNorth, goSouth, goEast, goWest;
#Override
public void start(Stage stage) throws Exception {
heroImage = new Image(HERO_IMAGE_LOC);
hero = new ImageView(heroImage);
Group dungeon = new Group(hero);
moveHeroTo(W / 2, H / 2);
Scene scene = new Scene(dungeon, W, H, Color.FORESTGREEN);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP: goNorth = true; break;
case DOWN: goSouth = true; break;
case LEFT: goWest = true; break;
case RIGHT: goEast = true; break;
case SHIFT: running = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP: goNorth = false; break;
case DOWN: goSouth = false; break;
case LEFT: goWest = false; break;
case RIGHT: goEast = false; break;
case SHIFT: running = false; break;
}
}
});
stage.setScene(scene);
stage.show();
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
int dx = 0, dy = 0;
if (goNorth) dy -= 1;
if (goSouth) dy += 1;
if (goEast) dx += 1;
if (goWest) dx -= 1;
if (running) { dx *= 3; dy *= 3; }
moveHeroBy(dx, dy);
}
};
timer.start();
}
private void moveHeroBy(int dx, int dy) {
if (dx == 0 && dy == 0) return;
final double cx = hero.getBoundsInLocal().getWidth() / 2;
final double cy = hero.getBoundsInLocal().getHeight() / 2;
double x = cx + hero.getLayoutX() + dx;
double y = cy + hero.getLayoutY() + dy;
moveHeroTo(x, y);
}
private void moveHeroTo(double x, double y) {
final double cx = hero.getBoundsInLocal().getWidth() / 2;
final double cy = hero.getBoundsInLocal().getHeight() / 2;
if (x - cx >= 0 &&
x + cx <= W &&
y - cy >= 0 &&
y + cy <= H) {
hero.relocate(x - cx, y - cy);
}
}
public static void main(String[] args) { launch(args); }
}
On filters, handlers and focus
To receive key events, the object that the event handlers are set on must be focus traversable. This example sets handlers on the scene directly, but if you were to set handlers on the pane instead of the scene, it would need to be focus traversable and have focus.
If you want a global intercept point to override or intercept events that are to be routed through the in-built event handlers which will consume events you want (e.g. buttons and text fields), you can have an event filter on the scene rather than a handler.
To better understand the difference between a handler and a filter, make sure that you study and understand the event capturing and bubbling phases as explained in the JavaFX event tutorial.
Generic input handler
Please ignore the rest of this answer if the information already provided is sufficient for your purposes.
While the above solution is sufficient to answer this question, if interested, a more sophisticated input handler (with a more general and separated, input and update handling logic), can be found in this demo breakout game:
Breakout input handler.
Example generic input handler from the sample breakout game:
class InputHandler implements EventHandler<KeyEvent> {
final private Set<KeyCode> activeKeys = new HashSet<>();
#Override
public void handle(KeyEvent event) {
if (KeyEvent.KEY_PRESSED.equals(event.getEventType())) {
activeKeys.add(event.getCode());
} else if (KeyEvent.KEY_RELEASED.equals(event.getEventType())) {
activeKeys.remove(event.getCode());
}
}
public Set<KeyCode> getActiveKeys() {
return Collections.unmodifiableSet(activeKeys);
}
}
While an ObservableSet with an appropriate set change listener could be used for the set of active keys, I have used an accessor which returns an unmodifiable set of keys which were active at a snapshot in time, because that is what I was interested in here rather than observing changes to the set of active keys in real-time.
If you want to keep track of the order in which keys are pressed, a Queue, List, or TreeSet can be used rather than a Set (for example, with a TreeSet ordering events on the time of keypress, the most recent key pressed would be the last element in the set).
Example generic input handler usage:
Scene gameScene = createGameScene();
// register the input handler to the game scene.
InputHandler inputHandler = new InputHandler();
gameScene.setOnKeyPressed(inputHandler);
gameScene.setOnKeyReleased(inputHandler);
gameLoop = createGameLoop();
// . . .
private AnimationTimer createGameLoop() {
return new AnimationTimer() {
public void handle(long now) {
update(now, inputHandler.getActiveKeys());
if (gameState.isGameOver()) {
this.stop();
}
}
};
}
public void update(long now, Set<KeyCode> activeKeys) {
applyInputToPaddle(activeKeys);
// . . . rest of logic to update game state and view.
}
// The paddle is sprite implementation with
// an in-built velocity setting that is used to
// update its position for each frame.
//
// on user input, The paddle velocity changes
// to point in the correct predefined direction.
private void applyInputToPaddle(Set<KeyCode> activeKeys) {
Point2D paddleVelocity = Point2D.ZERO;
if (activeKeys.contains(KeyCode.LEFT)) {
paddleVelocity = paddleVelocity.add(paddleLeftVelocity);
}
if (activeKeys.contains(KeyCode.RIGHT)) {
paddleVelocity = paddleVelocity.add(paddleRightVelocity);
}
gameState.getPaddle().setVelocity(paddleVelocity);
}
Scene myScene = new Scene();
KeyCombination cntrlZ = new KeyCodeCombination(KeyCode.Z, KeyCodeCombination.CONTROL_DOWN);
myScene.setOnKeyPressed(new EventHandler<KeyEvent>(){
#Override
public void handle(KeyEvent event) {
if(contrlZ.match(event)){
//Do something
}
}
});
using JNativeHook:
https://github.com/kwhat/jnativehook
<!-- https://mvnrepository.com/artifact/com.1stleg/jnativehook -->
<dependency>
<groupId>com.1stleg</groupId>
<artifactId>jnativehook</artifactId>
<version>2.1.0</version>
</dependency>
private void initKeyListener(Stage primaryStage){
/* Note: JNativeHook does *NOT* operate on the event dispatching thread.
* Because Swing components must be accessed on the event dispatching
* thread, you *MUST* wrap access to Swing components using the
* SwingUtilities.invokeLater() or EventQueue.invokeLater() methods.
*/
try {
GlobalScreen.registerNativeHook();
} catch (NativeHookException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
GlobalScreen.addNativeKeyListener(new NativeKeyListener() {
public void nativeKeyPressed(NativeKeyEvent e) {
if ( (e.getModifiers() & NativeKeyEvent.CTRL_MASK) != 0
&& (e.getModifiers() & NativeKeyEvent.ALT_MASK) != 0
&& (e.getKeyCode() == NativeKeyEvent.VC_B)){
logger.debug("key :Hide");
primaryStage.hide();
}
if ( (e.getModifiers() & NativeKeyEvent.CTRL_MASK) != 0
&& (e.getModifiers() & NativeKeyEvent.SHIFT_MASK) != 0
&& (e.getModifiers() & NativeKeyEvent.ALT_MASK) != 0
&& (e.getKeyCode() == NativeKeyEvent.VC_B)){
logger.debug("key :Show");
primaryStage.show();
}
//System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public void nativeKeyReleased(NativeKeyEvent e) {
//System.out.println("Key Released: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public void nativeKeyTyped(NativeKeyEvent e) {
//System.out.println("Key Typed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
});
/*
GlobalScreen.addNativeMouseListener(new NativeMouseListener() {
#Override
public void nativeMouseReleased(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("MouseReleased()");
}
#Override
public void nativeMousePressed(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("MousePressed()");
}
#Override
public void nativeMouseClicked(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("MouseClicked()");
}
});
*/
}
Is it a keyboard limitation problem?
I'm having an issue with some code I'm just playing around with. Imagine a top down space shooter. The issue I'm having is that, on my computer, when I press and hold the up and left arrows, I cannot shoot (Spacebar). Any other direction (up, down, left, right, up + right, right + down, left + down) works. I had a friend run the code on his computer and he found that all directions worked except up + right and right + down, but up + left worked fine for him. We both looked at the code and can't figure it out. Could this be a hardware issue?
Basically, this is what I'm doing:
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame
{
boolean up, down, left, right, fire;
// Main constructor
public Test()
{
// listeners for user input
this.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_UP:
{
up = true;
break;
}
case KeyEvent.VK_LEFT:
{
left = true;
break;
}
case KeyEvent.VK_RIGHT:
{
right = true;
break;
}
case KeyEvent.VK_DOWN:
{
down = true;
break;
}
case KeyEvent.VK_SPACE:
{
fire = true;
break;
}
case KeyEvent.VK_ESCAPE:
{
// Exit
System.exit(0);
}
}
}
public void keyReleased(KeyEvent e)
{
// Upon releasing key, stop direction
switch(e.getKeyCode())
{
case KeyEvent.VK_UP:
{
up = false;
break;
}
case KeyEvent.VK_LEFT:
{
left = false;
break;
}
case KeyEvent.VK_RIGHT:
{
right = false;
break;
}
case KeyEvent.VK_DOWN:
{
down = false;
break;
}
}
}
});
}
public static void main(String[] args)
{
// create frame
Test test = new Test();
test.setLocationRelativeTo(null);
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setVisible(true);
test.loop();
}
public void loop()
{
Timer timer = new Timer(250, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (up)
System.out.println("Moving UP.");
if (left)
System.out.println("Moving LEFT.");
if (right)
System.out.println("Moving RIGHT.");
if (down)
System.out.println("Moving DOWN.");
if (fire)
{
System.out.println("FIRING.");
fire = false;
}
}
});
timer.start();
}
}
This question was originally asked here.
Yes, it looks like a hardware limitation. You can try to check whether it behaves the same way in other programs, if yes, it's definitely a hardware issue.
Keyboards have these kinds of limitations, see Rollover (key).