Simple Pong Game Keyboard Input - java

(The game is not complete yet but nevertheless)
Using the keyboard input does not do anything, I believe this is due to KeyListener not being defined properly. Here is my code:
mainClass:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class mainClass extends JComponent{
private static ballAndGameplay ball;
private static calculateDrawPos blocks;
public static void main(String[] a) {
JFrame window = new JFrame("PONG");
window.setSize(1280,720);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainClass mc = new mainClass();
window.getContentPane().add(new mainClass());
window.setVisible(true);
ball = new ballAndGameplay(630,300,5,5);
blocks = new calculateDrawPos(false,false,false,false);
mc.addKeyListener(blocks);
while (true){
blocks.moveBlocks();
ball.moveBall();
mc.removeAll();
mc.paint(window.getGraphics());
try{
Thread.sleep(10);
}
catch (Exception e){
}
}
}
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect (-10, -10, 1300, 740);
g.setColor(Color.WHITE);
g.fillRect (10, blocks.PlayerOneY, 25, 125); //left player
g.fillRect (1230, blocks.PlayerTwoY, 25, 125); //right player
g.fillRect (638, -10, 4, 740); //middle line
g.fillRect (ball.ballX, ball.ballY, 20, 20); //ball
}
}
calculateDrawPos:
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class calculateDrawPos extends KeyAdapter implements KeyListener {
int PlayerOneY=275;
int PlayerTwoY=275;
boolean wPressed;
boolean sPressed;
boolean upPressed;
boolean downPressed;
public calculateDrawPos (boolean a, boolean b, boolean c, boolean d) {
this.wPressed=a;
this.sPressed=b;
this.upPressed=c;
this.downPressed=d;
}
public void keyPressed(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.VK_W);
{
wPressed=true;
}
if (keyCode == KeyEvent.VK_S);
{
sPressed=true;
}
if (keyCode == KeyEvent.VK_UP);
{
upPressed=true;
}
if (keyCode == KeyEvent.VK_DOWN);
{
downPressed=true;
}
}
public void keyReleased(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.VK_W);
{
wPressed=false;
}
if (keyCode == KeyEvent.VK_S);
{
sPressed=false;
}
if (keyCode == KeyEvent.VK_UP);
{
upPressed=true;
}
if (keyCode == KeyEvent.VK_DOWN);
{
downPressed=true;
}
}
public void moveBlocks(){
if (wPressed==(true)){
PlayerOneY-=5;
}
if (sPressed==(true)){
PlayerOneY+=5;
}
if (upPressed==(true)){
PlayerTwoY-=5;
}
if (downPressed==(true)){
PlayerTwoY+=5;
}
}
}
ballAndGameplay:
import java.util.Random;
public class ballAndGameplay {
private static Random rand;
int ballX;
int ballY;
int ballXVelocity;
int ballYVelocity;
public ballAndGameplay (int a, int b, int c, int d) {
rand = new Random();
this.ballX=a;
this.ballY=b;
this.ballXVelocity=c;
this.ballYVelocity=d;
}
public void moveBall() {
boolean pointFinished = (ballX <= -20 || ballX >= 1280);
if (ballY <= 20 || ballY >= 700) {
ballYVelocity*=-1;
}
// if ((ballY >= PlayerOneY && ballY <= PlayerOneY+125 && ballX <= 35) || (ballY >= PlayerTwoY && ballY <= PlayerTwoY+125 && ballX >= 1245)){
// ballXVelocity*=-1.2;
// }
if (pointFinished==(true)){
try{
Thread.sleep(500);
}
catch (Exception e){
}
ballX=630;
ballY=300;
getBallX();
getBallY();
}
ballX+=ballXVelocity;
ballY+=ballYVelocity;
// System.out.println("ballX: "+ballX+" ballY: "+ballY+" ballXVelocity: "+ballXVelocity+" ballYVelocity: "+ballYVelocity);
}
public int getBallX(){
if (ballX != 630){
return ballXVelocity;
}
int side = rand.nextInt(2);
int number = rand.nextInt(5);
number+=4;
if (side==0){
ballXVelocity=-1*number;
}
else if (side==1){
ballXVelocity=1*number;
}
return ballXVelocity;
}
public int getBallY(){
if (ballY != 300){
return ballYVelocity;
}
int side = rand.nextInt(2);
int number = rand.nextInt(5);
number+=4;
if (side==0){
ballYVelocity=-1*number;
}
else if (side==1){
ballYVelocity=1*number;
}
return ballYVelocity;
}
}

