1

I'm wondering why my game objects are not showing. I am able to draw to the JPanel if I use g.drawRect outside of the for-each loop, but calling PipeObject inside of the loop doesn't seem to work for me. Am I doing something wrong here? Thanks for any help or solutions.

This is an updated version of my old question, which can be found here.

UPDATE - The pipes are drawing correctly, but not moving to the left by calling pipe.move().

Game

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
//import javax.swing.border.EmptyBorder;
import javax.swing.SwingUtilities;

public class Game {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {             
                // the GUI as seen by the user (without frame)
                final CardLayout cl = new CardLayout();
                final JPanel gui = new JPanel(cl);
                // remove if no border is needed
                //gui.setBorder(new EmptyBorder(10,10,10,10));

                JPanel menu = new JPanel(new GridBagLayout());
                JButton playGame = new JButton("Play!");

                ActionListener playGameListener = new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        cl.show(gui, "game");
                    }
                };
                playGame.addActionListener(playGameListener);
                Insets margin = new Insets(20, 50, 20, 50);
                playGame.setMargin(margin);
                menu.add(playGame);
                gui.add(menu);
                cl.addLayoutComponent(menu, "menu");

                final JPanel pipes = new Pipes();
                gui.add(pipes);
                cl.addLayoutComponent(pipes, "game");

                JFrame f = new JFrame("PipeGame");
                f.add(gui);
                // Ensures JVM closes after frame(s) closed and
                // all non-daemon threads are finished
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                // See https://stackoverflow.com/a/7143398/418556 for demo.
                f.setLocationByPlatform(true);

                // ensures the frame is the minimum size it needs to be
                // in order display the components within it
                f.pack();
                // should be done last, to avoid flickering, moving,
                // resizing artifacts.
                f.setVisible(true);
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

Pipes

import java.util.*;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Pipes extends JPanel {
    boolean gameNotOver = true;
    int x1 = 754;
    int y1 = setHeightVal();
    int y2 = setHeightVal();
    int y3 = setHeightVal();

    List<PipeObject> pipes = new ArrayList<PipeObject>();

    public Pipes() {
        pipes.add(new PipeObject(x1, y1));
        pipes.add(new PipeObject(x1 + 300, y2));
        pipes.add(new PipeObject(x1 + 600, y3));
    }

    public void drawEndlessPipes() {
        if (gameNotOver) {
            Timer pipeSpeed = new Timer(10, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (PipeObject pipe : pipes) {
                        pipe.move();
                    }
                }
            });
            pipeSpeed.start();
        }
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (PipeObject pipe : pipes) {
            pipe.drawPipe(g);
        }
    }

    public int setHeightVal() {     //Get a random number and select a preset height
        int num = (int)(9*Math.random() + 1);
        int val = 0;
        if (num == 9)
        {
            val = 295;
        }
        else if (num == 8)
        {
            val = 246;
        }
        else if (num == 7)
        {
            val = 216;
        }
        else if (num == 6)
        {
            val = 185;
        }
        else if (num == 5)
        {
            val = 156;
        }
        else if (num == 4)
        {
            val = 125;
        }
        else if (num == 3)
        {
            val = 96;
        }
        else if (num == 2)
        {
            val = 66;
        }
        else
        {
            val = 25;
        }
        return val;
    }

    public Dimension getPreferredSize() {
        return new Dimension(751,501);
    }
}

PipeObject

import java.awt.Graphics;

public class PipeObject {
    //Declare and initialiaze variables
    int x1;
    int x2 = 75;                //pipe width, total is 83
    int y1 = -1;                // Y should be -1
    int y2;
    int gap = 130;              //gap height

    public PipeObject(int x, int y) {
        this.x1 = x;
        this.y2 = y;
    }

    public void drawPipe(Graphics g/*, int x1, int y2*/) {
        g.drawRect(x1,y1,x2,y2);                        //Draw part 1
        g.drawRect(x1-3,y2-1,x2+6,25);                  //Draw part 2
        g.drawRect(x1-3,y2+25+gap,x2+6,25);             //Draw part 3
        g.drawRect(x1,y2+25+gap+25,x2,500-y2-49-gap);   //Draw part 4
    }

    public void move() {
        x1--;
    }

    public int getMyX() {   //To determine where the pipe is horizontally
        return x1-3;
    }

    public int getMyY() {   //To determine where the pipe is vertically
        return y2+25;
    }
}
Community
  • 1
  • 1
Cyber Storm
  • 217
  • 1
  • 13
  • Let me know if you're still having problems? Without going through all your code, the answers below looked pretty valid. If it's still not working, let me know. – Paul Samsotha Feb 11 '14 at 02:44

2 Answers2

1

