I am trying to make a very simple grid in which a user can move through. Through my research i have concluded that the best way to achieve this would be using a two-dimensional array to represent the grid. However i am unsure of how to draw this array to a Jframe or Jpanel if i were to make an array of rectangles.
Many Stackoverflow questions seem to ask simmilar queries but unforunately i have found non that entirely explains how to draw a simple grid of rectangles.
You can make arrays out of everything. Notice how the way to implement an array is
*datatype* [] *arrayname* = new *datatype* [*lengthOfArray*];
Lets say the name of the class that contains the rectangles is RECTANGLE. So if you want an Array, that contains, lets say, 5 rectangles, it would look somewhat like that:
RECTANGLE [] rectangelArray = new RECTANGLE [5];
If you want to take that to a 2 dimensional Level, just add another bracket:
RECTANGLE [][] rectangelMatrix = new RECTANGLE [4][5];
Assuming that by "drawing to the JPanel" you mean that you want to put the rectangles onto the screen, you would then have a for-loop in a for-loop, that would for example call each rectangle to draw itself:
for(int i = 0; i<rectangleMatrix.length; i++){
for(int j = 0; j<rectangleMatrix[i].length; j++){
rectangleMatrix[i][j].draw();
}
}
rectangleMatrix.draw() calls a method that will draw the rectangle based on its coordinates and size. you could also in a similar fashion call a method that will read the information of each rectangle and then draw it based on that information. This will help you seperate between information and drawing purposes in your classes, which is always a good thing to do:
for(int i = 0; i<rectangleMatrix.length; i++){
for(int j = 0; j<rectangleMatrix[i].length; j++){
drawRectangle(rectangleMatrix[i][j]);
}
}
drawRectangle(RECTANGLE toDraw) is in the same class that you have the method with the for-loop in.
In your parent component of grid set layout like
gamePanel.setLayout(new GridLayout(ix, iy));
where ix and iy is dimension size
you also need array of cells private Cell[][] cells; in this case cell is simply
public class Cell extends JPanel{
//some game specific code, fields, constructors
}
now use it
for (int i = 0; i < ix; i++) {
for (int j = 0; j < iy; j++) {
progres.setValue(progres.getValue() + 1);
cells[i][j] = new Cell(i, j, passer);
gamePanel.add(cells[i][j]);
}
}
now if in constructor of cell you will set a border this.setBorder(new LineBorder(Color.GRAY)); grid will appear. in cell constructor or setter method you can also pass whole cells so each cell will be aware of another, and be able to interact with them. but be aware- if you pass it in loop that also create cells, you might encounter a null values.
this way you can use swing components so each cell can be clickable etc.
You can extend a JComponent and overriding its paint(Graphics) method to draw the grid using Graphics.drawLine.
If you need the grid cells to be interactive in some way, then you should probably just create components with rectangular borders and position them using a grid layout.
Related
how can I make on a button press a new deep copy of a 2 dimensional array?
Basically I created a game field with buttons. The game is called sokoban and it's a puzzle. The player is moving from one button to the other with arrow keys on a fixed map (8x8 buttons).
I want to implement an undo function. So I thought that I just create a deep copy of the JButton array before each move and save it into a stack. So when I press the undo button it calls the pop function of my stack. The problem is that I need to declare and initialize another JButton[][] where I can save the game field to before each move. Since I want infinite possible moves and also undos it seems impossible to me. I can't declare and initalize infite diffrent JButton[][] arrays. Any idea on how I can solve that?
That's how I copy a 2d object array:
JButton[][] tempArray = new JButton[jbArray.length][jbArray[0].length];
for (int i = 0; i < getJbArray().length; i++) {
for (int j=0;j<getJbArray()[0].length;j++) {
tempArray[i][j]=jbArray[i][j];
}
}
movesStack.push(tempArray);
Unfortunately you can't clone swing components in general, as they do not implement the Cloneable interface. As I see it you have two options:
Create a new JButton inside your double loop and copy whatever properties (like alignment, color etc.) you have set to the new JButton
Write your own class that extends JButton and implement the Cloneable interface
The first way is somewhat of a hack and not very robust or reusable. The second way is much better practice. In this case you'll have to define how the deep copy is supposed to happen, and ensure that all relevant properties are copied over.
You've got the right idea. You're not quite going deep enough.
public JButton[][] copy(JButton[][] jbArray) {
JButton[][] tempArray = new JButton[jbArray.length][jbArray[0].length];
for (int i = 0; i < jbArray.length; i++) {
for (int j = 0; j < jbArray[0].length; j++) {
tempArray[i][j] = new JButton(jbArray[i][j].getText());
}
}
return tempArray;
}
Rather than copying JButtons, you should have a model that you use to set the JButtons. Maybe a ModelClass[][] array?
I am learning Java and am trying to implement MineSweeper as a learning experience. I've got most of the logic working, but I am running into trouble with my recursive checkMine() method. I think the problem is my understanding, or misunderstanding rather, of how the GridLayout interacts with 2D arrays.
What I need to be able to do is to construct a 2D array full of Mines--which are an object extending JButton--and assign each element of the array to its own GridLayout location. Currently, I have the game working, but the numbers are not displaying the correct number of bombs, and I believe after debugging this could only be an issue with my implementation of the 2D Array with the GridLayout.
QUESTION: Is it possible to fill a GridLayout with individual elements of a 2D array? If not, what would be the best way for me to do this?
dAssuming your class extends java.applet.Applet
// Columns, Rows
Mines[][] mineGrid;
// Add stuff to the `mineGrid` array
// Set the height to the number of rows, length to number of columns
setLayout(new GridLayout(mineGrid.length, mineGrid[0].length);
// For each row
for(int rowIndex = 0; rowIndex < mineGrid.length; rowIndex++) {
// For each column
for(int colIndex = 0; colIndex < mineGrid[0].length; colIndex++) {
// Add the button, because of GridLayout it starts # the top row, goes across left to right, down a row, across left to right, etc.
add(mineGrid[rowIndex][colIndex];
}
}
I am working on a lab, it's a connect four game. I'm having trouble specifically with basic concepts like how classes communicate with each other, how to use private instance variables, how to use an ArrayList, how to compare JLabels or set them as something comparable...
To give a brief breakdown I have four classes GUI, Game, Player, Name
I can create the GUI by using two four loops, the game is a grid with 7 columns of 6 pieces. The pieces are images,
JLabel Piece = new JLabel("images/blank.png");
for example to denote an empty spot.
The GUI is based on a JFrame, single content pane and four panels, one for a header which indicates who is playing and who won, another for the 7 buttons accompanying the 7 rows, the grid itself of the possible places to be played and then a button panel which gives you the option to replay.
I'm lacking in a lot of concepts. For instance, the replay button shouldn't appear until the game has ended.
I don't understand how to use an ArrayList. I tried to use
ArrayList<ArrayList<JLabel>> myList = new ArrayList<ArrayList<JLabel>>();
So when I create the GUI by running two for loops like so
For ( c = 0 ; c<8 ; c++) {
ArrayList<JLabel> column = new ArrayList<JLabel>();
For ( r = 0 ; r<7 ; r++) {
ArrayList<JLabel> row = new ArrayList<JLabel>();
JLabel empty = new JLabel("images/blank.png");
row.add(empty);
}
column.add(row);
}
Even this small step I've already got confused.
I know the two for loops above are not correct specifically the ArrayList.
I don't know how to create the arraylist and then use them.
using something like
column.get().get();
myList.get().get();
to get a specific piece.
I don't know how to pass that to an argument so that for example if I push on button 7 for column 7, and no pieces have been played yet, I can start from the lowest area column 7 row 6 and update that to a played piece, red or yellow for the appropriate player.
This is vague and I doubt I'll get anywhere but I am desperate for help. There isn't much time available from the TA's / Teacher and I believe I am lacking significantly to be able to finish this project.
I understand how it works/what I have to do in words but in terms of applying Java code...
I'd appreciate any help.
OK first off you should use an array of Enums. ArrayLists are intended for lots of items and that can have rapidly changing numbers. Arrays are intended to house data in a grid of some sorts. Since you are using a static board, use arrays! They are also much less memory-intensive. Example:
//Note you should use [column][row] as that is common practice.
States[][] grid = new States[7][6];
//And initialize it:
for(int i = 0; i < grid.length; i++)
for(int o = 0; o < grid[i].length; o++)
grid[i][o] = EMPTY_JLABEL;
Then declare an enum (this is a new class) (NOTE: replace FULL_PLAYER_ONE_JLABEL and FULL_PLAYER_TWO_JLABEL with the JLabels that have the image for each.):
public enum States {
FULL_PLAYER_ONE(FULL_PLAYER_ONE_JLABEL), FULL_PLAYER_TWO(FULL_PLAYER_TWO_JLABEL), EMPTY(EMPTY_JLABEL);
//The image of the appropriate state.
private JLabel label;
//Enum constructors must be private
private States(JLabel label) {
this.label = label;
}
public JLabel getLabel() {
return label;
}
}
In your GUI, have a JButton that is only added to the frame when the game is over. Also add a button to indicate when each column has been clicked by the player.
JButton button = new JButton();
//Initialize JButton and add to frame...
//Anytime before the frame is set to visible:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/* Perform tests for for what should happen.
For example test whose turn it is then call a method to add a piece to that column. Then call a checker to see if someone has won. If so, display the replay button, otherwise do nothing (allow other player to move).
*/
}
}
I don't know what to do for this. Print a box with a hole in its center. That is, print a box as in normally but with the single # in the center (or one close to the center for boxes with an even width) replaced with a space.
I have the box. How do I calculate the center of the box?
import java.util.Scanner;
public class square {
public square(){
Scanner H=new Scanner(System.in);
int y=H.nextInt();//int for width
int x=H.nextInt();//int for height
int [][]shape=new int[x][y];//2d array stores the above
for(int i=0; i<shape.length; i++){//loops through height and width below
for(int j=0; j<shape[i].length; j++){
System.out.print("#");//prints box of #
}
System.out.println();
}
}
public static void main(String[]args){
new square();
}
}
First of all, not sure why you are making an array (shape) at all, unless that is part of your assignment?
If you use a for loop that steps from 0 to y inside one that steps from 0 to x instead of using the lengths of the array, you will get the same results without needing the array.
As for the center, its location is x/2, y/2. If you change your inner loop to check your variables i and j to see if the current position is x/2, y/2 and print a space instead of an # in that case, I think you will have the results you're looking for.
I'm having a little trouble building the grids for a Battleship game for my Java class. So far, I can easily make a for loop to add JPanel or JButton objects to the JFrame. However, my issue is that I'll need to use those Panels or Buttons again when playing the game (such as clicking on a button to see if your opponent put a ship on that square, et cetera). Is there a simple way in Java to initialize reference variables for a LOT of objects? Or will I have to declare all of them individually?
You could try a multi dimensional array of JPanels (or any other object). Create an array with the same size as your grid. The line below initializes an array with 5 rows and 5 columns.
JPanel[][] battleField = new JPanel[5][5];
Use nested for loops to create the panels in the array.
for (int rowIndex = 0; rowIndex < battleField.length; rowIndex++)
{
for (int cellIndex = 0; cellIndex < battleField[rowIndex]; cellIndex++)
{
battleField[rowIndex][cellIndex] = new JPanel();
}
}
If you want to reference the battleField array later on you would just make it into a instance variable.
For a battleship game, you most likely want to retrieve the location of a button after is has been clicked. You can create a hashtable using your buttons as keys and the point it is located at as a value.
HashMap<JButton, Point> buttonMap = new HashMap<JButton, Point>();
for (int x = 0; x < COLUMNS; x++)
{
for (int y = 0; y < ROWS; y++)
{
JButton btn = new JButton();
btn.addActionListener(this);
buttonMap.put(btn, new Point(x, y));
//then add the button to your container
}
}
The in your actionPerformed method you can convert the button to the point it is located at like this.
JButton btn = (JButton)actionEvent.getSource();
Point p = buttonMake.get(btn);
Of course you will need to properly handle error conditions such as source not being a button or the button not being in the map...
You can always extend JButton to keep track of the info you need. A simple example:
class MyButton extends JButton{
private MyGameInfo mygameInfo;
private int buttonId;
//More fields....
//Getters/Setters
}
Then instead of creating and adding JButton objects to your layout, create MyButton objects(which is also a JButton so your layout will not be effected) and use its extra functionality for your game logic.
For reference, here is a related matching game that uses a grid of buttons. This related answer demonstrates the application of the Model–View–Controller pattern to a simple game.