Java Objects in Array - collision detection - java

Let's say that I have code like this:
private void actuallyDrawGraphics(Canvas canvas) {
canvas.drawColor(Color.WHITE);
for(Ball ball : balls){
canvas.drawBitmap(ballBitmap,
-16 + (ball.x / 100f) * canvas.getWidth(),
-16 + (ball.y / 100f) * canvas.getHeight(),
paint
);
}
}
Every ball is registered in an array. I need to make a collision (when one collides with the second) and everything goes well, until I have more balls, for example 10. It's not efficient to make a check like:
ball 1 with 2, 3, 4...
ball 2 with 1, 3, 4...
Is there any way that this can be done?

for (int i = 0; i < balls.size(); i++) {
Ball ball = balls[i];
for (int a = i + 1; a < balls.size(); a++) {
Ball ball2 = balls[a];
// check for collision with ball and ball2.
}
}
Like Nacho was saying, I believe that this would be a better way to check every possible collision, but if you have a very large number of balls, then you may need to do something to reduce the number of checks you are making here. Or, you may need to improve your code that checks for a collision.

You need another data structure. For example an object Collision containing a List<Ball> ballsThatCollide; or something similar. Or for each Ball to have List<Ball> inCollisionWith. If you want simple arrays, then you'll need a N dimensional array where the dimensions are the balls and the intersection are collisions.

Related

Using Data from Array