You are painting the pipes beyond the visual bounds of the panel. The dimension of Pipes panel is 751x501, but the pipes begin at x1 = 754. Try changing x1 to 1 in Pipes and you should see the three pipes. Or, you can maximize the frame, and you should see the missing pipes far on the right side.

tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • Did you see the timer though? – Cyber Storm Feb 10 '14 at 23:11
  • In theory, the pipes should move toward the left. – Cyber Storm Feb 10 '14 at 23:12
  • I will try that though – Cyber Storm Feb 10 '14 at 23:16
  • So, those pipes are drawing, but not moving – Cyber Storm Feb 10 '14 at 23:18
  • 1
    @CyberStorm as far as I can see the timer is never started. `drawEndlessPipes` is never called. – tenorsax Feb 10 '14 at 23:25
  • @CyberStorm Also, don't forget to call `repaint()` at the end of a `for` loop in the timer routine to repaint all the pipes at the new location. – tenorsax Feb 10 '14 at 23:28
  • 1
    @CyberStorm I got the pipes moving by adding a call to `drawEndlessPipes();` in `Pipes` constructor and adding `repaint();` after the `for` loop in timer's `actionPerformed()` method. Were you able to resolve the issue? – tenorsax Feb 11 '14 at 06:24
  • If you want to be of some more help. you could point me towards how to color those jpanels and loop the pipes endlessly. i know about setBackgroundColor, but im not exactly sure on how to use it in this case, since i have multiple panels in a card layout. – Cyber Storm Feb 11 '14 at 22:07
  • @CyberStorm to change color you set the color on the `Graphics`, ie `g.setColor(Color.RED);` You can introduce a member variable in `PipeObject` that indicates its color and then use it in `drawPipe()` method. See [Getting Started with Graphics](http://docs.oracle.com/javase/tutorial/2d/basic2d/index.html) for some examples. – tenorsax Feb 11 '14 at 22:18
  • @CyberStorm as for cycling the pipes, you'd have to restore the original point of a pipe once it goes out of visual bounds. For example, inside `PipeObject.move()` check if `x1` became negative and reset it to the original value, ie, `754`. Of course, you'd have to make the logic a bit smarter to consider panel size, pipe size, avoid hard coded numbers, let the pipe disappear properly, support multiple pipes properly, etc. – tenorsax Feb 11 '14 at 22:28
  • sounds like a good plan to me, ill work on it when i get the chance – Cyber Storm Feb 12 '14 at 02:53
1

As CyberStorm said, you never called drawEndlessPipes() to start the swing timer at all. Also I don't see a repaint() call to Pipes panel inside your timer, just changing the x value won't magically move anything, you need to call repaint() in Pipes.java to make it repaint the screen and show animation.

So here it goes:

Modified Runnable in Game.java

Runnable r = new Runnable() {
        @Override
        public void run() {
            // the GUI as seen by the user (without frame)
            final CardLayout cl = new CardLayout();
            final JPanel gui = new JPanel(cl);
            // remove if no border is needed
            //gui.setBorder(new EmptyBorder(10,10,10,10));

            JPanel menu = new JPanel(new GridBagLayout());
            JButton playGame = new JButton("Play!");

            ActionListener playGameListener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    cl.show(gui, "game");
                }
            };
            playGame.addActionListener(playGameListener);
            Insets margin = new Insets(20, 50, 20, 50);
            playGame.setMargin(margin);
            menu.add(playGame);
            gui.add(menu);
            cl.addLayoutComponent(menu, "menu");

            final JPanel pipes = new Pipes();
            gui.add(pipes);
            cl.addLayoutComponent(pipes, "game");

            JFrame f = new JFrame("PipeGame");
            f.add(gui);
            // Ensures JVM closes after frame(s) closed and
            // all non-daemon threads are finished
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            // See http://stackoverflow.com/a/7143398/418556 for demo.
            f.setLocationByPlatform(true);

            // ensures the frame is the minimum size it needs to be
            // in order display the components within it
            f.pack();
            // should be done last, to avoid flickering, moving,
            // resizing artifacts.
            f.setVisible(true);

            ((Pipes) pipes).drawEndlessPipes();
        }
    };

Modified drawEndlessPipes() in Pipes.java

public void drawEndlessPipes() {
    if (gameNotOver) {
        Timer pipeSpeed = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                for (PipeObject pipe : pipes) {
                    pipe.move();
                    Pipes.this.repaint();
                }
            }
        });
        pipeSpeed.start();
    }
}
ask-dev
  • 606
  • 2
  • 13
  • 30
  • Its still only drawing a single pipe, and I need it to draw all three and I also need to make random pipes keep being scrolled endlessly – Cyber Storm Feb 11 '14 at 02:05