Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 4 of 4
  1. #1
    New to the CF scene
    Join Date
    May 2010
    Posts
    2
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Help with Key Events and JPanel Animation

    Hello! I have been working on a game where the objective will eventually be to avoid randomly generated side-scrolling blocks with a user-controlled piece, as of now only controlled by buttons. I have a few questions though.

    I have looked in many tutorials and places online, but I can't seem to get key events to work. I want to have the option of controlling the player with a key event or the buttons that already exist. If someone could just give me an example of how I could implement this in my code it would be great.

    My second question is about how to create animation in a JPanel, specifically side-scrolling boxes. Where should I put the code? I think I understand the logic that I would use, I'm just unsure of the specifics. A friend said that a timer object is an easy way to do this but I've never used one. Would you agree?

    If someone could help me out with any of this I would be really grateful.


    Here is the panel code:
    Code:
    package BlockGame;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.util.Random;
    
    
    public class BlockGamePanel extends JPanel implements ActionListener, KeyListener
    {
    
        Random generator = new Random();
        final int INITIALX=300;
        final int INITIALY=150;
        JButton right, left, up, down;
        int x=50, y=50;
    
        public BlockGamePanel(int width, int height)
    
        {
            left = new JButton ("left");
            add(left);
            left.addActionListener(this);
            
            right = new JButton("right"); 
            add (right); 
            right.addActionListener(this); 
    
            up = new JButton ("up");
            add (up);
            up.addActionListener(this);
    
            down = new JButton ("down");
            add (down);
            down.addActionListener(this);
    
        }
        
     public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            g.setColor(Color.red);
            g.fillRect (x,y,15,15);
    
            repaint();
        }
    
     //move the player piece around
         public void actionPerformed (ActionEvent event)
        {
            if (event.getSource() == right) 
                x+=15;
    
            if (event.getSource() == left)
                x-=15;
    
            if (event.getSource() == up)
                y-=15;
    
            if (event.getSource() == down)
                y+=15;
    
            repaint();
        }
    
        public void keyTyped(KeyEvent e) {
    
        }
    
        public void keyPressed(KeyEvent e) {
    
        }
    
    
        public void keyReleased(KeyEvent e) {
    
        }
    
    
    }

    And, just in case, this is the run class.
    Code:
    package BlockGame;
    
    import java.awt.*;
    import javax.swing.*;
    
    public class BlockGame {
    
        public static void main(String[] args)
        {
        JFrame frame = new JFrame ("BlockGame");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setPreferredSize(new Dimension(400,400));
        frame.getContentPane().add(new BlockGamePanel(400,400));
    
        frame.pack();
        frame.setVisible(true);
        }
    }

  • #2
    Senior Coder TheShaner's Avatar
    Join Date
    Sep 2005
    Location
    Orlando, FL
    Posts
    1,126
    Thanks
    2
    Thanked 40 Times in 40 Posts
    I don't know anything about animation in Java unfortunately; maybe look at these samples -> http://java.sun.com/products/java-me...samples/suite/

    This is a great Key Listener tutorial, mainly because running the actual program gives you a lot of insight on how key events work. Play with it and you'll see.

    For you, you'll need to addKeyListener to your JPanel. Then, in your keyPressed method, you'll have to check which key event is coming in. For example:
    Code:
    switch(e.getKeyCode())
    {
        case 40: // Down
            y += 15;
        // and so on...
    }
    The key codes you are probably interested in:
    Code:
    Down: 40
    Up: 38
    Left: 37
    Right: 39
    Running the demo I linked you to will enable you to get all the key codes. Also, you can do KeyEvent.getKeyText(e.getKeyCode()), which will print the string name of the key you've pressed, i.e. "Right".

    I actually recommend creating a separate class that will hold your "player" that will be moving around in your environment. You would then call move commands on the instance of your player as keys or buttons are pressed. You'll repaint the object every time you move it.

    -Shane

  • Users who have thanked TheShaner for this post:

    Alice.B (05-27-2010)

  • #3
    New to the CF scene
    Join Date
    May 2010
    Posts
    2
    Thanks
    1
    Thanked 0 Times in 0 Posts
    Thank you very much for your help, TheShaner. My program is now compiling and working well. I have modified the original slightly, in order to scroll circles to the right. I still need to create a separate Player class as per your suggestion, but I don't foresee many issues with that. I am having a slight problem with my logic though. I want to iterate through the 'for' loop going one at a time, with a slight delay between each. Unfortunately right now all the circle objects seem to fire off at once. I'm sure there's simply something I'm doing wrong, and if anyone could help out that would be wonderful. Here is my current code:

    Code:
    //****************************************
    //  NOTE:
    //  It would be wise to create a class called player that does all of the controlling,
    //  rather than having it in the panel class.
    
    package BlockGame;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.util.Random;
    
    
    /**
     *
     * @author alibresnah10
     */
    public class BlockGamePanel extends JPanel implements 
                                                            KeyListener,
                                                                FocusListener,
                                                                    MouseListener
    {
    
        Random generator = new Random();
        final int WH=300;
        final int AWIDTH, AHEIGHT;
        Timer timer;
        private int arraySize =8;
        private int squareTop=200, squareLeft=200;
        int moveX, moveY;
        private static final int SQUARE_SIZE = 20;
    
    
        Circle[] carray = new Circle[8];
    
    
        public BlockGamePanel(int width, int height)
    
        {
            timer = new Timer(20, new ReboundListener());
            moveX=moveY=generator.nextInt(15);
            for (int i = 0; i < arraySize; i++)
            {
               carray[i]=new Circle();
            }
           
             AWIDTH=width;
             AHEIGHT=height;
    
             setBackground(Color.WHITE);
    
             addKeyListener(this);     // Set up event listening.
             addFocusListener(this);
             addMouseListener(this);
    
    
    
        }
     public void paintComponent(Graphics g)
        {
            super.paintComponent(g);
    
            //change the color for if the panel has focus... needed for keyevents
             if (hasFocus())
                  g.setColor(Color.RED);
             else
                g.setColor(Color.LIGHT_GRAY);
    
            //draw a border that shows whether the panel has focus.
             int width = getSize().width;  // Width of the applet.
             int height = getSize().height; // Height of the applet.
             g.drawRect(0,0,width-1,height-1);
             g.drawRect(1,1,width-3,height-3);
             g.drawRect(2,2,width-5,height-5);
    
    
    
             //draw the player piece, controllable by keyboard.
             g.fillRect(squareLeft, squareTop, SQUARE_SIZE, SQUARE_SIZE);
    
    
    
             for (int i=0; i<carray.length; i++)
             {
                 carray[i].draw(g);
             }
    
    
    
             if (hasFocus()) {
                g.drawString("Arrow Keys Move Player",7,20);
             }
             else
             {
                g.drawString("Click to activate",7,20);
                g.setColor(Color.cyan);
             }
             g.setColor(Color.green);
    
    
            repaint();
        }
    
        public void keyPressed(KeyEvent ke)
        {
            int key = ke.getKeyCode();  // keyboard code for the pressed key
    
             if (key == KeyEvent.VK_LEFT) {
                squareLeft -= 8;
                if (squareLeft < 3)
                   squareLeft = 3;
                repaint();
             }
             else if (key == KeyEvent.VK_RIGHT) {
                squareLeft += 8;
                if (squareLeft > getWidth() - 3 - SQUARE_SIZE)
                   squareLeft = getWidth() - 3 - SQUARE_SIZE;
                repaint();
             }
             else if (key == KeyEvent.VK_UP) {
                squareTop -= 8;
                if (squareTop < 3)
                   squareTop = 3;
                repaint();
             }
             else if (key == KeyEvent.VK_DOWN) {
                squareTop += 8;
                if (squareTop > getHeight() - 3 - SQUARE_SIZE)
                   squareTop = getHeight() - 3 - SQUARE_SIZE;
                repaint();
            }
        }
    
    
    
        public void focusGained(FocusEvent e)
        {
            repaint();
        }
    
        public void focusLost(FocusEvent e)
        {
            repaint();
        }
    
        public void mouseClicked(MouseEvent e) {
            requestFocus();
            timer.start();
        }
     //provide empty definitions
        public void keyTyped(KeyEvent e) { }
        public void keyReleased(KeyEvent e) {    }
        public void mousePressed(MouseEvent e) {    }
        public void mouseReleased(MouseEvent e) {    }
        public void mouseEntered(MouseEvent e) {    }
        public void mouseExited(MouseEvent e) {    }
    
    
        public class ReboundListener implements ActionListener
        {
            public void actionPerformed(ActionEvent action)
            {
    
                for (int i = 0; i < carray.length; i++)
                {
    	    carray[i].move(moveX);
    
    
    	    if (carray[i].getX() < 0 || carray[i].getX() >= AWIDTH - carray[i].getRadius())
                {
                    carray[i].setX(0);
                    carray[i].setY(generator.nextInt(AHEIGHT));
                }
    
    
    	    repaint();
                }
            }
    	// ----------------------------------------------------
    	// actionPerformed is called by the timer -- it updates
    	// the position
    	// ----------------------------------------------------
    
        }
    }
    And here is my 'circle' class, the one whose objects I am firing off using the timer.

    Code:
    import java.awt.*;
    import java.util.Random;
    
    public class Circle
    {
        private int x, y;       // coordinates of the corner
        private int radius;     // radius of the circle
        private Color color;    // color of the circle
        private int width, height =300;
    
        static Random generator = new Random();
    
    
        public Circle()
        {
            radius = Math.abs(generator.nextInt(20)+5);
    
            x = 1;//modify for original plan... scrolling to the left.
            y = Math.abs(generator.nextInt(300));
        }
    
        //----------------------------------------------------------
        // Creates a circle of a given size (diameter).  Other
        // attributes are random (as described above)
        //---------------------------------------------------------
        public Circle(int size)
        {
            radius = Math.abs(size/2);
            color = new Color(Math.abs(generator.nextInt())% 16777216);
            x = 0;
            y = Math.abs(generator.nextInt())%400;
        }
    
    
        //---------------------------------------------------------
        // Draws circle on graphics object given
        //---------------------------------------------------------
        public void draw(Graphics page)
        {
            page.setColor(color);
            page.fillOval(x,y,radius*2,radius*2);
        }
    
    
        //--------------------------------------------------------
        // Shifts the circle's position 
        //--------------------------------------------------------
        public void move (int over)
        {
            x = x + over;
            //y = down;
        }
    
        // ---------------------------------------------
        // Return the x coordinate of the circle corner
        // ---------------------------------------------
        public int getX()
        {
            return x;
        }
    
        public int setX(int set)
        {
            x=set;
            return x;
        }
        public int setY(int set)
        {
            y=set;
            return y;
        }
        // ---------------------------------------------
        // Return the y coordinate of the circle corner
        // ---------------------------------------------
        public int getY()
        {
            return y;
        }
        public int getRadius()
        {
            return radius;
        }
    }

  • #4
    Senior Coder TheShaner's Avatar
    Join Date
    Sep 2005
    Location
    Orlando, FL
    Posts
    1,126
    Thanks
    2
    Thanked 40 Times in 40 Posts
    Well, it all depends on what you're attempting to do. The way you have it set up, you have a timer that calls it's Action Listener's actionPerformed method every 20ms. In that actionPerformed method, you loop through the array of 8 Circles to change their locations. That means, every 20ms, all 8 circles move virtually at once!

    What do you really want to happen? Do you want only 1 Circle moved every 20ms? You said you want a delay in between, so use the timer to execute this delay. Instead of looping through all 8 Circles, only perform a move on 1 Circle at time, using your Timer to do the delay between moving them.

    In your ReboundListener class, add a private variable that stores which Circle you want to move next (let's call it circleToMove) and initialize it with 0. Then, completely ditch the for loop in your ReboundListener class and just do a move on carray[circleToMove]. After you perform the move, increment circleToMove by 1 so that when the timer executes 20ms later, it'll move the next Circle in your array. You'll also have to do a check to see if circleToMove is greater than 7 after you increment, because if so, you'll want to go back to 0.

    -Shane


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •