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...
Related
This is my code, I have a key listener however it does do what it is supposed to do when the key is pressed. The shape moves as it should in the ActionListener however when I press one of the keys it does nothing.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class Snake extends JPanel implements ActionListener {
Timer t = new Timer(5, this);
double x = 0 , y = 0, xVel = 2, yVel = 2;
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D circle = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(circle);
t.start();
}
public void actionPerformed(ActionEvent e){
if(x < 0 || x >460)
{
xVel = -xVel;
}
if(y < 0 || y > 459)
{
yVel = -yVel;
}
x += xVel;
y += yVel;
repaint();
}
public void keyPressed(KeyEvent e) //This part of the Code Doesnt seem to be running
{
int key = e.getKeyCode();
if( key == KeyEvent.VK_DOWN)
{
yVel = yVel; //There may be something wrong with the way i wrote this
xVel = 0;
}
if(key == KeyEvent.VK_UP)
{
yVel = -yVel;
xVel = 0;
}
if(key == KeyEvent.VK_RIGHT)
{
xVel = xVel;
yVel = 0;
}
if(key == KeyEvent.VK_LEFT)
{
xVel = -xVel;
yVel =0;
}
x+= xVel;
y+= yVel;
repaint();
}
}
It appears as though you haven't implemented the KeyListener interface. You're going to want to add that to your implements ActionListener, KeyListener and then register the the class for the KeyListener as well as implement the methods provided by the KeyListener interface.
For more information on KeyListener look at this link
I'm currently working on a similar project, how I do it:
1) Implement KeyListener (can't recall if that is the exact name*)
2) addKeylistener(this)
3) Write the method which you have already done.
*Might be KeyboardListener
You need to .addKeyListener to your frame. So where ever you created your frame you need to add this:
JFrame frame = new JFrame();
frame.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if( key == KeyEvent.VK_DOWN)
{
yVel = 2;
xVel = 0;
}
if(key == KeyEvent.VK_UP)
{
yVel = -2;
xVel = 0;
}
if(key == KeyEvent.VK_RIGHT)
{
xVel = 2;
yVel = 0;
}
if(key == KeyEvent.VK_LEFT)
{
xVel = -2;
yVel =0;
}
x+= xVel;
y+= yVel;
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
});
Snake snake = new Snake();
frame.add(snake);
frame.setSize(500, 500);
frame.setVisible(true);
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 am making a class (called Play), that extends JFrame, and implements ActionListener and KeyListener. This class does not hold the main() method, because there is a different class for that.
I am getting an error which states, "Class Play must either be declared abstract, or implement abstract method keyReleased(KeyEvent) in KeyListener".
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;
public class Play extends JFrame implements ActionListener, KeyListener {
Timer timer = new Timer(5, this);
double x = 0, y = 0, velx = 0, vely = 0;
public Play() {
timer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void actionPreformed(ActionEvent e) {
repaint();
x += velx;
y += vely;
}
public void up() {
vely = -1.5;
velx = 0;
}
public void down() {
vely = 1.5;
velx = 0;
}
public void left() {
vely = 0;
velx = -1.5;
}
public void right() {
vely = 0;
velx = 1.5;
}
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_LEFT) {
left();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
Well, do what it says. Since you're inheriting the KeyListener interface, you have to implement all of the interface's methods, including 'keyReleased'
The KeyListener must have all of it's methods implemented.
Simply add this method to the class and it should work
#Override
public void keyReleased(KeyEvent e) {
}
You must also Override all of the KeyListener implemented methods
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.
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.