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
Related
I have managed to push the other object but not the way I want it to, what I was trying to do is to push the other object towards the direction where I am pushing to other object like when you push a box or something. But in this case, I can't quite get how to push the other object to the same direction I am pushing it.
In this case: Box 1 pushing Box 2 from the -x(left) direction so the Box 2 will go towards the +x(right) direction and same with box 1 pushing box 2 from the -y(down) direction then box 2 will go towards +y(up) direction.
Here is the code:
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Main2 extends JFrame implements KeyListener, ActionListener {
public static int x = 0;
public static int y = 0;
public static int x2 = 100;
public static int y2 = 100;
public Main2() {
add(new panel());
}
public static void main(String[] args) {
Main2 test = new Main2();
test.setTitle("TEST");
test.setSize(Toolkit.getDefaultToolkit().getScreenSize());
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setVisible(true);
test.addKeyListener(test);
}
public class panel extends JPanel {
public panel() {
Container c = getContentPane();
c.setBackground(Color.white);
}
public void paint(Graphics g) {
super.paint(g);
object1(g, x, y);
g.setColor(Color.RED);
object2(g, x2, y2);
Rectangle object1 = new Rectangle(x, y, 25, 25);
Rectangle object2 = new Rectangle(x2, y2, 50, 50);
object1.contains(x, y);
object2.contains(x2, y2);
if (object1.intersects(object2.getX(), object2.getX(), object2.getX(), object2.getX())) {
x2 += 50;
y2 += 0;
}
pause(1);
repaint();
}
}
public static void pause(int time) {
try
{
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
public void actionPerformed(ActionEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_RIGHT) {
x += 20;
repaint();
}
if (e.getKeyCode() == e.VK_LEFT) {
x -= 20;
repaint();
}
if (e.getKeyCode() == e.VK_UP) {
y -= 20;
repaint();
}
if (e.getKeyCode() == e.VK_DOWN) {
y += 20;
repaint();
}
}
public void object1(Graphics g, int x, int y) {
g.fillRect(x, y, 30, 30);
}
public void object2(Graphics g, int x, int y) {
g.fillRect(x2, y2, 50, 50);
}
}
One option would be to keep track of the direction the box is moving:
enum Direction {NONE, LEFT, RIGHT, UP, DOWN};
Direction dir = Direction.NONE;
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == e.VK_RIGHT) {
x += 20;
dir = Direction.RIGHT;
repaint();
}
if (e.getKeyCode() == e.VK_LEFT) {
x -= 20;
dir = Direction.LEFT;
repaint();
}
if (e.getKeyCode() == e.VK_UP) {
y -= 20;
dir = Direction.UP;
repaint();
}
if (e.getKeyCode() == e.VK_DOWN) {
y += 20;
dir = Direction.DOWN;
repaint();
}
}
Then, when you intersect with the other rectangle, move accordingly:
if (object1.intersects(object2)) {
if (dir == Direction.RIGHT) x2 += 50;
else if (dir == Direction.LEFT) x2 -= 50;
else if (dir == Direction.DOWN) y2 += 50;
else if (dir == Direction.UP) y2 -= 50;
}
I am build a graph, with a while circle moving along a line, and stoping over for a few seconds at 3 points of the path.
I have managed to do it, however, it does not display the circle moving, it displays only when the circle stops...
I can't understand why.
Many thanks in advance for your help
Here is my code:
public class Robot0 extends JFrame implements ActionListener {
public Robot0(String nom, int larg, int haut) {
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
Timer tm = new Timer(10, this);
private int posX = 0;
private int posY = 0;
private int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
tm.start();
}
int segment = 0;
public void actionPerformed(ActionEvent e) {
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0) {
segment = 1;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0) {
segment = 3;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100) {
segment = 6;
try {
Thread.sleep(15000);
} catch (InterruptedException ex) {
Logger.getLogger(Robot0.class.getName()).log(Level.SEVERE, null, ex);
}
}
repaint();
}
// Build the Panel
public static void main(String[] args) {
Robot0 r = new Robot0("Robot0", 800, 600);
}
}
Swing is a single Thread library. All painting tasks are executed in the Event Dispatcher Thread
(EDT).
As commented by Andrew Thompson, running long processes (such as sleep) on the EDT makes keeps this thread busy, so it does not do other things
like updating the gui.
The gui becomes unresponsive (freezes).
So the first thing to do is to remove all sleeping.
To park at each stop, use a second timer:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame implements ActionListener {
private static final int PARKING_TIME = 15000;
Timer moveTimer , waitTimer;
private boolean isParking = false;
public Robot0(String nom, int larg, int haut) {
moveTimer = new Timer(10, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
setTitle(nom);
setSize(larg, haut);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private int posX = 0;
private int posY = 0;
private final int velX = 1;
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.BLACK);
// Draw the pathway
int xt[] = { 50, 50, 250, 250, 350, 350 };
int yt[] = { 50, 150, 150, 50, 50, 150 };
g.drawPolyline(xt, yt, 6);
// On the pathway, draw 3 squares (the 3 rooms)
g.setColor(Color.GREEN);
g.drawRect(35, 135, 30, 30);
g.drawRect(235, 35, 30, 30);
g.drawRect(335, 135, 30, 30);
g.setColor(Color.WHITE);
g.fillOval(40 + posX, 40 + posY, 20, 20);
g.setColor(Color.RED);
g.drawLine(45 + posX, 50 + posY, 55 + posX, 50 + posY);
g.drawLine(50 + posX, 45 + posY, 50 + posX, 55 + posY);
moveTimer.start();
}
int segment = 0;
#Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
// move along the 1st segment
if (posY < 100 && segment == 0) {
setPosY(posY + velX);
}
if (posY == 100 && posX == 0 && segment != 1) { //!=1 so it will not be invoked again
segment = 1;
isParking = true; //flag that robot is parking
waitTimer.start();
return;
}
// move along the second segment
if (posX <= 200 && segment == 1) {
setPosX(posX + velX);
}
if (posX == 200 && posY == 100) {
segment = 2;
}
// move along the third segment
if (posY > 0 && segment == 2) {
setPosY(posY - velX);
}
if (posX == 200 && posY == 0 && segment !=3) {
segment = 3;
isParking = true;
waitTimer.start();
return;
}
// move along the fourth segment
if (posX < 300 && segment == 3) {
setPosX(posX + velX);
}
if (posX == 300 && posY == 0) {
segment = 4;
}
// move along the fifth segment
if (posY < 100 && segment == 4) {
setPosY(posY + velX);
}
if (posX == 300 && posY == 100 && segment !=6) {
segment = 6;
isParking = true;
waitTimer.start();
return;
}
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0", 800, 600));
}
}
TODO:
Implement custom painting on JPanel.
Simplify actionPerformed
logic
Edit: the following is an implementation with some improvements not necessarily related to question asked:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Robot0 extends JFrame {
public Robot0(String nom) {
setTitle(nom);
setLocationRelativeTo(null);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new Floor());
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()->new Robot0("Robot0"));
}
}
class Floor extends JPanel implements ActionListener{
private static final int PARKING_TIME = 5000, REPAINT_TIME = 10, W = 400, H = 200;
private static final int ROOM_SIZE = 30, ROBOT_SIZE = 20, CROSS_SIZE = 10;
private final Timer moveTimer , waitTimer;
private boolean isParking = false;
private int posX = 0, posY = 0;
private final int velX = 1;
// pathway
private static final int PATH_X[] = { 50, 50, 250, 250, 350, 350 };
private static final int PATH_Y[] = { 50, 150, 150, 50, 50, 150 };
//rooms
private static final Point[] ROOM_CENTERS = {new Point(PATH_X[1],PATH_Y[1]),
new Point(PATH_X[3],PATH_Y[3]),
new Point(PATH_X[5],PATH_Y[5]) };
Floor() {
moveTimer = new Timer(REPAINT_TIME, this);
waitTimer = new Timer(PARKING_TIME, e-> isParking = false);
waitTimer.setRepeats(false);
posX = PATH_X[0]; posY = PATH_Y[0];
setPreferredSize(new Dimension(W, H));
moveTimer.start(); //no need to restart with every paint
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawPolyline(PATH_X, PATH_Y, 6);
// draw rooms
g.setColor(Color.GREEN);
for(Point center : ROOM_CENTERS){
drawSquareAround(center, g);
}
//robot
g.setColor(Color.WHITE);
g.fillOval( posX - ROBOT_SIZE/2 , posY - ROBOT_SIZE/2 , ROBOT_SIZE, ROBOT_SIZE);
//cross
g.setColor(Color.RED);
g.drawLine(posX - CROSS_SIZE/2, posY, posX + CROSS_SIZE/2, posY);
g.drawLine(posX, posY - CROSS_SIZE/2, posX, posY + CROSS_SIZE/2);
}
private void drawSquareAround(Point center, Graphics g) {
g.drawRect(center.x - ROOM_SIZE/2, center.y - ROOM_SIZE/2, ROOM_SIZE, ROOM_SIZE);
}
#Override
public void actionPerformed(ActionEvent e) {
if(isParking) return; //execute only when not parking
if (posX <= PATH_X[0] && posY < PATH_Y[1]) {// move along the 1st segment
setPosY(posY + velX);
}else if (posX < PATH_X[2] && posY == PATH_Y[1]) { //move along the second segment
setPosX(posX + velX);
}else if (posX == PATH_X[2] && posY > PATH_Y[3]) { //move along the third segment
setPosY(posY - velX);
}else if (posY == PATH_Y[3] && posX < PATH_X[4]) {// move along the fourth segment
setPosX(posX + velX);
}else if (posX == PATH_X[4] && posY < PATH_Y[5]){// move along the fifth segment
setPosY(posY + velX);
}else {
moveTimer.stop(); //move finished, stop repainting
return;
}
//park if at room center
if(isRoomCeter()){
park();
}
repaint();
}
private void park() {
isParking = true; //flag that robot is parking
waitTimer.start();
}
private boolean isRoomCeter() {
for (Point center : ROOM_CENTERS){
if(posX == center.x && posY == center.y) return true;
}
return false;
}
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}
I'm creating a Java game for fun and I want to add many things to a JFrame at once. But for some reason, one class and the main method class executes, but the third class containing the second object I want to add doesn't execute. I'm still new to Java so I might get some terms wrong.
Basically I have 3 classes:
main.java (main method class + JFrame constructor class)
Infout.java (class that draws a keyboard-controlled circle + some stationary rectangles)
obj2.java (class that draws a second stationary circle)
Here is the code:
main.java
import javax.swing.JFrame;
public class main
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
Infout m = new Infout();
obj2 o = new obj2();
frame.add(o);
frame.add(m);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
frame.setSize(300, 400);
frame.setTitle("Circle");
}
}
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) {
System.out.println("sum1 has reached tha corner");
g.drawString("You win!",115,35);
}
if (x <= 120 && y >= 270) {
System.out.println("sum1 has reached tha corner");
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) {}
}
obj2.java
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class obj2 extends JPanel {
public void paintComponent(Graphics g1)
{
super.paintComponent(g1);
Graphics2D g3 = (Graphics2D)g1;
Ellipse2D circle = new Ellipse2D.Double(50.0D, 50.0D, 40.0D, 40.0D);
g3.fill(circle);
}
public obj2(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
So basically, I get no compile errors, but even though I created an instance of each class variable in the main method, and added them both to the JFrame, they cannot both execute at once. If I comment out obj2 from the main method, Infout will show up. If I comment out Infout from the main method, obj2 will show up. But not both at once. If I try both at once, only Infout shows up.
As you may have saw, I thought maybe it had something to do with multithreading so I added some code for multithreading that you may have noticed but I'm sure it's wrong since I only learned about multithreading like an hour ago.
May someone pleeeease help me figure this out? I've tried everything I know to solve it, but it just won't work :C.
I would absolutely LOVE example code of maybe a simple program you guys could quickly whip up showing me how this works. I would even love more if you could explain why/how it works the way it does. I like learning! :)
Thanks!
Ab
By default a JFrame uses a BorderLayout. When you use the add(...) method without a constraint the component will be added tot he CENTER or the BorderLayout. However, only one component (panel) can be displayed in the CENTER, so only the last panel added is visible.
Read the section from the Swing tutorial on How to Use the BorderLayout for more information and examples.
Generally when I see code like you have you can display the components on top of one another with code like:
panel1.add( panel2 );
frame.add( panel1 );
Or if you want the coponents side by side then you can change the layout manager of the content pane to use a FlowLayout. Again, read the tutorial. There are examples for the FlowLayout and other layout managers.
I created an oval which shoots a bullet(rectangle) that if it hits the red rectangle, the collision would detect the bullet hitting the rectangle. However, when I run my program, the collision has already been done and I haven't even pressed the space bar yet to shoot. What I wanted to happen is that, when I shoot and if the bullet hits the rectangle, that's when it detects the collision. I tried to analyze it and do something but I just couldn't get it. here is my source code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JavaGame2 extends JPanel implements KeyListener,Runnable{
//variables
JFrame frame;
int x, y, xDir, yDir,bx,by;
Rectangle bullet;
boolean readyTofire, shot = false;
//constructor for game
public JavaGame2(){
frame = new JFrame("Java Game");
int x=150;
int y=150;
}
//drawings
public void paintComponent(Graphics g){
super.paintComponent(g);
this.setBackground(Color.WHITE);
Rectangle rec = new Rectangle(50, 20, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(x, y, 55, 55);
g.fillRect(x+23, y-15, 10, 20);
g.setColor(Color.RED);
g.fillRect(rec.x, rec.y, rec.width, rec.height);
bullet = new Rectangle(bx, by, 5, 3);
if(shot){
g.setColor(Color.BLACK);
g.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
}
if(bullet.intersects(rec));
g.drawString("collision!", 50, 20);
repaint();
}
public void setxDir(int xdir){
xDir = xdir;
}
public void setyDir(int ydir){
yDir = ydir;
}
//key event listener keypressed
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_UP){
setyDir(-1);
}
if(code == KeyEvent.VK_DOWN){
setyDir(+1);
}
if(code == KeyEvent.VK_LEFT){
setxDir(-1);
}
if(code == KeyEvent.VK_RIGHT){
setxDir(+1);
}
if(code == KeyEvent.VK_SPACE){
if(bullet == null ){
readyTofire = true;
if(readyTofire){
bx = x+26;
by = y-15;
bullet = new Rectangle(bx, by, 5, 3);
shot = true;
}
}
}
}
//key event listener for key released
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if(code == KeyEvent.VK_UP){
setyDir(0);
}
if(code == KeyEvent.VK_DOWN){
setyDir(0);
}
if(code == KeyEvent.VK_LEFT){
setxDir(0);
}
if(code == KeyEvent.VK_RIGHT){
setxDir(0);
}
if(code == KeyEvent.VK_SPACE){
readyTofire = false;
if(bullet.y <= -5){
bullet = new Rectangle(0, 0, 0, 0);
shot = false;
readyTofire = true;
}
}
}
public void keyTyped(KeyEvent e) {
}
//shot of bullet
public void shoot(){
if(shot){
bullet.y--;
}
}
//movement of the oval
public void move(){
x += xDir;
y += yDir;
if(x <= 0){
x = 0;
}
else if(x >= 500){
x = 500;
}
else if(y <= 0){
y = 0;
}
else if(y >= 500){
y = 500;
}
}
//thread
public void run() {
try{
while(true){
shoot();
move();
Thread.sleep(5);
}
}
catch(Exception e){
System.out.println("error!");
}
}
}
Take a moment to have a look at you collision detection statement...
if (bullet.intersects(rec));
g.drawString("collision!", 50, 20);
The problem is, you've ended your if statement with a ;
if (bullet.intersects(rec));
^---
This means that the statement is effectively ignored, it would be the same as...
if (bullet.intersects(rec)) {
}
g.drawString("collision!", 50, 20);
Which would have alerted you to the problem in the first place
Instead, try using
if (bullet.intersects(rec)) {
g.drawString("collision!", 50, 20);
}
Now, don't call repaint or any method that might call repaint (like setBackground) from any paint method. This will set up a cycle of repeated paint events that will eventually consume your CPU.
I don't think you really need 200fps and Thread.sleep of roughly 40 would give you 25fps and would typically be more then adequate for your purposes.
You should also consider using key bindings, which will allow you to over come the focus related issues of KeyListener.
I'd also encourage you to explore the use of a Swing Timer which will reduce the possibility of un-synchorised updates between the model and the view, which could cause random and difficult to solve artificates or other issues...
Shooting Problems
There's a bunch of logic issues and mis-use of variables...
To start with...
Remove bx and by, you don't need them. You actually don't really need x and y either, but that might be come a little more apparent as we go...
Don't create bullet in paintComponent, this is causing some confusion...
You may not need the keyReleased check of VK_SPACE but if you did, you should set shot to false and bullet to null...
Setting readyToFire to true right before you check to see if it's true seems weird...however, when you detect a VK_SPACE in keyPressed check to see if bullet is null or not, if it's not, then a bullet already exist, don't know if this is an issue, but if you were to use a List, you could have multiple bullets firing at the same time...any way, create a new Rectangle and assign to to bullet
if (code == KeyEvent.VK_SPACE) {
readyTofire = true;
if (readyTofire) {
int bx = x + 26;
int by = y - 15;
bullet = new Rectangle(bx, by, 5, 3);
shot = true;
}
}
In you shoot method, do forget to do a bounds check...
public void shoot() {
if (shot) {
bullet.y--;
// Have we past the edge of the screen
if (bullet.y < 0) {
shot = false;
bullet = null;
}
}
}
And finally, paint it all...Here you should be taking advantage of the 2D Graphics API
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle rec = new Rectangle(50, 20, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(x, y, 55, 55);
g.fillRect(x + 23, y - 15, 10, 20);
g.setColor(Color.RED);
g.fillRect(rec.x, rec.y, rec.width, rec.height);
if (shot && bullet != null) {
g2d.setColor(Color.BLACK);
g2d.fill(bullet);
if (bullet.intersects(rec)) {
g2d.drawString("collision!", 50, 20);
}
}
g2d.dispose();
}
And in case I missed anything, here's you the code I tested with...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class JavaGame2 extends JPanel implements KeyListener, Runnable {
//variables
int x, y, xDir, yDir;
Rectangle bullet;
boolean readyTofire, shot = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JavaGame2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
//constructor for game
public JavaGame2() {
int x = 150;
int y = 150;
this.setBackground(Color.WHITE);
setFocusable(true);
addKeyListener(this);
requestFocusInWindow();
Thread t = new Thread(this);
t.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
//drawings
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Rectangle rec = new Rectangle(50, 20, 50, 50);
g.setColor(Color.BLUE);
g.fillOval(x, y, 55, 55);
g.fillRect(x + 23, y - 15, 10, 20);
g.setColor(Color.RED);
g.fillRect(rec.x, rec.y, rec.width, rec.height);
if (shot && bullet != null) {
g2d.setColor(Color.BLACK);
g2d.fill(bullet);
if (bullet.intersects(rec)) {
g2d.drawString("collision!", 50, 20);
}
}
g2d.dispose();
}
public void setxDir(int xdir) {
xDir = xdir;
}
public void setyDir(int ydir) {
yDir = ydir;
}
//key event listener keypressed
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
setyDir(-1);
}
if (code == KeyEvent.VK_DOWN) {
setyDir(+1);
}
if (code == KeyEvent.VK_LEFT) {
setxDir(-1);
}
if (code == KeyEvent.VK_RIGHT) {
setxDir(+1);
}
if (code == KeyEvent.VK_SPACE) {
readyTofire = true;
if (readyTofire) {
int bx = x + 26;
int by = y - 15;
bullet = new Rectangle(bx, by, 5, 3);
shot = true;
}
}
}
//key event listener for key released
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
setyDir(0);
}
if (code == KeyEvent.VK_DOWN) {
setyDir(0);
}
if (code == KeyEvent.VK_LEFT) {
setxDir(0);
}
if (code == KeyEvent.VK_RIGHT) {
setxDir(0);
}
// if (code == KeyEvent.VK_SPACE) {
// readyTofire = false;
// if (bullet.y <= -5) {
// bullet = new Rectangle(0, 0, 0, 0);
// shot = false;
// readyTofire = true;
//
// }
// }
}
public void keyTyped(KeyEvent e) {
}
//shot of bullet
public void shoot() {
if (shot) {
bullet.y--;
if (bullet.y < 0) {
shot = false;
bullet = null;
}
}
}
//movement of the oval
public void move() {
x += xDir;
y += yDir;
if (x <= 0) {
x = 0;
} else if (x >= 500) {
x = 500;
} else if (y <= 0) {
y = 0;
} else if (y >= 500) {
y = 500;
}
}
//thread
public void run() {
try {
while (true) {
shoot();
move();
repaint();
Thread.sleep(40);
}
} catch (Exception e) {
System.out.println("error!");
}
}
}
No offense, but you approach is a little primitive. Instead of containing the entire game model within the same class that is trying to display it, you should separate your game "logic" into a model and update the model state and then simply have your view paint the model...IMHO
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.