Hello StackOverflow users!
I have a problem and I did find a solution to the problem, but I feel that the solution is not optimal. I feel like I used brute force to achieve what I wanted to do and am wondering if there might be a better way to achieve what I want.
Essentially what I have is a Java GUI application using the GridBagLayout. I use the GridBagLayout because the layout is essentially always center-aligned. When something else is added in, it shifts everything up, down, left, or right (depending on where the new object is added in). The issue, is that my program also needs to remove certain objects (depending on what happens in other blocks of code). So lets say I have four objects lined up like this [1] [2] [3] [4] and I want to remove [3]. I essentially want the layout to change to [1] [2] [3], essentially shifting everything over after the [3]. There was no problem doing this visually (because of how GridBagLayout works). However, when something new was to be added to the display, there would be overlap because though [4] took the visual position of [3], the GridBagPosition (not sure what else to call it) did not change. So I implemented the code below for the removal process.
public void removeSubImagePanel (int subPanelIdx) {
int x, y, nextX, nextY;
this.remove(this.portraits[subPanelIdx]);
nextX = this.portraits[subPanelIdx].getGbx();
nextY = this.portraits[subPanelIdx].getGby();
for (int i = subPanelIdx; i < this.numberOfPortraits; i++) {
x = nextX;
y = nextY;
this.portraits[i] = this.portraits[i+1];
if (this.portraits[i+1] != null) {
nextX = this.portraits[i+1].getGbx();
nextY = this.portraits[i+1].getGby();
this.portraits[i].getObject().setSubPanelIdx(i);
gbc.gridx = x;
gbc.gridy = y;
this.portraits[i].setGbLocation(x, y);
gb.setConstraints(this.portraits[i], gbc);
}
}
this.portraits[this.numberOfPortraits] = null;
this.numberOfPortraits--;
}
Essentially, I added two integer variables to the "portraits" object to hold the position of the X and Y on the GridBagLayout. That way, I could get the position [3], get the position of [4] set [4]s position to where [3]'s was and then (if there was a [5], set [5]'s position to [4]'s old position and so on until I arrived at the last element.
It feels too "brute force", having to add those integers, and I feel like it would be even worse if I were to make an individual GridBagConstraint for each object. Is there a better way to do this shifting that I need to do?
Sorry, this question is quite long. I didn't think it would be so long. I hope this is still okay. If I was unclear and you need any clarification, please don't hesitate to ask!
Edit: Would it be better if this were on the CodeReview stackexchange? It actually seems to make more sense to have it there. I'm not quite sure though.
This example shows that it is possible to remove all components from a container and completely replace each component in arbitrary order. The time required to validate() the enclosing container is negligible, as the components themselves remain unchanged.
I'm not sure what your requirements are for this project, but I would check out the Spring Layout - this layout lets you specify things like:
the left of [1] should be 10 pixels from the left of the panel
the right of [1] should be 10 pixels from the left of [2]
etc.
It is much easier (imo) to implement a nice fluid layout like you are describing here.
Edit: Just to try and add to the discussion:
maybe you could have a class called PortraitPanel that extends from Panel and in there you could maintain a List of your image panels. You could have public methods:
add(int index);
remove(int index);
So that when you call add(2) it will add that panel to the list at that index - and then take the panel at index - 1 and index + 1 and do the routine to adjust the constraints on these so it lays them out on either side of the newly added panel. Similarly, for remove you could take index - 1 and set it's constraints to lay out next to index + 1 and then remove the item at index. Again, if you use a SpringLayout it will be really easy to set it up so that things remain fluid when the window resizes, etc.
Hopefully this is in line with what you are trying to do.
Related
I'm trying to write a tetris clone. My board is a 10x20 array of integers on which 0 means no tile, 1-7 means a tile of specific color. It is constantly translated to graphic interpretation. My shapes are 4x4 arrays of integers. I've just come to a realisation that while making all of the shapes 4x4 makes some things easier, it also causes a problem when moving a piece left and right. Let's say we've got the I shape:
0010
0010
0010
0010
Now, if I move it to left wall there will always be a two units long gap, since the 0s cant move outside of the main board array. What would be the easiest way to allow the 1s to move to the left wall without causing an out of bounds exception?
Using your described method, one way to simply avoid getting the IndexOutOfBoundsException would be to expand your board to be 18 x 24 instead of 10 x 24, and then write in additional code that doesn't let you move a block left/right if there would be any 1's in the object array that leave the middle 10 squares of the grid. By adding this 'padding' to your grid, you avoid the exception and should still be able to implement.
I hope this approach makes sense to you. If not I can provide a more pseudo-code driven answer, but I hope you get the idea. (Just comment if you have any questions.)
BTW, #assylias makes a very good point. It is important to have a good design/plan before you start implementing things to avoid road-bumps like these. It comes with experience, so keep practicing and you will get the hang of it.
NOTE: As Nick pointed out in the comment, another way of doing this is to simply check if any 1's leave the grid before moving any of the arrays. This is certainly possible (and arguably a more elegant/simple solution), although it may be a bit harder to get right.
You need a way of detecting collisions with borders and existing pieces.
You would probably have a fixed handle on each piece, you'll also have an X and Y offest for the piece which indicates it's position as it moves down the grid.
To stop a piece moving out of bounds, loop through the 4*4 matrix of the moving piece and for the bits which are set to 1 simply check
to make sure that the X position + X offset is >= 0 and <=9 and the Y Position is >=0 and <=19 if either of these checks fail
then your piece would be moving outside the limits of the board array so stop the change to x or y offest as appropriate.
Translating the co-ordinates of the set bits in your piece matrix with the board array also allows you to check and see whether your piece has collided with a tile already in the board.
You should be doing these collision checks when a piece rotates as well I would have thought.
I am making a simple game.
I have 6 buttons and i want to shuffle them each time on different locations.
So i've made a simple method to achieve this.
private void changeButtonPlace(ImageView button) {
Random r = new Random();
int newXloc = r.nextInt(getScreenWidth() - (2 * button.getLayoutParams().width));
int newYloc = r.nextInt(getScreenHeight() - (3 * button.getLayoutParams().height));
button.setX(newXloc);
button.setY(newYloc);
}
It works pretty well, but sometimes the buttons override each other which means that it goes on the almost the same location. I want each button to be on a unique location and don't touch other buttons.
Any idea how i can achieve this?
Thanks in advance!
What you are looking for is collision detection, and my answer will greatly simplified this process. I suggest searching for collision detection algorithms to learn more.
So, for super simple starts, we can compare the position, length, and height of 2 boxes. For my example, I am going to assume the origin of these to boxes are their upper left corner.
if((boxA.xPos + boxA.length ) < boxB.xPos || boxA.xPos > (boxB.xPos + boxB.length))
That will check if the two boxes are touching along the x-axis, and we can change the values for the y-axis as well
if((boxA.yPos + boxA.height ) < boxB.yPos || boxA.yPos > boxB.yPos + boxB.height)
Now, this is not a very efficient way of doing this. There are lots and lots of better ways to simplified this logic, and save on resources. But, it is quick and dirty, and probably good enough for a small application like your simple game involving only 6 buttons.
So, with these two equations, you can either nest them then run your collision code inside, or you can OR them together to one equation like this:
if(((boxA.yPos + boxA.height) < boxB.yPos || boxA.yPos > (boxB.yPos + boxB.height)) || ((boxA.xPos + boxA.length ) < boxB.xPos || boxA.xPos > (boxB.xPos + boxB.length)))
That is a lot to read for one line, and if you just starting out, I would suggest nesting them so you can better see the flow of logic through the equations. But, keep in mind for the future, if you ever need to squeeze those few extra bits of performance, OR them together to one if statement is alright place to start.
One way would be to make a grid and instead of a random location on the screen use a random point on the grid. That way you can check if the current grid location has a button on it already.
If you want them to be more scattered you could add each button to an array and check that the new doesn't touch the other buttons. Loop infinitely creating random locations and another loop to check they don't hit the other buttons in the array. Once a new location is found add the button and break out of the infinite loop.
You should take in account the width of the button , and before setting the location of the button make sure no button intersect with a simple if, if they do just randomize the intersecting buttons, should be easy to programm
Edit :
Lets make it a bit simpler an assume you have 3 buttons an assuming they are located on a 2d axis with these coordinates
A : 1,0
B : 2,0
C : 5,0
button width : X=2 Y=2
As you can see in this example at first glance it seems as though no button intersects with each other yet if you add the width to B you understand that is real location is B [1,3] ,[-1,1] intersects with the real location of C [4,6],[-1,1] assuming the coordinates are the center of the button
first [,] represents X axis second [,] represents Y axis
therefore your check will be something like so:
For each Button x
For each button x
calculate real coordinates of button x and y check intersection
if exists recalculate the coordinates and start the loop over
this solution is a bit expensive when talking about running time but once you get the idea you will be able to find something easier.
I have made threads in the past about similar questions but because of my lack of detail the answers have not really been related to what I needed so I am going to try explain my question in as much detail as I can and hopefully it will be easier for you to understand what I require.
I watched Bucky's slick game tutorials on youtube and made a 2D Java game, the game is basically a 2D player viewed from above (birds eye view) can move around a 2D map with user key input (up, down, left, right). The map the player moves around is very small so that meant boundaries had to be set so that the player could not walk off of the map, to give you a better idea of how this was done, here is the tutorial for setting up the voundries:
http://www.youtube.com/watch?v=FgGRHId8Fn8
The video will also show you exactly what the game is like.
The problem is, these boundaries only require one axis meaning that if the player is walking down you say something like "if player gets to the coordinate (number) on the X axis change the player movement to the opposite direction so that he can not go any further."
Now this creates a problem for me because this only requires one axis so it easy to set up and understand but if you look on the video, on the map there is a house and I want my player not to be able to walk over that also but this deals with 2 dimensions, I have looked at things like rectangle collisions and have seen things relating to them in the other posts but I get confused because I am new to Java and havent really done much with it at the moment apart from watching Bucky's tutorials.
My code at the moment for my game class has got the following methods: init, render and update. So to sum it up I really just want to set up a way of not letting my player walk through the house, I will mention also (I should have mentioned it in my other threads) as I am very new to Java, could you please take a step by step method of showing me how to set up the collisions, I mean even the basics of things like making the rectangle if required.
If my code is required please tell me and I will post it as soon as possible.
Thank you in advance.
You can set up the board as a 2x2 grid of a class that has has property such as 'isBlocked'. By default the edges of the board would have this property set to true to prevent the character from walking off the edge. When you add other obstacles such as a house or a wall the grid position(s) the object occupies would also have the property set to true. Then when moving a character you just check if the grid position the character moves to has the property set to false to see if it's an allowable move. This also makes it quite trivial to save the level data so you can just load them from disk later on.
Two possible options:
Extend Shape or Rectangle or the relevant Slick objects (they should exist IMO) and just check for intersect()
Look for (x1,y1) and (x2,y2) values such that it starts outside and ends up inside.
Assuming you have intersect() methods:
//Grab the previous position
prevPosX = movingobject.X;
prevPosY = movingobject.Y;
//Update the position
movingobject.update();
//Test for collision
if(movingobject.intersects(targetobj)) {
//If it collided, move it back
movingobject.X = prevPosX;
movingobject.Y = prevPosY;
//And reverse the direction
//(might want to do other stuff - e.g. just stop the object)
movingobject.speed *= -1; //Reverse the speed
}
in this case your update class should also add one more condition to look for the house. let say the cooridnates of house(assuming rectanglular house here for other shape just change x and y values) are (x1,y1)(x1,y2)(x2,y2)(x3,y1) you have to add a condition to make sure
x value is not between x1 and x2 and at the same time y value cannot between y1 and y2.
Okay I have a game I'm working on that sets a 12x16 grid on the screen and then draws a pattern on the screen like so http://oi49.tinypic.com/53odih.jpg
I'm just wondering if there is a way using code to see if the box exists inside of the pattern or not?
This is how I'm looping though my grid boxes
//Set all blocks to default
for(int i=0;i<tilesX;i++){
for(int j=0;j<tilesY;j++){
blocks[i][j] = 0;
}
}
If a block is part of a pattern I set the block to 1. I want the blocks inside the pattern set to 2, but I can't think of a way to do this programmatically. The pattern will always be a complete shape and will always connect back to the starting point.
I hope that's not too confusing and I'm willing to provide you with what ever you need but I'm just lost on how to do it. Thanks
You need to implement the flood fill algorithm. Depending on how you draw the state of 2, you can flood fill the area starting at a known point inside the shape. Then check to see if its 0 (outside), 1 (border), or 2 (inside).
I think I'm grasping what you want here, but let me know if I'm off base.
I'm about to create a java crossword application but I am unsure of what packages to use to draw the crossword grid. I know you can manually draw grids with Graphics2D etc. but I'm not sure if this is the easiest way to do it as I'll need text fields in the grid squares.
Anyone have any suggestions as to creating the crossword grid.
Actually I don't think you need textfields in the grid squares but just to write down every single letter for every grid cell..
To allow editing you just catch keyboard strokes over the component you use and set crossword cells according to what the user writes.
Doing it this way would be quite easy because you can use a back 2-dimensional array that stores the whole grid, then when the user select a definition you just start filling single letters whenever keys are typed starting from the first cell of the definition.. your draw routine will need just to be able to draw the grid and center letters inside cells, nothing more..
A JTable could work but it think it's oversized for your problem, because you'll end up interfacing with a lot of things you don't need at all..
EDIT (for comment):
I did it something similar this way:
you can have a cell class
class Cell
{
boolean isBlank;
char value;
}
with an array of cells you obtain your grid:
Cell[][] gamefield = new Cell[15][15];
then inside paint() you can easily iterate:
for (int i = 0; i < Scheme.rows; ++i)
{
for (int j = 0; j < Scheme.cols; ++j)
{
g2.drawRect(i*32, j*32, 32, 32);
if (Scheme.scheme[i][j].isBlank)
g2.fillRect(i*32 + 3, j*32 + 3, 32 - 5, 32 - 5);
}
}
Just because I still have a screenshot result was something like
Maybe use a JTable and custom renderer for the cells. That should be at least a simple solution. Of course it takes a little time to get used to JTable, but eventually it's quite simple.
Did you consider JavaFX at all? JavaFX will let you create "scene-graphs" based on vector/graphics edited using Adobe Photoshop/Inkscape etc.
If not, most simple way would be to extend JTextField such that that will just hold 1 char and will be black/or whatever color to indicate non-editable and disabled. Also, add a custom Border to indicate puzzle question number. Put everything in to a GridLayout.