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.
Related
It's like if you were in a mirror maze, you might have trouble finding one specific reflections of yourself. So you would have multiple reflections of yourself, confusing you when you try to find that direct reflection of yourself.
Sadly I cannot post an image..........
So...
Character is "C"
It goes from
C
to
C C
when I attempt to move right.
package WASD;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.*;
public class WASD extends JFrame implements KeyListener, ActionListener{
private int playerX = 400;
private int playerY = 400;
int C = 1;
private int RESTART = 0; // Three ENTER = Restart
private Timer timer;
JFrame j = new JFrame();
private int previousX = -50;
private int previousY = -50;
public WASD() {
JPanel panel = new JPanel();
setTitle("Not supposed to be a painting program.");
setSize(2000, 2000);
timer = new Timer(8, this);
this.getContentPane().add(panel);
addKeyListener(this);
setVisible(true);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args){
WASD W = new WASD();
}
public void paint(Graphics g) { //TODO paint is only working once, then failing forever.
//////////////////////////
g.setColor(Color.BLACK);
g.drawRect(0, 0, 3000, 3000); // Background
if(C == 1) g.setColor(Color.RED);
else if (C == 2) g.setColor(Color.BLUE);
else if (C == 3) g.setColor(Color.GREEN);
else if (C == 4) g.setColor(Color.YELLOW);
else if(C>4){
g.setColor(Color.GRAY);
try {
Thread.sleep(1000); //Gray pauses for a second I guess...
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
C = 1;
}
g.fillRect(playerX, playerY, 50, 50); // Player/
g.setColor(Color.BLACK);
g.fillRect(previousX, previousY, 50, 50);
g.dispose(); //Last thing
}
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
repaint();
}
#Override
public void keyPressed(KeyEvent K) {
// TODO Auto-generated method stub
int e = K.getKeyCode();
repaint(); //timer.start(); does not affect this. g.dispose() is unavailable.
/*
If this repaint is used, then the previous locations
that the player was at will be painted as well.
Basically, instead of moving, all instances
made will not be deleted. #PaintingApplication
However, if it is not used, then the CHARACTER will not move at all.
It seems that the problem is not about
playerX, or playerY,
instead, it is about the program not refreshing.
*/
if((e == KeyEvent.VK_RIGHT || e == KeyEvent.VK_D) && playerX<2000){
playerX += 200;
}
else if((e == KeyEvent.VK_LEFT || e == KeyEvent.VK_A) && playerX>0){
playerX -= 200;
}
else if((e == KeyEvent.VK_UP || e == KeyEvent.VK_W) && playerY>0){
playerY -= 200;
}
else if(e == KeyEvent.VK_DOWN || e == KeyEvent.VK_S && playerY<2000){ // Easter egg bug 1
playerY += 200;
}
else if (e == KeyEvent.VK_C){
C++;
}
else if(e == KeyEvent.VK_ENTER){
if(RESTART == 3){
playerX = 400;
playerY = 400;
RESTART = 0; //TODO
repaint();
}
else{
RESTART++;
}
}
else{
RESTART = 0;
}
}
#Override public void keyTyped(KeyEvent arg0) {}
#Override public void keyReleased(KeyEvent arg0) {}
}
I apologize for making such a simple mistake. The problem is in the function "paint". The line
g.drawRect(0, 0, 3000, 3000); //Outline of Rectangle
should be
g.fillRect(0, 0, 3000, 3000); //Actually filling the background.
I have a simple program with three rectangles: one that can move with the push of the arrow keys, and two that are already moving back and forth on their own.
When the 'player' rectangle and top red collide, the player driven rectangle gets put back to (0,0). When I try to collide the player rectangle with the bottom red rectangle, it does not have those collision properties and I have no idea why.
What am I missing?
import java.awt.*;//needed for graphics
import javax.swing.*;//needed for JFrame window
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class javaapplication23 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 javaapplication23() {//constructor for JPanel
add(new JP());
}//close Jpanel Contructor
public static void main(String[] args) {
javaapplication23 w = new javaapplication23();
w.setTitle("MIKE IS AWESOME");
w.setSize(Toolkit.getDefaultToolkit().getScreenSize());
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
w.setVisible(true);
w.addKeyListener(w);
}
public class JP extends JPanel {//start JPanel CLass
public JP() {
Container c = getContentPane();
c.setBackground(Color.white);//backgraund color can be changed
}
public void paint(Graphics g) {//opens paint method
super.paint(g);
player(g, x, y);
g.setColor(Color.RED);
enemylevel1(g, x2, y2);
Rectangle enemyblocks = new Rectangle(x2, y2, 25, 25);
Rectangle player = new Rectangle(x, y, 25, 25);
enemyblocks.contains(x2, y2);
player.contains(x, y);
if (player.getBounds().intersects(enemyblocks.getBounds())) {
x = 0;
y = 0;
}
pause(1);
repaint();
}//close paint method
}//close JPanel Class
public static void pause(int time) {
try //opens an exception handling statement
{
Thread.sleep(time);
} catch (InterruptedException e) {
} //captures the exception
}
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;//global variable controlling right movement
repaint();
}
if (e.getKeyCode() == e.VK_LEFT) {
x -= 20;//global variable controlling left movement
repaint();
}
if (e.getKeyCode() == e.VK_UP) {
y -= 20;//global variable controlling up movement
repaint();
}
if (e.getKeyCode() == e.VK_DOWN) {
y += 20;//global variable controlling down movement
repaint();
}
}
public void player(Graphics g, int x, int y) {
g.fillRect(x, y, 30, 30);
}
public void enemylevel1(Graphics g, int x, int y) {
g.fillRect(x2, y2, 25, 25);
g.fillRect(x2, y2 + 100, 25, 25);
if (x2 < 200 && y2 == 100) {
x2 += 1;
}
if (x2 == 200 && y2 >= 100) {
y2 += 1;
}
if (x2 <= 200 && y2 >= 101) {
x2 -= 1;
}
if (x2 == 100 && y2 <= 101) {
y2 -= 1;
}
pause(10);
repaint();
}
}
Start by having a look at Working with Geometry, this will allow you to reduce much of the code complexity.
Basically, a enemy is just a Rectangle, Graphics2D can paint these without to much of an issue. What you need to do is create an instance which can also update it's position based on your needs
public class Enemy extends Rectangle {
private int xDelta;
public Enemy(int x, int y) {
super(x, y, 20, 20);
if (x == 0) {
xDelta = 1;
} else {
xDelta = -1;
}
}
public void update(Rectangle bounds) {
x += xDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x > bounds.x + bounds.width - width) {
x = bounds.x + bounds.width - width;
xDelta *= -1;
}
}
}
So, this creates a single unit of work, which is isolated from everything else and carries it's own logic with it. This makes updating it, painting and generally working with much simpler.
Next, you need to create a List of these
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
//...
public Bounce() {
enemies = new ArrayList<>(5);
int y = 100;
for (int index = 0; index < 5; index++) {
int x = (index % 2 == 0) ? 0 : 200;
Enemy enemy = new Enemy(x, y);
enemies.add(enemy);
y += 60;
}
This creates a List of Enemys which are distributed evenly within the container.
Now, we need to paint them....
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
}
}//close paint method
nb: General convention suggests that you should override paintComponent when you want to perform custom painting
But they don't move, that kind of sucks. So we need a way to, on a regular bases, update the position of the enemies...
First, we create a simple method which we can call to update the enemies, remember, they are capable of updating themselves, we just need to tell them when
public void updateState() {
Rectangle bounds = new Rectangle(20, 20, 200, 200);
for (Enemy enemy : enemies) {
enemy.update(bounds);
}
}
Remember, the Enemy is self contained, it knows how to update itself based on the constraints you have provided.
And now, we need to call this method on a regular bases...
javax.swing.Timer timer = new javax.swing.Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
repaint();
}
});
timer.start();
Okay, this will schedule a callback every 40 milliseconds which will allow us to call the updateState method and repaint the component. This is neat because it won't block the Event Dispatching Thread (making our program look like it's hung) but which notifies us within the context of the EDT, making it safe to update the UI from within - WIN/WIN :)
Take a look at Concurrency in Swing and How to use Swing Timers for more details.
Okay, but that doesn't solve the collision...
The player is also a Rectangle, so why not use the same concept we have with the enemies...
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
private Rectangle player;
//...
public Bounce() {
player = new Rectangle(0, 0, 30, 30);
enemies = new ArrayList<>(5);
//...
}
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawPlayer(g2d);
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
if (player.intersects(enemy)) {
player.x = 0;
player.y = 0;
}
}
}//close paint method
public void drawPlayer(Graphics2D g) {
g.fill(player);
}
Which ends up with something like...
This allows you to add/remove enemies as you want and also change the way in which the enemies move, simply and easily
An my "awesome" test code...
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.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Bounce extends JPanel implements KeyListener, ActionListener {
private List<Enemy> enemies;
private Rectangle player;
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) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Bounce());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public Bounce() {
player = new Rectangle(0, 0, 30, 30);
enemies = new ArrayList<>(5);
int y = 100;
for (int index = 0; index < 5; index++) {
int x = (index % 2 == 0) ? 0 : 200;
Enemy enemy = new Enemy(x, y);
enemies.add(enemy);
y += 60;
}
setBackground(Color.white);//backgraund color can be changed
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
repaint();
}
});
timer.start();
setFocusable(true);
requestFocusInWindow();
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
requestFocusInWindow();
}
});
addKeyListener(this);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(240, 400);
}
#Override
protected void paintComponent(Graphics g) {//opens paint method
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
drawPlayer(g2d);
g2d.setColor(Color.RED);
for (Enemy enemy : enemies) {
g2d.fill(enemy);
if (player.intersects(enemy)) {
player.x = 0;
player.y = 0;
}
}
}//close paint method
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) {
player.x += 20;//global variable controlling right movement
}
if (e.getKeyCode() == e.VK_LEFT) {
player.x -= 20;//global variable controlling left movement
}
if (e.getKeyCode() == e.VK_UP) {
player.y -= 20;//global variable controlling up movement
}
if (e.getKeyCode() == e.VK_DOWN) {
player.y += 20;//global variable controlling down movement
}
}
public void drawPlayer(Graphics2D g) {
g.fill(player);
}
public void updateState() {
Rectangle bounds = new Rectangle(20, 20, 200, 200);
for (Enemy enemy : enemies) {
enemy.update(bounds);
}
}
public class Enemy extends Rectangle {
private int xDelta;
public Enemy(int x, int y) {
super(x, y, 20, 20);
if (x == 0) {
xDelta = 1;
} else {
xDelta = -1;
}
}
public void update(Rectangle bounds) {
x += xDelta;
if (x < bounds.x) {
x = bounds.x;
xDelta *= -1;
} else if (x > bounds.x + bounds.width - width) {
x = bounds.x + bounds.width - width;
xDelta *= -1;
}
}
}
}
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
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 wrote a Java program that has 3 classes:
main.class (main method class)
Infout.class (class that draws circle + methods for circle that allow it to be controlled with keyboard input (arrow keys)
obj2.class (class that draws a rectangle)
All the code is compiled fine, but for some reason when I run the program, the program executes all the code from obj2.class but does not execute the one from Infout.class.
In other words, it draws the rectangle (obj2.class) but it does not draw the controllable circle (Infout.class). Is Obj2.class over riding Infout.class? If it is, what should I do?
The code is much too big to post here, the website says the post is "mostly code" :c.
Thanks!
EDIT: Ok here's the relevant code:
main.class
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(m);
frame.add(o);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 400);
frame.setTitle("Circle");
}
}
Infout.class
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);
}
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) {
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.class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class obj2 extends JPanel{
int x;
int y;
public obj2(){
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(10, 20, 40, 40));
}
}
Infout and obj2 are not related.
Because obj2 extends JPanel, the call super.paintComponent(g) calls JPanel's version. If you obj2 to be a subclass of Infout, then you need to use extends:
public class obj2 extends Infout {
// Code here
}
Once this is done, super will refer to Infout.