You wrote
mainClass mc = new mainClass();
window.getContentPane().add(new mainClass());
That means that the mainClass that you added to your window isn't the same one that mc references. So all those operations you do to mc won't make any changes in your window.
You could try writing
mainClass mc = new mainClass();
window.getContentPane().add(mc);
instead.

Issues:
A KeyListener only works on a component that has current focus.
Your adding your KeyListener to a JComponent, a component that by default isn't even able to gain the focus (unlike a JButton, JTextField, and other components that typically allow keyboard interaction.)
One short term solution is to make your JComponent, the mc variable focusable by calling mc.setFocusable(true); and then giving it the system focus by calling mc.requestFocusInWindow();.
But having said this, you're still far better off using Key Bindings
Other issues:
Override and draw in the JComponent's paintComponent method not the paint method, if only to avoid the jerky graphics you'll get using paint.
Don't forget to call the super's paintComponent method in your override to erase the old ball image.
Never use a Graphics object obtained from a component by calling getGraphics() on it as the object thus obtained my become invalid or go null over time leading to invalid graphics or worse.
Never call the paint(...) or paintComponent(...) method directly as you're doing.
Instead use passive graphics as per the Swing graphics tutorials which I urge you to read.
Use a Swing Timer instead a while (true) loop since your while (true) loop risks tying up the Swing event thread, freezing your application.

Related

Difference between implementing JFrame and JPanel

