How do i check, if two Circles are intersecting in Processing? - java

So I'm currently learning Java, and i struggle a lot to get my Code working.
I made a "Fun" Code in which some circles are popping up and it calculates how many of them are on the Upper Side of the Screen. (I know, some silly code.)
I'm coding it in the "Processing" Environment, Language is Java.
Here's my main File:
Circle[] circles = new Circle[50];
int index = 0;
boolean finished = false;
void setup() {
size(900, 900);
background(0);
for(int i = 0; i < circles.length; i++) {
circles[i] = new Circle();
}
if(finished = true) {
}
}
void draw() {
if(index < circles.length) {
circles[index].show(circles);
index++;
} else {
finished = true;
}
}
void count(Circle[] arr) {
int n = 0;
for(Circle c : arr) {
if(c.getY() > height / 2) {
n++;
}
}
println(n);
}
And here's the "Problem" Circle class:
class Circle {
private int x, y;
private float r = random(10, 25);
Circle() {
this.x = Math.round(random(0 + r, width - r));
this.y = Math.round(random(0 + r, height - r));
}
public int getX() {
return this.x;
}
public int getY() {
return this.y;
}
public void show(Circle[] arr) {
if(isColliding(arr)) {
this.x = Math.round(random(0 + r, width - r));
this.y = Math.round(random(0 + r, height - r));
} else {
ellipse(this.x, this.y, r * 2, r * 2);
stroke(255);
fill(255);
}
}
public boolean isColliding(Circle[] arr) {
boolean result = false;
if(arr == null) {
result = false;
} else {
for(Circle c : arr) {
float d = dist(c.getX(), c.getY(), this.x, this.y);
if(d < r * 2) {
result = true;
println("Collision at: " + c.getX() + " " + c.getY());
break;
}
}
}
return result;
}
}
As you can see, i already have a isColliding Method, and the Outputs in the Console seem to be right, however it won't work in the show() Method, the Circles won't stop intersecting each other.
So how can i make it work, that the Position is re-calculated when it is colliding?

Are you sure your collision method works? Unless I'm missing something, it should ALWAYS return true as you're passing in an array that includes itself.
That aside, I'd start looking at how your show() logic is laid out. You are checking for overlap, and then assigning a new random position if it finds any. This new position could very likely be on a circle that has already been drawn and in a good position.
Put your re-positioning in a loop so that it checks to make sure that it didn't just place itself onto an existing circle.
public void show(Circle[] arr)
{
/*
You could potentially get into a situation where you will NEVER find an empty spot.
Add an escape method for the loop.
*/
int failLimit = 500;
while(failLimit-- > 0 && isColliding(arr))
{
this.x = Math.round(random(0 + r, width - r));
this.y = Math.round(random(0 + r, height - r));
}
ellipse(this.x, this.y, r * 2, r * 2);
stroke(255);
fill(255);
}
You could simplify this and make it a bit more efficient by spawning in circles one at a time, checking to make sure their positions are good then.

Related

Can't find the NullPointerException Error

