Java - Loop gets executed, but header doesnt fit condition - java

This function should check if the explosion hit a box and should be canceled on the first box it hits.
For example bsp.getBomb().getStrength() is currently 2, when a box is hit i=3, but the loop is executed one more time even if the condition isn't met, why is that?
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY()+i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
// i = bsp.getBomb().getStrength()+1;
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}

Try adding break to the loop:
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY() + i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
You may be seeing duplicate print statements if you are calling the detectBomb method multiple times. Putting a breakpoint or print statement at the beginning of this method will help determine what the problem is.
Another thing to keep in mind is that you are creating a new Texture for the Sprite every time the method get executed - it would be wise to only instantiate the Texture once and share it with all subsequent Sprite instances that require it.

Related

For loop and if statements acting odd

I am making a chess game and so far everything is good and I am writing the rules of each piece now. The problem is that a for loop is acting oddly. Its for the bishop so x is going down and y is going up. At this point it acts oddly whenever I try to add the point to a possible move
for (int i = 0; i < 8; i++) {
Point newLoc = new Point(x-i, y+i);
if(team.equals("white")) {
if(containsPiece(newLoc)) {
if(ChessBoard.black.containsKey(newLoc)) {
possibilities.put(newLoc, rating);
break;
}
else {
break;
}
} else
possibilities.put(newLoc, rating);
}
containsPiece() is working just fine and possibilities is the HashMap I am storing the possible moves in.
The way I see it it should be working perfect because if the tile at newLoc is white it shouldn't add it to the possible moves and stop getting any moves after it in that direction. Does anyone see why it seems to abandon all the previous possible moves added to possibilities
i should start in 1, not 0, since when i==0, newLoc is the position of the bishop ((x-0,y+0)), so you break from the loop, since the bishop is a white tile.

How to stop one thread from modifying an array which is being used by another thread?

I have a java program which is basically a game. It has a class named 'World'. The "World" class has a method 'levelChanger()', and another method 'makeColorArray()'.
public class World {
private BufferedImage map, map1, map2, map3;
private Color[][] colorArray;
public World(int scrWd, int scrHi) {
try {
map1 = ImageIO.read(new File("map1.png"));
map2 = ImageIO.read(new File("map2.png"));
map3 = ImageIO.read(new File("map3.png"));
} catch (IOException e) {
e.printStackTrace();
}
map = map1;
makeColorArray();
}
private void makeColorArray() {
colorArray = new Color[mapHi][mapWd]; // resetting the color-array
for(int i = 0; i < mapHi; i++) {
for(int j = 0; j < mapWd; j++) {
colorArray[i][j] = new Color(map.getRGB(j, i));
}
}
}
//color-array used by paint to paint the world
public void paint(Graphics2D g2d, float camX, float camY) {
for(int i = 0; i < mapHi; i++) {
for(int j = 0; j < mapWd; j++) {
if(colorArray[i][j].getRed() == 38 && colorArray[i][j].getGreen() == 127 && colorArray[i][j].getBlue() == 0) {
//draw Image 1
}
else if(colorArray[i][j].getRed() == 255 && colorArray[i][j].getGreen() == 0 && colorArray[i][j].getBlue() == 0) {
//draw Image 2
}
}
}
}
public void levelChanger(Player player, Enemies enemies) {
if(player.getRec().intersects(checkPoint[0])) {
map = map2;
//calls the color-array maker
makeColorArray();
}
else if(player.getRec().intersects(checkPoint[1])) {
map = map3;
makeColorArray();
}
}
public void update(Player player, Enemies enemies) {
levelChanger(player, enemies);
}
}
The makeColorArray() method makes a 2d array of type 'Color'. This array stores Color-objects from a PNG image. This array is used by the paint() method of the JPanel to paint the world on the screen.
The levelChanger() method is used to change the levels (stages) of the game when certain codition is true. It is the method which calls the makeColorArray() method to re-make the color-array while changing game-level.
The problem is that I have a game-loop which runs on a Thread. Now, the painting of swing components like JPanel is done on a different background thread by java. When the game-level is being changed, the color-array object is re-made. Now, like I previously said, the color-array object is used by the paint() method to paint the world on the screen. Sometimes, the color-array object is still being used by the background Thread (not finished painting) when, according to game logic, color-array object is re-made and its members set to null. This is causing a null-pointer exception, only sometimes. Clearly a race condition.
I want to know how can i stop my game thread from resetting the color-array until the background swing thread has finished painting.
Suggestions:
Use a Model-View-Control design for your program, or use one of the many similar variants.
Use a Swing Timer to drive your GUI game loop, but use real time slices, not the timer's delay, in your model to determine length of time between loop steps.
The model should run in the GUI Swing event thread.
But its long-running tasks should be run in background threads using a SwingWorker.
This is key: Don't update the model's data, the data used by the JPanel to draw, until the background thread has completed working on it. A PropertyChangeListener and SwingPropertyChangeSupport can be useful for this.
Be sure that the JPanel draws in its paintComponent(...) method, not its paint(...) method, and that you call the super method.
Best if you make the background image a BufferedImage, and have the JPanel draw that in its paintComponent(...) method for efficiency.
Be sure that all Swing GUI code, except perhaps repaint() calls, are called on the Swing event thread.
And yes, definitely read the Concurrency in Swing tutorial.
One way with minimal changes is to synchronize access to the color array.
I personally would have the shared data abstracted out to an individual class which is completely thread-safe, that way you wouldn't have to make sure two separate parts of the code base both have to know what to synchronize on (it seems like your class here does more than just handle the map at first glance, perhaps it is such a class that I am describing though).
private void makeColorArray() {
Color[][] colorArrayTemp = new Color[mapHi][mapWd]; // resetting the color-array
for(int i = 0; i < mapHi; i++) {
for(int j = 0; j < mapWd; j++) {
colorArrayTemp [i][j] = new Color(map.getRGB(j, i));
}
}
synchronized(colorArray)
{
colorArray = colorArrayTemp;
}
}
//color-array used by paint to paint the world
public void paint(Graphics2D g2d, float camX, float camY) {
synchronized(colorArray)
{
for(int i = 0; i < mapHi; i++) {
for(int j = 0; j < mapWd; j++) {
if(colorArray[i][j].getRed() == 38 && colorArray[i][j].getGreen() == 127 && colorArray[i][j].getBlue() == 0) {
//draw Image 1
}
else if(colorArray[i][j].getRed() == 255 && colorArray[i][j].getGreen() == 0 && colorArray[i][j].getBlue() == 0) {
//draw Image 2
}
}
}
}
}
If you only want one thread modifying colorArray at once, make it synchronized.
The purpose of synchonization, is that it requires a thread to get the lock on the object. Any other thread that attempts to access that object while its locked will be blocked (it will wait).
See this post: Java: how to synchronize array accesses and what are the limitations on what goes in a synchronized condition

Applying class methods to a whole ArrayList

I am wondering if there is a bit of code or that can apply a method from a class to all of the objects in the ArrayList? I'm making a basic space invaders program and I am trying to implement a move method that will apply to all of enemies, so that they move in a group rather than individually.
I've created the items in the array list here:
for (int i = 0; i < 6; i++) {
venWidth = venWidth - 139;
enemyList.add(new Venusian("/venusian.jpg", venWidth, height));
}
for (int i = 6; i < 12; i++) {
merWidth = merWidth - 145;
enemyList.add(new Mercurian("/mercurian.jpg", merWidth, merHeight));
}
for (int i = 12; i < 18; i++) {
marWidth = marWidth - 125;
enemyList.add(new Martian("/martian.jpg", marWidth, marHeight));
}
Here is where I call the move method:
for (int i = 0; i < enemyList.size(); i++) {
Invader Invaders = (Invader) enemyList.get(i);
Invaders.draw(g);
Invaders.Move(1024);
This makes them move independently and overlap, at the moment I am just moving them right and left using the boundaries of my created window. So is there any way of moving them together at the same time? I have searched for a way to apply a class method to all of the lists items but I haven't found anything after a couple of hours.
Any material, sources or advice relating to this would be greatly appreciated.
You will have to come up with a solution that can decouple the Invaders you are moving from those you are displaying.
This is due to the fact that your individual Invaders will always be more or less sequentially moved - even if you are working with multiple threads, etc. Even if you would start using Java8 Lambdas to write your code like this:
ArrayList<Invader> badGuys;
//fill your List here
badGuys.forEach( badGuy -> badGuy.move());
This would also create intermediate states where some Invaders were moved, some were not.
So you have to make sure that you only draw a consistent set of Invaders to your screen. You could do this several ways:
Only draw to screen after all Invaders were moved
Make a copy of your invaders for drawing, while the Invaders are being moved. After all Invaders were moved, start displaying the Invaders from the moved List
...
1st Edit: How do you draw the Invaders to screen? Is this happening in separate threads?
3rd EDIT: Okay so maybe you can stop your timerThread before starting to move your Invaders. And when you are finished with moving them you can restart the timer again. Check what methods your timer offers It should have start() and stop() or maybe suspend() methods.
Do something like this:
timer.stop();
badGuys.moveAll();
timer.start();
2nd EDIT: Just looked over your code again. There is no need for you to start your for loop number 2 and 3 from indexes other than 0. Your code will be easier to read if for example you just say:
for (int i = 0; i < 6; i++) { // start from 0 (to 6) instead of 6 to 12
merWidth = merWidth - 145;
enemyList.add(new Mercurian("/mercurian.jpg", merWidth, merHeight));
}
create an interface like Moveable. and put Move method on it. then implement it on Venusian, Martian and Mercurian. and use this interface on arraylist
interface Moveable {
public void Move(int dist);
}
class Mercurian implements Moveable {
public void Move(int dist)
{
//do something
}
}
class Venusian implements Moveable {
public void Move(int dist)
{
//do something
}
}
class Martian implements Moveable {
public void Move(int dist)
{
//do something
}
}
ArrayList<Moveable> enemyList = new ArrayList<Moveable>();

libgdx-Actions create stuttering

I try to improve the movement of my figures but i dont find the real reason why they stutter a bit. I am moving them with an SequenceAction containing an MoveToAction and an RunnableAction that does reset the moveDone flag so there can be started a new move.
The game itself is gridbased so if a move is done the squence starts a move to the next grid depending on the direction. So here is how it looks like:
note that this is inside of the Act of the figure
....//some more here
if (checkNextMove(Status.LEFT)) //check if the position is valid
{
status = Status.LEFT; //change enum status
move(Status.LEFT); // calls the move
screen.map.mapArray[(int) mapPos.x][(int) mapPos.y] = Config.EMPTYPOSITION;
screen.map.mapArray[(int) (mapPos.x - 1)][(int) mapPos.y] = Config.CHARSTATE;
mapPos.x--;
moveDone = false;
}
//... same for the up down right and so on.
//at the end of this checking the updating of the actor:
// methode from the absctract to change sprites
updateSprite(delta);
super.act(delta); // so the actions work
//end of act
And here is the move Method that does add the Actions
protected void move(Status direction)
{
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
//restart all actions to they can used again
sequence.restart();
switch (direction)
{
case LEFT:
moveAction.setPosition(getX() - Config.TILE_SIZE, getY());
addAction(sequence);
break;
case RIGHT:
moveAction.setPosition(getX() + Config.TILE_SIZE, getY());
addAction(sequence);
break;
case UP:
moveAction.setPosition(getX(), getY() + Config.TILE_SIZE);
addAction(sequence);
break;
case DOWN:
moveAction.setPosition(getX(), getY() - Config.TILE_SIZE);
addAction(sequence);
break;
default:
break;
}
}
The figures dont really move smothy.
Anyone does see a misstake or isnt it possible to let them move smothy like this?
It always stutter a bit if a new move is started. So i think this might not work good. Is there a differnt approach to move them exactly from one Grid to an nother? (Tried it myself with movementspeed * delta time but this does not work exactly and i struggeled around and used the Actionmodel)
it seems to make troubles with the one Frame where it does not move for example.
Here is an mp4 Video of the stuttering:
stuttering.mp4
just to mention, the camera movement is just fine. it's smothy but the figure stutters as you can see i hope
If you use your moveAction each move, you should call moveAction.restart() to reset the counter inside it:
// delete all old actions if there are some left.
clearActions();
sequence.reset(); // clear sequence
// add movementspeed. Note it can change!
moveAction.restart();
moveAction.setDuration(speed);
UPDATE:
Now issue occurs, because you call restart of SequenceAction after clearActions(). If your clearActions() removes all actions from SequenceAction then restart will be called for empty SequenceAction. So, do this instead:
//restart all actions to they can used again
sequence.restart();
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
Okay so i solved it myself. It has nothing todo with changing sequences around. It has something todo with the updatefrequency of the act() of the figures. The MoveToAction interpolates between the 2 points given by time. So if the last update, updates the MoveToAction by "to much time" it would need to go over the 100% of the action. So it would move to far but the action does not do this it set the final position and thats what it should do. Thats why it does not look fluent.
So how to solve this issue?
By decreasing the updatetime the "to far movement" decreases too because the steplength is getting smaller. So i need to increase the updatespeed above the 60fps. Luckily i got an thread for my updating of the figures and positions and so on. GameLogicThread. This ran on 60fps too. So i solved the stuttering by increasing it's frequence. up to around 210fps at the moment so the "overstep" is minimal. You can't even notice it.
To Show how my thread works:
public class GameLogicThread extends Thread
{
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen)
{
m_screen = screen;
setName("GameLogic");
}
#Override
public void run()
{
m_runing = true;
Logger.log("Started");
while (m_runing)
{
m_timeBegin = TimeUtils.millis();
// hanlde events
m_screen.m_main.handler.processEvents();
synchronized (m_screen.figureStage)
{
// now figures
if (m_screen.m_status == GameStatus.GAME)
{
m_screen.character.myAct(1f / GameLogicThread.FRAMERATE);// and here it is ;)
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0)
{
try
{
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e)
{
Logger.error("Couldn't sleep " + e.getStackTrace());
}
}
else
{
Logger.error("we are to slow! " + m_sleepTime);
}
}
}
public void stopThread()
{
m_runing = false;
boolean retry = true;
while (retry)
{
try
{
this.join();
retry = false;
}
catch (Exception e)
{
Logger.error(e.getMessage());
}
}
}
}

ActionEvent in Java moves multiple buttons

Okay so I am pretty much doing a crash course through creating a java application and am having an issue with executing an action. The program is the 15 puzzle, the game where you slide one piece at a time and try to get all numbers in order, so I allow for an 'Auto' mode option that will solve the board for the user once clicked. So my code reads the solution from a text file which is working fine just none of the 'squares' (JButtons) move when I click the auto button. So i am not sure if I just don't understand the action even process completely or not. heres my code, I can supply more of it if necessary.
if (e.getSource() == ctrButtons[0]) {
System.out.println("Auto Mode started\n");
Scanner s = null;
try {
s = new Scanner(new BufferedReader(new FileReader("move_list.txt")));
int count = 0;
while (s.hasNext()) {
//Cycle through to move in move_list
if (count != 18) {
s.next();
count+=1;
}
else {
int cur_move = Integer.parseInt(s.next());
count = 0;
/*Use cur_move to move blank space accordingly
*UP------------3
*LEFT----------2
*RIGHT---------1
*DOWN----------0
*/
int zero_index = -1;
for (int j=0; j<jbnButtons.length; j++) {
if (Integer.parseInt(jbnButtons[j].getText()) == 0) {
zero_index = j;
break;
}
}
Point zero = jbnButtons[zero_index].getLocation();
//Check if move is up
if (cur_move == 3) {
Point next = jbnButtons[zero_index-4].getLocation();
jbnButtons[zero_index].setLocation(next);
jbnButtons[zero_index-4].setLocation(zero);
}
//Check if move is left
else if (cur_move == 2) {
Point next = jbnButtons[zero_index-1].getLocation();
jbnButtons[zero_index].setLocation(next);
jbnButtons[zero_index-1].setLocation(zero);
}
//Check if move is right
else if (cur_move == 1) {
Point next = jbnButtons[zero_index+1].getLocation();
jbnButtons[zero_index].setLocation(next);
jbnButtons[zero_index+1].setLocation(zero);
}
//Check if move is down
else {
System.out.println("Current move = 0");
Point next = jbnButtons[zero_index+4].getLocation();
jbnButtons[zero_index].setLocation(next);
jbnButtons[zero_index+4].setLocation(zero);
}
}
}
}
So my code executes when I click the 'Auto' button and I was printing output to the screen to see if it was looping through the code which it was, just none of the buttons move each time through the loop. Any ideas??
You code is executing on the Event Dispatch Thread. The GUI can't repaint itself until the code finishes executing, so you won't see the intermediate steps only the final location of each component.
Read tje section from the Swing tutorial on Concurrency for a more complete explanation.
Maybe you should use a Swing Timer (the tutorial also has a section on this). Each time the Timer fire you do the next move.

Categories

Resources