If statement seems to run some code but not all in java - java

I'm making a 2d platformer in libgdx with box2d. The below is the update method for one of my enemies. It's an extension of the 'Enemy' class, which is what 'super.update' refers to. I want the enemy to run when the player is behind it or far away and to stop and shoot when the player is close to it and in front of it.
I try to achieve this by setting the speed (velocity.x) initially [depending on the enemy's direction], then setting whether or not it's shooting afterwards.
The problem I have at the moment is that the enemy doesn't run when the player is behind it. As you can see, I printed out a lot of strings to console to see when the velocity.x gets changed back to 0. According to the console, it happens in the last if/else pair of statements which are supposed to check how far away the player is and which direction the enemy is running. However, the console strings within those statements, the ones that say 'Shoot Left' or 'Shoot Right', don't get printed out. Despite this, the line that changes velocity.x must get run because the it's value changes according to the string output in the next line. The if statements at the top which check direction must get run as well because the console outputs within those statements get printed, and the output that says the velocity says the correct velocity (either 2 or -2).
What is going on? It seems like the IDE is running only one of the lines in the if statement. That's impossible so what am I missing here?
Thanks for any help.
public void update (float dt, Player player){
super.update(dt, player);
if (b2body.isActive()){
System.out.println(b2body.getPosition().x - player.b2body.getPosition().x);
System.out.println("After Enemy code: " + velocity.x);
if (getRunningRight()) {
System.out.println("Right");
velocity.x = 2;
}
else if (!getRunningRight()) {
System.out.println("Left");
velocity.x = -2;
}
System.out.println("After checking direction: " + velocity.x);
if ((b2body.getPosition().x - player.b2body.getPosition().x <= 2 &&
b2body.getPosition().x - player.b2body.getPosition().x >= 0) && !getRunningRight()){
velocity.x = 0;
System.out.println("Shoot left");
}
else if ((b2body.getPosition().x - player.b2body.getPosition().x >= -2 &&
b2body.getPosition().x - player.b2body.getPosition().x < 0) && getRunningRight()){
System.out.println("Shoot right");
velocity.x = 0;
}
System.out.println("After shooting: " + velocity.x);
}
}

In your first set of ifs, you evaluate getRunningRight() after you have already determined that it will be false (by the initial if failing), so there is no need to evaluate it again.
If you think you are doing the same thing in the second block, you are not; the expression in the inner if is not the opposite of the first one. That is, (A && B) && C is not the opposite of (!A && !B) && !C. Thus, it is possible for both expressions to be false.

Related

How to move an object back and forth?

I'm trying to move an object back and forth. This is what i have tried, but it just moves right and stops but doesn't go back.
public void moveBug()
{
bugX++;
if (bugX > 400){
bugX--;
}
if (bugX < 0){
bugX++;
}
}
I also have this piece of code from my lecturer but I'm not sure how to apply it to the code.
if ((frameCount % 60) == 0)
{
// Do something
}
Your code unconditionally runs bugX++ every time it's called which causes the bug to always move right. You'll need another variable to keep track of the direction the bug is moving. You need to do different things based on whether it's moving right or left..
If it's moving right, increment x: bugX++.
If it's moving left, decrement x: bugX--.
If it reaches the right side, switch the direction to left.
If it reaches the left side, switch the direction to right.

Making game with automatic enemy number/speed increases at certain score increments - how to achieve logically?

Update: Added in some more details so a bit more context is given to the snippet of code I gave.
I recently submitted a game I made in Processing as part of my university coursework, but it didn't turn out exactly how I wanted it to, so I'm working on adding some features and re-coding some of it to make it more fun and replayable.
Anyway, the problem I'm having is with enemy wave generation. How my game works is that there is a class specifically for a single enemy instance, and I made an ArrayList for enemy generation. The below code has a for loop that sets itself depending on the amount of waves set as the integer waveCount. It adds a number of enemies to the ArrayList equal to the value waveCount, and then shows the enemies on the screen. The enemy is removed individually if they are shot, and if they touch the player, the player's health is reduced, then the player position is reset, as are the enemy's positions. They simply come from the top of the screen and move down towards the player at the bottom, slowly orientating themselves to the player's x and y position.
I have the enemy waves working correctly, but in the last version of my game I manually increased the waves as the player reaches certain scores with if statements, and now I want to figure out a way to have the game automatically add a wave when the player score reaches a 200 increment. I also want the enemy speed to increase slightly every time the play score reaches a 1000 increment.
Right now, the way I've coded it leads to it it only increasing the number of waves once at 200/400/600/etc before going back to a single wave. I've handled the enemies as an ArrayList of classes. If anyone can help me figure out a way to code an automated, infinite wave system, with one wave being added at score increments of 200, and the enemy speed increasing at score increments of 1000, that would be MASSIVELY helpful!
updateWave = false;
hasAddedWave = false;
scoreCheck = score.score;
enemySpeedX = 0.6;
enemySpeedY = 1;
waveCount = 1;
if(scoreCheck > 0 && scoreCheck % 200 == 0 && hasAddedWave == false){
updateWave = true;
}
if(updateWave == true && hasAddedWave == false){
waveCount += 1;
hasAddedWave = true;
}
if(updateWave == true && hasAddedWave == true){
updateWave = false;
hasAddedWave = false;
}
for(int i = 0; i < waveCount; i++){
zombiePosition = random(100,400);
zombies.add(new Enemy(zombiePosition,-50,enemySpeedX,enemySpeedY));
zombies.get(i).show();
}
In theory, what you need is a way to say :
"Hey, this guy reached 200 points further than before! Let's throw a new wave at him! "
Just by that sentence you can easily deduce that it's going to pass a LOT by repetitive cicles, evidently I cannot give you a code sample, as I can't guess what your code is (as someone already pointed, you haven't given us much to work with) . Try out something such as
if (pointsNow >= pointsBefore+200) doSomething
Furthermore, the reason why it goes back to a single wave is :
if(scoreCheck > 0 && scoreCheck % 200 == 0 && hasAddedWave == false){
updateWave = true;
}
What this if-statement means that scoreCheckis bigger than 0, AND divisible by 200. Which means that scoreCheck divided by 200 has a remainder of 0. Imagine if your player gets a score of 401, the score check wouldn't be able to be divided by 200, as the remained is NOT 0. Instead, try to:
scoreCheck > lastScoreCheck where you add 200 to lastScoreCheck (or whatever ammount you want)
And finally, about the speed, once again, play with the variables. Instead of having speed = 1 (for example) have : speed = 1 + level*multiplier , what this do is it sets the speed to a certain value in this case, 1, and adds a multiplier, which is depended by another variable which would be the level. You can manipulate it to make the game easier or harder, for example : speed = 1 + level*5 is a LOT faster than speed = 1 + level*0.5

How to correctly write a maze algorithm using loops

I am writing a code for a class assignment to get a character through a maze. I have been working on this for hours and I can't figure out what I am doing wrong. The character moves left to right and right to left. Except when I add the code to have the character move around a block if (maze.moveRight() == false), it causes the character to move up and down at the end of each row a bunch of times before it moves the other direction. Also it messes up my count as the character moves across the rows. I feel like I am making it much more complicated than it should be. Can someone help?
Algorithm
The student always starts at the top left corner, that is row and column zero.
The Java logo can be anywhere in the maze, which also contains obstacles shown as "Wrong Way" signs.
You must traverse every row in the maze from top to bottom according to the rules below, until you find the Java logo.
Row and column numbers are zero based, so the first row and column is index 0. the second row and column is index 1, and so on. The number zero is even.
On even rows, you must move left to right using maze.moveRight(), on odd rows, you must move right to left using maze.moveLeft().
After completing each row, use maze.moveDown() to proceed to the next row, until you reach the last row or find the Java logo.
You can detect that you have encountered an obstacle by checking the return value from move methods in the Maze object, true means no obstacle, false means obstacle.
If you run into an obstacle when when moving left to right: Move down, right, right, and up.
Adjustment the loop counter for the extra move right!
If you run into an obstacle when when moving right to left: Move down, left, left, and up. Adjustment the loop counter for the extra move left!
Every time you move left or right, not including when avoiding an obstacle, you must call maze.isDone() to see if you have found the Java logo.
When you find the Java logo, you must immediately break out of all loops, and exit the program.
There are mazes that cannot be solved using the algorithm, but we will not test your program with any of them.
public static void main(String[] args) {
// Create maze
String fileName = args[1];
Maze maze = new Maze(fileName);
System.out.println("Maze name: " + fileName);
// Get dimensions
int mazeWidth = maze.getWidth();
int mazeHeight = maze.getHeight();
// Print maze size
System.out.println("Maze width: " + mazeWidth);
System.out.println("Maze height: " + mazeHeight);
int r = 0;
int c = 0;
// Move commands
while (c < maze.getWidth() - 1 && r % 2 == 0 && maze.isDone() == false)
{
maze.moveRight();
maze.isDone();
c++;
if (maze.moveRight() == false && maze.isDone() == false){
maze.moveDown();
maze.moveRight();
maze.moveRight();
maze.moveUp();
}
if (maze.isDone() == true){
System.exit(1);
}
}
while (c == maze.getWidth() - 1 && r % 2 == 0 && maze.isDone() == false)
{
maze.moveDown();
maze.isDone();
r++;
}
while (c != 0 && c <= maze.getWidth() -1 && r % 2 != 0
&& maze.isDone() == false){
maze.moveLeft();
maze.isDone();
c--;
if (maze.moveLeft() == false && maze.isDone() == false) {
maze.moveDown();
maze.moveLeft();
maze.moveLeft();
maze.moveUp();
}
if (maze.isDone() == true){
System.exit(1);
}
}
}
I'm having a hard time following what your intent is and thus what the problem is. Perhaps it's due to lack of understanding of how this maze is set up. I also don't know the scope of the class so I don't know if this is above your current level or not, but here goes how I would personally implement a maze solver:
For each position in a maze that I find myself, I would create a maze "space" object. This object will keep track of remaining options of directions to be traversed and whether or not I have visited that space. If I can turn left and right, I would create new spaces for both, pick one direction, and mark only that one direction to say I've been there. When I reach a dead end, I will turn around until I find a choice of direction to go. If I've not visited a direction, I'd take that. Otherwise, If I've visited all ways, I would call a recursive function to determine if there are any directions available along down any of the paths I've taken previously.
So it's creating objects, using recursion, and flagging an object for whether or not I've been there. (you'd also need a flag to indicate if your recursive algorithm has checked a square as well lest you find yourself in an infinite loop).
Hopefully that's within the constraints of the assignment! Otherwise, we may need more information as to what the limitations are and the true scope of the assignment.
Ok so a few problems you are only moving down on the right wall.
You aren't updating your row column counters when you are navigating hazards.
You should be testing the results of every move and isDone method call and breaking or updating your counters accordingly.
Also you shouldn't be updating your counters as you do outside an if statement associated with a move test method call.

Text based battleship enemy AI not working as wanted - Java

Im making a text based battleship game and the player plays against the computer. 3 random 3 unit long ships are placed on the board, and I want the computer to be able to guess around where his last guess was if his last guess was a hit. (but I want it to work so that he keeps guessing around the same spot until he got a hit and keep guessing around there until he gets the whole ship, or 3 hits)
It works a bit; the computer will guess near his last guess if it was a hit, but if he misses that guess then he starts guessing randomly again. Can someone help me out a bit?
-getGuess() method is the one with the AI-
/*
* computer class to handle computers guesses/ etc
* most methods are copied from player class, but slightly altered to account for variable names
* Methods that havent been copied have comments
*/
public class Computer{
static int firstCo, secondCo;
static int[] guessedHits={7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
//int array to store last guess
static int[] lastGuess = new int[2];
//int array to store current guess
static int[] guess=new int[2];
public static int[] computerShip1=new int[6];
public static int[] computerShip2=new int[6];
public static int[] computerShip3=new int[6];
/*
* method to choose random guess for computer - but make it guess around last guess if last guess was a hit
* return guess coordinate numbers in an array
*/
public static int[] getGuess(){
int[] guess=new int[2];
int firstCo, secCo;
int ran; //random int between 0 and 1 - will help to make random choices for guesses
if(isHit(lastGuess[0],lastGuess[1])){
ran=(int)(Math.random()*2);
//if ran is 0 and last guesses x coordinate was correct, set next guess to last x, and next y to last y +1
if((ran==0 && lastGuess[0]==Player.playerShip1[0]) || (ran==0 && lastGuess[0]==Player.playerShip1[2]) || (ran==0 && lastGuess[0]==Player.playerShip1[4])){
guess[0]=lastGuess[0];
guess[1]=lastGuess[1]+1;
//if ran is 1 and last guesses x coordinate was correct, set next guess to last x, and next y to last y -1
}else if((ran==1 && lastGuess[0]==Player.playerShip1[0]) || (ran==1 && lastGuess[0]==Player.playerShip1[2]) || (ran==1 && lastGuess[0]==Player.playerShip1[4])){
guess[0]=lastGuess[0];
guess[1]=lastGuess[1]-1;
//if ran is 0 and last guesses y coordinate was correct, set next guess to last y, and next x to last x +1
}else if((ran==0 && lastGuess[1]==Player.playerShip1[1]) || (ran==0 && lastGuess[1]==Player.playerShip1[3]) || (ran==0 && lastGuess[1]==Player.playerShip1[5])){
guess[0]=lastGuess[0]+1;
guess[1]=lastGuess[1];
//if ran is 1 and last guesses y coordinate was correct, set next guess to last y, and next x to last x -1
}else if((ran==1 && lastGuess[1]==Player.playerShip1[1]) || (ran==1 && lastGuess[1]==Player.playerShip1[3]) || (ran==1 && lastGuess[1]==Player.playerShip1[5])){
guess[0]=lastGuess[0]-1;
guess[1]=lastGuess[1];
}
return guess;
}else{
guess[0]=(int)(Math.random()*7);
guess[1]=(int)(Math.random()*7);
return guess;
}
}
public static boolean isHit(int firstC, int secC){
for(int i=0; i<Player.playerShip1.length; i=i+2){
if(firstC==Player.playerShip1[i] && secC==Player.playerShip1[i+1]){
return true;
}
if(i==4){
break;
}
}
for(int i=0; i<Player.playerShip2.length; i=i+2){
if(firstC==Player.playerShip2[i] && secC==Player.playerShip2[i+1]){
return true;
}
if(i==4){
break;
}
}
for(int i=0; i<Player.playerShip3.length; i=i+2){
if(firstC==Player.playerShip3[i] && secC==Player.playerShip3[i+1]){
return true;
}
if(i==4){
break;
}
}
return false;
}
public static void addHits(int firstC, int secC){
int index=-1;
for(int i=0; i<guessedHits.length; i++){
if(guessedHits[i]==7){
index=i;
break;
}
}
guessedHits[index]=firstC;
guessedHits[index+1]=secC;
}
public static void setComputerShips(){
int randX, randY;
int direction; //will be random int 0-1, determines direction ship will extend(up/down, left/right)
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
direction=(int)(Math.random()*2);
computerShip1[0]=randX;
computerShip1[1]=randY;
if(direction==0){//extend upwards or downwards 2 units(y values change, x stays the same)
computerShip1[2]=randX;
computerShip1[4]=randX;
if(randY>3){//if y value is greater than 3, has to extend down or it wont fit
computerShip1[3]=randY-1;
computerShip1[5]=randY-2;
}else if(randY<2){//if y value is less than 2, has to extend up or it wont fit
computerShip1[3]=randY+1;
computerShip1[5]=randY+2;
}else{//if direction doesnt matter, just extend upwards
computerShip1[3]=randY+1;
computerShip1[5]=randY+2;
}
}else if(direction==1){//extends left or right 2 units(y values stay the same, x changes)
computerShip1[3]=randY;
computerShip1[5]=randY;
if(randX>3){//if x is greater than 3, must extend left or it wont fit
computerShip1[2]=randX-1;
computerShip1[4]=randX-2;
}else if(randX<2){//if x is less than 2, must extend right or it wont fit
computerShip1[2]=randX+1;
computerShip1[4]=randX+2;
}else{//if direction doesnt matter, just extend right
computerShip1[2]=randX+1;
computerShip1[4]=randX+2;
}
}
//do same for both other ships
do{
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
}while((randX==computerShip1[0] && randY==computerShip1[1])||(randX==computerShip1[2]&&randY==computerShip1[3])||(randX==computerShip1[4]&&randY==computerShip1[5]));
direction=(int)(Math.random()*2);
computerShip2[0]=randX;
computerShip2[1]=randY;
if(direction==0){
computerShip2[2]=randX;
computerShip2[4]=randX;
if(randY>3){
computerShip2[3]=randY-1;
computerShip2[5]=randY-2;
}else if(randY<2){
computerShip2[3]=randY+1;
computerShip2[5]=randY+2;
}else{
computerShip2[3]=randY+1;
computerShip2[5]=randY+2;
}
}else if(direction==1){
computerShip2[3]=randY;
computerShip2[5]=randY;
if(randX>3){
computerShip2[2]=randX-1;
computerShip2[4]=randX-2;
}else if(randX<2){
computerShip2[2]=randX+1;
computerShip2[4]=randX+2;
}else{
computerShip2[2]=randX+1;
computerShip2[4]=randX+2;
}
}
do{
randX=(int)(Math.random()*7);
randY=(int)(Math.random()*7);
}while((randX==computerShip1[0] && randY==computerShip1[1])||(randX==computerShip1[2]&&randY==computerShip1[3])||(randX==computerShip1[4]&&randY==computerShip1[5])||(randX==computerShip2[0] && randY==computerShip2[1])||(randX==computerShip2[2]&&randY==computerShip2[3])||(randX==computerShip2[4]&&randY==computerShip2[5]));
direction=(int)(Math.random()*2);
computerShip3[0]=randX;
computerShip3[1]=randY;
if(direction==0){
computerShip3[2]=randX;
computerShip3[4]=randX;
if(randY>3){
computerShip3[3]=randY-1;
computerShip3[5]=randY-2;
}else if(randY<2){
computerShip3[3]=randY+1;
computerShip3[5]=randY+2;
}else{
computerShip3[3]=randY+1;
computerShip3[5]=randY+2;
}
}else if(direction==1){
computerShip3[3]=randY;
computerShip3[5]=randY;
if(randX>3){
computerShip3[2]=randX-1;
computerShip3[4]=randX-2;
}else if(randX<2){
computerShip3[2]=randX+1;
computerShip3[4]=randX+2;
}else{
computerShip3[2]=randX+1;
computerShip3[4]=randX+2;
}
}
}
public static boolean hasWon(){
if(guessedHits[17]!=7)
return true;
else
return false;
}
}
Your getGuess() function is the one you're after right?
1) You never account for times when you guess the same spot twice. Make a boolean value that determines whether the coordinates you're attempting to guess haven't already been guessed.
2) Your method of keeping ship coordinates is very awkward where 0,2,4 are X coords while 1,3,5 are Y coords? You're better off creating a Ship class that handles coordinates, and checks like isHit.
public class Ship {
int[] xCoords = new int[3];
int[] yCoords = new int[3];
public boolean isHit(int x, int y) {
return (Arrays.asList(xCoords).contains(x) && Arrays.asList(yCoords).contains(y));
}
}
Then you can:
if (Player.ship1.isHit(guess[0],guess[1])) {
....
}
At the very heart of it you have a little ways to go. You'll get better responses here if you start working at the problem then come back with specific problems you may have. Try to be as concise as possible when giving code snippets because not many people will spend much time going through an entire class to find a line or two giving issues.
Good luck!
---PS---
I wrote a battleship game about 3-4 years ago with some fairly advanced AI. I'll link it here:
https://github.com/GrahamBlanshard/AI-Battleship/blob/master/prograham/battleship/player/AIPlayer.java
First, I apologize for the... lame code (I was a much younger programmer, I swear!). If you want to view it to get hints that is fine. A brief explanation:
At the heart of it you need to create some form of datatype that stores his hits. Once a "hit" is scored you push it to the datatype, I used a Stack. The shots that are successful hits get stored on the stack until the ship is sunk. At that point it removes shots from the stack that belonged to the ship that just sunk. If there are shots still on the stack it knows it has hit a second ship during that process and continues to guess in the area.
To accomplish this, it goes through phases:
1) Shoot randomly until a hit.
2) Shoot around that shot (use a random(4) call to get N/S/E/W direction)
-- Keep doing this until you score a second shot
3) Create a "line" with the two points and fire along it until the ship sinks or...
4) Reverse the line and shoot the other direction.
Does that give you a good start to work with?
That's a lot of code to look at. So for now I will give some general suggestions that come to mind:
When the computer AI gets a "hit", set a "global" flag (more likely a class variable) and "remember" where the hit occured. On the following turns, guess the neighboring squares in some predetermined order (say north, south, east, west) until another hit is found. Then set another flag and on the next turn guess in the same direction as the second hit. The initial flag should only be reset when all three hits are found. This should fix the problem that a subsequent miss causes the computer AI to start guessing randomly again.

