I've made a simple game, where you are the box and you are shooting little boxes.
Now to check if the shoot tocuhed the monster, i check if its x is highter or equals to the monster's x, and then i check if its less or equals to the monsters x, and then the same for y.
But the thing is, I have two for loops for this, therefore when I shoot and it touched the monster, the monster will not always get deleted cause the for loop did not reach that monster yet, and im sure it's bad for performance.
IS there a faster way to do this? why is it happening?
private void checkKilled() {
for (int i = 0; i < this.shoots.size(); i++) {
for (int j = 0; j < this.monsters.size(); j++) {
Monster m = this.monsters.get(j);
Shoot s = this.shoots.get(i);
if (s.getX() >= m.getX() && s.getX() <= m.getX() + 15
&& s.getY() >= m.getY() && s.getY() <= m.getY() + 15) {
m.isDead = true;
s.isExploded = true;
}
}
}
}
Not fully understanding the problem, but for performance you can break from inner loop if condition is true; it will then go to next shoot.
...
s.isExploded = true;
break;
}
Related
I began developing a "Spaceship vs Comets" style game last week and now I have come to a stop.
The purpose of the game is to shoot the comets before they pass your ship. You make the comets explode by firing at them. Simple idea!
However, sometimes when I play I get the "IndexOutOfBounds" error. It almost always appears when I haven't fired for a while (The size of my shots ArrayList is 0) and when I then fire and it collides it crashes.
So I have some kind of error in my code, but I really can't see it. I now hope that one of you might see why this accurs and save me from further "IndexOutOfBounds" errors! :)
Here is the part of the code that fails, including the functions that I use to move the comets and shots:
GAME CLASS
if(!Game.player.getShots().isEmpty() && !comet.getComets().isEmpty()) { //Om de är tomma så ignorera
for(int x = 0; x < Game.player.getShots().size(); x++) { //Shots X
if(!comet.getComets().isEmpty() && !comet.getComets().isEmpty()) {
for(int y = 0; y < comet.getComets().size(); y++) { //Comets Y
if(comet.getComets().get(y).intersects(Game.player.getShots().get(x)) && !comet.getComets().isEmpty() && !Game.player.getShots().isEmpty()) {
//the for loop above is the line that won't compile sometimes
comet.getComets().remove(y);
Game.player.getShots().remove(x);
score++;
}
}
}
}
}
//Comet spawn timer
comet.addComets();
//Move the comets and shots!
Game.player.moveShots();
comet.moveComets();
repaint();
COMET CLASS
public ArrayList<Rectangle> getComets() {
return comets;
}
public void moveComets() {
if(!comets.isEmpty()) {
for(int x = 0; x < comets.size(); x++) {
comets.get(x).x -= cometSpeed;
}
}
}
PLAYER CLASS (Shots are in this class)
public void fire() {
shots.add(new Rectangle(x + player.width, y + 23, shotWidth,shotHeight));
}
public ArrayList<Rectangle> getShots() {
return shots;
}
public void moveShots() {
if(!shots.isEmpty()) {
for(int x = 0; x < shots.size(); x++) {
shots.get(x).x += fireSpeed;
}
}
}
Keep in mind that comets and shots are both "ArrayList out of the object Rectangle"
I will provide screenshots of error and a picture of the game below!
The error line is marked in the code above, the if statement should block it from crashing (I thought).
Thanks in advance! All help is appreciated! :)
You should change the order at the if statement to avoid it from evaluate one part of it.
You should change your condition to:
if( x < Game.player.getShots().size() && comet.getComets().get(y).intersects(Game.player.getShots().get(x))) {
That's because you're removing a shot and inside the comets for when the shoot is removed at the next comet iteration it will throw IndexOutOfBounds as the array no longer have the shot you're checking at the if, so you'll need to check again for the x existing on shots.
You can also do it at the for, you check for both conditions and you let the intersect as only check at the if.
A better performance if would be:
if(!Game.player.getShots().isEmpty() || !comet.getComets().isEmpty()) {
//if one of them is empty, won't be intersections
for(int x = 0; x < Game.player.getShots().size(); x++) { //Shots X
for(int y = 0; y < comet.getComets().size() && x < Game.player.getShots().size(); y++) {
//Comets Y only if the shoot still available
if(comet.getComets().get(y).intersects(Game.player.getShots().get(x))) {
//the for loop above is the line that won't compile sometimes
comet.getComets().remove(y);
Game.player.getShots().remove(x);
score++;
y = 0; // if you don't set the y = 0 the next shoot (as you removed the x, getShots.get(x) would be the x + 1 shoot) will only evaluate for the comets after y, won't evaluate the firsts comets at the array.
}
}
}
}
Try to adjust here if(!comet.getComets().isEmpty() && !comet.getComets().isEmpty()). You are checking for comet array twice.
Let me know if it works.
Is this code multithreaded?
I am also wondering why you are verifying comet.getComets().isEmpty() so many times.
My guess is that you are manipulating the ArrayList in some other part of your code. Reason I think this is because you are checking the size of the list multiple times and because within the for loop you are only deleting in the end, so that should not be the problem.
For instance if you run this method at two threads at the same time, the ArrayList can be checked at one point, but can reduce after checking the size. then when for instance the size was 10, but became 9, but you still try to delete x with value 10, you will get the out of bounds error.
Currently, we are working on a shoot-em-up game. We have classes for both the bullets and the enemies. We have also created two arraylists where these elements can be found. Whenever a bullet hits an enemy, said enemy is supposed to simply disappear. Instead, we get this error.
void hit()
{
for(int i = 0; i < Bullet.size(); i++)
{
Bullet bul = (Bullet) Bullet.get(i);
Enemy enm = (Enemy)enemies.get(i);
if(bul.x < enm.x + enm.l && bul.x > enm.x - enm.l && enm.y<bul.y)
{
enm.health -= 1;
println("Pew");
if(enm.health <= 0)
{
enm = null;
enemies.remove(i);
}
}
}
}
A couple of things could be going wrong here. First, your for-loop goes through the Bullet ArrayList, however, you are using that index to modify the Enemy ArrayList as well. So if bul.size() > enm.size() "i.e. the bullet array is bigger than the enemy array", this would be what is causing the IndexOutOfBoundsException.
Additionally, if you are trying to check for an intersection of each bullet with each enemy you would want nested for-loops. Currently, you are just checking for if each bullet and enemy at the same index are intersecting.
You could resolve this with the following:
for(int i = 0; i < bul.size(); i++){
for(int j = 0; j < enm.size(); j++){
//if bullet is intersecting enemy
//do something
}
}
I am trying to add a score feature to my game. I know that where I have a remove function I now need to add code which means that whenever an enemy is removed it contributes to the score of the game but I don't know how to implement that into my game using code. Below I have included relevant code.
boolean alive() {
for (int i = 0; i < bullets.size(); i++) {
Bullet bullet = (Bullet) bullets.get(i);
if (bullet.x > x && bullet.x < x + pixelsize * 7 && bullet.y > y && bullet.y < y + 5 * pixelsize) {
bullets.remove(i);
bullet.alive = false;
return false;
}
}
for (int i = 0; i < bullets.size(); i++) {
Bullet bullet = (Bullet) bullets.get(i);
if (bullet.alive == false) {
bullets.remove(i);
}
}
return true;
}
Step 1: Create an int score variable at the sketch level.
int score = 0;
Step 2: Increment that variable whenever you want to increase the score.
score += 100;
Step 3: Display that score in the draw() function whenever and wherever you want the score to be displayed.
text("Score: " + score, 20, 20);
Also, I noticed that you're comparing String values with the == operator. Don't do that. Instead, use the equals() function:
String x = "test";
if(x.equals("blah")){
//whatever
}
You didn't mention if you'd like the score to be permanent or not. If so, you could write the scores to a simple csv file to get a leaderbord. Eaven a normal texfile would do.
I have a processing program with shapes that move across the screen, and lose health when they collide. Like a battle. But the collision detection only works on one set of colliding units at a time. If a battle is happening at a point on the screen, other battles won't happen until that one finishes.
for(int i = 0; i < enemies.size(); i++){
for(int j = 0; j < friendlies.size(); j++){
if(checkCollision(friendlies.get(j),enemies.get(i))){
if(ttime == 0){
ttime = millis();
}
if((millis()-ttime)>1000){
if(enemies.get(i).getXSpeed()==0 && enemies.get(i).getYSpeed()==0){
enemies.get(i).attackfriendly(friendlies.get(j));}
if(friendlies.get(j).getXSpeed()==0 && friendlies.get(j).getYSpeed()==0){
friendlies.get(j).attackenemy(enemies.get(i));
}
ttime=0;
}
}
}
}
boolean checkCollision(friendlyUnit f, enemyUnit e){
if(Math.abs(f.getX()-e.getX()) < 21 && Math.abs(f.getY()-e.getY()) < 21){
return true;
}
else{
return false;
}
}
void attackenemy(enemyUnit e){
int damage=0;
ArrayList<friendlyUnit>friendnear = new ArrayList<friendlyUnit>();
for (int i=0; i< friendlies.size(); i++){
if ((checkCollision(friendlies.get(i),e))&& friendlies.get(i).isAlive()){
friendnear.add(friendlies.get(i));
}
}
for (int j=0; j<friendnear.size();j++){
damage=damage+friendnear.get(j).getAttack();
}
e.changeHealth(damage);
}
enemies and friendlies are arrays of enemy and friendly shapes. The ttime stuff is a timer. getX and getY return X and Y coorinates.
It appears that ttime is a global and is getting checked/reset for all friendly/enemy interactions, rather than each interaction having it's own ttime. Does only 1 attack happen about every second? You need to have an array of ttimes so that a timer is only associated with one interaction, which means an array/ArrayList of size (enemies.size()*friendlies.size()), one for each interaction.
I am trying to solve the Knights tour problem on a 4x4 board with backtracking and recursion in java, and on the output I get this step sequence:
1 13 16 15
10 7 4 14
5 2 11 8
12 9 6 3
in the right upper corner, the 14, 15 and 16 neighbour with each other, which is impossible, because the knight moves on the chessboard into an L-shape. I would be thankful if someone could help me solve this.
the code:
public class KnightsTour {
private static int board[][] = new int[4][4];
private static int stepCounter = 1;
public Test() {
initBoard(board);
tour(0,0);
printSol(board);
}
public static void printSol(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
if(a[i][j]>9){
System.out.print(a[i][j] + " ");
}else{
System.out.print(a[i][j] + " ");
}
}
System.out.println();
}
System.out.println();
}
public static void initBoard(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
a[i][j] = -1;
}
}
}
public void tour(int x, int y) {
if (((x < 0) || (x >= 4) || (y < 0) || (y >= 4)) || (board[x][y] != -1)) {
return;
}else{
board[x][y] = stepCounter++;
tour(x+2, y+1);
tour(x+1, y-2);
tour(x+1, y+2);
tour(x-1, y+2);
tour(x-2, y-1);
tour(x-2, y+1);
tour(x-1, y-2);
tour(x+2, y-1);
}
}
public static void main(String[] args){
new KnightsTour();
}
}
You need to make the function return a boolean so it can tell the calling function whether or not it succeeded. Otherwise you just carry on until you've tried every possible combination, even after you've found a solution.
Then, at each call of the function, you need to check the return value and return true if it succeeded.
Then you also obviously need to return true when done.
I suggest something like:
if (stepCounter == 1 + board.length * board[0].length)
return true;
Right after board[x][y] = stepCounter++;.
You need to revert any changes made at the end of the function call, i.e. stepCounter needs to decrease and board[x][y] needs to be set to -1.
After you've successfully made these changes, you should actually see a result of all -1's, because it's not possible on a 4x4 board, but changing it to 8x8 should succeed.
Note that I didn't use 17 above - it's good practice to not use hard-coded values (in, for example, x >= 4). Use either the size of the array, or final values, instead.
Your tour() function appears to set the value of a square to the step-counter of the order it's visited for the first time. But you're trying multiple options. Your first tour dead ends when you get to 12 - one of the subsequent attempts touches each of the 13-16 squares.
You need to store the state of the current tour, rather than the order in which you visited. E.g. if you backtrack, the current square is no longer part of the tour. If you find a tour, you should stop, because you're done.