I'm in the process of creating a frogger type game and have gotten pretty far in getting the program to do what I want it to do. However, I'm starting to think that to finish the game I will have to use way to much code and there must be a simpler way achieve the same results. I'm not looking for an answer, just need some more information.
Question 1: What can I use for the images that represent the moving Icons or cars? I'm currently using JButtons. The problem is that is difficult to get the buttons to move uniformly and I want to use 24 different moving Icons and from what I've learned so far I will have to add a new JButton for each icon.
Question 2: The way that I've gotten the Jbutton icons to move is to use a timer delay and then a counter to increment the x values. This works for the most part, but is there a better, perhaps simpler, way to move icons across the screen?
Any tips, tutorials etc are greatly appreciated.
Here is one of the classes that I've created to get movement of the icons:
public class EnemyJPanel extends JButton {
JButton enem = new JButton();
JButton enem12 = new JButton();
JButton enem13 = new JButton();
JButton enem1 = new JButton("1");
JButton enem2 = new JButton("2");
JButton enem3 = new JButton("3");
JButton enem4 = new JButton("4");
JButton score = new JButton("Score");
JButton enem5 = new JButton("5");
JButton enem6 = new JButton("6");
JButton enem7 = new JButton("7");
JButton enem8 = new JButton("8");
JButton yard = new JButton("50 Yard Line");
int i = 16;
int u = 576;
int d = 16;
int n = 576;
int k = 16;
int l = 16;
int dummyval = 16;
public EnemyJPanel(){
super();
setLayout(null);
enem1.setBounds(16,300,40,55);
enem2.setBounds(16,245,40,55);
enem3.setBounds(16,190,40,55);
enem4.setBounds(16,135,40,55);
score.setBounds(16,80,601,55);
yard.setBounds(16,355,601,55);
enem5.setBounds(16,410,40,55);
enem6.setBounds(16,465,40,55);
enem7.setBounds(16,520,40,55);
enem8.setBounds(16,575,40,55);
enem12.setBounds(16,300,40,55);
enem13.setBounds(16,300,40,55);
add(enem1);
add(enem2);
add(enem3);
add(enem4);
add(score);
}
public void addEnemy(){
enem1.setBounds(16,300,40,55);
enem2.setBounds(16,245,40,55);
enem3.setBounds(16,190,40,55);
enem4.setBounds(16,135,40,55);
score.setBounds(16,80,601,55);
add(enem1);
add(enem2);
add(enem3);
add(enem4);
add(score);
}
public void enemyMovement(){
i++;u--;d++;n--; // increments lateral movement from a timer in
dummyval++; // the dummy value is needed to keep the icons looping
dummyval = dummyval + 2;
enem1.setBounds(i,300,40,55);
i = i + 2;
if (dummyval > 176){
k++; k = k + 2;
enem12.setBounds(k,300,40,55);
}
if (k > 176){
l++;
l = l + 2;
enem13.setBounds(l,300,40,55);
}
enem2.setBounds(u,245,40,55);
enem3.setBounds(d,190,40,55);
enem4.setBounds(n,135,40,55);
enem5.setBounds(i,410,40,55);
enem6.setBounds(u,465,40,55);
enem7.setBounds(d,520,40,55);
enem8.setBounds(n,575,40,55);
if(i > 576){ // resets button
i = 16;
}
if(k > 576){
k = 16;
}
if(u < 16){
u = 576;
}
u = u - 2; // increase lateral speed
if(d == 576) {
d = 16;
}
if(n < 16){
n = 576;
}
n = n - 5; //increases lateral speed
}
}
The problem is created because you try to manage all the "stuff" separately. It looks like you may be missing some basic information on classes
First, I would create a custom class, something like
class ButtonObject extends JButton
{
public ButtonObject(String text, int x, int y, int width, int height)
{
super(text);
this.setBounds(x, y, width, height);
}
}
You also may want to take a look at arrays and create an array of your new ButtonObject.
The for loop will help you get through all the objects in your array.
ButtonObject[] enemies = new ButtonObject[10];
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
int y = 300 - (i * 55);
enemies[i] = new ButtonObject(text, 16, y, 40, 55);
}
There is probably a better way to do it than buttons but you may want to stick with them for now for simplicity.
Related
I'm attempting to build Minesweeper in Java (Using Eclipse, if that matters for any reason whatsoever) and while making it, I've encountered an issue I haven't had before.
The window that's supposed to show up whenever a mine is pressed is opened... A lot. The window is only meant to open once and prompt the user to either continue or give up.
Important to note this only occurs whenever a mine is pressed on the top row of buttons. Not entirely sure if this is important, but the amount of times a window pops-up is 11. There are also no error codes given.
The following chunk of code is for whenever a user clicks on a mine.
//These are here just for clarification
private int continues = 3;
private Listen l = new Listen();
private class Listen extends MouseAdapter implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (source == mines[i][j])
{
//Though probably not optimal, I created mines based around a number referred to as difficulty
if (minePlacement[i][j] <= difficulty)
{
Frame f = new Frame();
Label L = new Label("You have " + continues + " continues remaining.");
Button B = new Button ("Try Again?");
Label La = new Label("You're out of continues...");
Button But = new Button("Exit");
f.setLayout(new FlowLayout());
B.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
f.dispose();
}
});
if (continues <= 0)
{
f.add(La);
f.add(But);
/*
For clarification,
This actionListener is used
solely to do System.exit(0);
*/
But.addActionListener(li);
f.setSize(250,125);
}
else
{
f.add(L);
f.add(B);
f.setSize(250,100);
}
f.setLocationRelativeTo(null);
f.setAlwaysOnTop(true);
f.setVisible(true);
f.setTitle("You Hit A Mine!");
continues--;
}
This following chunk of code is used in order to build the board itself.
for (int i = 0; i < rows; i++)
{
int x = (int) ((Math.random() + .1) * 10);
minePlacement[i][0] = x;
mines[i][0] = new Button();
mines[i][0].addMouseListener(l);
mines[i][0].addActionListener(l);
add(mines[i][0]);
for (int j = 0; j < cols; j++)
{
int y = (int) ((Math.random() + .1) * 10);
minePlacement[i][j] = y;
mines[i][j] = new Button();
mines[0][j].addMouseListener(l);
mines[0][j].addActionListener(l);
mines[i][j].addMouseListener(l);
mines[i][j].addActionListener(l);
add(mines[i][j]);
}
I've tried looking for other posts which may answer my question, though as it stands, I have failed to find any other posts that have been coded in Java. I've mainly found them in C++ or C, to which I don't understand how the solution was brought about.
I'd like to know if there's any way to set a limit on the amount of windows on the screen, or if there's a way to prevent the window from popping up more times than expected.
Thanks in advance!
I am creating a grid of 4 by 2 buttons and I want them to continuously change color. A button will stop changing colors once I press it. I have having trouble figuring how to make that one button stop changing colors if I press on it and have other buttons to continuously change color. If I press another button, that button stops changing color as well.
public class Hw1 extends JPanel {
static JFrame jf;
static JPanel jp;
static JButton jb;
public static void main(String[] args) {
jf = new JFrame("Hello World!");
int xAxis = 500;
int yAxis = 300;
jf.setSize(xAxis, yAxis);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jp = new JPanel();
int num = 8;
JButton[] buttonList = new JButton[num];
int count = 0;
// creates buttons and initially assigns random color
for(int i = 0; i < 2 ; i++){
for(int j = 0; j < 4; j++){
jb = new JButton("press me!");
jb.setBounds(i * (xAxis/2), j * (yAxis/4), xAxis/2, yAxis/4);
jb.setVisible(true);
jb.setOpaque(true);
int primeR = (int)(Math.random() * 255+ 0);
int primeG = (int)(Math.random() * 255 + 0);
int primeB = (int)(Math.random() * 255 + 0);
Color random = new Color(primeR, primeG, primeB);
jb.setBackground(random);
// adds action listener to each button aka checks if button is pressed
jb.addActionListener(new ActionListener(){
// action if button is pressed
//if pressed change stop changing colors
public void actionPerformed(ActionEvent ae) {
JButton theButton = (JButton)ae.getSource();
theButton.setBackground(random);
}
});
buttonList[count] = jb;
count++;
jp.add(jb);
}
}
jf.add(jp);
jf.setVisible(true);
for (int k = 0; k < buttonList.length; k++) {
new Thread(){
public void run(){
while(true){
try {
sleep(1000);
}
catch (InterruptedException ex) {
}
for (int i = 0; i < buttonList.length; i++) {
int primeR = (int)(Math.random() * 255);
int primeG = (int)(Math.random() * 255);
int primeB = (int)(Math.random() * 255);
Color random = new Color(primeR, primeG, primeB);
buttonList[i].setBackground(random);
}
}
}
}.start();
}
}
}
you need to keep state of button.
If you have grid of 4 button, make an array of it's state buttonState = new Boolean[2][2]
when button on position x,y is pressed, set value of [x][y] to true. check buttonState before changing color of button.
OR
Overwrite JButton and add bolean field pressed to it, and set it to true in onClick, and based on that value change or not change color
I have a little issue with selecting from an array list. I am writing some code to enable me fix about 10 JButtons in a circle, I got that right, but then ..... I want to set an actionListener on each of the Buttons, but I don't get it, all the buttons inherit the actions required for one. How do I make it specific,... here's my code.... Thanks in advance!
private JButton quest;
public Beginner() {
int n = 10; // no of JButtons
int radius = 200;
Point center = new Point(250, 250);
double angle = Math.toRadians(360 / n);
List<Point> points = new ArrayList<Point>();
points.add(center);
for (int i = 0; i < n; i++) {
double theta = i * angle;
int dx = (int) (radius * Math.sin(theta));
int dy = (int) (radius * Math.cos(theta));
Point p = new Point(center.x + dx, center.y + dy);
points.add(p);
}
draw(points);
}
public void draw(List<Point> points) {
JPanel panels = new JPanel();
SpringLayout spring = new SpringLayout();
// Layout used
int count = 1;
for (Point point : points) {
quest = new JButton("Question " + count);
quest.setForeground(Color.BLUE);
Font fonte = new Font("Script MT Bold", Font.PLAIN, 20);
quest.setFont(fonte);
add(quest);
count++;
spring.putConstraint(SpringLayout.WEST, quest, point.x, SpringLayout.WEST, panels);
spring.putConstraint(SpringLayout.NORTH, quest, point.y, SpringLayout.NORTH, panels);
setLayout(spring);
panels.setOpaque(false);
panels.setVisible(true);
panels.setLocation(10, 10);
add(panels);
// action Listener to be set on individual buttons
quest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent a) {
if (quest.equals(points.get(5)))
;
String c = "Hello!";
JOptionPane.showMessageDialog(null, c);
}
});
}
}
The problem is that expression
if (quest.equals(points.get(5)));
does nothing. I guess it should be rewritten like this
if (quest.equals(points.get(5))) {
String c = "Hello!";
JOptionPane.showMessageDialog(null, c);
}
The way I am understanding the question is that you have multiple buttons and you would like each button to have it's own action associated with it. There are a couple ways to go about doing this. Either you create a new ActionListener for each JButton depending which button you are creating.
You can also create a large case/switch or if/else within the ActionListener that gets determined by which button was selected. To do this you can call the getActionCommand() function for the ActionEvent object.
quest.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent a) {
if (a.getActionCommand().equals("Question 1"))
{
String c = "Hello!";
JOptionPane.showMessageDialog(null, c);
}
else if(a.getActionCommand().equals("Question 2"))
{
//have it do something else
}
//and so on so forth
}
});
You need to rethink the entire design. You have this line:
if (quest.equals(points.get(5))) {
But points is a list containing Point objects; points.get(5) returns a Point.
quest is a JButton. How can a JButton instance equal a Point instance?
This is what I am having trouble with. I am making a Keno game out of a Crystals code I was given. So far, I have been able to choose 20 of the 80 and turn them red. However, I have the button set to when I press it it says "Game is a draw" and the window closes.
I am trying to put in a code where it will randomly draw 20 numbers without repeating, and then they turn yellow, however, if the CPU and the human match a number, it will turn green. I have no idea how to start this code or how to go about doing it. Here is what I have:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.lang.String;
public class Kenogame {
// constants
public static final int WIDTH = 4;
public static final int HEIGHT = 20;
public static final int INITIAL = 0;
public static final int RED = 1;
public static final int YELLOW = 3;
public static final int CHECKED = 4;
private int turn = RED; // to track which player should play next
private int[][] playerGrid; // to record each player's move
private int[][] shadowGrid; // to keep track of which atoms have been FOUND
private int[][] crystalGrid; // to extract a single crystal from playerGrid
private int row, column; // position of most recently added atom
private int lowX, lowY, highX, highY; // corner coordinates of current crystal
private int player1Score = 0;
private int player2Score = 0;
// GUI related fields
private JButton[] buttonArray;
// private JTextField scoreField1;
// private JTextField scoreField2;
// private JLabel labelRED; // Label "Red" on GUI
// private JLabel labelYELLOW; // Label "Yellow" on GUI
private JLabel labelTurn; // Label displays whose turn is next
private int numberToSelect = 20;
Kenogame() {
createGUIAndPlay();
}
private void createGUIAndPlay() {
final JFrame f = new JFrame();
// create the panels
JPanel topPanel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel(new GridLayout(WIDTH, HEIGHT));
JPanel labelPanel = new JPanel();
// represents the 2D grid of buttons on the GUI
buttonArray = new JButton[WIDTH * HEIGHT];
// stores the positions of atoms in both player's crystals
playerGrid = new int[WIDTH][HEIGHT];
// shadowGrid keeps track of which atoms have been found
shadowGrid = new int[WIDTH][HEIGHT];
// used to store a crystal to determine if it is a perfect crystal
crystalGrid = new int[WIDTH][HEIGHT];
JButton endGameButton = new JButton("Start Draw");
// labelRED = new JLabel("Red");
// scoreField1 = new JTextField(3);
// scoreField1.setEditable(false);
//labelYELLOW = new JLabel("Yellow");
labelTurn = new JLabel(Integer.toString(numberToSelect), Label.LEFT);
Dimension dim = labelTurn.getPreferredSize();
labelTurn.setPreferredSize(new Dimension(dim.width + 100, dim.height + 10));
// scoreField2 = new JTextField(3);
// scoreField2.setEditable(false);
// scoreField1.setText("0");
// scoreField2.setText("0");
// create the buttons on which players will make their moves
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i] = new JButton(Integer.toString(i + 1));
buttonPanel.add(buttonArray[i]);
}
final Color buttColor = buttonArray[0].getBackground();
// add the action listener to the buttons
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i].setActionCommand(Integer.toString(i));
buttonArray[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
if (button.getBackground() == Color.RED) {
button.setBackground(buttColor);
numberToSelect++;
} else {
if (numberToSelect > 0) {
button.setBackground(Color.RED);
numberToSelect--;
}
}
// button.setEnabled(false);
int buttonIndex = Integer.valueOf(button.getActionCommand());
row = buttonIndex / WIDTH;
column = buttonIndex % WIDTH;
// playMove();
labelTurn.setText(Integer.toString(numberToSelect));
// updateGUI();
}
});
}
endGameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s;
// Need to add "ball draw here" for Keno
// 20 random numbers between 1 and 80
// each time a "ball" matches one selected on the Keno ticket add to a counter
// at end look up payout for the number of matches corresponding to the counter
if (player1Score > player2Score)
s = "RED wins the game";
else if (player1Score < player2Score)
s = "YELLOW wins the game";
else
s = "Game is a draw";
JOptionPane.showMessageDialog(f, s, "Game Over", JOptionPane.PLAIN_MESSAGE);
System.exit(1);
}
});
labelPanel.add(endGameButton);
labelPanel.add(labelTurn);
topPanel.add(labelPanel, BorderLayout.NORTH);
topPanel.add(buttonPanel, BorderLayout.CENTER);
f.add(topPanel);
f.setSize(1000, 400);
f.setTitle("Keno");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
private void playMove() {
playerGrid[row][column] = turn;
if (turn == RED) {
turn = YELLOW;
} else {
turn = RED;
}
}
private void initialize() {
highX = highY = Integer.MIN_VALUE;
lowX = lowY = Integer.MAX_VALUE;
for (int row = 0; row < HEIGHT; row++)
for (int column = 0; column < WIDTH; column++) {
crystalGrid[row][column] = INITIAL;
}
}
public static void main(String[] args) {
new Keno();
}
}
// green for a match, yellow for a no-match.
I have 4 lines towards the bottom where I am supposed to insert the code. I would really appreciate it if someone could give me a hand on this.
To draw 20 non-repeating numbers, you can do the following:
put your 80 numbers in a collection.
shuffle the collection
the elements are now in random order and you can loop over the collection to get the first 20 elements.
If you give me more details on what you are stuck, I can provide further information.
the basic aim is to have a JPanel filled with 9 white squares in a 3x3 pattern; The squares are 150x150 blank white .jpg files. It must be this way since later on, the program will have to change the blank squares to one of a selection of simple images, and must be able to change any square at any time.
The problem, simply, is I'm getting a NullPointerException. I have to assume it's something to do with initialising the array as null but NetBeans(yes, NetBeans...) seems to get angry with me if I don't do that. Same if I try to declare the size of the array. (That would be... "ArrayType[arraysize] arrayName;", yes?"
Egh, I'm just guessing wildly.
Edit - NullPointerException fixed, but now the blank(white) images are simply not appearing in the frame. Code below edited to reflect its new state, more potentially relevant lines added.
Here be all relevant code:
JFrame controller = new JFrame("SmartHome Interface");
controller.setVisible(true);
controller.setSize(480,500);
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//[...]
JPanel labelPanel = new JPanel();
//[...]
labelPanel.setBackground(Color.GREEN);
//[...]
ImageIcon blank = new ImageIcon("../Images/blank.jpg");
//[...]
controller.add(labelPanel);
//[...]
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++)
{
int xLowBound;
int xUpBound;
int yLowBound;
int yUpBound;
//Maths for positioning the labels correctly. Should be 150px in size with 10px gaps each.
xLowBound = (i % 3) * 160;
xUpBound = xLowBound + 150;
yLowBound = (i / 3) * 160;
yUpBound = yLowBound + 150;
labels[i] = new JLabel();
labels[i].setIcon(blank);
labels[i].setBounds(xLowBound, yLowBound, xUpBound, yUpBound);
labelPanel.add(labels[i]);
}
Also.....is the filepath for the ImageIcon correct?
The code itself being located in "src/smarthome" and the images in "src/Images"
And apologies if I broke any forum conventions/codes of conduct/etc. Newby here, tried to be careful not to but I may have forgotten something.
Your problem reduces to this:
JLabel[] labels = null;
for (int i = 0; i <= 8; i++) {
labels[i].setIcon(blank);
}
This code fragment will fail because labels == null. Therefore labels[i] == null.
Use this instead:
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++) {
labels[i] = new JLabel();
labels[i].setIcon(blank);
}
Your filepath for imageIcons is incorrect. You should use:
ImageIcon img = new ImageIcon(getClass().getResource("../Images/blank.jpg"));
if your code is in static method use this:
ImageIcon img = new ImageIcon(YourClass.class.getResource("../Images/blank.jpg"));
There is a good answer about loading image icons(thanks to nIcE cOw).
You should call setVisible() and setSize() after adding all components to the frame.
Add components to frame's content pane(frame.getContentPane()).
You always should place your GUI code in separate thread.
So, your code will be:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame controller = new JFrame("SmartHome Interface");
controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel labelPanel = new JPanel();
labelPanel.setBackground(Color.GREEN);
// !!!
ImageIcon blank = new ImageIcon(YourClass.class
.getResource("../Images/blank.jpg"));
// !!!
controller.getContentPane().add(labelPanel);
JLabel[] labels = new JLabel[9];
for (int i = 0; i <= 8; i++)
{
int xLowBound;
int xUpBound;
int yLowBound;
int yUpBound;
xLowBound = (i % 3) * 160;
xUpBound = xLowBound + 150;
yLowBound = (i / 3) * 160;
yUpBound = yLowBound + 150;
labels[i] = new JLabel();
labels[i].setIcon(blank);
labels[i].setBounds(xLowBound, yLowBound, xUpBound,
yUpBound);
labelPanel.add(labels[i]);
}
// !!!
controller.setVisible(true);
controller.setSize(480, 500);
}
});