Java KeepPushing Key game Listener - java

I did a game where ship is moving like i wanna to move him. But my problem is when i have pushed a button. My ship is move but he have to wait a 1 sec to start moving in right way.
public void keyPressed(KeyEvent e) {
int jakiPrzycisk = e.getExtendedKeyCode();
if(jakiPrzycisk == 39 )
{
kierunek="prawo";
czyRuch = true;
}
if(jakiPrzycisk == 37)
{
kierunek="lewo";
czyRuch = true;
}
if(jakiPrzycisk == 38)
{
kierunek="gora";
czyRuch = true;
}
if(jakiPrzycisk == 40)
{
kierunek="dol";
czyRuch = true;
}
In game im checking if he will move with "czyRuch" and i move in right direction with "kierunek". There is a way to fastest reading from keybord ?

Don't use "magic numbers". 37, 38, 39 40 mean nothing to anybody reading your code.
But my problem is when i have pushed a button. My ship is move but he have to wait a 1 sec to start moving in right way.
Then you have a problem with code that is not posted. Java will respond to the KeyEvent right away.
However, there is a "delay" for repeating an event if the key is held down. This delay is OS dependent. If you need the ability to handle repeat events, then you should be using your own Timer to schedule these events. Check out Motion Using the Keyboard for more thoughts on this subject as well as working code.

Yes im sorry that was my mistake. Now i can show u an example where i've got a problem.
There is a example code
public class KeyTest extends JFrame implements KeyListener {
long start;
long end;
public KeyTest() {
super("KeyListener Test");
setPreferredSize(new Dimension(300, 100));
addKeyListener(this);
start = System.nanoTime();;
pack();
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public void keyPressed(KeyEvent evt) {
end = System.nanoTime();;
char c = evt.getKeyChar();
System.out.print(c+" ");
System.out.println(end-start);
}
#Override
public void keyReleased(KeyEvent evt) {
}
#Override
public void keyTyped(KeyEvent evt) {
}
}
and when i press any key for example "s". Ive got a
s 810407913
s 1312851842
s 1344314575
s 1377971356
s 1409969550
s 1441512603
s 1475051136
s 1507228263
between first and second "s" is a lot of difference. This is why my ship is stoping for a while when i wanna to press any key for few seconds but i dont know how to change that difference between time

Related

How to ask for a keybind within an action

I was playing around in Java and trying to make an autoclicker just as a challenge for myself. I was making key bindings to turn it on and off when I discovered that I needed to turn off a while loop from a different class. Normally I would think this to be easy but I am using actions, so the action keeps playing until it is broken. I thought about it for a little bit and came to the conclusion that I needed to ask for a keybind within an action, but I have no idea how to do this. Here is my code right now if you want to help me make some improvements
package autoclicker;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Autoclicker {
JFrame frame;
JLabel label;
boolean endis;
Action enableAction;
public Autoclicker() {
frame = new JFrame("Autoclicker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(420, 420);
frame.setLayout(null);
label = new JLabel();
label.setBackground(Color.red);
label.setBounds(100, 100, 100, 100);
label.setOpaque(true);
enableAction = new EnableAction();
label.getInputMap().put(KeyStroke.getKeyStroke("UP"), "enableAction");
label.getActionMap().put("enableAction", enableAction);
frame.add(label);
frame.setVisible(true);
}
public class EnableAction extends AbstractAction {
#Override
public void actionPerformed(ActionEvent e) {
endis = true;
try {
Robot robot = new Robot();
while(endis) {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
} catch (AWTException e1) {
e1.printStackTrace();
}
}
}
}
Assuming you want to use your autoclicker on other programs besides the java application, this isn't an easy thing to do. Java Swing was only designed to get events (such as keyboard presses) from the window that's currently focused on.
However, according to MasterID on this stack overflow post, it is possible with this library: https://github.com/kwhat/jnativehook. I haven't used this library myself though.
I've made my own auto clicker a long time ago, and here's how I dealt with exiting the loop. Mouse Position is something that is easy to get in Java. MouseInfo.getPointerInfo().getLocation(); So, rather than breaking on a keypress (requiring JFrame focus in Swing), you can break on if the mouse has been moved. In your loop, if the mouse is ever not in the same position, that means it has been moved, so exit the loop.
Perhaps something like this:
public void mainLoop() {
// Sleep for an amount of time to get mouse into proper position
Thread.sleep(4000);
...
Point p = MouseInfo.getPointerInfo().getLocation();
int lastX = (int)p.getX();
int lastY = (int)p.getY();
while(!isMoved(lastX, lastY)) {
// Do Click or other Stuff...
}
}
/** Returns true if the last x and y position don't match the current mouse x and y position on the screen. False if same position. */
public boolean isMoved(int lastX, int lastY){
Point p = MouseInfo.getPointerInfo().getLocation();
return (int)p.getX() != lastX || (int)p.getY() != lastY;
}
This breaks out of the loop if the mouse is ever moved. And if you want to use Robot.mouseMove(), you could make a simple wrapper class for Robot to handle updating the last position for you.

Java - KeyListener Multiple Keys

Now I know this topic has been brought up several times, here: Swing's KeyListener and multiple keys pressed at the same time, here: How do I have multiple key inputs Listened to at the same time and here: How do I handle simultaneous key presses in Java? for instance. So I can't really expect to get any different kind of help than what's in these examples. I have also read that most of you suggest that I use KeyBindings instead of KeyListeners for the situation I'm in (see below) which I now have decided to do. However I still want to know if you guys have any idea as to why my code is acting up.
So the situation, I am making a simple 2D game. I have been following thenewboston's tutorials to get started and he recommended KeyListeners. They've been working fine for me until now when I encountered a rather weird bug.
The problem is that when I steer my spaceship up to the left it will not shoot. This only happens in this particular direction (out of the eight possible) and also if I'm already shooting I cannot steer my ship towards the top left corner.
Below is the code where I know the problem occurs. I really see no good explanation as to why though. I honestly do believe there is something wrong where my computer cannot register the up arrow, left arrow and the space bar being pressed at the same time. The ultimate proof of this then is of course that when I change the fire button from space bar to F, for instance, the code runs without issues.
//Imports
public class SpaceGame extends Core implements KeyListener{
public static void main (String[] args){
SpaceGame sg = new SpaceGame();
sg.init();
sg.run();
}
//Making all variables
private ScreenManager s;
private AffineTransform identityTransform;
private Image bg;
private Image[] shipImage = new Image[2];
private Image[] missileImage = new Image[2];
private String shipLocations[] = {/*IMAGE LOCATIONS*/};
private String missileLocations[] = {/*IMAGE LOCATIONS*/};
private Animation shipAnimation;
private Animation missileAnimation;
private Ship ship;
private ArrayList<Shot> shotList = new ArrayList<Shot>();
private boolean shooting;
private int shots = 0;
public void init(){
//Makes image objects, animations and some other stuff.
}
//This is called from the core class which has a continously running while loop in it.
public void update(long timePassed){
if(shooting){
makeShot();
}
ship.update(timePassed);
for(Shot shot : shotList){
if(shot.getAlive()){
shot.update(timePassed);
}
}
}
public void makeShot(){
//Makes shots
}
public synchronized void draw(Graphics2D g, long time) {
Window w = s.getFullScreenWindow();
w.setFocusTraversalKeysEnabled(false);
w.addKeyListener(this);
g.drawImage(bg, 0, 0, null);
for(Shot shot : shotList){
if(shot.getAlive()){
g.setTransform(shot.getTransform());
g.drawImage(shot.getImage(), Math.round(shot.getCorsClone()[0]), Math.round(shot.getCorsClone()[1]), null);
}
}
g.setTransform(ship.getTransform());
g.drawImage(ship.getImage(), Math.round(ship.getCorsClone()[0]), Math.round(ship.getCorsClone()[1]), null);
g.setTransform(identityTransform);
}
//Where the problem occurs
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_ESCAPE){
stop();
} else if(keyCode == KeyEvent.VK_UP){
ship.setDY(-1);
e.consume();
} else if(keyCode == KeyEvent.VK_RIGHT){
ship.setDX(1);
e.consume();
} else if(keyCode == KeyEvent.VK_DOWN){
ship.setDY(1);
e.consume();
} else if(keyCode == KeyEvent.VK_LEFT){
ship.setDX(-1);
e.consume();
} else if(keyCode == KeyEvent.VK_SPACE){
shooting = true;
e.consume();
}
}
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_UP){
ship.setDY(0);
e.consume();
} else if(keyCode == KeyEvent.VK_RIGHT){
ship.setDX(0);
e.consume();
} else if(keyCode == KeyEvent.VK_DOWN){
ship.setDY(0);
e.consume();
} else if(keyCode == KeyEvent.VK_LEFT){
ship.setDX(0);
e.consume();
} else if(keyCode == KeyEvent.VK_SPACE){
shooting = false;
e.consume();
}
}
public void keyTyped(KeyEvent e) {
e.consume();
}
}
So to conclude my question is a vague one of sorts. Is there something special with the space bar I don't know about, is there in fact a bug in my program or maybe, just maybe is there something wrong with my keyboard?
Any comments, ideas, complaints about my coding, complaints about my English, strong opinions about whether to use KeyListeners or KeyBindings, code you feel like you need to see or anything at all just give me a shout and I shall try to be quick to respond.
A lot of people have that problem. It is called Keyboard Ghosting and means that some combinations simply don't work on cheap keyboards. Thats why high class gaming keyboards exists. So nothing wrong with your code. No optimization possible. You need to use key combination that work. To proof my answer here are some links for you.
http://board.flashkit.com/board/showthread.php?789015-wont-respond-to-keyboard-up-left-and-space-at-the-same-time
http://forums.steampowered.com/forums/showthread.php?t=1928521
http://www.tomshardware.co.uk/answers/id-2159074/alt-space-bar-work-holding-left-arrow.html
https://unix.stackexchange.com/questions/268850/leftupspace-keys-not-working-on-thinkpad-x201

