Im learning Java and Im creating a memory type game where you have to find two equal cards.
I have created a Window etc etc but my problem is adding multiple JButtons to it. (my cards are JButtons with icons). I have commented my code where my problem is.
//Get the images.
private File bildmapp = new File("bildmapp");
private File[] bilder = bildmapp.listFiles();
//My own class extending JButton
Kort[] k = new Kort[bilder.length];
for(int i = 0; i < bilder.length; i++){
k[i] = new Kort(new ImageIcon(bilder[i].getPath()));
}
//Later in my code:
int sum = rows * columns;
Kort[] temp = new Kort[sum];
//My function to randomize.
Verktyg.slumpOrdning(k);
//***********************//
//Trying to fill a array from K (which contains all cards) so my temp contains SUM cards and SUM/2 pairs
for(int i = 0; i < sum/2; i++){
temp[i] = k[i];
temp[i+sum/2] = k[i];
}
//Problem is that i only get SUM/2 (half of the cards) cards, not the 16 (8 pairs) i would like to add in this case
//SYNLIGT = VISIBLE.
for(int i = 0; i < sum; i++){
temp[i].setStatus(Kort.Status.SYNLIGT);
j.add(temp[i]);
}
Your code ends up adding each Kort object to the container twice, since the array temp contains two references to each Kort. When you add a Kort a second time, it moves to the second location. A Component can only appear in one place at a time.
You may not add the same widget twice. You need two separate buttons (but you may use the same icon on both).
You have to create sum JButton objects not sum/2; otherwise 2 buttons are the same and therefore only displayed once.
Related
If you want the TLDR without context: I need help figuring out how to properly define and fill a data structure from a 2D array for a pathfinding algorithm. Scroll to the bottom for my code.
I'm developing a game (early version available for viewing/playing on my github) For those curious about the map making program specifically, here is a link to that directory on my github.
If you just want to see how the game functions to get a better grasp, here is a video demo.
The game itself loads maps utilizing LUA, and I made a simple map maker to generate Lua using the Swing library in Java.
Basic Premise:
Navigate to the Goal of the map from the designated starting position.
Once a player starts moving, you can't stop or change directions until you hit a wall. Also you can't move diagonally.
Players can make their own maps and challenge their friends.
I want to restrict players to making only valid (winnable) maps to avoid frustration. - How do I best accomplish this in your opinion?
The A* algorithm I believe is my best starting point for a method like this. However, I need to wrap my head around defining a valid path.
My maps in Java are currently represented as a 2D Array of Image Icons. (For now)
The buttons can have 1 of 4 properties:
Empty - represents the floor, IE a normal navigatable part of the map.
Wall - represents a wall, Players will be stopped when coming into contact.
Start - represents where the player will start on the map.
Goal - represents the tile where the player will have completed the map.
Here is what I have (algorithm not included since its currently nothing different from a typical example on wiki)
class Tile {
JLabel payload = null; // wall, empty, goal, start
Tile up = null;
Tile down = null;
Tile left = null;
Tile right = null;
}
// Fill and return a list with the information for each tile on the map
public static ArrayList<Tile> checkMapStatus(JLabel[][] map){
ArrayList<Tile> mapList = new ArrayList<Tile>();
for(int i = 0; i < map.length; i++){
for(int j = 0; j < map.length; j++){
// create the surrounding tiles around the current tile (needs fixing)
Tile tile = new Tile();
Tile tileUp = new Tile();
Tile tileDown = new Tile();
Tile tileLeft = new Tile();
Tile tileRight = new Tile();
tile.payload = map[i][j];
if(map[j + 1] != null) // prevent accessing inexistant array position
tileUp.payload = map[i][j+1];
if(j > 0) // prevent accessing inexistant array position
tileDown.payload = map[i][j-1];
if(i > 0) // prevent accessing inexistant array position
tileLeft.payload = map[i-1][j];
if(map[i + 1] != null) // prevent accessing inexistant array position
tileRight.payload = map[i+1][j];
tile.up = tileUp;
tile.down = tileDown;
tile.left = tileLeft;
tile.right = tileRight;
mapList.add(tile);
}
}
return mapList;
}
Issues with the above code:
I'm creating tile objects that aren't technically connected to eachother right? That is, the up down left and right tiles aren't ever referenced again once created, so I'm creating 5 tiles when really I should only be creating 1 and refering the existing ones. How do I fix this in Java?
Possibility for efficiency? Would it be better for me to only define the wall, goal and starting tiles since the other ones are technically empty space?
What I would do is to start off with a Tile[][] temp variable to help with the objects referencing eachother, and flatten it as you go. It's slightly less efficient, but not enough to worry about if this is just to initialize things.
public static ArrayList<Tile> checkMapStatus(JLabel[][] map){
ArrayList<Tile> mapList = new ArrayList<Tile>();
Tile[][] temp = new Tile[map.length][];
for(int i = 0; i < map.length; i++){
temp[i] = new Tile[map[i].length];
for(int j = 0; j < map.length; j++){
// create the surrounding tiles around the current tile (needs fixing)
Tile tile = new Tile();
temp[i][j] = tile;
tile.payload = map[i][j];
//Just look up and to the left, populate the existing Tiles as you populate the current one
if(i > 0 && j < temp[i-1].length){
tile.up = temp[i-1][j];
temp[i-1][j].down = tile;
}
if(j > 0){
tile.left = temp[i][j-1];
temp[i][j-1].right = tile;
}
mapList.add(tile);
}
}
return mapList;
}
I would like to create a minesweeper game. Firstly, this will work on buttons. I think I will work on two dimensional array, and there will be like boolean array that will present where are bombs, for example if booleanArray[0][4] is true, there is a bomb.
Now, how can I implement this in my buttons? I can set Names on these buttons, and then if I click some button, then I will get the name from this div. For example when i click first button, i will get "00" name, then i will get first letter "0" and second letter "0" and parse it to int. And this will be the indexes from my previous booleanArray, in this case it will be booleanArray[0][0].
So, can I do this another, better way, instead of that?
This is the way I will be creating the buttons:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
JButton button = new JButton("");
button.setPreferredSize(new Dimension(50, 50));
button.setName(Integer.toString(i) + Integer.toString(j));
}
}
EDIT
I will have a two dimensional Array, that will reflect my buttons:
and now, how can I check if I hit the bomb after I click for example in the first button?
Just hold a two dimensional array of buttons,
JButton[][] myButtons = new JButton[10][10];
which you use to draw them and they all call the same method with their value
for (int x=0; x<10; x++){
for (int y=0; y<10; y++){
myButtons[x][y] = new JButton("0");
//add to page, or do it elsewhere
myButtons[x][y].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
selectionButtonPressed(x,y);
}
});
}
}
Then a call to yout method selectionButtonPressed() will tell you what button has been pressed, you can take action and even make changes to the button with myButtons[x][y].whatever()
That is one way but you should create the String of the name by using something like:
button.setName(i + ":" j);
This will make it easier to parse out the two values as you can just use the String.split(...) method.
Another option might be to create a HashTable with the JButton as the key and then use a Point object (representing the row/column) as the value Object of the HashTable. Then you just use the get(...) method of the HashMap to retrieve the Point for the clicked button.
Another option is to extend JButton and add two parameters (row, column) when creating the button. Then you also add getRow() and getColumn() methods.
Either of this approaches will keep the logic simple and you only need to create a single ActionListener to be used by all the buttons.
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?
Im adding buttons for a game but when removing the button in a loop it will only get rid of one button even though i added them in the same way
for(int i=0 - 1; i < 4 ; i++) {
panelButtonsub.remove(buttonBlankItems);
}
panelButtonsub.setLayout (new GridLayout (intLayout,intLayout));
revalidate();
repaint();
If you want to remove all the buttons in the panel you can use:
panel.removeAll();
If you want to remove the first 4 buttons in the panel you can use:
for (int i = 0; i < 4, i++)
panel.remove(0);
If you are trying to remove a certain type of component from the panel then you need to start at the end to remove the components:
int components = panel.getComponentCount();
for (int i = components - 1; i >= 0; i --)
{
Component c = panel.getComponent(i);
if (c instance of BlankButton)
panel.remove(i);
}
Where BlankButton is the component you created to represent the extra space by using panel.add( new BlankButton(...) ).
If you are trying to do something else then you need to clarify your question.
You must have distinct instances for each buttonBlankItems button. I guess that you are adding the same button 5 times and then you are trying to remove them.
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.