I've built a simple animation program that moves a box to a direction depending on the
arrow key pressed (similar to snake), in JFrame using KeyListener and ActionListener. but I've noticed that if I start the application and I move the mouse the application wont continue to check what arrow key was pressed and which direction to move to.
Can some one explain this to me, and is it because I need to disable something involving mouse events?
heres the code:
public class gui extends JPanel implements ActionListener, KeyListener{
Timer tm = new Timer(5, this);
int x = 300, y = 178, velx = 0, vely = 0;
public gui() {
tm.start();
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(x, y, 50, 30);
}
#Override
public void keyPressed(KeyEvent e) {
keys(e);
}
public void keys(KeyEvent e) {
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velx = -1;
vely = 0;
}
if (c == KeyEvent.VK_UP)
{
velx = 0;
vely = -1;
}
if (c == KeyEvent.VK_RIGHT)
{
velx = 1;
vely = 0;
}
if (c == KeyEvent.VK_DOWN)
{
velx = 0;
vely = 1;
}
}
public void borders(ActionEvent e) {
if (x < 0) {
velx = 0;
x = 0;
JOptionPane
.showMessageDialog(null, "you hit the borders you lost!");
System.exit(0);
}
if (x > 530) {
velx = 0;
x = 530;
JOptionPane
.showMessageDialog(null, "you hit the borders you lost!");
System.exit(0);
}
if (y < 0) {
velx = 0;
y = 0;
JOptionPane
.showMessageDialog(null, "you hit the borders you lost!");
System.exit(0);
}
if (y > 330) {
velx = 0;
y = 330;
JOptionPane
.showMessageDialog(null, "you hit the borders you lost!");
System.exit(0);
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void actionPerformed(ActionEvent e) {
x += velx;
y += vely;
repaint();
borders(e);
}
}
I don't know what your problem is. I used your code and had no problem.
Here is what I used:
public gui()
{
addKeyListener(this);
setFocusable(true);
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velx = -1;
vely = 0;
}
if (c == KeyEvent.VK_UP)
{
velx = 0;
vely = -1;
}
if (c == KeyEvent.VK_RIGHT)
{
velx = 1;
vely = 0;
}
if (c == KeyEvent.VK_DOWN)
{
velx = 0;
vely = 1;
}
}
public void actionPerformed(ActionEvent e)
{
x += velx;
y += vely;
repaint();
borders(e);
}
public static void main(String[] args)
{
JFrame frame = new JFrame("gui");
frame.add(new gui());
frame.setVisible(true);
frame.setSize(600, 400);
}
}
I clicked the mouse and moved it before I started the program, then I used the keys; it works fine. I would switch to KeyBindings though.
Related
Hey so I'm fairly new to java, but based on doing a lot of research and analyzing various code, I came up with some code to move a basic circle on a screen by using arrow keys.
However, for some reason, the code does not run the whole key event. If I press any key on the keyboard, even different arrow keys, it will cause the circle to only move one direction.
Based on my code, I feel like everything should work, but it just won't run the KeyEvent function properly. Any ways to fix it?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class second extends JPanel implements ActionListener, KeyListener
{
Timer t = new Timer(5, this);
int x = 0, y = 0, velx = 0, vely = 0;
public second()
{
t.start();
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void actionPerformed(ActionEvent e)
{
x += velx;
y += vely;
repaint();
}
public void up()
{
velx = 0;
vely = 2;
}
public void down()
{
velx = 0;
vely = -2;
}
public void left()
{
velx = -2;
vely = 0;
}
public void right()
{
velx = 2;
vely = 0;
}
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP);
{
up();
}
if (keyCode == KeyEvent.VK_DOWN);
{
down();
}
if (keyCode == KeyEvent.VK_LEFT);
{
left();
}
if (keyCode == KeyEvent.VK_RIGHT);
{
right();
}
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
velx = 0;
vely = 0;
}
public static void main(String args[])
{
second s = new second();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
}
}
First of all, ActionListener is not required in this case. KeyListener is sufficient. Also there is a semicolon beside if statements, this is causing all the functions up, down, left and right to be invoked negating the effect.
Also for up, y should be reduced and for down, y should be increased.
Please find the below code which works fine. You can limit the right and down movement with MAX_LIMIT based on the window size. I limited it for 0,0 for left and up movement.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class Second extends JPanel implements KeyListener
{
int x = 0, y = 0;
public Second()
{
addKeyListener(this);
setFocusable(true);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void up()
{
if(y >= 5) {
y -= 5;
repaint();
}
}
public void down()
{
y += 5;
repaint();
}
public void left()
{
if(x >= 5) {
x -= 5;
repaint();
}
}
public void right()
{
x += 5;
repaint();
}
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP)
{
up();
}
if (keyCode == KeyEvent.VK_DOWN)
{
down();
}
if (keyCode == KeyEvent.VK_LEFT)
{
left();
}
if (keyCode == KeyEvent.VK_RIGHT)
{
right();
}
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent e)
{
}
public static void main(String args[])
{
Second s = new Second();
JFrame f = new JFrame();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
}
}
First, you have a semi-colon following your first if statement in keyPressed(), which impeaches considering following instructions. cf :
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP)
up();
if (keyCode == KeyEvent.VK_DOWN)
down();
if (keyCode == KeyEvent.VK_LEFT)
left();
if (keyCode == KeyEvent.VK_RIGHT)
right();
}
You also have a negative value for vely in down() where it should be positive (and vice-versa). And since you already reset velx and vely to 0 on keyReleased(), it is unnecessary to do it in your directions functions.
public void up() {
vely = -2;
}
public void down() {
vely = 2;
}
Class names should be CamelCase (not lowercase as presented).
Have fun.
I tried this code in BlueJ which should create a rectangle and move it around but it does not function. Then I put the same exact code into Eclipse and it functions as I thought it would. Any ideas to why this works in Eclipse but not in BlueJ?
import javax.swing.*;
import java.awt.*;
public class Shapes
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Test");
Draw object = new Draw();
frame.add(object);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Draw extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5,this);
int x = 0, y = 0, velX = 0, velY = 0;
public Draw()
{
tm.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(x,y,100,20);
}
public void actionPerformed(ActionEvent e)
{
x += velX;
y += velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if(c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if(c == KeyEvent.VK_UP)
{
velX = 0;
velY = 1;
}
if(c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = -1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e)
{
velX = 0;
velY = 0;
}
}
I can see what you mean I believe it attaches it to that corner of the screen because when I resize the screen it moves with that corner. I think its not that BlueJ can't Run it properly i believe it can but it does it differently than what eclipse does.
I believe this question asks the same thing and it gets pretty good answers you should look at it first.
So I am trying to make a game like Snake, but I am running into some issues.
I want to repeat the if statement inside of of the moveup class using a while loop, but
when I try to use the KeyListener to listen for the key press of the up arrow key to break the while loop it acts like it only looped once (moved up 5 pixels). The loop is supposed to make the snake continue going up without having to click multiple times, but it just moves five (the value I set it to do) pixels. Here is the code:
public class Snake extends JFrame implements KeyListener {
int ballX = 50;
int ballY = 50;
int playerX = 250;
int playerY = 250;
boolean up = false;
boolean right = false;
boolean down = false;
boolean left = true;
class DrawPane extends JPanel {
public void paintComponent(Graphics gc) {
Random rand = new Random();
int dotsX = rand.nextInt(500) + 1;
int dotsY = rand.nextInt(500) + 1;
Graphics g = this.getGraphics();
setVisible(true);
super.paintComponents(gc);
gc.setColor(Color.BLUE);
gc.fillRect(ballX, ballY, 10, 10);
gc.setColor(Color.RED);
gc.fillRect(playerX, playerY, 10, 10);
}
}
public Snake(String title) {
super(title);
JFrame frame = new JFrame();
setContentPane(new DrawPane());
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setSize(500, 500);
this.setBackground(Color.YELLOW);
this.setResizable(false);
this.addKeyListener(this);
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode() == KeyEvent.VK_UP) {
up = true;
right = false;
down = false;
left = false;
moveup(e);
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
up = false;
right = false;
down = true;
left = false;
movedown(e);
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
up = false;
right = true;
down = false;
left = false;
moveright(e);
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
up = false;
right = false;
down = false;
left = true;
moveleft(e);
}
}
public void moveup(KeyEvent e) {
while (up) {
if (playerX < 500 || playerX > 0) {
playerX = playerX + 5;
repaint();
if (e.getKeyChar() == KeyEvent.VK_UP)
break;
}
}
}
public void moveright(KeyEvent e) {
if (playerX < 500 || playerX > 0) {
playerX = playerX + 5;
repaint();
// moveright();
}
}
public void movedown(KeyEvent e) {
if (playerY < 500 || playerY > 0) {
playerY = playerY + 5;
repaint();
// movedown();
}
}
public void moveleft(KeyEvent e) {
if (playerX < 500 || playerX > 0) {
playerX = playerX - 5;
repaint();
// moveleft();
}
}
public void snakePanel() {
JPanel panel1 = new JPanel();
panel1.setBackground(Color.red);
}
public void ActionListener() {
}
public static void main(String[] args) {
Snake r = new Snake("Snake");
}
}
It never loops because of the break. Effectively you're saying:
if keycode is up
loop
move up
break if keycode is up // Will always be true
More so, you shouldn't be looping in an event handler like that. Event handlers should execute and return quickly else you'll block the event thread. Should be using a timer to act as a heartbeat and update the position/repaint periodically.
Keep in mind that you DON'T want to use Swing for more advanced games in the future.
--- Quick solution:
Just remove your while(). The KeyListener interface lets you abstract the concept of "while this key is pressed, do this". Instead, when you implement the interface, you say: "whenever this key is pressed, do this". It's an event.
Here's your working code:
http://pastebin.com/b0CZDxpD
I created a small Java program that basically draws a keyboard controllable circle and some "walls" in a JFrame. Here's what it looks like when executed;
The program has 3 classes:
main.java (the main method class)
Infout.java (circle + walls constructor class)
world.java (the class that draws the JFrame)
Here is the code:
main.java
public class main {
public static void main(String[] args) {
world w = new world();
Infout o = new Infout();
w.frame();
}
}
world.java
import javax.swing.JFrame;
public class world {
JFrame f = new JFrame();
Infout o = new Infout();
public void frame(){
f.setVisible(true);
f.setDefaultCloseOperation(3);
f.setSize(300, 400);
f.setTitle("Circle");
f.add(o);
}
}
Infout.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class Infout extends JPanel implements ActionListener, KeyListener {
Timer t = new Timer(5, this);
double x = 0, y = 0, velx = 0, vely = 0;
public Infout(){
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
g2.fill(new Rectangle2D.Double(0, 270, 300, 5));
g2.fill(new Rectangle2D.Double(140, 270, 5, 300));
g2.fill(new Rectangle2D.Double(140, 60, 70, 5));
g2.fill(new Rectangle2D.Double(50, 140, 5, 70));
g2.fill(new Rectangle2D.Double(150, 130, 5, 40));
g2.fill(new Rectangle2D.Double(190, 210, 40, 5));
if (x >= 120 && y >= 270) {
g.drawString("You win!",115,35);
}
if (x <= 120 && y >= 270) {
g.drawString("You lose!",115,35);
}
if (x == 120 && y >= 270){
velx = 0;
vely = 0;
}
if (x == 31.5 && y <= 200 && y >= 100){
velx = 0;
}
if (x == 132 && y <= 170 && y >= 100){
velx = 0;
}
if (x <= 190 && x >= 120 && y == 42){
velx = 0;
}
if (x <= 210 && x >= 171 && y == 192){
velx = 0;
}
}
public void actionPerformed(ActionEvent e) {
System.out.println("x "+x+"y "+y);
repaint();
x += velx;
y += vely;
if (x < 0 || x > 260)
{
velx = 0;
vely = 0;
}
if (y < 0 || y > 340)
{
velx = 0;
vely = 0;
}
}
public void up() {
vely = -1.5;
velx = 0;
}
public void down() {
vely = 1.5;
velx = 0;
}
public void left() {
velx = -1.5;
vely = 0;
}
public void right() {
velx = 1.5;
vely = 0;
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
}
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
The problem is the circle is not moving when I try to move it with the keyboard keys! :(. All the code in Infout.java is correct because I used this same class is another program and I was able to move the circle around :/
Thanks!
Ab
Are you calling the actionPerformed method?
If not, then the panel is probably not repainting itself
So I was making a game for my Computer Science class, pretty much making a modified version of the game Frogger, and I first started off by just moving a circle across the JPanel to mimic the frogs movement and I realized a very annoying lag between the interactions with the buttons. Does anyone know how to completely get rid of the lag or perhaps reduce it? Any tips or help would be much appreciated! Here is the code so far for just the circle movement and if you see any improvements that could be done, please feel free to leave your comments.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class second extends JPanel implements ActionListener, KeyListener
{
Timer t = new Timer (5, this);
double x = 0, y = 0, velx = 0, vely = 0;
public second()
{
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 10, 10));
}
public void actionPerformed (ActionEvent e)
{
repaint();
x += velx;
y += vely;
}
public void up()
{
vely = -5;
velx = 0;
}
public void down()
{
vely = 5;
velx = 0;
}
public void left()
{
velx = -5;
vely = 0;
}
public void right()
{
velx = 5;
vely = 0;
}
public void upEnd()
{
velx = 0;
vely = 0;
}
public void downEnd()
{
velx = 0;
vely = 0;
}
public void leftEnd()
{
velx = 0;
vely = 0;
}
public void rightEnd()
{
velx = 0;
vely = 0;
}
public void keyPressed (KeyEvent e)
{
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP)
{
up();
}
if (code == KeyEvent.VK_DOWN)
{
down();
}
if (code == KeyEvent.VK_RIGHT)
{
right();
}
if (code == KeyEvent.VK_LEFT)
{
left();
}
}
public void keyTyped (KeyEvent e) {}
public void keyReleased (KeyEvent e)
{
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP)
{
upEnd();
}
if (code == KeyEvent.VK_DOWN)
{
downEnd();
}
if (code == KeyEvent.VK_RIGHT)
{
rightEnd();
}
if (code == KeyEvent.VK_LEFT)
{
leftEnd();
}
}
}
And here is the Main file:
import javax.swing.JFrame;
public class Macheads
{
public static void main (String[] args)
{
JFrame f = new JFrame();
second s = new second();
f.add(s);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800,600);
}
}
Don't use a KeyListener. Instead you should be using Key Bindings.
The keyboard has a delay for repeating events. Use a Swing Timer to schedule the animation instead of relying on key events to be generated. See Motion Using the Keyboard for more information and examples.
Try using only the keyListener without the timer and actionlistener.
public void keyPressed (KeyEvent e)
{
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP)
{
up();
}
if (code == KeyEvent.VK_DOWN)
{
down();
}
if (code == KeyEvent.VK_RIGHT)
{
right();
}
if (code == KeyEvent.VK_LEFT)
{
left();
}
x += velx;
y += vely;
repaint(); //added and will repaint everytime key is pressed
}
//no need to place arguments in keyTyped and keyReleased because JPanel is repainted on keypressed...