Why is my KeyListener not getting called?

I'm working on a school project that has two images...a good guy and a bad guy. I'm using a timer to send the bad guy towards the good guy and that is working find, but I'm supposed to use a KeyListener to move the good guy towards or away from the bad guy....and then eventually attack but that is for later.
I'm just trying to get my "good guy" to move on KeyListener and its not getting called. I have no idea why.
Here is my constructor which calls my EventLIstener in my main panel:
//monster 1 coordinates
int mon1x = 0;
int mon1y = 300;
KeyListenerAction myKeyActionListener = new KeyListenerAction();
public BlobFighterPanel()
{
addKeyListener(myKeyActionListener);
this.setPreferredSize(new Dimension(1300,600)); //set size of main panel
//add button
startButton.addActionListener(startListener);
add(startButton);
}
Then below I have my KeyListener, but its not getting called:
public class KeyListenerAction implements KeyListener {
public void keyPressed (KeyEvent event)
{
switch(event.getKeyCode())
{
case KeyEvent.VK_LEFT:
goodx -= 10;
break;
case KeyEvent.VK_RIGHT:
System.out.println("Right");
goodx += 10;
break;
}
repaint();
}
public void keyTyped(KeyEvent event){}
public void keyReleased(KeyEvent event){}
}
What am I doing wrong? Why is my KeyListener not being called?
KeyListener is fickle mistress. It what's all the attention all the time or it isn't going to talk to you. What does this mean? In order for a KeyListener to raise events, the component is registered to must HAVE focus AND be focusable...
This means that the moment that another component becomes focused (like a button), the KeyListener will no longer respond.
Instead, you should use the key binding API, which was designed to overcome this issue. See How to Use Key Bindings for more details

