Java Repaint method creates new objects on top of old ones - java

This is probably a stupid question but I can not seem to either remember how to stop the program from doing this or I never learned it.
I'm creating a blackjack game which draws random cards with the paintComponent. When the hit button is clicked, I want it to draw the next card and generate the new total. However, whenever I click the hit button, it draws the new card perfect, but it then creates all new cards on top of my already drawn cards.
How do I stop the repaint method from picking new random cards and keep them the same throughout the program? I should mention, all the cards are stored in an array and are called to with a random number generator. Also, this happens when I resize the java window.
If asked, I will post the code but I feel like this has a simple solution.

You will need to move your 'select random card' logic outside of the paint method.
It might be a better idea to calculate all the cards in your array when you first build it, rather than selecting randomly at paint time. In other words, when you create the 'deck' array, build the entire deck so that every card knows what they are, before the user even begins to be dealt any cards from the deck. This way, there is no risk of them changing during gameplay. If you're only talking about 52 cards, or a small multiple of 52 cards, then the array is still pretty small and it'll be quick to randomise the entire array.
Alternatively, you could put a check on your "select random card" method that says something like this...
int cardValue = -1;
paintComponent(){
if (cardValue == -1){
cardValue = drawRandomCard();
}
// now paint it.
}
ie - restrict the drawRandomCard() to only run if the card doesn't already have a value.
Ultimately though, the best solution would be to completely separate the painting code from the logic - its bad coding practice for GUI activities like painting to be mixed in with programming logic.

Related

JPanel.removeAll() not functioning properly

So I'm currently teaching myself to use GUI, and I decided to go back to the code for a game of Go Fish that I created and add in a GUI to it. For the panel that holds the CPU Player's cards, it displays the back of some playing cards to indicate the size of the CPU's hand.
Whenever a change occurs in the CPU's hand size, my method updateComputerCards gets called to adjust the amount of cards appearing on the screen. It does this by calling the removeAll() method for my panel, and then proceeds to re-add the proper amount of card images.
My issue though, is that when the game first begins, and matches are found within the CPU's hand, the method works as intended, and the amount of cards appearing shrinks. However, every subsequent time that the method is called, nothing changes in the GUI despite the CPU having a hand of cards of a different size.
Through the debugger I can see that the removeAll() method is not removing all the components on the panel for some reason, even though it succeeds in doing so without issue the first time it is called. Can anyone help me out here?
public void updateComputerCards(ArrayList<Integer> hand) {
labelPanel.removeAll();
for (int i = 0; i < hand.size(); i++) {
labelPanel.add(computerCardLabels.get(i));
labelPanel.add(b.createHorizontalStrut(10));
}
}
You need to call the repaint() method after making the changes.
See Painting in AWT and Swing.

Java: Drawing grid to screen using 2D Array without lag/screen flickering

I am attempting to create a very simple top-down game in Java, but I am unsure how to approach a problem dealing with program performance.
I used a 2D array to store certain values that represent certain things, such as the surrounding environment and the player's position. I then used the paint() method to draw a grid to the screen based on a section of the 2D array. The player is always in the center of the grid. I have it coded such that the player never truly "moves", but rather the environment around him "moves" (if you press a key to move up, a new section of the array is drawn that is the same as the past section except it has a new row at the top and the bottom-most row is now the past section's second-to-bottom row, all the while the player stays in the center, if that makes sense).
Thus, we have a situation where the whole screen needs to be redrawn each time the player moves. As you might have gathered, this is bad for the program's performance, since it has to iterate through a 2D array and draw it the screen each time I call repaint(). If the user hits the key to move upwards twice in succession, the program will lag and the screen will flicker as it redraws the whole section of the array.
How can I improve the performance issue, given that I want to keep the player in the center of the screen at all times and have the environment move around him? Should I instead investigate Jscrollpanes? Is iterating through arrays in the paint() method not the way to go?
Thank you so much for both your time and also helping an inexperienced programmer.

Design idea of "Turn" in chess

I am writing a chess program, and I am at the stage of implementing the game loop.
To implement player Turn in chess, I want to get some advice on how to do it efficiently.
So, this is how my chess with GUI works so far:
I generate a class called BoardGUI(JPanel) with a size of 8x8 and place a class called TileGUI(JPanel) on each grid.
I also added a MouseListener on TileGUI and wrote all functions regarding the Piece's movement on the board.
All tiles that have a Piece also contains the information of the Piece (color, type).
My initial thought of implementing the "Turn" is to create an integer called turn, initialized to 0, and make the Black Piece movable when the turn integer is an odd number and make the White Piece movable when the turn integer is an even number.
This is the best idea, or will there be a more clever way to do this?

2D Arrays Battleship place random ships

