1

I'm creating a whack a mole game on java swing applet but I am having trouble with timing the moles to come up. I can't seem to avoid paint () looping on me and thus randomizing the coordinates of the mole too fast. How can I delay the moles to come up and stay for a while and go down if they were not hit? How can I create this delay without delaying the entire program?

please help

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;
import javax.swing.Timer;

public class Game extends JApplet
{

    boolean titleScreen = true;
    boolean gameBegin = false;

    // /////////////////////////////////
    // ///// IMAGE /////////
    // /////////////////////////////////

    Dimension dim;
    Image offscreen;
    static Graphics bufferGraphics;
    static Image h1, h2, bg, gamebg, button1a, button1b, button2a, button2b;
    static Image m1, m1a, m1b, m2a, m2b;
    static Image[] mk = new Image [9];

    // /////////////////////////////////
    // ///// MOUSE /////////
    // /////////////////////////////////

    Cursor c;
    boolean myButtonPressed = false;
    boolean myButtonEntered = false;
    int myMouseX = 0, myMouseY = 0;
    int myRow = -1, myCol = -1;

    // /////////////////////////////////
    // / GAME VARIABLES ///
    // /////////////////////////////////

    private static final int[] mX = {5, 170, 335, 5, 170, 335, 5, 170, 335};
    private static final int[] mY = {5, 5, 5, 170, 170, 170, 335, 335, 335};
    int rand, randm;

    static int[] t = new int [9];

    static boolean mhhit = false;
    static boolean[] mhit = {false, false, false, false, false, false, false, false, false};
    private int[] respawnCounter = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    private int[] removeCounter = {0, 0, 0, 0, 0, 0, 0, 0, 0};

    static int score = 0;

    public JFrame window;
    // /////////////////////////////////
    // ///// BUTTON /////////
    // /////////////////////////////////

    GameScreen g1 = new GameScreen ();
    Timer repaintTimer = null;
    // GameTime m1 = new GameTime (t[]);
    // GameTime m2 = new GameTime (t[]);
    // GameTime m3 = new GameTime (t[]);
    // GameTime m4 = new GameTime (t[]);
    // GameTime m5 = new GameTime (t[]);
    // GameTime m6 = new GameTime (t[]);
    // GameTime m7 = new GameTime (t[]);
    // GameTime m8 = new GameTime (t[]);
    // GameTime m9 = new GameTime (t[]);

    public Game ()
    {
        window = new JFrame ("Monkeying Around");
        window.setResizable (false);
        window.setSize (800, 400);
        window.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

    }


    public void init ()
    {
        // /////////////////////////////////
        // ///// IMAGE /////////
        // /////////////////////////////////
        dim = getSize ();
        setBackground (Color.white);
        offscreen = createImage (dim.width, dim.height);
        bufferGraphics = offscreen.getGraphics ();

        // Getting all the images
        m1a = getImage (getCodeBase (), "m1a.gif");
        m1b = getImage (getCodeBase (), "m1b.gif");
        m1 = getImage (getCodeBase (), "m1.gif");

        h1 = getImage (getCodeBase (), "hammer.gif");
        h2 = getImage (getCodeBase (), "hammer2.gif");
        bg = getImage (getCodeBase (), "mainbg.gif");
        gamebg = getImage (getCodeBase (), "gbg.gif");
        button1a = getImage (getCodeBase (), "button1a.gif");
        button1b = getImage (getCodeBase (), "button1b.gif");
        button2a = getImage (getCodeBase (), "button2a.gif");
        button2b = getImage (getCodeBase (), "button2b.gif");

        for (int mnum = 0 ; mnum < 9 ; mnum++)
        {
            mk [mnum] = m1;
        }
        ///////////////////////
        /////// MOUSE /////////
        ///////////////////////

        Toolkit tk = Toolkit.getDefaultToolkit ();
        c = tk.createCustomCursor (tk.getImage (""), new Point (0, 0), "invisible");
        setCursor (c);

        addMouseListener (new MyMouseListener ());
        addMouseMotionListener (new MyMouseMotionListener ());

        repaintTimer = new Timer (500, new RepaintAction (this));
        // start the timer.

    } // end init method


    public void start ()
    {
    }


    public Image getMouseImage ()
    {
        if (myButtonPressed)
        {
            return h2;
        }
        return h1;
    }


    public void handleMouseEvents ()
    {
        int nCol = myMouseX - 50;
        int nRow = myMouseY - 50;
        if (!myButtonEntered) // assumed to be: if myButtonEntered is
            // not = true i.e. false
            nCol = nRow = -1;
        if (nCol != myCol || nRow != myRow)
        {
            myRow = nRow;
            myCol = nCol;
        }

        repaint ();
    } // end handleMouseEvents method


    /////////////////////////////////////
    /////// MOUSELISTENER CLASS /////////
    /////////////////////////////////////