JLabel.setText() is only setting text for last element in a loop

First of all, apologies for how long winded this is.
I'm trying to make a simple roulette game that allows a user to add players, place bets for these players, and spin the roulette wheel, which is represented as a simple JLabel that updates it's text with each number it passes.
However, I've run into a bug that I'm having a lot of trouble with: the JLabel only updates the text for the last element in my loop.
Basically, my solution works like this:
When a user presses a button labelled "Spin" (given that users have been added to the game), I call a method from a class called SpinWheelService, which is an Observable singleton which in turn calls the notifyObservers() method:
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
String description = null;
if (ADD_PLAYER.equals(cmd)) {
addDialog();
} else if (PLACE_BET.equals(cmd)) {
betDialog();
} else if (SPIN.equals(cmd)) {
SpinWheelService.sws.setSpinWheelService();
} else if (DISPLAY.equals(cmd)) {
System.out.println("Display selected!");
}
}
Here is my SpinWheelService class:
package model;
import java.util.*;
public class SpinWheelService extends Observable {
public static SpinWheelService sws = new SpinWheelService();
public void setSpinWheelService() {
setChanged();
notifyObservers();
}
}
The only listener registered for SpinWheelService is this class, where GameEngine is my game engine that handles internal game logic, WheelCallbackImpl is a class that updates the View:
class SpinWheelObserver implements Observer {
GameEngine gameEngine;
ArrayList<SimplePlayer> players;
WheelCallbackImpl wheelCall;
int n;
public SpinWheelObserver(GameEngine engine, WheelCallbackImpl wheel, ArrayList<SimplePlayer> playerList) {
players = playerList;
gameEngine = engine;
wheelCall = wheel;
}
public void update(Observable sender, Object arg) {
// check if any players are present
if (players.size() == 0) {
System.out.println("Empty player array!");
return;
}
do {
gameEngine.spin(40, 1, 300, 30, wheelCall);
n = wheelCall.playback();
} while (n== 0);
}
}
The main point of note here is my gameEngine.spin() method, which is this:
public class GameEngineImpl implements GameEngine {
private List<Player> playerList = new ArrayList<Player>();
// method handles the slowing down of the roulette wheel, printing numbers at an incremental delay
public void delay(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
System.out.println("Sleep method failed.");
}
}
public void spin(int wheelSize, int initialDelay, int finalDelay,
int delayIncrement, WheelCallback callback) {
Random rand = new Random();
int curNo = rand.nextInt(wheelSize) + 1;
int finalNo = 0;
assert (curNo >= 1);
// while loop handles how long the wheel will spin for
while (initialDelay <= finalDelay) {
delay(initialDelay);
initialDelay += delayIncrement;
// handles rotating nature of the wheel, ensures that if it reaches wheel size, reverts to 1
if (curNo > wheelSize) {
curNo = 1;
callback.nextNumber(curNo, this);
curNo++;
}
assert (curNo <= wheelSize);
callback.nextNumber(curNo, this);
curNo++;
finalNo = curNo - 1;
}
calculateResult(finalNo);
callback.result(finalNo, this);
}
The method callback.nextNumber(curNo, this):
public void nextNumber(int nextNumber, GameEngine engine) {
String strNo = Integer.toString(nextNumber);
assert (nextNumber >= 1);
System.out.println(nextNumber);
wcWheel.setCounter(strNo);
}
Where in, wcWheel is my singleton instance of my View, which contains the method setCounter():
public void setCounter(String value) {
label.setText(value);
}
Sorry for how convoluted my explanation is, but basically what it boils down to is that setCounter() is definitely being called, but seems to only call the setText() method on the final number. So what I'm left with is an empty label that doesn't present the number until the entire roulette has finished spinning.
I've determined that setCounter() runs on the event dispatch thread, and I suspect this is a concurrency issue but I have no idea how to correct it.
I've tried to include all relevant code, but if I'm missing anything, please mention it and I'll post it up as well.
I'm at my wits end here, so if anyone would be kind of enough to help, that would be so great.
Thank you!
Your while loop along Thread.sleep() will block and repainting or changing of the UI until the loop is finished.
Instead you'll want to implement a javax.swing.Timer for the delay, and keep a counter for the number of ticks, to stop it. You can see more at How to Use Swing Timers
The basic construct is
Timer ( int delayInMillis, ActionListener listener )
where delayInMillis is the millisecond delay between firing of an ActionEvent. This event is listened for by the listener. So every time the event is fired, the actionPerfomed of the listener is called. So you might do something like this:
Timer timer = new Timer(delay, new ActionListener()(
#Override
public void actionPerformed(ActionEvent e) {
if (count == 0) {
((Timer)e.getSource()).stop();
} else {
//make a change to your label
count--;
}
}
));
You can call timer.start() to start the timer. Every delay milliseconds, the label will change to what you need it to, until some arbitrary count reaches 0, then timer stops. You can then set the count variable to whatever you need to, if you want to to be random, say depending on how hard the wheel is spun :D
I think you didn't post all the relevant code that is required to know exactly the problem.
But most likely the problem is due to you run your loop and JLabel.setText() in the EDT (Event Dispatching Thread).
Note that updating the UI components (e.g. the text of a JLabel) also happens in the EDT, so while your loop runs in the EDT, the text will not be updated, only after your loop ended and you return from your event listener. Then since you modified the text of the JLabel it will be refreshed / repainted and you will see the last value you set to it.
Example to demonstrate this. In the following example a loop in the event listener loops from 0 to 9 and sets the text of the label, but you will only see the final 9 be set:
JPanel p = new JPanel();
final JLabel l = new JLabel("-1");
p.add(l);
JButton b = new JButton("Loop");
p.add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for ( int i = 0; i < 10; i++ ) {
l.setText( "" + i );
try { Thread.sleep( 200 ); } catch ( InterruptedException e1 ) {}
}
}
} );
A proposed solution: Use javax.swing.Timer to do the loop's work. Swing's timer calls its listeners in the EDT so it's safe to update swing components in it, and once the listener returns, a component UI update can happen immediately:
JPanel p = new JPanel();
final JLabel l = new JLabel("-1");
p.add(l);
JButton b = new JButton("Loop");
p.add(b);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new Timer(200, new ActionListener() {
int i = 0;
#Override
public void actionPerformed(ActionEvent e2) {
l.setText("" + i);
if ( ++i == 10 )
((Timer)e2.getSource()).stop();
}
}).start();
}
} );
In this solution you will see the label's text counting from 0 up to 9 nicely.
It's appears to me that your entire game must block in the action handler until the while loop has finished? So the text of the label will be getting updated but only the last update will be visible once the AWT thread is running again.

