Opening a new JFrame using a JButton - java

I have two classes (Sampling and Stacker). The Sampling class (my Main class) is extends JFrame and has a JButton with an ActionListener to open the Stacker class.
The problem is when the button is clicked, the Stacker class will open but only a frame without any components. When I switch the main method into the Stacker class, the program works fine. What is the problem?
Here is the code:
The Sampling class:
public class Sampling extends JFrame implements ActionListener
{
private JButton openStacker;
Stacker st;
public Sampling()
{
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
dispose();
st = new Stacker();
}
public static void main (String args[])
{
new Sampling();
}
}
The Stacker game class:
public class Stacker extends JFrame implements KeyListener
{
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5,5};
int layer = 19;
int deltax[] = {0,0};
boolean press = false;
boolean forward = true;
boolean start = true;
public Stacker()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton [m][n];
setLayout(new GridLayout(n,m));
for (int y = 0;y<n;y++)
{
for (int x = 0;x<m;x++)
{
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
this.addKeyListener(this);
this.setVisible(true);
go();
}
public void go()
{
int tmp = 0;
Component temporaryLostComponent = null;
do{
if (forward == true)
{
forward();
} else {
back();
}
if (deltax[1] == 10-length[1])
{
forward = false;
} else if (deltax[1] == 0)
{
forward = true;
}
draw();
try
{
Thread.sleep((long) time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}while(press == false);
if (layer>12)
{
time= 150-(iteration*iteration*2-iteration);
} else
{
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");
repeat();
}
last = deltax[1];
start = false;
go();
}
public int check()
{
if (start == true)
{
return length[1];
}
else if (last<deltax[1])
{
if (deltax[1]+length[1]-1 <= last+length[0]-1)
{
return length[1];
}
else
{
return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
}
}
else if (last>deltax[1])
{
return length[1]-Math.abs(deltax[1]-last);
}
else
{
return length[1];
}
}
public void forward()
{
deltax[0] = deltax[1];
deltax[1]++;
}
public void back()
{
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw()
{
for (int x = 0;x<length[1];x++)
{
b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0;x<length[1];x++)
{
b[x+deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat()
{
if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
{
dispose();
new Stacker();
}else{
System.exit(0);
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
press = true;
}
}
public void keyReleased(KeyEvent arg0)
{
}
public void keyTyped(KeyEvent arg0)
{
}
}

Just to put all my comments into an answer, and give you somewhere to start with:
Comment 1:
Take out go(); see that happens. I tested it and it will work. If you leave it there, even the frame's close button is jammed. You're blocking the edt with the while->Thread.sleep junk. You'll want to do some refactoring. You're code it hard to follow and I have no idea what you're trying to do, so I didn't even attempt it
Comment 2:
If you're wondering why it works when you just run the main from the Stacker class, it's probably because you are running it outside the EDT,
public static void main(String[] args) { new Stacker(); }. What happens when you click the button, that action is performed within the EDT, and hence your new Stacker() will be run on the EDT. In which case the EDT gets blocked by your while loop. If you try run the program from the Stacker class, but wrap it in a SwingUtilities.invokeLater, you will also notice the program fails to work. Swing programs should be run on the EDT though.
Comment 2: Read the first few sections on Concurrency with Swing
So what you can do is use a Swing Timer (which operates on the EDT) for the game loop. What I did was refactor your code a bit. It doesn't operate the way you want it to yet, only because I didn't really understand the logic of your code. So I couldn't get it to work. What I did though, is put some of the logic into the Timer.
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
And when the go() method is called, it just starts the timer by calling timer.start(). Basically what you need to know about the timer, is that every tick (the milliseconds you pass it), the actionPerformed will be called. So you can update the game state in that method, just like you did in the while loop each iteration.
Take some time to go over How to Use Swing Timers
To get the game working properly, you still need to make some adjustments, but this should give you a head start.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Sampling extends JFrame implements ActionListener {
private JButton openStacker;
Stacker st;
public Sampling() {
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
dispose();
st = new Stacker();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sampling();
}
});
}
}
class Stacker extends JFrame implements KeyListener {
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5, 5};
int layer = 19;
int deltax[] = {0, 0};
boolean press = false;
boolean forward = true;
boolean start = true;
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
public Stacker() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400, 580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton[m][n];
setLayout(new GridLayout(n, m));
for (int y = 0; y < n; y++) {
for (int x = 0; x < m; x++) {
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
JPanel panel = (JPanel)getContentPane();
panel.addKeyListener(this);
this.setVisible(true);
panel.requestFocusInWindow();
go();
}
public void go() {
int tmp = 0;
Component temporaryLostComponent = null;
timer.start();
if (layer > 12) {
time = 150 - (iteration * iteration * 2 - iteration);
} else {
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");
repeat();
}
last = deltax[1];
start = false;
//go();
}
public int check() {
if (start == true) {
return length[1];
} else if (last < deltax[1]) {
if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
return length[1];
} else {
return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
}
} else if (last > deltax[1]) {
return length[1] - Math.abs(deltax[1] - last);
} else {
return length[1];
}
}
public void forward() {
deltax[0] = deltax[1];
deltax[1]++;
}
public void back() {
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw() {
for (int x = 0; x < length[1]; x++) {
b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0; x < length[1]; x++) {
b[x + deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat() {
if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dispose();
new Stacker();
} else {
System.exit(0);
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("Pressed");
press = true;
}
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
Notice the SwingUtilities.invokeLater in the main. That's how you can start up the program on the EDT. The link on Concurrency In Swing will give you more information.

Related

Java 2D Game Programming : Missile shooting is too fast?

Hello I'm fairly new to programming and this is my first time posting here so any help would be appreciated so:
my problem is that I"m trying to create some kind of 2D shooter game in java but I don't know if my simple game loop is good because when i shoot a missile it shoots a one every 20 ms and it's too fast and shoots a ton of missiles at once so is there any way to adjust it ? Like to keep some delay between every missile and the other??
and please tell me if i have problems or bad programming in my code !!
this is my game panel where most of the game happens and where my loop and adding missiles method in
public class GamePanel extends JPanel implements KeyListener {
Measurments mesure = new Measurments();
int panel_width = mesure.getUniversalWidth();
int panel_height = mesure.getUniversalHeight();
Timer timer;
Random rand = new Random();
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Missile> missiles = new ArrayList<>();
Player player = new Player(0, 0);
boolean up = false;
boolean down = false;
boolean right = false;
boolean left = false;
boolean isShooting = false;
boolean isRunning = true;
public boolean gameRunning() {
return isRunning;
}
int count = 5;
int missilesCount = 6;
public GamePanel() {
timer = new Timer(20, new ActionListener() {
public void actionPerformed(ActionEvent e) {
StartGame();
repaint();
}
});
setSize(panel_width, panel_height);
addKeyListener(this);
timer.start();
for (int i = 0; i < count; i++) {
addEnemy(new Enemy(rand.nextInt(750), rand.nextInt(500)));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.paint(g2d);
for (int i = 0; i < enemies.size(); i++) {
Enemy temp = enemies.get(i);
temp.paint(g2d);
}
for (int i = 0; i < missiles.size(); i++) {
Missile mis = missiles.get(i);
mis.paint(g2d);
mis.behave();
}
}
public void StartGame() {
if (isRunning) {
runGame();
setBackground(Color.YELLOW);
} else {
setBackground(Color.BLACK);
}
}
public void runGame() {
update();
};
public void update() {
player.checkBorders();
checkColls();
if (up) {
player.updateUp();
}
if (down) {
player.updateDown();
}
if (right) {
player.updateRight();
}
if (left) {
player.updateLeft();
}
if (isShooting) {
for (int i = 0; i < 5; i++) {
missiles.add(new Missile(player.getX() + 16, player.getY() + 16));
}
}
for (int i = 0; i < missiles.size(); i++) {
Missile temp = missiles.get(i);
if (temp.getX() == panel_width) {
RemoveMissile(temp);
}
}
}
public void addEnemy(Enemy e) {
enemies.add(e);
}
public void removeEnemy(Enemy e) {
enemies.remove(e);
}
public void addMissile(Missile e) {
missiles.add(e);
}
public void RemoveMissile(Missile e) {
missiles.add(e);
}
public void checkColls() {
for (int i = 0; i < enemies.size(); i++) {
Enemy tempEnm = enemies.get(i);
for (int e = 0; e < missiles.size(); e++) {
Missile tempMis = missiles.get(e);
if (tempMis.missileRect().intersects(tempEnm.enemyRect())) {
enemies.remove(tempEnm);
missiles.remove(tempMis);
}
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = true;
}
if (key == e.VK_DOWN) {
down = true;
}
if (key == e.VK_RIGHT) {
right = true;
}
if (key == e.VK_LEFT) {
left = true;
}
if (key == e.VK_ENTER) {
isRunning = true;
}
if (key == e.VK_SPACE) {
isShooting = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = false;
}
if (key == e.VK_DOWN) {
down = false;
}
if (key == e.VK_RIGHT) {
right = false;
}
if (key == e.VK_LEFT) {
left = false;
}
if (key == e.VK_SPACE) {
isShooting = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
Thanks in advance !!
private long fired = 0L;
public void update() {
...
// firing missiles: only if the missile count is less than the max., and the elapsed
// time is more than a limit (100 ms)
if ( isShooting && missiles.size() < missilesCount &&
( System.currentTimeMilis() - this.fired ) > 100 ) {
missiles.add( new Missile( player.getX() + 16, player.getY() + 16 ) );
// time of last firing
this.fired = System.currentTimeMilis();
}
...
}
public void RemoveMissile(Missile e) {
// as Guest is asked in another answer, this method should remove, not add...
missiles.remove(e);
}

GUI timer does not stop

I have a problem with my GUI timer. I start my timer when the player clicks on a button in the mine field, and I stop my timer when the game ends.
The first time I test my game, the timer starts and ends normally. However, if I try to play a second round of the game, my timer does not stop.
public class Minesweeper7 extends JFrame implements ActionListener {
static public boolean revealed [][];
public static CountTimer ct;
public Minesweeper7 (int row, int column) {
ct = new CountTimer ();
}
private void setTimerText (String sTime) {
timeLabel.setText (sTime);
}
public void actionPerformed(ActionEvent event){
String coords = event.getActionCommand();
String[] squarePressed = coords.split(",");
x_pressed = Integer.parseInt(squarePressed[0]);
y_pressed = Integer.parseInt(squarePressed[1]);
System.out.println("The button you have pressed is " + x_pressed + ", " + y_pressed);
if (ct.timer.isRunning() == false){
ct.start ();
System.out.println ("timer is running");
}
reveal (row,column,x_pressed,y_pressed,revealed,mines,revealed_number);
gameEnd (row, column, revealed, mines, countMines, counter, end);
System.out.println("There are " + countMines + " .");
System.out.println("");
for (int r = 0;r<row;r++){
for (int c = 0;c<column;c++){
label[r][c].setText(String.valueOf(revealed_number[r][c]));
}
}
}
public void reveal () {
//a recursive method that reveals my buttons
}
public static void main (String args []) {
java.awt.EventQueue.invokeLater (new Runnable () {
public void run () {
new Minesweeper7 (10, 10);
}
});
}
public void gameEnd (int row, int column, boolean revealed [][], boolean mines [][], int countMines, int counter, boolean end) {
for (int r = 0; r < row; r++) {
for (int c = 0; c < column; c++) {
if (mines [r][c] == false && revealed [r][c] == true) {
counter++;
}
else if (mines [r][c] == true && revealed [r][c] == true) {
System.out.println ("Sorry, you lost because you clicked on a mine.");
end = true;
break;
}
}
}
if (counter == (row*column-countMines)) {
System.out.println ("Congratulations! You won the game!");
end = true;
instruction.setText("Congratulations! You won the game!");
}
if (end == true) {
ct.stop ();
}
}
public class CountTimer implements ActionListener {
public static final int ONE_SECOND = 1000;
public int count = 0;
public boolean isTimerActive = false;
public Timer timer = new Timer (ONE_SECOND, this);
public CountTimer () {
count = 0;
setTimerText (TimeFormat (count));
}
public void actionPerformed (ActionEvent e) {
if (isTimerActive) {
count++;
setTimerText (TimeFormat (count));
}
}
public void start () {
count = 0;
isTimerActive = true;
timer.start ();
}
public void stop () {
timer.stop ();
}
public void reset () {
count = 0;
isTimerActive = true;
timer.restart ();
}
}
}
if you start a new game, you could just make a new timer instead of starting and stopping.
if (game end) {
timer = new Timer();
timer.start();
}

Why is my simple java2d Space Invaders game lagging?

I'm currently making a space invaders-esque game for my software engineering course. I've already got everything working that satisfies the requirements, so this isn't a 'solve my homework' kind of question. My problem is that the game will lag (at what seems like random times & intervals) to the point where it becomes too frustrating to play. Some things I think might be causing this - though I'm not positive - are as follows:
Problem with timer event every 10 ms (I doubt this because of the very limited resources required for this game).
Problem with collision detection (checking for collision with every visible enemy every 10 ms seems like it would take up a large chunk of resources)
Problem with repainting? This seems unlikely to me however...
#SuppressWarnings("serial")
public class SIpanel extends JPanel {
private SIpanel panel;
private Timer timer;
private int score, invaderPace, pulseRate, mysteryCount, distanceToEdge;
private ArrayList<SIthing> cast;
private ArrayList<SIinvader> invaders, dead;
private ArrayList<SImissile> missileBase, missileInvader;
private SIinvader[] bottomRow;
private SIbase base;
private Dimension panelDimension;
private SImystery mysteryShip;
private boolean gameOver, left, right, mysteryDirection, space, waveDirection;
private boolean runningTimer;
private Music sound;
private void pulse() {
pace();
processInputs();
if (gameOver) gameOver();
repaint();
}
private void pace() {
// IF invaders still live
if (!invaders.isEmpty()) {
invaderPace++;
// Switch back manager
if (distanceToEdge <= 10) {
switchBack();
pulseRate = (pulseRate >= 16) ? (int) (pulseRate*(0.8)) : pulseRate;
waveDirection = !waveDirection;
distanceToEdge = calculateDistanceToEdge();
}
// Move invaders left/right
else if (invaderPace >= pulseRate) {
invaderPace = 0;
distanceToEdge = calculateDistanceToEdge();
moveAI();
invadersFire();
if (!dead.isEmpty()) removeDead();
if (mysteryCount < 1) tryInitMysteryShip();
}
// All invaders are kill, create new wave
} else if (missileBase.isEmpty() && missileInvader.isEmpty() && !cast.contains(mysteryShip)) {
// System.out.println("New Wave!");
newWave();
}
// Every pace
if (!missileBase.isEmpty()) moveMissileBase();
// Every two paces
if (invaderPace % 2 == 0) {
if (!missileInvader.isEmpty()) moveMissileInvader();
if (mysteryCount > 0) moveMysteryShip();
}
}
private void processInputs() {
if (left) move(left);
if (right) move(!right);
if (space) fireMissile(base, true);
}
protected void fireMissile(SIship ship, boolean isBase) {
if(isBase && missileBase.isEmpty()) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()-(ship.getHeight()/4));
missileBase.add(m);
cast.add(m);
} else if (!isBase && missileInvader.size()<3) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()+(ship.getHeight()/4));
missileInvader.add(m);
cast.add(m);
}
}
private void newWave() {
pulseRate = 50;
int defaultY=60, defaultX=120, defaultWidth=30, defaultHeight=24;
for(int i=0; i<5; i++) {
for(int j=0; j<10; j++) {
if (i<1) invaders.add(new SItop((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<3) invaders.add(new SImiddle((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<5) invaders.add(new SIbottom((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
}
}
for (SIinvader s: invaders) {
cast.add(s);
}
if (!cast.contains(base)) {
cast.add(base);
}
bottomRow = getBottomRow();
}
private void tryInitMysteryShip() {
Random rand = new Random();
int x=rand.nextInt(1000);
if (x<=3) {
mysteryCount = 1;
if (rand.nextBoolean()) {
mysteryDirection = true;
}
if (mysteryDirection) {
mysteryShip = new SImystery(0, 60, 36, 18);
} else {
mysteryShip = new SImystery(480, 60, 36, 18);
}
cast.add(mysteryShip);
}
}
private void moveMysteryShip() {
int distance = 0;
if (mysteryDirection) {
mysteryShip.moveRight(5);
distance = getWidth() - mysteryShip.getX();
} else {
mysteryShip.moveLeft(5);
distance = 30+mysteryShip.getX()-mysteryShip.getWidth();
}
if (distance <= 5) {
dead.add(mysteryShip);
mysteryShip = null;
mysteryCount = 0;
}
}
private void removeDead() {
#SuppressWarnings("unchecked")
ArrayList<SIinvader> temp = (ArrayList<SIinvader>) dead.clone();
dead.clear();
for (SIinvader s : temp) {
invaders.remove(s);
cast.remove(s);
}
bottomRow = getBottomRow();
}
private void invadersFire() {
int[] p = new int[bottomRow.length];
for (int i=0; i<p.length; i++) {
for (int j=0; j<p.length; j++) {
p[j] = j;
}
Random rand = new Random();
int a=rand.nextInt(101);
if (a>=20) {
int b=rand.nextInt(p.length);
fireMissile(bottomRow[b], false);
}
}
}
private int calculateDistanceToEdge() {
int distance = 0;
SIinvader[] outliers = getOutliers();
if (waveDirection) {
distance = getWidth() - outliers[0].getX()-outliers[0].getWidth();
} else {
distance = outliers[1].getX();
}
return distance;
}
private SIinvader[] getOutliers() {
SIinvader leftMost = invaders.get(0), rightMost = invaders.get(0);
for (SIinvader s : invaders) {
if (s.getX() < leftMost.getX()) {
leftMost = s;
}
if (s.getX() > rightMost.getX()) {
rightMost = s;
}
}
return new SIinvader[] { rightMost, leftMost };
}
private SIinvader[] getBottomRow() {
SIinvader[] x = new SIinvader[(invaders.size()>10)?10:invaders.size()];
for (int i=0; i<x.length; i++) {
x[i] = invaders.get(i);
for (SIinvader s:invaders) {
if (s.getX() == x[i].getX()) {
if (s.getY() > x[i].getY()) {
x[i] = s;
}
}
}
}
return x;
}
private void move(boolean b) {
int defaultX = 5;
if (b) base.moveLeft(defaultX);
else base.moveRight(defaultX);
}
private void moveAI() {
for(SIinvader s : invaders) {
s.changeImage();
int defaultX = 5;
if (waveDirection) s.moveRight(defaultX);
else s.moveLeft(defaultX);
}
}
private void moveMissileBase() {
if (invaders.isEmpty()) return;
int movement = -5, bound = 0;
SImissile missile = missileBase.get(0);
missile.moveDown(movement);
SIinvader lowestInvader = getLowestInvader();
if (missile.getY() < (lowestInvader.getY() + lowestInvader.getHeight())) {
for (SIinvader s:bottomRow) {
if (checkCollision(missile, s)) {
s.setHit();
dead.add(s);
cast.remove(missile);
missileBase.clear();
score += s.value;
return;
}
}
if (mysteryCount > 0) {
if (checkCollision(missile, mysteryShip)) {
mysteryShip.setHit();
dead.add(mysteryShip);
cast.remove(missile);
missileBase.clear();
score += mysteryShip.value;
return;
}
}
if (missile.getY() < bound) {
missileBase.remove(missile);
cast.remove(missile);
}
}
}
private SIinvader getLowestInvader() {
SIinvader lowest = bottomRow[0];
for (SIinvader invader : bottomRow) {
if (invader.getY() > lowest.getY()) {
lowest = invader;
}
}
return lowest;
}
private void moveMissileInvader() {
int movement = 5, bound = (int) panelDimension.getHeight();
for (SImissile missile : missileInvader) {
missile.moveDown(movement);
if(missile.getY() >= base.getY()) {
if (checkCollision(missile, base)) {
base.setHit();
gameOver = true;;
missileInvader.remove(missile);
cast.remove(missile);
return;
} else if (missile.getY() >= bound-25) {
missileInvader.remove(missile);
cast.remove(missile);
return;
}
}
}
}
private boolean checkCollision(SIthing missile, SIthing ship) {
Rectangle2D rect1 = new Rectangle2D.Double(
missile.getX(),
missile.getY(),
missile.getWidth(),
missile.getHeight()
);
Rectangle2D rect2 = new Rectangle2D.Double(
ship.getX(),
ship.getY(),
ship.getWidth(),
ship.getHeight()
);
return rect1.intersects(rect2);
}
private void switchBack() {
int defaultY = 12;
for (SIinvader s : invaders) {
if (s.getY() > getHeight()) {
gameOver = true;
return;
}
s.moveDown(defaultY);
}
}
private void gameOver() {
pause(true);
SI.setGameOverLabelVisibile(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
Font font = new Font("Arial", 0, 20);
setFont(font);
String score = "Score: "+this.score;
Rectangle2D rect = font.getStringBounds(score, g2.getFontRenderContext());
int screenWidth = 0;
try { screenWidth = (int) panelDimension.getWidth(); }
catch (NullPointerException e) {}
g2.setColor(Color.GREEN);
g2.drawString(score, (int) (screenWidth - (10 + rect.getWidth())), 20);
for(SIthing a:cast) {
a.paint(g);
}
}
public SIpanel() {
super();
setBackground(Color.BLACK);
cast = new ArrayList<SIthing>();
missileBase = new ArrayList<SImissile>();
score = invaderPace = mysteryCount = pulseRate = 0;
sound = new Music("AmbientMusic.wav");
panel = this;
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = true; break;
case KeyEvent.VK_RIGHT : right = true; break;
case KeyEvent.VK_SPACE : space = true; break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = false; break;
case KeyEvent.VK_RIGHT : right = false; break;
case KeyEvent.VK_SPACE : space = false; break;
}
}
});
setFocusable(true);
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulse();
}
});
}
public void reset() {
SI.setGameOverLabelVisibile(false);
score = invaderPace = mysteryCount = 0;
pulseRate = 50;
cast = new ArrayList<SIthing>();
invaders = new ArrayList<SIinvader>();
dead = new ArrayList<SIinvader>();
missileBase = new ArrayList<SImissile>();
missileInvader = new ArrayList<SImissile>();
base = new SIbase(230, 370, 26, 20);
waveDirection = true;
gameOver = false;
sound.stop();
sound.loop();
panelDimension = SI.getFrameDimensions();
bottomRow = getBottomRow();
newWave();
timer.start();
runningTimer=true;
}
public SIpanel getPanel() {
return this.panel;
}
public void pause(boolean paused) {
if (paused) timer.stop();
else timer.start();
}
}
I believe that collision detection may be the reason for lagging and you should simply investigate it by trying to increase and decrease count of enemies or missiles drastically to see if that makes a difference.
Consider garbage collector your enemy. In your checkCollision method you are instantiating two (very simple) objects. It may not seem like a lot, but consider that your might be creating them for each collision check, and that at 60fps it adds up until it may reach critical mass when GC says "stop the world" and you see noticeable lag.
If that is the case, possible solution to that would be to not instantiate any objects in a method called so frequently. You may create Rectangle2D once, and then update its position, instead of creating a new one each time, so you will avoid unnecessary memory allocation.

java Swing timer to perform few tasks one after another

I am perfectly aware very similar questions few asked before. I have tried to implement solutions offered - in vain. ...The problem i am facing is to blink buttons ONE AFTER ANOTHER. I can do it for one, but when put the order of blinking in a loop - everything breaks. Any help to a new person to Java is appreciated. P.S. I am not allowed to use Threads. What i am having now is:
Timer colorButton = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < pcArray.length; i++) {
playSquare = pcArray[i];
System.out.println("PlaySquare " + playSquare);
if (playSquare == 1) {
if (alreadyColoredRed) {
colorBack.start();
colorButton.stop();
} else {
red.setBackground(Color.red);
alreadyColoredRed = true;
System.out.println("RED DONE");
}
} else if (playSquare == 2) {
if (alreadyColoredGreen) {
colorBack.start();
colorButton.stop();
} else {
green.setBackground(Color.green);
alreadyColoredGreen = true;
System.out.println("GREEN DONE");
}
}
}
}
});
Timer colorBack = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < pcArray.length; i++) {
playSquare = pcArray[i];
System.out.println("PlaySquare " + playSquare);
if (playSquare == 1) {
red.setBackground(Color.gray);
alreadyColoredRed = false;
System.out.println("RED PAINTED BACK");
colorBack.stop();
} else if (playSquare == 2) {
green.setBackground(Color.gray);
alreadyColoredGreen = false;
System.out.println("GREEN PAINTED BACK");
colorBack.stop();
}
}
}
});
I don't think that having two Timer instances is the way to go. The Swing Timer is notorious for 'drifting' away from the perfect beat over time.
Better to create a single timer with the logic needed to control all actions.
E.G. Showing the allowable moves for a Chess Knight.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class KnightMove {
KnightMove() {
initUI();
}
ActionListener animationListener = new ActionListener() {
int blinkingState = 0;
#Override
public void actionPerformed(ActionEvent e) {
final int i = blinkingState % 4;
chessSquares[7][1].setText("");
chessSquares[5][0].setText("");
chessSquares[5][2].setText("");
switch (i) {
case 0:
setPiece(chessSquares[5][0], WHITE + KNIGHT);
break;
case 1:
case 3:
setPiece(chessSquares[7][1], WHITE + KNIGHT);
break;
case 2:
setPiece(chessSquares[5][2], WHITE + KNIGHT);
}
blinkingState++;
}
};
public void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new GridLayout(8, 8));
ui.setBorder(new CompoundBorder(new EmptyBorder(4, 4, 4, 4),
new LineBorder(Color.BLACK,2)));
boolean black = false;
for (int r = 0; r < 8; r++) {
for (int c = 0; c < 8; c++) {
JLabel l = getColoredLabel(black);
chessSquares[r][c] = l;
ui.add(l);
black = !black;
}
black = !black;
}
for (int c = 0; c < 8; c++) {
setPiece(chessSquares[0][c], BLACK + STARTING_ROW[c]);
setPiece(chessSquares[1][c], BLACK + PAWN);
setPiece(chessSquares[6][c], WHITE + PAWN);
setPiece(chessSquares[7][c], WHITE + STARTING_ROW[c]);
}
Timer timer = new Timer(750, animationListener);
timer.start();
}
private void setPiece(JLabel l, int piece) {
l.setText("<html><body style='font-size: 60px;'>&#" + piece + ";");
}
private final JLabel getColoredLabel(boolean black) {
JLabel l = new JLabel();
l.setBorder(new LineBorder(Color.DARK_GRAY));
l.setOpaque(true);
if (black) {
l.setBackground(Color.GRAY);
} else {
l.setBackground(Color.WHITE);
}
return l;
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
KnightMove o = new KnightMove();
JFrame f = new JFrame("Knight Moves");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.setResizable(false);
f.pack();
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
private JComponent ui = null;
JLabel[][] chessSquares = new JLabel[8][8];
public static final int WHITE = 9812, BLACK = 9818;
public static final int KING = 0, QUEEN = 1,
ROOK = 2, KNIGHT = 4, BISHOP = 3, PAWN = 5;
public static final int[] STARTING_ROW = {
ROOK, KNIGHT, BISHOP, KING, QUEEN, BISHOP, KNIGHT, ROOK
};
}