    public class MyMouseListener implements MouseListener
    {
        public void mousePressed (MouseEvent me)
        {
            myButtonPressed = true;
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        }

        public void mouseReleased (MouseEvent me)
        {
            myButtonPressed = false;
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        }

        public void mouseEntered (MouseEvent me)
        {
            myButtonEntered = true;
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        }

        public void mouseExited (MouseEvent me)
        {
            myButtonEntered = false;
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        }

        public void mouseClicked (MouseEvent me)
        {
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        }
    } // end MyMouseListener class


    public class MyMouseMotionListener implements MouseMotionListener
    {
        public void mouseMoved (MouseEvent me)
        {
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        } // end mouseMoved method

        public void mouseDragged (MouseEvent me)
        {
            myMouseX = me.getX ();
            myMouseY = me.getY ();
            handleMouseEvents ();
        } // end mouseDragged method
    } // end MyMouseListener class


    public void mouse ()
    {
        // logic to render mouse...
        if (myRow != -1 && myCol != -1)
        { // if you do not hit co-ordinates -1
            // (out of bounds) then
            Image mouseImage = getMouseImage ();
            bufferGraphics.drawImage (mouseImage, myCol, myRow, 100, 100, null, this);
        } // end if
    }


    public void paint (Graphics g)
    {
        bufferGraphics.clearRect (0, 0, dim.width, dim.height);
        repaint ();
        if (titleScreen == true)
        {
            // System.out.println("drawing the main screen");
            mainScreen ();
        }
        if (gameBegin == true)
        {
            game (g);
        }
        mouse ();
        g.drawImage (offscreen, 0, 0, this);
    } // end Paint method


    public void update (Graphics g)
    {
        paint (g);
    }


    public void mainScreen ()
    {
        bufferGraphics.drawImage (bg, 0, 0, 600, 500, Color.red, this);
        bufferGraphics.drawImage (button1a, 427, 384, 159, 49, Color.red, this);
        bufferGraphics.drawImage (button2a, 427, 440, 159, 49, Color.red, this);
        mouse ();
        if (myButtonPressed == true)
        {
            if (myRow > (384 - 50) && myRow < (433 - 50) && myCol > (427 - 50)
                    && myCol < (586 - 50))
            {
                titleScreen = false;
                gameBegin = true;
            }
            else if (myRow > (340 - 50) && myRow < (489 - 50)
                    && myCol > (427 - 50) && myCol < (586 - 50))
            {
                titleScreen = false;
            }
        }
    }





    public void game (Graphics g)
    {
        // new ReminderBeep (5);
        bufferGraphics.drawImage (gamebg, 0, 0, 600, 500, Color.red, this);
        for (int i = 0 ; i < 9 ; i++)
        {
            bufferGraphics.drawImage (mk [i], mX [i], mY [i], 160, 160, Color.red, this);
        }

        g.drawString ("har", 520, 140);
    }


    public void monkeyhit ()
    {
        if (myButtonPressed == true)
        {
            for (int hit = 0 ; hit < 9 ; hit++)
                if (mhit [hit] == true && myRow > (mY [hit] - 50) && myRow < (mY [hit] + 160 - 50)
                        && myCol > (mX [hit] - 50) && myCol < (mX [hit] + 160 - 50))
                {
                    mk [hit] = m1b;
                    mhhit = true;
                    mhit [hit] = false;
                    score += 10;
                }
        }
        // reset ();
    }


    public void run ()
    {
        monkey ();
    }


    // public void reset ()
    // {
    //     mhhit = false;
    //     for (int x = 0 ; x < 9 ; x++)
    //     {
    //         mk [x] = m1;
    //         mhit [x] = false;
    //
    //     }
    //
    // }


    public void monkey ()
    {
        rand = ((int) (Math.random () * 100000000)) + 10000000;
        randm = ((int) (Math.random () * 100));


        if (randm <= 8)
        {
            for (int a = 0 ; a < 9 ; a++)
            {
                if (randm == a)
                {
                    mhit [randm] = true;
                    mk [randm] = m1a;
                }
                else if (randm != a)
                {
                    mhit [a] = false;
                    mk [a] = m1;
                }
            }

            for (int i = 0 ; i < rand * 100 ; i++)
            {
                monkeyhit ();
                if (mhit [randm] = false)
                    mk [randm] = m1;
                break;
            }
        }
    }



    // Timer
    class GameTime
    {
        Toolkit toolkit;
        Timer timer;

        public GameTime (int seconds)
        {
            toolkit = Toolkit.getDefaultToolkit ();
            timer = new Timer (seconds, new MTask ());
            timer.start ();
        }


        /*
        public void delay(int seconds) {
                toolkit = Toolkit.getDefaultToolkit();
                timer = new Timer();
                timer.schedule(new Mdelay(), seconds * 1000);
        }
        */