Java Array Index out of Bounds

OK so I seem to be getting an Array Index out of Bounds error in a part of my code. Specifically in lines 85-102...
My code: http://www.sosos.pastebin.com/f0JQBWui
I just want it to check for blocked tiles AHEAD of time that way my sprite doesn't move in the direction it can't. This exception only happens when I am on the RIGHT or BOTTOM corners of my map.
My GUESS of why this error happens if because when I am on the corner.. it checks for the tiles to the RIGHT and BOTTOM of it which are not there...
1) The way you implemented blocked(tx,ty), it only accepts legal board coordinates (0<=tx<=12 and 0<=ty<=8). Otherwise it checks an illegal array position, producing an ArrayIndexOutOfBoundsException. Are you sure this is your intention? I think it makes sense to consider off board tiles as blocked.
2) In lines 85-102 there seems to be many errors. I think you meant something like:
if (spawnX == 0 || blocked(spawnX - 1, spawnY)) {
left = false;
System.out.println("You can't go left!");
}
if (spawnX == 12 || blocked(spawnX + 1, spawnY)) {
right = false;
System.out.println("You can't go right!");
}
if (spawnY ==0 || blocked(spawnX, spawnY - 1)) {
up = false;
System.out.println("You can't go up!");
}
if (spawnY == 8 || blocked(spawnX, spawnY + 1)) {
down = false;
System.out.println("You can't go down!");
}
Anyway, if you fix (1) as I suggested, the extra bound condition per direction is unecessary.
3) isInBound(r,c) is implemented incorrectly. It always returns false, due to the conditions on c.
4) There are many other problems with the code, but I will not enter into details. As a principle, try to make your design simple and make sure the code does not repeat itself.
You're going to have to do some bounds-checking in your blocked() function. Make sure that the coordinates they're giving you actually exist and return some "blocked" value if they don't.
The description of getting the error at the bottom or right would seem to suggest that you need to test if the value exceeds the array bounds. Have a look at Array.length

Categories