I am making small java game, and I am trying to set enemies x coordinate through array of coordinates.
public Enemy()
{
int[] xcoordinate = new int[]{40,60,80,100,120,140,160,180,200,220,240,260};
for(int i = 0;i <= xcoordinate.length;i++){
addObject(new enemy(5,5),*sets enemy's x coordinate to a number from an array*,180);
}
}
Basically what I am trying to do, is to automatically add 12 enemies, and their x coordinates will be taken from an array, but I am not sure how to do it. So enemy number 5, will have an x coordinate of 120. Any help will be useful. Thank you
You use a counter in your loop.
To access an array at position x, just use xcoordinate[x].

processing: trouble using global array in if condition in for loop

I am trying to write a small program that has a given number of balls (in the example code below it's 3) travel back and forth across the screen at different speeds and phases (start offset).
This much has been achieved in the code. Although I want to be able to select the balls (one at a time) using a mouse click.
I have used the word "HIT!!!" to signify in the console that a ball has been clicked.
My problem is that when I run the code below, I only get a "HIT!" in the console when I click the top ball. That is when the first element y[0] matches with the click_Y variable. When I am sure (but obviously mistaken somehow) that there should be matches when I click in the vicinity of y[1] & y[2].
I'd really be grateful for any help with these. As it's gotten to the point where I am starting to stare blankly at the screen. Thanks.
int noCircles; // the number of items in the array (# of circles)
float[] y; // y-position of each circle (fixed)
float[] speed; // speed of each circle
float[] phase; // phase of each circle
float red = 120;
float green = 120;
float blue = 120;
float click_X;
float click_Y;
void setup() {
size(500, 500);
noCircles = 3;
// allocate space for each array
y = new float[noCircles];
speed = new float[noCircles];
phase = new float[noCircles];
// calculate the vertical gap between each circle based on the total number
// of circles
float gap = height / (noCircles + 1);
//setup an initial value for each item in the array
for (int i=0; i<noCircles; i++) {
y[i] = gap * (i + 1);
// y is constant for each so can be calculated once
speed[i] = random(10);
phase[i] = random(TWO_PI);
}
}
void draw() {
background(155);
for (int i=0; i<noCircles; i++) {
// calculate the x-position of each ball based on the speed, phase and
//current frame
float x = width/2 + sin(radians(frameCount*speed[i] ) + phase[i])* 200;
if (dist(x, y[i], click_X, click_Y) <= 20){
println("HIT!!!!!!!!!!!!!!!!!!");
}
ellipse(x, y[i], 20, 20);
click_X = 0;
click_Y = 0;
}
}
void mousePressed() {
println("You clicked******************************************");
click_X = mouseX;
click_Y = mouseY;
println("click_X =" + click_X);
println("click_Y =" + click_Y);
}
Problems like these are best solved by debugging your program. Start by tracing through the code by hand, then add print statements (more than you've already added), and if that doesn't work then don't be afraid to use the debugger.
You're using the click_X and click_Y variables to check the position of the mouse against the position of each ball. Trace through the for loop in your draw() function. What happens at the end of the first iteration?
You reset the values of click_X and click_Y. That's why you aren't detecting any hits on the other circles.
You could probably refactor your code to only reset those variables if something has been hit, but really, I would stop using them altogether.
I'm guessing that you're using those variables because you only want to check when the mouse is pressed? Just use the mousePressed variable for that. Then you can use the mouseX and mouseY variables directly.
Then your if statement would look like this:
if (mousePressed && dist(x, y[i], mouseX, mouseY) <= 20) {
println("HIT: " + i);
}
Also, using separate arrays like this is called parallel arrays, and is general a bad habit to get into. You should probably use classes instead.

Java Graphics2D - Detecting collisions between two objects

I'm creating a trial game where a spacecraft fires missiles to a stationary enemy spacecraft. The missile moves from left to right, and the enemy spacecraft is positioned on the right side. If a missile hits the enemy craft, it "explodes" (disappears from the screen). My problem is when should I execute the explode method because it is kinda tricky to tell if one of the missiles's plot coincides with that of the enemy craft. In my main program, I have the following:
private void updateMissiles(){
ArrayList ms = craft.getMissiles();
for(int i = 0; i < ms.size(); i++){
Missile m = (Missile) ms.get(i);
if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
enemcraft.explode();
}
if(m.isVisible()){
m.move();
}else{
ms.remove(i);
}
}
}
This does not work especially because the missile and the enemy spacecraft have different dimensions (8x5 pixels and 20x20 pixels, respectively). However, when I changed if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()) to simply if(m.getX() == enemcraft.getX()), the program works, but it disregards the y position of the missile and will make the enemy craft explode as long as the missile reaches the same x position of the enemy.
I tried experimenting with different ranges of the x and y positions, but to no avail. Is there an intuitive way to tell when the missile "hits" the enemy craft?
AABB (Axis Aligned Bounding Boxes)
You have not given much to go by but making a comparison based on position is not going to solve your problem.
The line
if(m.getX() == enemcraft.getX() && m.getY() == enemcraft.getY()){
Requires that the missile and enemy have the same position (x,y), there is only one point on the screen that has that coordinate so it's going to be hard to hit. You have effectively made your bad guy and missiles one pixel width and one pixel in height.
Bounding boxes
Both the missile and enemy have a size (area) you need to test if these areas hit. Imagine two rectangles each containing the missile and enemy. When these two rectangles overlap you can count that as a collision.
As I dont know where the x,y of the missile and enemy are (top left or center or something else) I will assume that you use the top left. Nor do I know if the two objects provide a width and height so I will hard code that. (20,20) and for missile (8,5)
private void updateMissiles () {
ArrayList ms = craft.getMissiles();
int mLeft = enemyCraft.getX(); // guessing position is an int . Set the correct type when you copy this
int mTop = enemyCraft.getY();
int mRight = mLeft + 20;
int mBottom = mTop + 20;
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
// only test if both missile and enemyCraft are visible
// I am guessing that enemyCraft has a isVisible method
if(m.isVisible() && enemyCraft.isVisible()){
int mx = m.getX(); // Again I am guessing the type as int
int my = m.getY();
if ( ! (my > mBottom || mx > mRight || mx + 8 < mLeft || my + 5 < mTop)) {
enemyCraft.explode();
ms.remove(i); // remove missile
}
}
if (m.isVisible()) {
m.move();
}
}
}
Better fit.
There is a problem with this method. The missiles and bad guys may not be the same shape as the bounding box. This will result in a collision even if they are not actually touching. But that is easily solved.
Do the test as above, this will let you know if you should do more testing. When you find a collision divide the two objects into a few smaller bounding boxes and test if they overlap. That will improve the accuracy.

Collision detection strategy for a pong game

I'm trying to implement a simple pong game. I want the ball to change X direction or Y direction depending what side of the ball was hit.
The ball moves at 3 pixels per second and has a width of 22 and height of 22. The paddles have a width and height of 32.
For collision detection on the ball, should I just create one rectangle and check for collision with the center point?
Alternatively I could create 4 rectangles around the ball to represent the sides, with an appropriate width, given that the ball moves at 3 pixels per frame.
Another option is to create a method that will check for collision at least 2 pixels in the direction of motion of the ball.
If the ball is moving to the right, and the x-position is 16, the next frame will be 19.
Should I create a method that will check x for 16, 17 and 18, to make sure if there is a collision it will hit the right side and not cause the ball to actually go inside the cube?
#Sig
I now have this as my collision detection
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
}
//Left
if(balls.get(j).xPos < levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
//Right
if(balls.get(j).xPos > levelBlocks.blocks.get(i).xPos)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
}
This works, but not 100%, it still seems abit off. if the ball hits two blocks at the same time, it will invert the invert so the direction will go back again.
I then changed it to this
if(Rect.intersects(balls.get(j).ball, levelBlocks.blocks.get(i).rect))
{
//Bottom
if(balls.get(j).yPos <= levelBlocks.blocks.get(i).yPos - (32/2))
{
collision = 2;
}
//Top
if(balls.get(j).yPos >= levelBlocks.blocks.get(i).yPos + (32/2))
{
collision = 2;
}
//Left
if(balls.get(j).xPos <= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
//Right
if(balls.get(j).xPos >= levelBlocks.blocks.get(i).xPos + (32/2))
{
collision = 1;
}
temp = levelBlocks.blocks.get(i);
levelBlocks.blocks.remove(i);
combo.blocksDestroied += 1;
Assets.score += 10 * combo.comboMultiplier;
}
}
if(collision == 1)
{
balls.get(j).xSpeed = balls.get(j).xSpeed * -1;
collision = 0;
}
if(collision == 2)
{
balls.get(j).ySpeed = balls.get(j).ySpeed * -1;
collision = 0;
}
This does work, but every now and then the ball will just start randomly going through blocks, it is very odd to look at, really confused on why it is doing it, but I do feel it is because of the 3 pixels per frame
Because the shapes you're working with are so simple, why not be perfect? Use a rectangle for the paddles and a circle for the ball when performing hit detection. Start by checking for collisions on a frame-by-frame basis; at the speeds you're working with, you shouldn't need to "look into the future" for future collisions.

