I am currently making a tower defence game.
Simply put it works like this: green circles (enemies) move across the screen. By clicking, you can place a tower. The enemy has a rectangle hidden underneath it, and the tower has a large opaque rectangle around it indicating its hit range. If they are colliding, the enemy starts to lose health, until it dies.
Before, I used this test to see if the enemy was within range of the tower:
for(int i=0;i<enemy.length; i++) //Runs for the total amount of enemies
{
for(int j=0; j<boxes.length;j++) //Runs for the total amount of towers placed
{
if(enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
{
enemy.setHealth(enemy.getHealth()-1);
}
}
}
However, I would like the towers to only be able to shoot one enemy at a time, most preferably the enemy at the front. To do this I need java to detect that there are multiple enemies colliding with the rectangle and only damage the front enemy.
Here is the test I ran to do this (The enemies array value go backwards so the first one to appear is enemy[0] and the last enemy[10] for example):
for(int i=1;i<enemy.length; i++)
{
for(int j=0; j<boxes.length;j++)
{
if(enemy[i].getEBox().intersects(boxes[j])&&!(enemy[i-1].getEBox().intersects(boxes[j])))
{
enemy.setHealth(enemy.getHealth()-1);
}
}
}
however, the second condition always returns a positive. How can I change my if statement to conduct a successful test?
To make a tower only shoot at one enemy, flip the loops and break the inner loop when shooting starts.
for(int j=0; j<boxes.length;j++) //Runs for the total amount of towers placed
{
for(int i=0;i<enemy.length; i++) //Runs for the total amount of enemies
{
if(enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
{
enemy[i].setHealth(enemy[i].getHealth()-1);
break; // skip remaining enemies, since towers has used
// up it's shooting capability for this round
}
}
}
If a tower can prioritize which enemy to shoot at, loop through all the enemies to find the best candidate, then shoot at it.
for (int j=0; j<boxes.length; j++) //Runs for the total amount of towers placed
{
int enemyToShootIdx = -1;
for (int i=0; i<enemy.length; i++) //Runs for the total amount of enemies
if (enemy[i].getEBox().intersects(boxes[j])) //boxes[j] is the towers' range box
if (enemyToShootIdx == -1 || betterCandidate(boxes[j], enemy[i], enemy[enemyToShootIdx]))
enemyToShootIdx = i;
if (enemyToShootIdx != -1)
enemy[enemyToShootIdx].setHealth(enemy[enemyToShootIdx].getHealth()-1);
}
Now you just have to implement the betterCandidate() method.
You could store the enemies in the order you detect them so you will know which is the closest. Like an ArrayList for detected enemies or an ID kind of variable for each enemy object, which initialized when detected. Im pretty sure there are a lot ways like this, so storing an order somehow could work. Once you have an order you can attack only that one and there is no need to test the detected objects anymore while still looking for coming enemies and keep storing them so on.
In your case
if(enemy[i].getEBox().intersects(boxes[j])&&!(enemy[i- 1].getEBox().intersects(boxes[j])))
I don't really see (or maybe just too tired) why you need these conditions to attack. If your array of enemies is already in order why dont you just attack the first? If inRange && isAlive if not you go on the next one.
I hope i did not misunderstand anything and probably could help a bit. :)
Related
I am a beginner and I am making a space shooter game in Netbeans. I want if the spacecraft's bullet hits the enemy's bullet that the 2 bullets are removed. I have created an Arraylist of bullets and bulletsEnemy. Then I created a method hitByBullet that should ensure that I can search for the bullets that collided. Then in the method bulletsHit (), the bullets should be removed.
My enemies shoot in a loop and don't move. My problem is that the bullets go through each other. The radius of the bullets is 5.
These is the 2 methods that I have written
'''
public int hitByBullet(){
for(int i=0; i<bullets.size(); i++){
for(int j= 0;j< bulletsEnemy.size(); j++){
if( bullets.get(i).getY() - bulletsEnemy.get(j).getY()<= 5)
if(bullets.get(i).getX() -bulletsEnemy.get(j).getX()<= 5){
return i;
}
}
}
return -1;
}
'''
public boolean bulletsHit(){
if (hitByBullet()!= -1){
bullets.remove(this); //with 'this' I refer too 'i'
bulletsEnemy.remove(this);
return true;
}
return false;
}
'''
[This is how it looks like] (https://i.stack.imgur.com/4XsCR.png)
I will try to answer in a way to let you find your way to implement what you want. There are several frameworks out there which will help you with this and as you are new to programming there are a lot of things you could change/do better. But I will ignore these things.
I think your are trying to check if one 5x5 bullet intersects with another 5x5 bullet.
To make it easy let us asume your bullets are squares:
In your hitByBullet you should check your square centers (i asume that are x,y of your bullets) distance in both dimensions:
Sth. like this should check the collision:
if(Math.abs(bullets.get(i).getY() - bulletsEnemy.get(j).getY()) < 5 &&
Math.abs(bullets.get(i).getX() - bulletsEnemy.get(j).getX()) < 5) {
return i;
}
Depending of the size of your bullets you need to change the distance check ( <=5). If your bullets have a size of 5 px it should be < 10. If your bullets are 10x10 you should check against < 20 ...
Regarding a more realistic scenario, that your bullets are circles (e.g. resulting of a 5x5 square px or a radius r=5):
You need to check if the distance between your two bullet centers is smaller than the bullet radius * 2.
That will bring you to use the theorem of pythagoras:
https://en.wikipedia.org/wiki/Pythagorean_theorem
The distance between your bullet centers is c. a is the distance in dimensional x and b the distance in dimensional y. You don't need to take care about negative dimensional values cause you need pow them by 2 which will always give you a positive value.
To check for collision you should calculate the distance c as follows:
c = SquareRootOf(a^2+b^2)
Math.sqrt(Math.pow(bullets.get(i).getX() - bulletsEnemy.get(j).getX()),2) + Math.pow(bullets.get(i).getY() - bulletsEnemy.get(j).getY(),2)) < 10
I think you should read basics about collision detection and geometry. Just two possible points of information:
An easy to start example with code:
https://zetcode.com/javagames/collision/
Circle intersection:
https://www.geeksforgeeks.org/check-two-given-circles-touch-intersect/
Regarding the removal of the bullets I asume you have some kind of game loop in which you frequently draw the bullets and calculate the collision (call the bulletsHit method):
I will make an assumption to make things easier: The movement speed of your bullets is not faster than one pixel per loop. Otherwise I think you need to take care of your loop circle time and calculate the positions of all elements and also take care about bullets that won't intersect in one loop circle because they could have passed by from one loop circle to the next loop circle. I'm not familiar with game dev, so maybe there are more things to cover.
Regarding this you should change things:
The method hitByBullet() will only return one collision per call.
You could store your collidedBullets in two sets and after removing them from your bullets and bulletsEnemy list clear these temporary sets.
I don't understand what you are doing with "this" and your result of
hitByBullet.
I would do it like this
public void hitByBullet(){
for(int i=0; i<bullets.size(); i++){
for(int j= 0;j< bulletsEnemy.size(); j++){
if( Math.sqrt(Math.pow(bullets.get(i).getX() - bulletsEnemy.get(j).getX()),2) + Math.pow(bullets.get(i).getY() - bulletsEnemy.get(j).getY(),2)) < 10){
bulletsToDelete.add(bullets.get(i));
bulletsEnemyToDelete.add(bulletsEnemy.get(j));
}
}
}
}
public boolean bulletsHit(){
hitByBullet();
bulletsToDelete.forEach(bullet -> bullets.remove(bullet);
bulletsEnemyToDelete.forEach(bullet -> bulletsEnemy.remove(bullet);
boolean bulletsHit = !bulletsToDelete.isEmpty();
bulletsToDelete.clear();
bulletsEnemyToDelete.clear();
return bulletsHit;
}
As I mentioned before there are a lots of things you should improve:
general structure of your code
naming of your method (e.g. bulletsHit sounds like only checking if bullets are hit but you are also removing them)
double checking of bullets
Greetings
I'm making a snake game and the apples shouldn't spawn inside the snake when randomly spawned on the screen. I have tried looking for a new place for the apples, when they get placed inside the snake with:
for (int i = 0; i < snake.size() - 1; i++) {
if (snake.get(i).xPos == plum.get(0).xPos && snake.get(i).yPos == plum.get(0).yPos) {
plum.remove(0);
plum.add(new Coordinate(rollDice(squaresX - 1) * (squareSize + sizeOfSpace) + sizeOfSpace, rollDice(squaresY - 1) * (squareSize + sizeOfSpace) + sizeOfSpace, new Color(199, 7, 255)));
}
}
This is not a good solution so I'm looking for a new one where I can create invalid coordiantes which are the snakes coordinates and valid coordinates that is the rest. So I can randomize the apples new position from just valid coordinates. But I'm not sure how I'm supposed to code this
This is just a general suggestion, but I think it might work for you.
Keep the length of the snake updated all of the time
Now when creating a new apple, create an array of Coordinations of size of the grid size minus snake length. For example: if your grid size is 9x9 and your snake length is 6, create an array of length 75.
Run over the grid and array and add to the array just Coordinations that do not have the snake in them. It should look something like this:
int arrayLocation=0;
for(int i=0; i< grid.length();i++)
{
for(int j=0; j<grid[i].length(); j++)
{
if (!snakeAtLocation(i,j))
{
arr[arrayLocation++] = new Coordinate(i, j);
}
}
}
Then you can randomly pick a number n between 0 to arr.length(), then retrieve the coordination from arr[n] and you should have a coordination without a snake in it. Hope it helps and if you need more detailed example I will provide tommorow as I'm writing this from my phone and I don't have pc right now:)
By the way, this answer if for a simple use case, as it isn't optimized and running with o(n)^2 each time you eat an apple. If you want more optimized solutions, you would have to track the snake location with each move he make. I'll be able to post both answers tommorow if needed:)
So well I tried creating a simpler Minesweeper game and I encountered one main problem..
I am not able to count the number of bombs and print it in a JTextField
Any ideas as to how to count these as I'm setting a random value to check whether they are a bomb
Tried counting it in the ActionListener but the bombs were counted only after the button was clicked.
if(e.getSource()==b[i][j])
{
b[i][j].setVisible(false);
tf[i][j].setVisible(true);
int r1 = rand.nextInt(6);
if(r1>1)
{
tf[i][j].setText("Safe");
tf[i][j].setBackground(Color.green);
}
else
{ count++;
tf[i][j].setText("Bomb");
tf[i][j].setBackground(Color.red);
f.setVisible(false);
restart.setVisible(true);
}
}
As I understand you decide if the the tile will be a bomb in the run-time using a random generator. Doing this you can't really know how many mines are in your game. I think you should decide the number of mines at the beginning of the game and randomly place them to your game board (you can choose the number according to a difficulty level).
EDIT
You can create a list with some random points that contain the mines
int numOfMines = 10;
int rows=5,columns=5;
ArrayList listWithMines = new ArrayList();
while(listWithMines.size()<numOfMines) {
int randRow = random.nextInt(rows);
int randCol = random.nextInt(columns);
Point point = new Point(randRow, randCol);
if(listWithMines.contains(point))
continue;
else
listWithMines.add(point);
}
This list now contains the Points that have the mines.
You can check if Point(x,y) has a mine like this:
if(listWithMines.contains(new Point(1, 2))) {...}
Instead of a list you can use a 2D array, store a boolean value (or int if you store more states) and make a loop until you place 10 mines. You should keep a counter(placedMines like the list.size()) of the mines you placed and make sure you don't add a mine to a tile that has already a mine and you increase the counter(placedMines) until it reaches the numOfMines.
I am currently building a game in AndEngine, but my collision detection seems a bit off. It works.. most of the time, but seems like when there is a collision with one object, it wont do the other. It's hard to explain and it's very unpredictable. If a car hits the snow, it should slow down. If a car hits ice, it should speed up.
for (int i = 0; i < rManager.carArray.length; i++)
{
if (rManager.getInstance().snowArray[0].getSnowSprite().collidesWith(rManager.getInstance().carArray[i].getCarSprite()))
{
Log.e("SNOW", "snow 0 collided with " + rManager.getInstance().carArray[i].ToString());
rManager.getInstance().carArray[i].setCarSpeed(0.1f);
break;
}
if (rManager.getInstance().iceArray[0].getIceSprite().collidesWith(rManager.getInstance().carArray[i].getCarSprite()))
{
Log.e("ICE", "ice 0 collided with " + rManager.getInstance().carArray[i].ToString());
rManager.getInstance().carArray[i].setCarSpeed(1f);
break;
}
else
{
rManager.getInstance().carArray[i].setCarSpeed(0.5f);
}
}
Is there anything wrong with my code? Currently, both enemy arrays only have 1 element. That is why I am only checking 0. Thanks!
You should remove the break; within the collision detection if test. (Or change it to continue if you only want snow or ice but not both for the same car...not sure quite how your game works in that regard).
I am creating a game using a 10x10 2D array. The player starts at the top left hand corner indicated as "P" and the objective is to get the player to avoid obstacles to get to the treasure indicated as "T" located in the lower right corner.
How would I go about making the player move about the grid using commands Up/Down/Left/Right?
Would I use a for loop to count through the elements in the array to designate the move?
Here is what I have so far:
import java.util.Scanner;
import java.util.Random;
public class Adventure {
public static void main(String[] args) {
char grid[][]= new char[10][10];
Scanner move = new Scanner(System.in);
System.out.println("Here is the current game board:");
System.out.println("-------------------------------");
for(int i=0; i<grid.length; i++) {
for(int j=0; j<grid.length; j++) {
double random = Math.random();
if(random <=.05) {
grid[i][j]='*';
}
else if(random > .06 && random <= .15) {
grid[i][j]='X';
}
else {
grid[i][j]='.';
}
grid[0][0]='P';
grid[9][9]='T';
System.out.print(grid[i][j]);
}
System.out.println("");
}
System.out.print("Enter your move (U/D/L/R)>");
}
}
you should keep track of the current position of the player and just update those variables.
initial values would be (0,0) as you said.
int px = 0;
int py = 0;
when a move is made, update the variables accordingly:
grid[px][py] = <empty cell>;
switch (move) {
case 'u': py += 1; break;
case 'r': px += 1; break;
...
}
grid[px][py] = 'P';
of course you shouldn't just updated the values "blindly", you should insert some validation logic to follow the rules of the game:
if (grid[px][py] != <obstacle> )
// update player coordinates...
Looks like you're using row-major ordering, judging from the way your board prints out. Based on that, here's what you'll need to do:
First, you need to store the player's position somewhere. Right now it's hardcoded to 0,0.
Second, you need to read in the player's move. That will have to happen in a loop, where you get a move, check if the move is allowed, perform the move, and display the results.
Third, you need to be able to calculate the new position based on the move. Up means row -= 1. Right means column += 1. Etc.
Given the new coordinates, you need to make sure the move is valid. At the very least, you have to stop them from walking off the board, but you may also prevent them from entering a square with an obstacle, etc.
Once you know that the move is valid, you have to update the variables you're storing the current coordinates in.
At the end of the loop, you'll need to redraw the board.
That's the basic gist of it. Right now you are doing everything in main(), and that's okay, but if it were me I would start to split things out into separate methods, like InitializeBoard(), GetNextMove(), CheckIfMoveIsValid(int r, int c), and so on. That way, main() becomes a high-level view of your game loop, and the guts of the different operations are compartmentalized and more easy to deal with. This will require storing off things like your game board into class variables rather than local variables, which should actually make things like obstacle detection easier than it would be currently.
All of the above answers are great. Here are a few suggestions I would make:
Instead of a char two-dimensional array, I would make a custom object, such as Space, and define a two-dimensional array of Spaces (eg, Space[][]). There are a few reasons for this:
You can define a space in a variety of ways (rather than just 1 character). For example, Space[i][j].hasTreasure() can return a boolean to let you know whether or not you found the treasure.
If you want to add functionality later, its as easy as adding an attribute to your Space class. Again, you are not limited to one character here.
More to your question of movement, I would also recommend a few things. Similar to redneckjedi's suggestion of a CheckIfMoveIsValid() method, I would pass the grid and move direction as parameters and return a boolean. To ensure that you do not end up with ArrayIndexOutOfBounds issues, I would also suggest adding a row/column of walls on each side. I would widen the grid out to 12x12 and put a strip of obstacle-type blocks around the outside. This will ensure that you cannot step outside of the grid as hitting a wall will always return 'false' on a valid move.