Java Applet Game Loop stops Mouse/Keyboard Input?

I got a problem I couldn't get to work after about 2 Hours of trying. I want to have a loop that do 2 Methods (Draw and update) but also listen to Mouse/Keyboard events. I have a loop that Draws and Updates, but does nothing outside of the loop ( Listening to events ) I tried alot of things but nothing worked. Help Please?
I tried using the Runnable Thread, using different orders, using wait() and notify(), I've tried alot of things. But basicly I want to know how to run a loop and still check for User Input
Also when I try to quit the program clicking the red "X", it won't quit but still work
Here's the Code:
import java.applet.Applet;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class main extends Applet implements MouseListener, Runnable {
public main() {
super();
init();
}
Thread t;
Screen screen = new Screen();
String Text = "Hello";
boolean Running = true;
boolean Click = false;
int R = 0x00;
int G = 0x00;
int B = 0x00;
int xpoints[] = {25, 40, 40, 25, 25};
int ypoints[] = {40, 40, 25, 25, 25};
int npoints = 5;
public void run() {
while (Running) {
GameLoop();
}
}
public void init() {
this.addMouseListener(this);
this.setSize(400, 300); //manually set your Frame's size
t = new Thread(this);
t.start();
}
public void paint(Graphics g) {
g.setColor(new Color(R, B, G));
g.fillPolygon(xpoints, ypoints, npoints);
Running = true;
t.run();
}
public void mousePressed(MouseEvent e) { //On Mouse Click
System.exit(0);
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
System.exit(0);
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public boolean keyDown(Event e, int key) {
return true;
}
public void GameLoop() {
if (Running) {
if (R != 0xff) {
R++;
} else {
if (G != 0xff) {
G++;
} else {
if (B != 0xff) {
B++;
} else {
System.exit(0);
}
}
}
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
paint(getGraphics());
}
}
public void sleep(int time) throws InterruptedException {
Thread.sleep(time, 0);
}
}
This tutorial should provide some insight as to how your program should be structured. And this one is helpful for the mouse listener.
Issues you should address:
1) You're doing something fishy with the paint method. Why are you calling t.run() in there? The thread t is already running and looping constantly calling the paint() method to redraw the screen. Remove this call and see what you get.
1) The destruction of your thread/applciation is poor. The first example above provides a better way for that to occur
2) You have your System.Exit(0) on mousePressed() with the comment //on mouse click but nothing in mouseClicked()... it works but its bad convention
3)Having your class named main is extremely poor convention that is both confusing and impractical. Rename your class to something like "Game" or similar.
4) Why declare Screen if you don't use it?
I see that you define a Running variable to be true upon initialization. This variable is used to determine whether or not the game should stop. I, however, don't see any place where you modify the value of this variable to false. This would explain why your game never exits.
As for the the game not working, try debugging the application in an IDE. You should then pay attention to what, if any, Exception are being thrown and the values of any variables you are questioning. Hopefully this will give you insight into the behavior of your app.
Don't forget to update us with any new info you discover so we can help you out along the way.

Categories

Resources