Hi, I just started to create a battleship game and I would like to know how to place random ships in my 2D Array. Here is the code for 2D Array.
public class javaapplication24 {
public static void main(String[] args) {
int[][] table = new int[10][10];
int i,j,k;
for(i=0;i<table.length;i++){
for(j=0;j<table.length;j++){
System.out.print(table[i][j]+" ");
}
System.out.println();
}
}
}
The problem that you have undoubtedly noticed is that as each ship is placed, it rules out possibilities of where subsequent ships can be placed. The easiest way around the difficulty is just trial and error. First write a function for randomly placing a ship of a given size somewhere on the board. Place the ships using a nested loop. The outer loop could be a for-loop which iterates through the ships to be placed. The inner loop can be a while loop (or maybe a do-loop) that repeatedly calls the ship-placing function to get a candidate placement, then checks if it clashes with previous choices, looping until a clash-free placement is found.
As far as placing a single ship goes:
1) First generate a random number which is either 0 or 1 to determine if the ship will be placed horizontally or vertically
2) Then pick a random number to determine what the row or column it will be in
3) Finally, pick a random number for the first square in the row or column that contains the ship. The size of the ship will enter in here. If it has length 3, for example, then there are only 10-3 = 7 possible choices for the first square (assuming a standard 10x10 board).
On Edit: #Manus raised a good point about difficulties that would be encountered if the number of ships are above a certain threshold. If you have a massive fleet of ships on a small board it is possible that certain partial placements (of some of the ships) would rule out any valid placement of the remaining ships. The only way I see around this difficulty is to use a back-tracking approach that checks if there is enough room for a ship before trying to place it and, if not, revisit the placement of previous ships until you get something that works. But -- the work involved in checking if there is any valid position can be done in such a way that you simultaneously determine the set of valid positions, in which case you might as well directly pick from that set rather than use trial and error. My approach is essentially a quick-and-dirty approach for simulating the child's game. You would need a more sophisticated approach if you want a more flexible game.

How to make a simple mini map for a Java rpg game

I have an array that holds the names and then displays the appropriate graphics using:
public void paintComponent(Graphics g){
for(int i = 0; i<20; i++)
{
for(int j = 0; j<20; j++)
{
if(testMap.getData(i+(rowX-7), j+(columnY-7)).indexOf("rock") >= 0)
{
g.drawImage(image3, j*50 + 5*add, i*50 + 5*add2, 50, 50, this);
}
}
}
This works well displaying the actual graphics of my game. However, for my minimap, I do the same thing, with different values and increased numbers in the 'i' and 'j' in the for loop. This creates a smaller version of the map with a bigger scope, which leaves me with this. (Note, I only included one of the drawImage() methods, I removed the rest here to make the code more readable):
This is pretty much my desired effect (aside from the positioning, which I can change easily), however, this only shows a smaller version of what I already see on the screen. Any larger than about 20 x20, though, and the game begins to lag heavily -- probably something to do with the terrible way that I coded it.
I have tried replacing the images with squares using fillRect, but it does not help the issue.
Here is the code of my main class if anybody would like to take a look: http://pastebin.com/eEQWs2DS
The for loop within the paintComponent method begins at around line 3160, the loop for the main display is around 2678. I set up the Jframe at around 1260.
So, with all that said, basically my question is this:
Is there a better, more efficient way to create my minimap? My idea was to generate an image at the beginning of the program so that the game wouldn't have to recalculate every time the frame refreshes. I could create the map in advance, but I would have to manually update that every time I changed the map, which is definitely a hassle. I am having trouble researching how to do the former. My other idea is to slow the refresh rate of the minimap only, but I also do not know how to do that.
Other than that, if there are any simple fixes to the lag issue, please enlighten me. I apologize for the very, very messy code -- This is my first time programming anything with a display so I sort of just...hacked at it until it worked.
I don't know how easy this would be with your implementation, but instead of drawing an image, perhaps you could draw a square of a certain color based on what type of tile it should be?
For instance if you're looping through your list of tiles and you find a grass tile, you would first draw the grass tile at its proper location, then draw a smaller green square on the minimap.
The downside to this is that first you'd have to define what colors to use for the tiles, or perhaps when you load the tiles you can compute an average color for each one, and then just use that. Another issue is that the houses may not translate well on to the minimap, since the tiles have much more detail. You could draw some kind of house icon on the minimap instead of actually drawing any of the house tiles, though.
Basically, you want to use simpler representations of the objects in your map on the minimap, since it's smaller and less detail can be drawn anyway.
Have a look at how I do it in Tyrant (a Java roguelike):
https://github.com/mikera/tyrant/blob/master/src/main/java/mikera/tyrant/LevelMapPanel.java
Key tricks:
Use an offscreen BufferedImage. Cache this to avoid recreating it each time you paint.
Use an int[] array to setup up a single colour for each tile
Use setRGB with the array to draw all the map at once
Draw the mini-map at x2 zoom to get 2x2 pixel blocks for each tile.
If you want to be even more efficient, keep a changed flag and only update the mini-map BufferedImage when something visible on the mini-map changes. I didn't think it was worth it as the above is already very efficient, but YMMV.

Categories

Resources