I was trying to understand the difference between JFrame and JPanel. I tend to use subclasses of JFrame instead of JPanel, but people always tell me that it's better to use a subclass of JPanel instead. Here is an example of me using JFrame:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class Game extends JFrame implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
public void move() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(+1);
}
if (keyCode == e.VK_UP) {
setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
setYCoord(+1);
}
Game.this.repaint();
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(0);
}
if (keyCode == e.VK_UP) {
setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
setYCoord(0);
}
Game.this.repaint();
}
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
addKeyListener(new AL());
setTitle("Game");
setSize(500, 500);
setResizable(true);
setVisible(true);
setBackground(Color.BLACK);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 250;
y = 250;
}
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run() {
try {
while (true) {
move();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
This works fine (except for there being a small delay when I hold down one of the buttons), but when I try to change my code by implementing JPanel instead of JFrame, nothing shows up... Here's the code for the JPanel subclass:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
JFrame frame;
public void move() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(+1);
}
if (keyCode == e.VK_UP) {
setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
setYCoord(+1);
}
Game.this.repaint();
}
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
setXCoord(0);
}
if (keyCode == e.VK_UP) {
setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
setYCoord(0);
}
Game.this.repaint();
}
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
frame = new JFrame();
frame.addKeyListener(new AL());
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.setVisible(true);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 250;
y = 250;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
#Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run() {
try {
while (true) {
move();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
As the code shows, you need a custom JPanel, because you want to change the behavior of some methods like paintComponent.
However, you don't need a custom JFrame, so no need to create a class extending it.
Finally, your main class has no need to be your panel class.
Here is an example class, I moved the frame stuff from Game's constructor to this main class.
public class MainClass {
public static void main(String[] args) {
Game game = new Game();
JFrame frame = new JFrame();
frame.addKeyListener(new AL());
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.getContentPane().add(game);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Thread t = new Thread(game);
t.start();
}
}
A JFrame is a far more complex component then you might think, for starters, it has a JRootPane as it's primary container, which contains the contentPane, JMenuBar and controls the glassPane
see How to Use Root Panes for more details.
The JFrame also has decorations (borders), these borders are painted within the confines of the window itself, the contents are then laid out within these, so the borders don't paint over then.
When you override paint of a top level container, like JFrame, there are a number of issues which you run into:
It's not double buffered, which can cause flickering as the window is updated
The other components can be painted independently of the frame (so the frame's paint method is not called), which can cause no end of issues
You can now paint beneath the frame's decorations, see Java graphic image, How to get the EXACT middle of a screen, even when re-sized and How can I set in the midst? for more details.
You're locking your self into a single use case, you can't add windows to other containers, which reduces your components re-use value
Generally speaking, from a OOP point of view, you're not actually adding any new functionality to the class (or least none which can't be generated through better approaches).
When you use something like JPanel, all other the above are no longer of concern:
They are double buffered by default
If you use a layout manager (on the content pane), the component will be laid out within the frame's decorations
The width and height of the component represent the whole viewable area
You can add this component to what ever container you want
You should also override the JPanel's getPreferredSize method and return the preferred size you want your panel to generally be, then you can use JFrame#pack to "pack" the window around it, this will make the window larger then the content area, but means you're not scratching your head wondering why you set the window to a certain size, but your component is smaller

Repaint taking up too much CPU

I'm writing a simple drawing program that uses keyListeners. It works, but every time it needs to draw another circle, I have to use the repaint() method or it won't automatically repaint the screen after using one of the arrow keys. It would be fine except that it uses up way too much CPU (around 50%) for such a simple program. Any ideas on how to NOT use the repaint() method so that it can do whatever it needs without eating up all my CPU? Here is the source code:
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class Game extends JFrame {
int x, y;
public class AL extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
x--;
}
if (keyCode == e.VK_RIGHT) {
x++;
}
if (keyCode == e.VK_UP) {
y--;
}
if (keyCode == e.VK_DOWN) {
y++;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
public static void main(String[] args) {
Game game = new Game();
}
public Game() {
addKeyListener(new AL());
setTitle("Game");
setSize(500, 500);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
}
#Override
public void paint(Graphics g) {
g.fillOval(x, y, 15, 15);
repaint();
}
}
You are doing a few things wrong when it comes to painting:
Don't paint on a top level component like JFrame, instead add a JPanel to it and paint on it instead.
Don't override paint, override paintComponent instead.
Don't call repaint inside methods that paint (like paint and paintComponent), it will cause a recursion.
Also, use key bindings instead of key listeners. Here is an example of everything coming together:
class Example extends JPanel {
int x = 0;
int y = 0;
Example() {
getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("RIGHT"), "right");
getActionMap().put("right", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
x++;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
public void paintComponent(Graphics g) {
g.clearRect(0, 0, getWidth(), getHeight());
g.drawRect(x, y, 30, 30);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new Example());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Don't call repaint(); inside paint(). Repaint schedules a paint(), so no wonder your CPU is having a hard time.
Like Kayaman said you should never call repaint() from within paint().
You can call the Frames repaint() Method in keyPressed() so the Frame will be repainted every time you press a key.
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
x--;
}
if (keyCode == e.VK_RIGHT) {
x++;
}
if (keyCode == e.VK_UP) {
y--;
}
if (keyCode == e.VK_DOWN) {
y++;
}
Game.this.repaint();
}
/*...*/
#Override
public void paint(Graphics g) {
g.fillOval(x, y, 15, 15);
}
Call to repaint() will cause RepaintManager to call paint() method. So if you call repaint() inside paint() it will loop infinitely. Instead you can repaint your JFrame once the key-pressed action performed.
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT) {
x--;
}
if (keyCode == KeyEvent.VK_RIGHT) {
x++;
}
if (keyCode == KeyEvent.VK_UP) {
y--;
}
if (keyCode == KeyEvent.VK_DOWN) {
y++;
}
repaint();
}
Remove repaint() call from paint() method and add it as above.
But if there are different places which you want the JFrame to be repainted and you choose the above method, it will be messy again. So, you can use a Timer to call repaint().
private final javax.swing.Timer timer;
private final int REFRESH_TIME = 100;
public Game() {
addKeyListener(new AL());
setTitle("Game");
setSize(500, 500);
setResizable(false);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
x = 150;
y = 150;
timer = new javax.swing.Timer(REFRESH_TIME, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
If you want, you can use another way to call repaint() once in a period. The calling Thread need not to be an EDT.

My repaint in JFrame is not working

I have a problem with repaint in JFrame i used repaint() earlier when i was making an animation and everything worked
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Draw extends JComponent implements KeyListener {
int x = 0;
int y = 0;
public void paint(Graphics g){
g.setColor(Color.BLUE);
g.fillRect(x, y, 50, 50);
}
public void keyPressed(KeyEvent k) {
if(k.getKeyCode() == KeyEvent.VK_UP){
y -= 2;
} else if(k.getKeyCode() == KeyEvent.VK_DOWN){
y += 2;
} else if(k.getKeyCode() == KeyEvent.VK_LEFT){
x -= 2;
} else if(k.getKeyCode() == KeyEvent.VK_RIGHT){
x += 2;
}
repaint();
}
public void keyReleased(KeyEvent k) {}
public void keyTyped(KeyEvent k) {}
}
This is my draw class which if i run as an applet everything works but i don't want an applet
My frame class
import javax.swing.*;
public class Frame {
Draw d = new Draw();
public Frame(){
JFrame f = new JFrame("Game");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
f.setVisible(true);
f.add(d);
f.addKeyListener(new Draw());
}
}
and my Main class
public class Main {
public static void main(String[] args) {
Frame f = new Frame();
}
}
The repaint() is the one not working i tested the key listener it works so why isn't the repaint() working?
The KeyListener shouldn't be working since a JComponent by default cannot get program focus, a necessary requirement for a KeyListener to work. One solution is to make it focusable via setFocusable(true) and then call requestFocusInWindow() on it. Better to use Key Bindings (tutorial link). Note that you should be overriding paintComponent, not paint and you should not forget to call the super's method within your override.
For example
Edit: I'm wrong since a JFrame can get focus and you're adding the KeyListener to the JFrame. But your problem is that you are creating a new Draw object to do this, not to the original displayed Draw object. Your code would actually work if you use the same Draw object for both displaying the image and for KeyListener:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Draw extends JComponent implements KeyListener {
int x = 0;
int y = 0;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(x, y, 50, 50);
}
public void keyPressed(KeyEvent k) {
if (k.getKeyCode() == KeyEvent.VK_UP) {
y -= 2;
} else if (k.getKeyCode() == KeyEvent.VK_DOWN) {
y += 2;
} else if (k.getKeyCode() == KeyEvent.VK_LEFT) {
x -= 2;
} else if (k.getKeyCode() == KeyEvent.VK_RIGHT) {
x += 2;
}
repaint();
}
public void keyReleased(KeyEvent k) {
}
public void keyTyped(KeyEvent k) {
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Draw d = new Draw();
JFrame f = new JFrame("Game");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(800, 600);
f.setVisible(true);
f.add(d);
f.addKeyListener(d);
}
});
}
}
Safer though is to use Key Bindings.

