So I have been trying to get into making very simple games in Java. I have been having success when I make the entire program in one class, but whenever I try to add object oriented principles everything falls apart. What I want is for a bullet to launch from my good guy, which is more or less a turret. I can set up something like this with ease, but when I try to do so using classes to represent the good guy and the bullet everything falls apart. Here is what I have so far. Sets up the main program frame:
import javax.swing.JFrame;
public class Shooter
{
public static void main (String[] args)
{
JFrame frame = new JFrame("Car");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ShooterPanel panel = new ShooterPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
ShooterPanel class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ShooterPanel extends JPanel
{
final int WIDTH = 200, HEIGHT = 100;
GoodGuy hero;
public ShooterPanel()
{
hero = new GoodGuy(0, HEIGHT-20, 20);
addKeyListener(new MoveListener());
setPreferredSize(new Dimension (WIDTH, HEIGHT));
setFocusable(true);
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
hero.draw(page);
}
private class MoveListener implements KeyListener
{
public void keyPressed (KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.VK_SPACE:
hero.shoot();
break;
}
}
//--------------------------------------------------------------
//Provide empty definitions for unused event methods.
//--------------------------------------------------------------
public void keyTyped (KeyEvent event) {}
public void keyReleased (KeyEvent event) {}
}
}
Our protagonist:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GoodGuy
{
private int x, y, size;
private Bullet bullet;
public GoodGuy(int x, int y, int height)
{
size = height;
this.x = x;
this.y = y;
}
public int getSize()
{
return size;
}
public void draw(Graphics page)
{
page.drawRect(x, y, size, size);
}
public void shoot()
{
bullet = new Bullet(x+size, y);
}
}
And his bullet:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Bullet
{
private int x, y;
final int LENGTH = 5, DELAY =200;
private Timer timer;
Graphics page1;
public Bullet(int x, int y)
{
this.x = x;
this.y = y;
timer = new Timer(DELAY, new BulletListener());
timer.start();
}
public void draw(Graphics page)
{
page.drawLine (x, y, x+LENGTH, y);
}
//*****************************************************************
// Represents the action listener for the timer.
//*****************************************************************
private class BulletListener implements ActionListener
{
public void actionPerformed (ActionEvent event)
{
x +=5;
draw(page1);
}
}
}
What I would like to happen is for the space bar to be pressed, a bullet to appear by the good guy, and for it to move across the screen to the right. I can't get the bullet to draw at all. I have tried several things, all to no avail. I'm sure this is very easy. As I've said I could do this all in my ShooterPanel class using variables to draw the bullet rather than creating objects, but I want to go object-oriented. Does anyone have a solution for me? I would greatly appreciate some help, but am looking for a solution. Please, if you are just going to give a vague suggestion I would prefer no response. EDIT: Here's how I want my program to work:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class ShooterPanel extends JPanel
{
final int WIDTH = 200, HEIGHT = 100;
GoodGuy hero;
ArrayList<BadGuy> enemies = new ArrayList<BadGuy>();
ArrayList<Bullet> bullets = new ArrayList<Bullet>();
private Timer timer, bulletTimer;
final int DELAY = 200;
int count=0;
private boolean bulletOut = false;
public ShooterPanel()
{
hero = new GoodGuy(0, HEIGHT-20, 20);
addKeyListener(new MoveListener());
timer = new Timer(DELAY, new EnemyListener());
bulletTimer = new Timer(100, new BulletListener());
setPreferredSize(new Dimension (WIDTH, HEIGHT));
//enemies.add(new BadGuy(WIDTH-10, HEIGHT-10));
setFocusable(true );
timer.start();
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
hero.draw(page);
for (int i = 0; i < enemies.size(); i++)
{
enemies.get(i).draw(page);
}
if (bulletOut)
for(Bullet bullet: bullets)
bullet.draw(page);
}
private class MoveListener implements KeyListener
{
//--------------------------------------------------------------
//Responds to the user pressing arrow keys by adjusting the
//image and image location accordingly.
//--------------------------------------------------------------
public void keyPressed (KeyEvent event)
{
switch (event.getKeyCode())
{
case KeyEvent.VK_SPACE:
bullets.add(new Bullet(20,95));
bulletOut = true;
bulletTimer.start();
break;
}
}
//--------------------------------------------------------------
//Provide empty definitions for unused event methods.
//--------------------------------------------------------------
public void keyTyped (KeyEvent event) {}
public void keyReleased (KeyEvent event) {}
}
//*****************************************************************
// Represents the action listener for the timer.
//*****************************************************************
private class EnemyListener implements ActionListener
{
//--------------------------------------------------------------
// Updates the position of the image and possibly the direction
// of movement whenever the timer fires an action event.
//--------------------------------------------------------------
public void actionPerformed (ActionEvent event)
{
if (count%20==0)
enemies.add(new BadGuy(WIDTH-10, HEIGHT-10));
for (BadGuy enemy: enemies)
{
enemy.move();
}
count++;
repaint();
}
}
private class BulletListener implements ActionListener
{
//--------------------------------------------------------------
// Updates the position of the image and possibly the direction
// of movement whenever the timer fires an action event.
//--------------------------------------------------------------
public void actionPerformed (ActionEvent event)
{
for(Bullet bullet: bullets)
bullet.move();
for(int i = 0; i < bullets.size(); i++)
{
if (enemies.size() != 0)
{
if (bullets.get(i).getX() > enemies.get(0).getX())
{
bullets.remove(i);
enemies.remove(0);
}
}
if (bullets.size() != 0)
{
if (bullets.get(i).getX()>WIDTH)
bullets.remove(i);
}
}
repaint();
}
}
}
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GoodGuy
{
private int x, y, size;
private Bullet bullet;
public GoodGuy(int x, int y, int height)
{
size = height;
this.x = x;
this.y = y;
}
public int getSize()
{
return size;
}
public void draw(Graphics page)
{
page.drawRect(x, y, size, size);
}
public void shoot()
{
bullet = new Bullet(x+size, y);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BadGuy
{
private int x, y;
final int RADIUS = 5;
public BadGuy(int x, int y)
{
this.x = x;
this.y = y;
}
public void move()
{
x -= 5;
}
public void draw(Graphics page)
{
page.drawOval(x, y, RADIUS*2, RADIUS*2);
}
public int getX()
{
return x;
}
}
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class Bullet
{
private int x, y;
final int LENGTH = 5, DELAY =200;
public Bullet(int x, int y)
{
this.x = x;
this.y = y;
}
public void draw(Graphics page)
{
page.drawLine (x, y, x+LENGTH, y);
}
public void move()
{
x += 5;
}
public int getX()
{
return x;
}
}
The shooter class remains the same. This is what I want the program to do, but it's not precisely how I want it to do it. I would prefer if it were more object-oriented, and each class took care of itself. The ShooterPanel is already starting to get a little convoluted for my taste, and only gets worse as more is added to the program. One thing I would like to change would be for each bullet to have its own timer, with an ActionListener defined in the Bullet class. However, I cannot figure out how to do this in such a way that the bullet is redrawn every time the timer fires an event. If anyone knows a way to do so, please let me know.