• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Need help with finishing a game in BlueJ

OK, so im making a crude version of Battleship in java, and it works 100%, the AI is working, the graphics all work. Everything works that needs to work.

But i was doing some side stuff to make the game a little more enjoyable/elegant, and i came across a roadblock.



I have a mouselistener (mouse clicked) that i use for almost the whole game. Its used to take shots, place ships, start the game over, etc.
I also have a wait method i created so i can pause the game at certain points (when a shot is taken, when a ship is sunk, etc)

But i noticed that with my mouselistener, when the wait method is being called, the game waits for the specified amount of time (pegs dont show up, hits dont show up, etc), but if during that waiting time i click on a square to take a shot, even though at the time nothing shows up, after the waiting is over it immedialty renders the shot i took during the wait.


What i want to know is is there an easy way to tell the mouselistener to become inactive, or stop listening during the wait time, but then as soon as the wait is over start listening again?
(so that it wont render any actions while the game is waiting)??















Heres the code for the mouselistener and the wait method
(ignore the variables, ill highlight where the wait methods are called in the code)
--------------------------------------------------------------------------

/**
* The main worker method of the game. Uses the mouse button (when its clicked)
* to set certain things in motion, such as setting ships, taking shots, restarting the
* game, or error checking
*/
public void mousePressed(MouseEvent event)
{
if (gameState == GAME_INTRO) {
gameState = GAME_SETUP;
blueBoard.placeComputerShips();
repaint();
setup();
}
else if (gameState == GAME_SETUP) {
int row = convertY(event.getY());
int col = convertX(event.getX());
if ((event.getY() >= 430) && (event.getY() <= 730) && (event.getX() >= 310) && (event.getX() <= 610)){
if (redBoard.didHitShip(row, col) == false){
if (posClick) {
setMessage("Click any of the green boxes to place the end of the ship. The box selected will determine the position of the ship (ie. up, down, sideways.)", true);
redBoard.setFirst(row, col);
posClick = redBoard.setFirst(row, col);
repaint();
}
else {
setMessage("Click any of the green boxes to place the end of the ship. The box selected will determine the position of the ship (ie. up, down, sideways.)", true);
posClick = redBoard.setSecond(row, col);
repaint();
if (redBoard.getShipCount() == 5) {
gameState = BattleshipApp.GAME_PLAYING;
setMessage("PLAY GAME!", true);
}
}
}
else{
setMessage("Please click on an empty grid location.", true);
}
}
else{
setMessage("Please click on a square inside the red grid.", true);
}
}
else if (gameState == GAME_PLAYING) {
int row = convertYEnemy(event.getY());
int col = convertXEnemy(event.getX());
if (targetValid(event.getX(), event.getY())) {
if (blueBoard.didHitShip(row, col)) {
setMessage(playName + "'s shot.........HIT!", true);
Ship hitShip = blueBoard.applyDamage(row, col);
blueBoard.putPegInSquare(row, col, true);
if (hitShip.getHits() == hitShip.getSize()){
if (hitShip.getSize() == 5){
size = "Aircraft Carrier";
}
else if (hitShip.getSize() == 4){
size = "Battleship";
}
else if (hitShip.getSize() == 3){
if (hitShip.getType() == 2){
size = "Cruiser";
}
else{
size = "Submarine";
}
}
else if (hitShip.getSize() == 2){
size = "PT Boat";
}
String message = "HIT! .....you sank my " + size + "!";
setMessage(message, true);
paint(this.getGraphics());
wait(2000);
}
paint(this.getGraphics());
wait(1000);
}
else{
setMessage(playName + "'s shot.........MISS!", true);
blueBoard.putPegInSquare(row, col, false);
paint(this.getGraphics());
wait(1000);
}
if (!blueBoard.anyShipLeft()) {
setMessage("YOU WIN!!!!!!!", true);
won = true;
playAgain();
gameState = GAME_GAMEOVER;
}
else{
enemyPlayer.selectTarget();
row = enemyPlayer.getTargetRow();
col = enemyPlayer.getTargetColumn();
if (redBoard.didHitShip(row, col)) {
setMessage("Computers shot.........HIT!", true);
Ship hitShip = redBoard.applyDamage(row, col);
redBoard.putPegInSquare(row, col, true);
if (hitShip.getHits() == hitShip.getSize()){
if (hitShip.getSize() == 5){
size = "Aircraft Carrier";
}
else if (hitShip.getSize() == 4){
size = "Battleship";
}
else if (hitShip.getSize() == 3){
if (hitShip.getType() == 2){
size = "Cruiser";
}
else{
size = "Submarine";
}
}
else if (hitShip.getSize() == 2){
size = "PT Boat";
}
String message = "HIT! .....you sank " + playName + "'s " + size + "!";
setMessage(message, true);
paint(this.getGraphics());
wait(2000);
}
if (hitShip.getHits() == hitShip.getSize()){
enemyPlayer.undoWeights(hitShip);
}
else{
enemyPlayer.hitWeights(row, col, false);
}
paint(this.getGraphics());
wait(1000);
}
else{
setMessage("Computers shot.........MISS!", true);
redBoard.putPegInSquare(row, col, false);
enemyPlayer.missWeights(row, col);
paint(this.getGraphics());
wait(1000);
}
if (!redBoard.anyShipLeft()) {
setMessage("YOU LOSE!!!!!!!!!!", true);
playAgain();
gameState = GAME_GAMEOVER;
}
}
}
else {
setMessage("Please click on a blue square.", true);

}
}
else if (gameState == GAME_GAMEOVER){
setMessage("Please use the buttons to play again or quit the game.", true);
}
}