Trouble Separating classes for GUI and Gameplay: GUI not connecting to game play

To make my code more efficient, I have tried to separate the GUI and Gameplay. The code complies but when I make a new Game(); the Gui displays correctly but when I try to interact with it (i.e. change a name on the board or click a button the methods do not work.
The GUI Class Constructor:
public GUI()
{
makeFrame();
assignmines();
}
note: Assign mines and make frame are the only methods in this class.
The Game Class: (From the constructor)
public Game()
{
new GUI();
//UPDATES THE LABELS
updateGamesPlayed() ;
UpdateName();
}
// *********************************GAME CONTROLS************
private void quit()
{
System.exit(0);
}
//RESETS THE BOARD
public void reset()
{
frame.setVisible(false);
String tempName = Game.this.namelabel.getText();
frame.dispose();
Game gb= new Game();
gb.namelabel.setText(tempName);
score = 0;
}
// iNITIATES NEW GAME
public void newGame(){
frame.setVisible(false);
frame.dispose();
new Game();
}
// INCREASE THE ARRAY OF BUTTONS
public void biggerBoard(){
boardsize = 10;
reset();
}
// INCREASES NUMBER OF MINES ASSIGNED TO THE BOARD
public void changeDifficulty(){
numberOfMines = 15;
mine = 15;
minesLeft = 15;
reset();
}
}
// LOSING THE GAME ALERT
public void lose() {
status.setText("You're finished");
gamegoing = false;
JFrame parent = new JFrame();
JOptionPane.showMessageDialog(parent, "Sorry, you lost");
reset();
}
// WINNING THE GAME ALERT
public void win() {
status.setText("You won!");
gamegoing = false;
JFrame parent = new JFrame();
JOptionPane.showMessageDialog(parent, "Congratualations, you won!");
updateGamesWon();
Game.this.setVisible(false);
Game.this.dispose();
reset();
}
// UPDATING THE SCORE
public void updatescore() {
scorelabel.setText("" + score + " points");
if (100 - score <= 10) win();
}
public void gamesPlayed() {
gamesPlayed.setText("" + noGamesPlayed + " Games Played");
}
//UPDATES THE NAME BASED ON BUTTON CLICK
public void UpdateName() {
saveName.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
playername = nameEnter.getText();
namelabel.setText(playername);
}
});
}
//INCREMENTS THE NUMBER OF GAMES THAT HAVE BEEN PLAYED
public void updateGamesPlayed() {
noGamesPlayed ++;
}
//uPDATES HOW MANY GAMES HAVE BEEN WON
public void updateGamesWon() {
noGamesWon ++;
}
//WHAT VALUES THE CHARACTER HAVE
static char getUserChar(int cellValue) {
if(cellValue == Mine) {
return 'X';
} else if( cellValue == Empty) {
return '+';
} else if (cellValue == Flag || cellValue == FlaggedMine) {
return 'F';
} else if (cellValue == UncoveredMine) {
return 'X';
} else { String adjMines = Integer.toString(cellValue);
return adjMines.charAt(0);
}
}
//METHOD TO DISPLAY HOW MANY MINES AROUND THE BUTTON CLICKED
static int numAdjMines(int[][] mineBoard, int row, int col) {
int numMines = 0;
for(int dr = -1; dr <= 1; dr ++) {
for(int dc = -1; dc <= 1; dc++) {
if(row + dr >= 0 && row + dr < mineBoard.length &&
col+ dc >= 0 && col + dc < mineBoard[0].length) {
if(mineBoard[row+dr][col+dc] == Mine ||
mineBoard[row+dr][col+dc] == FlaggedMine) {
numMines++;
}
}
}
}
return numMines;
}
// TAKES X AND Y VALUE DESCRIBES WHAT HAPPENS ON CLICK
public void click(int row, int col) {
if(mineBoard[row][col] == Mine) {
buttons[row][col].setIcon( new ImageIcon( "images/bomb.gif" ) );
lose();
} else {
score += 1;
updatescore();
buttons[row][col].setText("" + numAdjMines(mineBoard, row, col));
buttons[row][col].setForeground(Color.GREEN);
mineBoard[row][col] = UncoveredEmpty;
//buttons[row][col].setText(Character.toString(getUserChar(mineBoard[row][col])));
if(numAdjMines(mineBoard, row, col) == Empty) {
for(int dr = -1; dr <= 1; dr ++) {
for(int dc = -1; dc <= 1; dc++) {
if(row+dr >= 1 && row+dr < 10 &&
col+dc >= 1 && col+dc < 10) {
if(mineBoard[row+dr][col+dc] == Empty) {
click(row+dr,col+dc);
}
}
}
}
}
}
}
//ACTION WHEN USER CLICKS ON A BUTTON
private class MouseListener extends MouseAdapter {
private int x = 0;
private int y = 0;
public MouseListener(int row, int col) {
this.x = row;
int i = 0;
this.y = col;
}
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) {
if((mineBoard[x][y] == Empty) && (Game.this.gamegoing == true)) {
Game.this.click(x, y);
} else if(mineBoard[x][y] == Mine) {
buttons[x][y].setIcon( new ImageIcon( "images/bomb.gif" ) );
Game.this.lose();
}} else if(e.getButton() == MouseEvent.BUTTON3) {
Game.this.buttons[x][y].setText("F");
}
}
}
}
How can I link the GUI and the functionality? I think I have got the wrong logic in the constructors but i'm not sure. (I hope all the relevant code is there, I have omitted some fields and methods due to length).

Categories