Java pong can't move both paddles at once

Trying to make pong in java but can't move both paddles at once. You can move one or the other but not both at the same time. Do I need to create 2 threads with 2 different pannels?
Here is where I am specifying the key events
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A || e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_QUOTE || e.getKeyCode() == KeyEvent.VK_SEMICOLON){
if(e.getKeyCode() == KeyEvent.VK_A){
y-=10;
}
if(e.getKeyCode() == KeyEvent.VK_S){
y+=10;
}
if(e.getKeyCode() == KeyEvent.VK_QUOTE){
ytwo-=10;
}
if(e.getKeyCode() == KeyEvent.VK_SEMICOLON){
ytwo+=10;
}
}
}
Here is the full code
import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;
import java.util.Random;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Pong extends JFrame implements ActionListener{
//implement constants
PongPanel pongPanel = new PongPanel();
//JFrame pong x and y coordinates
static final int jfpX = 150;
static final int jfpY = 20;
// JFrame pong width and height
static final int jfpW = 800;
static final int jfpH = 600;
Thread thrd;
public static void main(String[] args) {
Pong jfp = new Pong();
jfp.setVisible(true);
}
public Pong(){
setBounds(jfpX,jfpY,jfpW,jfpH);
setTitle("Pong");
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBackground(Color.black);
add(pongPanel);
addKeyListener(pongPanel);
thrd = new Thread (pongPanel);
thrd.start();
}
public void actionPerformed(ActionEvent e) {
}
}
class PongPanel extends JPanel implements Runnable, KeyListener{
Random random = new Random();
static final int jpW = 800;
static final int jpH = 600;
int paddleStart = (jpH/2)-35;
int paddleStarttwo = (jpH/2)-35;
int ballStartX = (jpW/2)-20;
int ballStartY = (jpH/2)-20;
int ytwo,x,y;
int ballD = 30;
int paddleW1 = 20;
int paddleH1 = 100;
int paddleW2 = 20;
int paddleH2 = 100;
int min = -2;
int max = 2;
int randomBallx, randomBally;
// int randomBallx = random.nextInt(max-min+1)+min;
// int randomBally = random.nextInt(max-min+1)+min;
int rand1 = random.nextInt(2-1 + 1)+1; // random for function to determine ballx and bally
int rand2 = random.nextInt(2-1+2)+1;
int dx = 4;
int dy = 4; //direction of y
public void ballNotZero(){// makes sure the ball doesnt go straight up and down
if (randomBallx ==0){
randomBallx = random.nextInt(max-min+1)+min;
}
if(randomBally == 0){
randomBally=random.nextInt(max-min+1)+min;
}
// if(rand1 ==1){
// randomBallx=-1;
// }
// if(rand1 ==2){
// randomBallx=1;
// }
// if(rand2 ==1){
// randomBally =-1;
// }
// if(rand2==2){
// randomBally = 1;
// }
}
public PongPanel(){
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Color ball;
Color paddleOne;
Color paddleTwo;
ball = new Color(255,0,255);
paddleOne = new Color(255,0,0);
paddleTwo = new Color(0,0,255);
g.setColor(ball);
g.fillOval(ballStartX+randomBallx,ballStartY+randomBally,ballD,ballD);
g.setColor(paddleOne);
g.fillRect(20,paddleStart+y,paddleW1,paddleH1);
g.setColor(paddleTwo);
g.fillRect(760,paddleStarttwo+ytwo,paddleW2,paddleH2);
}
public void run() {
while(true){
ballNotZero();
detectPaddle();
randomBall();
ballMove();
repaint();
try {Thread.sleep(75); } catch(Exception e){
};
}
}
public static boolean intervallContains(int low, int high, int n) { //determines if something is in a certain range
return n >= low && n <= high;
}
public void detectPaddle(){ //determines if ball is close enough to paddle for detection
int withinY = (paddleStart+y) -(ballStartY+randomBally);
int withinY1 = (paddleStarttwo+ytwo)-(ballStartY+randomBally);
if (ballStartX+randomBallx <=20 && intervallContains(-50,50,withinY)){
dx = -dx;
}
if(ballStartX+randomBallx >=760 && intervallContains(-50,50,withinY1)){
dx = -dx;
}
}
public void randomBall(){
if(randomBallx >=0 ){
randomBallx+=dx;
}
if(randomBallx<0){
randomBallx-=dx;
}
if(randomBally>=0){
randomBally+=dy;
}
if(randomBally<0){
randomBally-=dy;
}
// randomBallx+=randomBallx;
// randomBally+=randomBally;
}
public void ballMove(){
if(ballStartY+randomBally > jpH-60){
dy= -dy;
}
if(ballStartY+randomBally <0){
dy = -dy;
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_A || e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_QUOTE || e.getKeyCode() == KeyEvent.VK_SEMICOLON){
if(e.getKeyCode() == KeyEvent.VK_A){
y-=10;
}
if(e.getKeyCode() == KeyEvent.VK_S){
y+=10;
}
if(e.getKeyCode() == KeyEvent.VK_QUOTE){
ytwo-=10;
}
if(e.getKeyCode() == KeyEvent.VK_SEMICOLON){
ytwo+=10;
}
}
}
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
Don't use while (true) but rather a Swing timer.
Don't use KeyListeners but rather Key Bindings.
Consider turning on a Swing Timer (which can act as your "background thread") that moves one paddle when the bindings detect the correct key has been pressed,
and stopping the timer that moves the paddle when the same key is released.
Same for the other paddle but of course having its actions respond to a bindings of a different pair of keys.
When attempting to get something like this working, try to get it working in a very simple program first, one without all the other junk required for your main program, but one which will allow you to test and prove your concept. Then if you get things working in your small program, great, you add the functionality to your main program. And if your small program code doesn't work and you need our help, you can post the small self-contained program here (an sscce) for us to test and modify.

Java - KeyListener Events not firing

I have begun to write a simple platform game in java. As a test, I wrote this simple
program that moves a rectangle around the applet when you press the arrow keys. The key events have not been firing at all. Here's the code:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Game extends Applet implements Runnable, KeyListener
{
//setup data
Thread t;
Image buffimg;
Graphics draw;
Dimension dim;
//game variables
int charx = 400;//rectangles X and Y positions
int chary = 50;
boolean leftArrow = false;
public void init()
{
setSize(800, 500);
t = new Thread(this);
t.start();
addKeyListener( this );
}
public void run()
{
while(true)
{
repaint();
moveChar();//move the rectangle
try {
t.sleep(1000/30);
} catch (InterruptedException e) { ; }
}
}
public void keyPressed( KeyEvent e )
{
int k = e.getKeyCode();
if(k == 37)
{
leftArrow = true;
charx--;
}
}
public void keyReleased( KeyEvent e )
{
if(e.getKeyCode() == 37)
{
leftArrow = false;
}
}
public void keyTyped( KeyEvent e )
{
}
public void moveChar()
{
//move rectangle on left arrow key press
if(leftArrow == true)
{
charx--;
}
}
public void paint(Graphics g)
{
g.drawRect(charx, chary, 100, 100);
}
public void update (Graphics g)
{
//double buffering
// initialize buffer
if (buffimg == null)
{
buffimg = createImage (this.getSize().width, this.getSize().height);
draw = buffimg.getGraphics ();
}
// clear screen in background
draw.setColor (getBackground ());
draw.fillRect (0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
draw.setColor (getForeground());
paint (draw);
// draw image on the screen
g.drawImage (buffimg, 0, 0, this);
}
}
Why aren't they firing and how should I fix this?
this.requestFocusInWindow(); // end of init(), or better, in start()
I tried your code. It works as it should.
The problem is you need to press the mouse on the drawing area to focus it first before it can receive events.
To do it automatically, use this command: requestFocusInWindow()

Categories