/**
* Used to allow for a small pause when shots have been taken
*/
public void wait(int milliseconds)
{
try
{
Thread.sleep(milliseconds);
}
catch (Exception e)
{

}
}





So, again, i want the mouselistener to become inactive whenever the wait method is called in the code above............
 
FYI, use the attach code function to preserve your code formatting in a post.

A quick fix (non-synchronized, ugly) would be to toss a boolean into your class. In your mousePressed method, evaluate that field, and return on false (continue on true). In your wait method, set that value to false @ start, and true @ end. Make sure to explicitly set it to true in your exception catch block as well, just in case your thread is interrupted. And make sure it is initialized to true.
 
Ok, ill try that later tonight (going out for a while)


thats what i was going to do, but i just didnt know where to put it in the catch/try.......thanks again
 
Ok, so i decided to try it real quick, and i have it almost done but the problem i guess im really having is i dont know where in my mouselistener method to put the appropriate statement?
And i dont know what statement/if structure to use?

(could you give me a small detail by editing my mouselistener code, or showing me what i might add in it)?


thanks
 
Do it at the start of your mousePressed method, as seen in the attached code.

If this is for a class, the prof. might not like the multiple function exit points. Also, there's a more elegant way of suspending the updates.

FYI, the finally block executes always, even when an exception was encountered.
 
Well i tried it, and then i tried a few different variations


but no matter what, it still renders mouseclicks during the wait method.


I looked in the javadocs.org code for the mouselistener class, and the mouseevent has its own wait method which suspends activity, or something like that (i cant read and interpret thier explenations that good).
And it has another method of its own, notify, which resumes activity.


Any thoughts/comments on those, or would they not work?


 
A better approach is to use a javax.swing.Timer. You can implement a custom ActionAdapter class that calls a generic repaint() method, then construct the timer to execute to fire an action event to your ActionAdapter every x milliseconds.

The nice thing about Timers is that they can easily be stopped and started, so pausing your game becomes trivially easy. You shouldn't be calling paint() directly from your MouseListener at all (actually, you shouldn't call paint() directly ever; repaint() is preferred, and it will execute your custom paint() method).
 
Originally posted by: MrChad
A better approach is to use a javax.swing.Timer. You can implement a custom ActionAdapter class that calls a generic repaint() method, then construct the timer to execute to fire an action event to your ActionAdapter every x milliseconds.

The nice thing about Timers is that they can easily be stopped and started, so pausing your game becomes trivially easy. You shouldn't be calling paint() directly from your MouseListener at all (actually, you shouldn't call paint() directly ever; repaint() is preferred, and it will execute your custom paint() method).

I can see the simplicity of the timer, but i dont even know where to begin to get it set up (im about 50% sure i know what i need to do)

Can you expand on what a timer can do for the mouselistener (or actionlisteners in general) and how it can easily be applied to where i have the wait() method currently being used?
 
Originally posted by: BigCoolJesus
I can see the simplicity of the timer, but i dont even know where to begin to get it set up (im about 50% sure i know what i need to do)

Can you expand on what a timer can do for the mouselistener (or actionlisteners in general) and how it can easily be applied to where i have the wait() method currently being used?

Well, I'll give it a shot. I developed an Asteroids-type game in college using Swing, so I'm basing my advice on that experience.

The basic problem that I needed to solve in the Asteroids game was that I had a bunch of objects in my game window that needed to move independently of one another. I accomplished this in two ways.

The first was to have my game window keep track of each object on the screen and its various properties (angle, speed, size, etc.). I overwrote the paintComponent() method of my game window to call a custom draw() method on each screen object. These draw methods changed the position of the object each time they were called and drew the resulting shape on the screen.

The second was to have a timer. The timer did a few things in terms of collision detection, but mostly it called redraw every 50 milliseconds. That in combination with my custom paint methods moved the objects around on the screen.

Your case is a bit simpler, since the Battleship game is relatively static. A timer is still useful, however. I would isolate your mouse and keyboard listeners from your drawing concerns. The mouse and keyboard events can change the state of the game, and your timer can draw the text messages according to the state. For instance, you might have something like this:

boolean shipHit = false;
boolean ignoreMouseEvents = false;

Action updateBoard = new AbstractAction(){
....public void actionPerformed(ActionEvent e){
........if (shipHit){
............label.setMessage("It's a hit");
............shipHit = false;
............ignoreMouseEvents = false;
........} else {
............label.setMessage("");
........}
........label.repaint();
....}
};

Timer gameTimer = new Timer(3000, updateBoard);

Your MouseListener would simply check the click of the mouse and determine if a hit had occurred. If it did, shipHit would get set to true. When the timer executes updateBoard() the next time, the label's message changes and it's redrawn.

To solve your original problem, you could also have the MouseListener only respond to events if ignoreMouseEvents is set to false. If you reach a condition where you want to pause the action, set ignoreMouseEvents to true in the MouseListener (such as when a ship is hit). When the Timer responds to the updated game state a few seconds later and displays the hit message, ignoreMouseEvents is set back to false and the MouseListener will continue to work again.

I hope this helps explain things better. Good luck with your project.
 
Back
Top