        class MTask implements ActionListener
        {
            public void actionPerformed (ActionEvent ae)
            {
                /*
                for (int tsec = 0; tsec < 9; tsec++) {
                        t[tsec] = ((int) (Math.random() * 11)) * 5;
                }
                */

            }
        }
    }


    class RepaintAction implements ActionListener
    {
        Game game;
        public RepaintAction (Game game)
        {
            this.game = game;
        }


        public void actionPerformed (ActionEvent e)
        {
            game.repaint ();
        }
    }
}
Machavity
  • 30,841
  • 27
  • 92
  • 100
jeesoo
  • 21
  • 1
  • 2

4 Answers4

3

In your painting method (or methods called from there), you should only do painting, nothing else (like checking where the mouse is and such).

Everything else should be done separately. For example, calculating (randomizing) the positions of the moles (or monkeys?) should not be done here, but in the timer method, for example.

Your applet needs to have a model, which will be modified by the user interaction and random events. The paint method then looks at this model, and paints according to this.

Paŭlo Ebermann
  • 73,284
  • 20
  • 146
  • 210
  • How would I create this model? A new class? new method? – jeesoo Jun 20 '11 at 00:36
  • In your case, the model would be most of your `GAME VARIABLES`, I think. You can put this in a separate class, of course, for clarity. The important part is from where you modify and from where only read. – Paŭlo Ebermann Jun 20 '11 at 00:50
  • @LFA2711: Yes, Paulo is saying better what I was trying to say in my comment to you in your answer. His answer is right on the money. – Hovercraft Full Of Eels Jun 20 '11 at 01:09
2

Never Don't override update() and paint(). That is old AWT code which is not used in Swing.

In Swing custom painting is done by overriding the paintComponent() method of JPanel or JComponent. Then you add the component to the content pane of the applet (or frame or dialog or window).

Read the section from the Swing tutorial on Custom Painting for more information and examples.

Also, in Swing you would never invoke repaint() from within a painting method as this would cause in infinite loop.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • 1
    `paint()` is still used in Swing...it's responsible for painting the content, borders, and children of any Swing component. But like you said, overriding an AWT component's `paint()` method is equivalent to overriding a Swing component's `paintComponent(...)` method. Also, there are situations where you may want to override `paint()`... for instance, when an application wants to alter the graphics state for all of that component's rendering (e.g. translucency). – mre Jun 20 '11 at 00:17
  • @mre, in the context of this question the poster was confusing AWT painting with Swing painting and I referred them to the Swing tutorial to understand the basics of painting which explains all about the painting of the content, borders and children. Also because the code did NOT invoke super.paint() and because it invoked repaint() directly this also showed lack of understanding about the painting process so I was attempting to keep the answer simple and basic. Once people understand the basics they can expand and be creative. – camickr Jun 20 '11 at 04:26
  • I knew what you were doing; I was just trying to prevent misinformation. :) – mre Jun 20 '11 at 10:22
2

How would I create this model?

Here's a very simple game that may guide your design. It illustrates the separation between model and view; it also links to related examples. A model having a List<Mole> with each Mole having a javax.swing.Timer seems apt. The model would notify the view when a mole changes state, and the view could query the model for mouse hit-testing.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
1

You could create a Mole class with a startTime, upTime, and coordinates and have an ArrayList of moles in your main game class. Then, in your paint loop, check if any of the moles have been up for their allocated up time, and if so, remove them. To keep a fairly uniform number of moles at all times, you could create a new mole to replace each mole that is destroyed with a random start time (based on current time), up time, and coordinates.

for(Mole mole : this.moles) {
    if(System.currentTimeMillis() - mole.getStartTime() >= mole.getUpTime()) {
        this.moles.remove(mole); 
    }
}

Threading could also be a suitable, but much more complex alternative.

Lane Aasen
  • 729
  • 4
  • 14
  • What do you mean by "in your paint loop"? If you mean have program logic in the painting method, then I have to strongly disagree. Painting methods should be all about painting and nothing else. There is no guarantee that they'll be called when you want them to, and they can be called when you don't expect them to, and they need to be as blindingly fast as possible. – Hovercraft Full Of Eels Jun 20 '11 at 00:40
  • What do you suggest doing? I suppose you could have a separate thread for updating the moles, or implement an MVC configuration like Paulo suggested. – Lane Aasen Jun 20 '11 at 00:58
  • 2
    for his purposes a simple Swing Timer would suffice, and I don't think that a background thread would be necessary. The logic could go in the Swing Timer, it would change the program state and then call repaint so that the GUI could visually display the changed state of the program. But again never change the state of the program in the painting method (paint or paintComponent). – Hovercraft Full Of Eels Jun 20 '11 at 01:02