I'm trying to build a Snake Game, where the snake is eating square orbs.
Before, the program was running perfectly, but when I ran it a couple of days ago, it yelled at me for something about a NullPointerException. I tried looking for what caused it, and it was in my Snake class.
Here is the code for the main class:
Snake s;
Score score;
//Menu m;
int sc1 = 20;
PVector food;
void setup() {
size(700, 700);
//m = new menu;
//m.show();
s = new Snake();
score = new Score();
//m.startGame();
frameRate(10);
}
void pickLocation() {
int cols = width/sc1;
int rows = height/sc1;
food = new PVector(floor(random(cols-20)), floor(random(rows-20)));
food.mult(sc1);
}
void draw() {
background(51);
if (s.eat(food)) {
pickLocation();
score.addPoints(10);
}
pickLocation();
score.show();
s.update();
s.show();
s.death();
if (s.dead == true) {
score.highScores();
}
if (score.totalScore != s.i/10) {
score.totalScore = s.i * 10;
}
if (s.dead && score.totalScore < score.highScore) {
score.totalScore = 0;
}
fill(255, 0, 100);
rect(food.x, food.y, sc1, sc1);
}
void keyPressed() {
if (keyCode == UP) {
s.dir(0, -1);
} else if (keyCode == DOWN) {
s.dir(0, 1);
} else if (keyCode == RIGHT) {
s.dir(1, 0);
} else if (keyCode == LEFT) {
s.dir(-1, 0);
}
}
The menu I commented out right now.
The Score class:
class Score {
int totalScore = 0; //will add the total score to the
int highScore; //will hold the user's high score in it.
int tempScore; //will hold the user's score after the snake dies.
Score() {
}
//this method is used when the snake eats the
//food. Eating the food will give 10 points to it.
void addPoints(int x) {
totalScore = totalScore + x;
}
//this method will calculate to see if the user
//has a new high score, only if the snake has
//officially died.
void highScores() {
if (totalScore > highScore) {
text("new highscore!", height/2, width/2);
highScore = totalScore;
totalScore = 0;
}
}
void show() {
text("Score: " + totalScore, 20, 20);
text("High Score: " + highScore, 20, 40);
}
}
And finally, my Snake class, where the problem is located at:
class Snake {
float x, y;
float xSpeed = 1;
float ySpeed = 0;
int total = 0;
ArrayList<PVector> tail = new ArrayList<PVector>();
boolean dead = false;
int i = 0;
Snake() {
}
boolean eat (PVector pos) {
float d = dist(x, y, pos.x, pos.y);
if (d < 1) {
total++;
return true;
} else {
return false;
}
}
void dir(float x, float y) {
xSpeed = x;
ySpeed = y;
}
void death() {
for (i = 0; i < tail.size(); i++) {
PVector pos = tail.get(i);
float d = dist(x, y, pos.x, pos.y);
if (d < 1) {
println("starting over");
total = 0;
tail.clear();
dead = true;
} else {
dead = false;
}
}
}
void update() {
if (total > 0) {
if (total == tail.size() && !tail.isEmpty()) {
tail.remove(0);
}
tail.add(new PVector(x, y));
}
x = x + xSpeed * sc1;
y = y + ySpeed * sc1;
x = constrain(x, 0, width-sc1);
y = constrain(y, 0, height-sc1);
}
void show() {
fill(0, 255, 0);
for (PVector v : tail) {
rect(v.x, v.y, sc1, sc1);
}
rect(x, y, sc1, sc1);
//rect(x, y, w, h);
}
}
My question is, is there something who can recognize the error and what should I do to fix such an error, please.
You need to get into the habit of debugging your code to understand exactly what's going on. You know that this line is throwing the NPE:
float d = dist(x, y, pos.x, pos.y);
So next, you need to understand the values of every variable on that line. You could just print them out:
boolean eat (PVector pos) {
println("x: " + x);
println("y: " + y);
println("pos: " + pos);
float d = dist(x, y, pos.x, pos.y);
If you do this, you'll see this output:
x: 0.0
y: 0.0
pos: null
This tells you that your pos variable is null, which is what's causing your NullPointerException.
Now you can trace backwards through your code to understand why the eat() function is being given a null argument.
In the future, please narrow your problem down to a MCVE instead of posting your whole program.

Processing 3.06b merging programs

i have been working on some code and merging two programs I have created but I understand I am missing a lot of information as I have many errors but I can't seem to fix the error. Below I have included the whole code which has been separated into classes. I am producing a version of space invaders.
Main class:
Bullets [] bullets = new Bullets[10];
Player player = new Player();
Boolean keyLftPressed = false, keyRghtPressed = false;
//Enemies[] enemies = new Enemies();
int state;
String gameLevel = "Main menu";
Boolean startTime = false;
void setup() {
for(int i=0; i<bullets.length; i++)
{
// if(i%2==0)
// bullets[i] = new Bullets();
// else
// bullets[i] = new Bullets(i);
}
size(800, 600);
state = 0;
}
void draw() {
background(255);
gameState();
player1.display();
movePlayer1();
handleEnemies();
handleBullets();
gamewon();
}
void gameState() {
if (gameLevel == "Main menu") {
background(0);
fill(255, 255, 255);
rect(270, 270, 280, 50, 20, 20, 20, 20);
//Draws rectangle for play game
fill(0);
textSize(30);
text("Play Game", 330, 305);
fill(255, 0, 0);
textSize(50);
text("Space Invaders", 220, 120);
if (mousePressed && mouseX > 250 && mouseX < 250 + 280 && mouseY > 270 && mouseY < 270 + 50)
{
gameLevel = "Level 1";
}
} else if (gameLevel == "Level 1")
{
background (255, 2555 , 255);
}
}
Bullets Class:
class Bullets {
class Bullet {
float x, y;
float velocity;
Bullet(float x, float y, float velocity) {
this.x = x;
this.y = y;
this.velocity = velocity;
}
void display(){
fill(80);
rect(this.x, this.y, 5,15);
}
void move(){
this.y+=this.velocity;
if (this.y > height || this.y < 0){
bullets.remove(this);
}
}
Class Enemies:
class Enemies {
float x, y;
float velocity;
Enemy(float x, float y) {
this.x = x;
this.y = y;
this.velocity = 3;
}
void display() {
fill(0,255,0);
ellipse(this.x, this.y, 30, 30);
noFill();
}
void move() {
this.x+=this.velocity;
if (this.x > width*.9) {
this.x = width*.9;
this.velocity *= -1;
this.y+=30;
}
if (this.x < width*.1) {
this.velocity*=-1;
this.x = width*.1;
this.y+=30;
}
}
void hitCheck() {
for (int i = 0; i < bullets.size(); i++){
Bullet b = (Bullet) bullets.get(i);
float distBetween = dist(b.x, b.y, this.x, this.y);
if (distBetween < 15 && b.velocity < 0){
score++;
enemies.remove(this);
float x = width*.1 + i%numCol*50;
float y = 60 + int(i/numCol)*60 ;
enemies.add(new Enemy(x, y));
}
}
}
}
Class Player:
class Player {
void movePlayer1() {
if (keyLftPressed) {
player1.x -=10;
}
if (keyRghtPressed) {
player1.x +=10;
}
}
void keyPressed() {
if (keyCode == LEFT) {
keyLftPressed = true;
}
else {
if (keyCode == RIGHT) {
keyRghtPressed = true;
}
else {
if (key == 'f') {
player1.shoot();
}
}
}
}
void keyReleased() {
if (keyCode == LEFT) {
keyLftPressed = false;
}
else {
if (keyCode == RIGHT) {
keyRghtPressed = false;
}
}
}
Class Score:
void gameFinish() {
{
for (int i = 0; i < 3; i++)
{
fill(color(255,0,0));
fill(255, 0, 0);
textAlign(CENTER);
text("Game over", width/2, height/2 - 50);
text(" Final score : "+ score, width/2, height/2 + 50);
}
}
}
}
void gamewon()
{
if (score == 10)
{
background(0);
fill(color(255,0,0));
fill(255, 0, 0);
textAlign(CENTER);
text("Congratulations you won!", width/2, height/5);
text(" Your final score is : "+ score, width/2, height/5 + 30);
text("Do you wish to continue?",width/2, height/2);
text(" If so press Y to Continue or N to exit ", width/2, height/2+30);
noLoop();
}
}
I don't want to be disheartening, but this code is a mess. You've got a ton of errors here, and asking us to go through all of them is asking quite a bit.
That being said, I'll try to get you started in the right direction.
First of all, you're missing closing curly brackets on several of these classes. Proper indenting will help you narrow this down, or you could consider putting each class in its own tab.
Then in your Player class, you use a variable named player1. Where is that variable defined? Do you mean to use the player variable? For that matter, since you're in the Player class already, why are you referring to a variable at all? Shouldn't you just use the x variables in that instance directly?
Which brings us to the next problem: your Player class doesn't actually define an x variable!
Similarly, your Player class calls a shoot() function, which doesn't seem to exist. You have to define that function.
Then let's see here... your Score class uses a score variable that doesn't seem to be declared anywhere.
Also, your bullets variable is an array, but you're calling functions on it that only work on an ArrayList object. Pick one or the other.
You also call a bunch of functions that don't exist: movePlayer1(), handleEnemies(), handleBullets(), and gameWon() for example. Some of these functions are defined inside of classes, so you need to use an instance of that class to get to the functions. Like this:
Example e = new Example();
e.function();
class Example{
void function(){
println("here");
}
}
Then your Enemies class has a constructor of Enemy, which isn't valid. Choose one or the other.
You're not going to like hearing this, but honestly, your best bet is probably to start from scratch. I would guess that you're trying to copy-paste all of this code from different sources without really understanding what the code is doing, which is a horrible idea. That never works, even for experienced programmers.
Instead, try breaking your problem down into smaller pieces. Get a single rectangle on the screen, then make it move around when you press the arrow keys, then add the ability to shoot. Then try adding some enemies, but only after the previous steps work perfectly!
If you get stuck, post an MCVE that shows the small step you're stuck on- not your entire project!

Java Test if circles overlap

I have a program to draw 20 circles w/ random rad x and y. After, I need to test which circles are overlapping and if they are, set them cyan, if not set them black. heres what I have so far, the problem, is it always sets it to cyan overlapping or not.
public class AppletP5 extends JApplet{
MyCircle[] circle = new MyCircle[20];
public AppletP5(){
for(int i = 0; i<20; i++){
int x0= (int) (Math.random()*500);
int y0= (int) (Math.random()*500);
int rad0= (int) (30 + Math.random()*70);
circle[i] = new MyCircle(x0,y0,rad0);
}
}
public void paint(Graphics g){
for(int i = 0; i<20; i++){
if(circle[i].isOverlapping(circle) == true){
g.setColor(Color.CYAN);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
} else if(circle[i].isOverlapping(circle) == false){
g.setColor(Color.BLACK);
g.drawOval(circle[i].x,circle[i].y,circle[i].rad*2,circle[i].rad*2);
}
}
}
}
public class MyCircle {
protected int x, y, rad;
public MyCircle(int x, int y, int rad){
this.x = x;
this.y = y;
this.rad = rad;
}
public boolean isOverlapping(MyCircle[] circles){
for(MyCircle c : circles){
if(Math.pow(c.rad - rad , 2) >= Math.sqrt(Math.pow(x - c.x, 2) + Math.pow(y - c.y , 2))){
return true;
}
}
return false;
}
}
You need to exclude the current Circle from the comparison, since a circle trivially overlaps itself.
You could go with an easy check as long as you just have one instance of each Circle:
for (MyCirlce c : circles) {
if (c != this && ...)
In addition you are checking if the difference of radii between two circles squared by two is greater than the distance of the two centres? Shouldn't you check for the sum of the radii, eg:
r1 + r2 <= distance(c1, c2)
isOverLapping is incorrect implemented.
Two circles intersect, if the distance between their centers is smaller than the sum of their radii. So:
int radSum = c.rad + rad;
int radDif = c.rad - rad;
int distX = c.x - x + radDif;
int distY = c.y - y + radDif;
if(radSum * radSum < distX * distX + distY * distY)
return true;
Apart from that you'll have to ensure you don't compare a circle with itself. And finally: Math.pow is rather costly, so replace it with the simpler version, if you only want the square of a number.

Brick Collision Java [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have been working on a Breakout game and have just about everything done except for the brick collision. The ball bounces of the wall and paddle fine, but when it comes to the brick it goes straight through them. I'm pretty sure the problem is in the checkBrick() part of the main class, but have no idea what to do about it.
Main Class:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.*;
import java.util.Random;
import javax.swing.JOptionPane;
public class Breakout extends Applet implements Runnable {
Ball ball = new Ball();
Paddle paddle = new Paddle(135, 375);
Brick[] brick = new Brick[50];
private int bX[] = new int[50];
private int bY[] = new int[50];
private int bW[] = new int[50];
private int bH[] = new int[50];
Thread t;
Random trajectory = new Random();
boolean lose;
Image buffer = null;
// The life cycle of the Applet
// Sets up window
public void init() {
setSize(377, 500);
buffer = createImage(377, 500);
// setBackground(Color.black);
System.out.println("init()");
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
System.out.println("start()");
}
public void run() {
System.out.println("run()");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (!lose) {
ball.move();
paddle.move();
checkWall();
checkPaddle();
checkBrick();
ball.move();
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
JOptionPane.showMessageDialog(null, "Game Over");
System.out.println("Termintated");
System.exit(0);
}
public void stop() {
System.out.println("stop()");
}
public void destroy() {
System.out.println("destroy()");
}
public void paint(Graphics g) {
Graphics screen = null;
screen = g;
g = buffer.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, 377, 500);
createBricks(g);
createPaddle(g);
createBall(g);
screen.drawImage(buffer, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
private void createBricks(Graphics g) {
int brickIndex = 0;
int brickX = 15, brickY = 160;
int brickW = 30, brickH = 10;
for (int i = 0; i <= 4; i++) {
brickX = 15;
brickY -= 20;
for (int n = 0; n < 10; n++) {
brick[brickIndex] = new Brick();
brick[brickIndex].setBounds(brickX, brickY, brickW, brickH);
bX[brickIndex] = brick[brickIndex].x();
bY[brickIndex] = brick[brickIndex].y();
bW[brickIndex] = brick[brickIndex].w();
bH[brickIndex] = brick[brickIndex].h();
brick[brickIndex].setColor(i);
brick[brickIndex].paint(g);
brickIndex++;
brickX += 35;
}
}
}
private void createPaddle(Graphics g) {
paddle.paint(g);
}
private void createBall(Graphics g) {
ball.paint(g);
}
private void checkWall() {
// If ball hits right wall it will bounce
if ((ball.getX() + ball.getR()) >= 380) {
ball.setVX(trajectory.nextInt(2) + -3);
}
// If ball hits left wall it will bounce
if ((ball.getX() - ball.getR()) < -10) {
ball.setVX(trajectory.nextInt(4) + 1);
}
// If ball hits ceiling it will bounce
if ((ball.getY() + ball.getR()) < 12)
ball.setVY(trajectory.nextInt(5) + 1);
// If ball goes through floor it will subtract a life
if ((ball.getY() + ball.getR()) > 515)
lose = true;
}
private void checkBrick() {
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
if ((ball.getX() + ball.getR()) < (tempX + tempW)
&& (ball.getX() + ball.getR()) >= tempX) {
if ((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY) {
System.out.println("Brick " + i + " has been hit.");
}
}
}
}
private void checkPaddle() {
// Check for paddle
if ((ball.getX() + ball.getR()) < (paddle.getX() + 100)
&& (ball.getX() + ball.getR()) >= paddle.getX() + 5) {
if ((ball.getY() + ball.getR()) > (paddle.getY() - 5)
&& (ball.getY() + ball.getR()) <= (paddle.getY() + 5)) {
ball.setVX((trajectory.nextInt(7) + -2) + 1);
ball.setVY(trajectory.nextInt(1) + -3);
}
}
}
// Key Detectors
public boolean keyDown(Event e, int key) {
if (key == Event.RIGHT) {
paddle.setVX(0);
if ((paddle.getX() + 100) < 377)
paddle.setVX(10);
}
if (key == Event.LEFT) {
paddle.setVX(0);
if (paddle.getX() > 0)
paddle.setVX(-10);
}
return true;
}
// To make sure it doesn't just keep moving one way
public boolean keyUp(Event e, int key) {
paddle.setVX(0);
return true;
}
}
Ball Class:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball
{
private int x, y; //Position
private int vx, vy; //Velocity
private int r; //radius
//constructor
public Ball()
{
x = 177;
y = 315;
vx = 0;
vy = 5;
r = 15;
}
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillOval(x, y, r, r);
}
//returns the x of origin
public int getX()
{
return x;
}
//returns the y of origin
public int getY()
{
return y;
}
public int getVX()
{
return vx;
}
//returns the y of origin
public int getVY()
{
return vy;
}
//returns the radius r of the ball
public int getR()
{
return r;
}
//sets the velocity of x to a different value
public void setVX(int vx)
{
this.vx = vx;
}
//sets the velocity of y to a different value
public void setVY(int vy)
{
this.vy = vy;
}
//sets the x value
public void setX(int x)
{
this.x = x;
}
//sets the y value
public void setY(int y)
{
this.y = y;
}
//starts making the ball move by changing its coords
public void move()
{
x+= vx;
y+= vy;
}
}
Paddle Class:
import java.awt.Color;
import java.awt.Graphics;
public class Paddle {
// declares variables for x and y coordinates
int x, y;
//The velocity of to move paddle
int vx;
// constructor that takes in x and y coordinates for paddle
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
}
public void paint(Graphics g)
{
// paints paddle
g.setColor(Color.WHITE);
g.fillRect(x, y, 100, 15);
g.setColor(Color.GREEN);
g.drawRect(x, y, 100, 15);
}
// gets x coordinate of paddle
public int getX() {
return x;
}
// sets x coordinate of paddle
public void setX(int x) {
this.x = x;
}
// gets y coordinate of paddle
public int getY() {
return y;
}
// sets y coordinate of paddle
public void setY(int y) {
this.y = y;
}
public void setVX(int vx)
{
this.vx = vx;
}
//Moves the paddle
public void move()
{
x+=vx;
}
}
Brick Class:
import java.awt.Color;
import java.awt.Graphics;
public class Brick
{
private Color color =(Color.cyan);
private int x, y, w, h;
public Brick()
{
//Garbage values that are there just for declaration
x = 0;
y = 0;
w = 10;
h = 10;
}
//Sets color for the brick
public void setColor(int paintC)
{
switch(paintC)
{
case 0:
color = (Color.magenta);
break;
case 1:
color = (Color.blue);
break;
case 2:
color = (Color.yellow);
break;
case 3:
color = (Color.orange);
break;
default:
color = (Color.red);
break;
}
}
//Sets the location then size of the brick
public void setBounds(int x, int y, int w, int h)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//returns x value
public int x()
{
return this.x;
}
//returns y value
public int y()
{
return this.y;
}
//returns width value
public int w()
{
return this.w;
}
//returns height value
public int h()
{
return this.h;
}
//Sets x for the brick
public void setX(int x)
{
this.x = x;
}
//Sets y for the brick
public void setY(int y)
{
this.y = y;
}
public void setW(int w)
{
this.w = w;
}
public void setH(int h)
{
this.h = h;
}
public void paint(Graphics g)
{
g.setColor(color);
g.fillRect(x, y, w, h);
g.setColor(Color.green);
g.drawRect(x, y, w, h);
}
}
I've begin running over your code, quite frankly can't be bothered trying to figure out your logic, but what I believe you're trying to deduce is if the brick "contains" the ball, rather then if the ball intersects with the brick.
You don't care how much of the ball or brick are intersecting, only if the they do...for example...
private void checkBrick() {
int tx = ball.getX();
int ty = ball.getY();
int tw = ball.getR();
int th = ball.getR();
tw += tx;
th += ty;
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
int rw = tempW + tempX;
int rh = tempH + tempY;
// overflow || intersect
if ((rw < tempX || rw > tx) &&
(rh < tempY || rh > ty) &&
(tw < tx || tw > tempX) &&
(th < ty || th > tempY)) {
System.out.println("Hit");
}
}
}
Now, I stole this from Rectangle#intersects
Basically, if you used the geometry class from the 2D Graphics API, you could reduce this down to...
private void checkBrick() {
Rectangle b = new Rectangle(ball.getX(), ball.getY(), ball.getR(), ball.getR());
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
Rectangle brick = new Rectangle(tempX, tempY, tempW, tempH);
System.out.println("brick = " + brick);
if (b.intersects(brick)) {
System.out.println("Break");
}
}
}
And, yes, I did actually run your code
The problem is that the method checkBrick() is not changing anything, it is just printing if the ball has a collision with the brick.
You may want to change the Ball velocity, as you did within checkWall() and checkPaddle().
private void checkBrick() {
for (int i = 0; i < 50; i++) {
...
if (...) {
ball.setVX(...); // Add these lines setting the correct values
ball.setVY(...);
}
}
}
You may also want to check if your if-conditions are correct, and do what you expected.
Assuming tempH is positive,
((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY)
can't ever be true. The > needs to be < and the <= needs to be >=.
Additionally, you'll need to take some kind of action if the brick is hit, rather than just printing out the fact. Sorry, I'm not sure what's supposed to happen - does the brick disappear? Or the ball bounce? Or both?
Second answer (in addition to other answer which I believe is ALSO a problem), your logic is asking if the ball is contained within a brick, but when you create the ball its radius is greater than the height of a brick, so even correcting that logic won't fix the problem.
You should refactor your code to make it read out like natural language, this would help a lot with debugging (or writing less bugs in the first place!) i.e.
in brick class:
public int bottom()
{
return y;
}
public int top()
{
return y + h;
}
in ball class:
public int bottom()
{
return y - r;
}
public int top() {
return y + r;
}
then in main class:
private boolean withinY(brick) {
return (ball.bottom => brick.bottom() && ball.top =< brick.top());
}
then the logic reads nicer (psuedo):
foreach brick in wall {
if (ball.withinY(brick) and ball.withinX(brick))
BAM!!
}
You're checking if the ball is between the left and right side of the brick, but then checking if the ball is both above AND below the brick, because you've got your greater than and less than's mixed up. Also the center of the ball needs to be subtracted from it's Y position.
if ((ball.getY() + ball.getR()) **>** (tempY + tempH) &&
(ball.getY() **+** ball.getR()) **<=** tempY)
could be
if ((ball.getY() + ball.getR()) < (tempY + tempH) &&
(ball.getY() - ball.getR()) >= tempY)
but I'd suggest finding if the top of the ball is between the top and bottom of the brick, OR if the bottom of the ball is between the top and bottom of the brick:
if (((ball.getY() + ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY)) ||
((ball.getY() - ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY))) {
CODE
}
And use similar logic for finding between left and right sides of the brick

2D Collision issues in Java game

I've been working on this game with LWJGL for a few weeks now. Ever since I added the ability to jump, the upward collision has been giving me a lot of problems.
The game is a 2D tile-based sidescroller. Overall, the collision is almost perfect except for when the player jumps. At first I thought "Oh, maybe I just need to change the jumping mechanics," but then I realized that it only happens when the player is passed a certain x coordinate.
Now, for the actual problem itself: if the player jumps when passed a certain x coordinate, they will pass through the tile and testing for top collision returns false.
This is the entire Player class:
package Minecraft2D;
import static Minecraft2D.World.BLOCK_SIZE;
import Minecraft2D.Tools.Tools;
import Minecraft2D.UI.Inventory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import static Minecraft2D.Boot.*;
import org.lwjgl.util.Rectangle;
import org.newdawn.slick.opengl.Texture;
import org.newdawn.slick.opengl.TextureLoader;
public class Player {
private float x;
private float y;
public int width = 32;
public int height = 50;
private float DX = 0;
private float DY = 0;
private Texture left = null;
private Texture right = null;
Texture texture = null;
public boolean direction[] = { false, false, false, false };
public boolean collision = false;
public boolean ground = false;
public boolean jump = false;
public boolean top = false;
public Player(float x, float y) {
this.x = x;
this.y = y;
try {
this.left = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_left.png")));
this.right = TextureLoader.getTexture("PNG", new FileInputStream(new File(path + "player_right.png")));
this.texture = this.right;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void draw() {
Tools.drawTexture((int)x, (int)y, width, height, texture);
}
public void checkCollision(Player player, Block block) {
if (player.getY() < block.getY() + BLOCK_SIZE && player.getX() < block.getX() + BLOCK_SIZE && player.getY() + this.height > block.getY() && player.getX() + this.width > block.getX() && block.getType() != BlockType.AIR) {
Rectangle top = new Rectangle();
top.setBounds((int) player.x + 4, (int) player.y + 1, this.width - 8, 1);
Rectangle bottom = new Rectangle();
bottom.setBounds((int) player.x + 4, (int) player.y + this.height, this.width - 8, 1);
Rectangle left = new Rectangle();
left.setBounds((int) player.x, (int) player.y + 1, 1, this.height - 5);
Rectangle right = new Rectangle();
right.setBounds((int) player.x + player.width, (int) player.y + 1, 1, this.height - 5);
Rectangle blok = new Rectangle();
blok.setBounds((int) block.getX(), (int) block.getY(), BLOCK_SIZE, BLOCK_SIZE);
if (bottom.intersects(blok)) {
player.setY((block.getY() - this.height - 1));
ground = true;
jump = false;
} else if (top.intersects(blok)) {
DY = 0;
this.top = true;
y -= (player.y) - (block.getY() + BLOCK_SIZE);
}
if (!top.intersects(blok)) {
if (left.intersects(blok)) {
player.setX(block.getX() + this.width);
} else if (right.intersects(blok)) {
player.setX(block.getX() - this.width);
}
}
} else {
collision = false;
ground = false;
}
if (!collision && !jump) {
setDY(.003f);
}
if (ground && !jump) {
DY = 0;
}
if (jump && DY < 0.003f) {
DY += 0.0001;
} else {
// jump = false;
}
if (top) {
DY = 0f;
top = false;
}
x += DX;
y += DY;
if (x > Boot.SCREEN_WIDTH) {
x = 0;
}
if (x < 0) {
x = Boot.SCREEN_WIDTH;
}
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public void setDX(float dx) {
this.DX = dx;
}
public void setDY(float dy) {
this.DY = dy;
}
public void setJump() {
if (!jump) {
jump = true;
ground = false;
DY = -0.13f;
y -= 1;
}
}
public void setTexture(int tex) {
if (tex == 0) {
this.texture = this.left;
}
if (tex == 1) {
this.texture = this.right;
}
}
}
==============
EDIT: I have no clue why, but as my character moves closer to the map's 0 x-coordinate, the character's y coordinate increases very slowly. This probably has something to do with the problem I have been getting. I am looking into it and I have a suspicion that it may have something to do when I cast the player's x and y values from doubles to integers for use in the top, bottom, left, and right Rectangles.
EDIT again:
I don't know if this matters, but I have been checking collision like this: (This is in the "Boot" class.)
private void checkCollision() {
for (int x = 0; x < BLOCKS_WIDTH - 1; x++) {
for (int y = 0; y < BLOCKS_HEIGHT - 1; y++) {
Block blk = grid.getAt(x, y);
player.checkCollision(blk);
}
}
}
Why are you passing a player into checkCollision? It seems like you should not be passing in a player, but instead using the members of the player that's calling the checkCollision method. I think that may be leading to some confusion for you. Such as:
y -= (player.y) - (block.getY() + BLOCK_SIZE);
This looks like you are trying to push the player below the block b/c they intersected it during their jump. If that's the case, it should just be
y = (block.getY() + BLOCK_SIZE);
I would remove the player from the function argument and rewrite the function and see what you get. Hope that helps.
EDIT
Your comment states that you can no longer pass the player into the function. Not sure about your exact implementation, but here's what games that I have typically seen look like:
public class Player
{
private int x, y, dx, dy;
public void checkCollision(Block block)
{
if (isTopCollision(block))
fall(block.getY() + block.getHeight());
}
private boolean isTopCollision(Block block)
{
return y > block.getY() + block.getSize() && y < block.getY();
}
private void fall(int adjustedY)
{
y = adjustedY;
top = true;
dy = 0;
// etc
}
}
public class MyGame
{
public void gameloop()
{
for (Block b : blocks)
player.checkCollision(b);
}
}

Categories