Iterating through a Java collection to make these balls bounce, any hints?

Apologies if the question isn't clear but I couldn't think of another way to phrase it.
This is for a class assignment which I've been working at in BlueJ all weekend. I have to change a method (bounce) to let a user choose how many balls should be bouncing.
Other requirements are: the balls should be of different sizes and should be displayed in a row along the top of the screen BEFORE they bounce.
In order to do this I have to use a collection (ArrayList, HashMap, HashSet). So far I've used HashMap and have been able to have the user choose a number of "balls" of random sizes which place themselves in random positions in the top half of the screen.
When I try to have each ball bounce from its position at the top of the screen, ending at the right hand side I come up stuck. I can make the code draw one ball, bounce it then draw another ball, bounce it etc until the user selected number of balls has looped round.
There are two other classes, one to draw the canvas and one to draw the balls and move them. Both of which I'm not allowed to touch.
What I'm doing the wrong way is probably right in front of me but i've been staring at this code so long I thought I'd ask.
My current version of the code looks like this:
import java.awt.Color;
import java.util.HashMap;
import java.util.Random;
import java.util.Iterator;
public class BallDemo
{
private Canvas myCanvas;
private HashMap<Integer, BouncingBall> ballMap;
private int n;
private int j;
private BouncingBall ball;
/**
* Create a BallDemo object. Creates a fresh canvas and makes it visible.
*/
public BallDemo()
{
myCanvas = new Canvas("Ball Demo", 600, 500);
}
And the method I have to edit to bounce the balls:
public void bounce(int numBalls)
{
ballMap = new HashMap<Integer, BouncingBall>();
int ground = 400; // position of the ground line
Random randomD1 = new Random();
Random xpos = new Random();
myCanvas.setVisible(true);
// draw the ground
myCanvas.drawLine(50, ground, 550, ground);
// add balls to HashMap
for(n = 0; n < numBalls; n++) {
ballMap.put(numBalls, (ball = new BouncingBall(xpos.nextInt(300), 50, randomD1.nextInt(200), Color.BLUE, ground, myCanvas)));
//
for(j= 0; j < ballMap.size(); j++) {
ball.draw();
boolean finished = false;
while(!finished) {
myCanvas.wait(50); // small delay
ball.move(); // bounce the ball
// stop once ball has travelled a certain distance on x axis
if(ball.getXPosition() >= 550) {
finished = true;
}
}
}
}
}
}
Am I even on the right lines using a HashMap? The combination of keys, values seemed the best way to go. I think I need to somehow iterate through the items placed in the collection to make them bounce using the move() method. But first I need the balls to stay in a row at the top of the screen, no matter how many the user defines.
I'm new to programming and I'm just coming up stumped.
Thanks for any help!
#16dots is partly right, except ballMap.put(numBalls, ball); will over write the same value in the hash map each time, as numBalls does not change...
The key should be unique.
It should read...
for (int n; n < numBalls; n++) {
BouncingBall ball = new BouncingBall(xpos.nextInt(300), 50,
randomD1.
nextInt(200), Color.BLUE, ground, myCanvas);
ballMap.put(n, ball);
}
boolean finished = false;
while (!finished) {
finished = true;
for (int j = 0; j < ballMap.size(); j++) {
BouncingBall selectedBall = ballMap.get(j);
selectedBall.draw();
// Only move the ball if it hasn't finished...
if (selectedBall.getXPosition() < 550) {
selectedBall.move(); // bounce the ball
// stop once ball has travelled a certain distance on x axis
if (selectedBall.getXPosition() < 550) {
finished = false;
}
}
}
myCanvas.wait(50); // small delay
}

Categories

Resources