I am simply trying to make a generic way to check for collision between rectangles. If you hit the top of a rectangle stop moving. However my rectangles seem to stop regardless of the x coordinate. I have three rectangles falling and one static rectangle that doesn't move, they are supposed to all fall on top of this static rectangle however when I run the code this happens.
Here is the collision handler code
float distanceY, furthestLeft;
public void update() {
for (int i = 0; i < stageObjects.size(); i++) {
iPos = stageObjects.get(i).getPosition();
iDim = stageObjects.get(i).getDimensions();
for(int k = 0; k < stageObjects.size(); k++){
kPos = stageObjects.get(k).getPosition();
kDim = stageObjects.get(k).getDimensions();
if(k == i){
continue;
}
distanceY = assignDy();
furthestLeft = assignDx();
//DistanceY is the subtraction of one objects y coordinate and
// if it equals 0 then they are colliding and the furthest left
// is the bottom right x coord of the furthest left objects x
//coord so it should check if this x is contained within an
// objects left x coord to right x coord
if(distanceY <= 1 && distanceY >= 0 && furthestLeft >= iPos.x && furthestLeft <= iPos.x + iDim.x){
stageObjects.get(i).react(Tuples.HIT_BOTTOM);
stageObjects.get(k).react(Tuples.HIT_FROM_TOP);
System.out.println("Collision: " + stageObjects.get(i).toString() + " with " +
stageObjects.get(k).toString());
}
}
}
}
}
public float assignDy(){
if(kPos.y > iPos.y){
return Math.abs(kPos.y - (iPos.y + iDim.y));
}else
return Math.abs(iPos.y - (kPos.y + kDim.y));
}
public float assignDx(){
if(kPos.x > iPos.x){
return kPos.x + kDim.x;
}else
return iPos.x + iDim.x;
}
The error lies here and here is the react method
public void react(int occurence){
if(occurence == Tuples.HIT_BOTTOM){
velocity.y = 0;
}
}
However, if they are further apart the code works perfectly look.
I have also noticed that the rectangle can fall through other rectangles if it is to the left of another rectangle, but if it further to the right at all it will get hung as if it landed on the rectangle. The only reason the above image worked is because the furthest right fell first, anything to the left to another rectangle will get hung as well if it falls after the rectangle to the left
I just don't see what exactly I am doing wrong any help is greatly appreciated!
Change iPos in the condition to something more generic, assign a variable like assignDx and dy to ccheck if Ipos or kPos is what you need to check for like so
public void assignOx(Vector2 ox){
if(kPos.x > iPos.x){
ox.x = iPos.x;
ox.y = iPos.x + iDim.x;
}else{
ox.x = kPos.x;
ox.y = kPos.x + kDim.x;
}
}
Related
I'm having trouble with making my comparisons. The project is supposed to draw a square from user input, and then wherever the user clicks would draw a dot of varying colors there. For instance, if they click inside the square it should make a red circle, if it's on the edge of the square it makes a green circle, and if outside it makes a blue circle. At the moment my program draws red and blue circles, but no greens. In fact it draws red circles when it's above a certain point as well.
public class Square extends GraphicsProgram {
// Instance variables
private int side; // the length of a side
private int anchorX; // the X value at the upper left corner
private int anchorY; // the Y value at the upper left corner
public Square(int x, int y, int side) {
anchorX = x;
anchorY = y;
this.side = side;
}
// mouseClicked method
public void mouseClicked(MouseEvent e) {
// Find the location where the mouse was clicked
int x = e.getX();
int y = e.getY();
// boolean variables to indicate location
boolean isInside = false;
boolean isOutside = false;
boolean isOnEdge = false;
if (x > anchorX + 1 && anchorY + 1 < y && anchorY + side + 1 > y) {
isInside = true;
}
if (x > anchorX + side + 1 && anchorY + side + 1 < y && x > anchorX + side - 1 & y > anchorY + side - 1) {
isOutside = true;
}
/*** NOTE: There a hard, and an easy way to do this! ***/
if (anchorX - 1 <= x && x <= anchorX - 3 && anchorY - 1 <= y && anchorY + side - 3 >= y) {
isOnEdge = true;
}
if (isOnEdge == true) {
System.out.println("(" + x + ", " + y + ") is on the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.GREEN);
circle.setFilled(true);
add(circle);
}
else if (isInside == true) {
System.out.println("(" + x + ", " + y + ") is inside the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.RED);
circle.setFilled(true);
add(circle);
}
else if (isOutside == true) {
System.out.println("(" + x + ", " + y + ") is outside the square");
GOval circle = new GOval(x - 2, y - 2, 4, 4);
circle.setFillColor(Color.BLUE);
circle.setFilled(true);
add(circle);
}
}
}
We were given a hint on how to do the (x,y) locations of the square as
"For example, the left edge of the square has:
x values in the range: anchorX-1 ≤ x ≤ anchorX+1, and
y values in the range: anchorY-1 ≤ y ≤ anchorY+side+1.
Which would mean that if we had a square with anchorX 50, anchorY 100 and side 60, coordinates like (49-51, 99-161) would be considered on the edge of the left side.
I think the problem is a little confusion with the bounds that make up the square - understandable as it's difficult to visualize.
Is Inside:
if (x > anchorX+1 && anchorY+1 < y && anchorY+side+1 > y) {
isInside = true;
}
Right now this:
Makes sure it's to the right of the left side x > anchorX+1
Makes sure it's to the below the top anchorY+1 < y
Makes sure it's above the bottom anchorY+side+1 > y
The problems with that are:
anchorY+side+1 > y will include the edge - the +1 will go over
There is nothing making sure it's to the left of the right side
A working solution would be:
if (x > anchorX+1 && y > anchorY+1 && x < anchorX+side-1 && y < anchorY+side-1) {
isInside = true;
}
Is Outside:
if (x > anchorX+side+1 && anchorY+side+1 < y && x > anchorX+side-1 & y > anchorY+side-1) {
isOutside = true;
}
Right now this:
Makes sure it's to the right of the right side x > anchorX+side+1
Makes sure it's below the bottom anchorY+side+1 < y
Makes sure it's to the right of the right side x > anchorX+side-1
Makes sure it's above the bottom y > anchorY+side-1
The problems with that are:
x > anchorX+side-1 and y > anchorY+side-1 will include the edge in the area considered outside.
There is nothing making sure it's to the left of the left side or above the top side.
x > anchorX+side+1 and x > anchorX+side-1 do practically the same.
You used the & symbol I'm not sure was intentional or not. The difference is && only runs if the previous are all true, while & always runs. && is therefore faster and usually preferred.
By checking all are true, it only runs when both to the right of and below the square.
A working solution would be:
if (x < anchorX-1 || y < anchorY-1 || x > anchorX+side+1 || y > anchorY+side+1) {
isOutside = true;
}
Is On Edge:
This is the more tricky one
if (anchorX-1 <= x && x <= anchorX-3 && anchorY-1 <= y && anchorY+side-3 >= y) {
isOnEdge = true;
}
Right now this:
Makes sure it's to the right of the left part of the edge anchorX-1 <= x
Makes sure it's to the left of the a point to the left of the left edge x <= anchorX-3
Makes sure it's below the top part of the bottom anchorY-1 <= y
Makes sure it's above a point above the bottom anchorY+side-3 >= y
The problems with that are:
anchorX-1 <= x and x <= anchorX-3 are contridictary, so there is no x such that both are true, so the whole thing must be false.
You used -3 a lot, when you probably meant to use +1 to get the other side of the edge.
You only check the left and bottom edges - the other two are ignored.
As you're using && instead of || (OR), you it will only be true when the whole thing is true - it must be within both edges at the same time - meaning only the corner would be counted.
This could be fixed to create a working solution for this one, but defining all the conditions manually would take a lot of work. This is what it refers to in the easy and hard comment.
As a hint, you can use the fact you already know if it's in the square to simplify it.
I suggest thinking on it.
If you're struggling to comprehend all this, I suggest drawing it out manually and writing down all the values onto it - it's much easier than trying to do it in your head. It gets easier the more you do it.
I have been stuck on making some collision detection in my game (its kind of like Terraria) for a while but i made this code and... well, it kind of works. It works if the collision is above or on the left of the player, but if the collision is on the right, or below, instead of bouncing back, the player accelerates through the blocks until there is empty space. Here is the code that i made:
private void checkCollision() {
for(int x = (int) (xpos-1); x <= xpos+1; x++){
if(x < 0 || x > main.mw-1) continue;
for(int y = (int) (ypos-2); y <= ypos+1; y++){
if(y < 0 || y > main.mh-1) continue;
if(main.map[x][y] == null) continue;
if(!main.map[x][y].solid) continue;
if(main.map[x][y].blocktype == -1) continue;
double distance = Math.sqrt((xpos-x)*(xpos-x) + (ypos-y)*(ypos-y));
if(distance > 1.0){
continue;
}else{
double x_overlap = Math.max(0, Math.min(xpos + 16, x + 16) - Math.max(xpos, x));
double y_overlap = Math.max(0, Math.min(ypos + 32, y + 16) - Math.max(ypos, y));
double overlapArea = x_overlap * y_overlap;
if(overlapArea > 0){
if(x_overlap > y_overlap){
yblock += y_overlap/2;
}
if(x_overlap < y_overlap){
xblock += x_overlap/2;
}
//guessing i need to do something here to make player
go other way if block is on other side
}
}
}
}
}
So how would i make the player bounce back if the block that he is colliding with is on the right or below. Also is there any way i can make this smoother - right now the player be bouncing all over the place. Thanks! :)
What you want to do is keep track of the player's location, and if the location after moving is out of bounds you can reset the player's position to be right on the edge of the limit.
That's how I dealt with collision detection, I answered another question similar to this one though some folk decided to downvote the answer, go figure.
I'm trying to make a pinball-style game for a school project for the Android in the SDK in Eclipse.
There's a really weird and super frustrating problem in which objects are moving without any code telling them to. Basically, each Wall instance contains 4 Line objects which are used for collision detection with the Ball. These Lines work the first time, but as soon as the ball collides with them once, then that Line somehow moves to another position on the screen.
I've been debugging it, and wouldn't ask if I hadn't already tried everything, but there is honestly no reason for the Line to shift anywhere. The way I handle a collision is by pushing the Ball to be 1px away from the wall, and then given new dx and dy (velocities) to move away. The code for checking for collisions is below, followed by the function that handles a collision to change the ball's position and velocity. Both are methods in the Ball class.
GameElement[] walls = currLevel.getWalls();
int i, j;
Line[] lines;
Line line;
RectF lineBounds;
boolean hadCollision = false;
for (i = 0; i < walls.length & !hadCollision; i++) {
lines = walls[i].getLines();
for (j = 0; j < lines.length & !hadCollision; j++) {
lineBounds = lines[j].getBounds();
if (lineBounds.intersect(point)) {
paint.setColor(Color.BLUE); // Colour ball blue.
reactToCollision3(lines[j]);
// TEST RESET!!!
//this.x = (float)(648+40);
//this.y = (float)(900-30);
hadCollision = true;
//printWallsLines();
}
}
}
and the function to handle the collision is:
public void reactToCollision3 (Line line) {
float liney = line.sy;
float linex = line.sx;
if (line.rotation == 0.0) { // HORIZONTAL EDGE
if (this.y > liney) { // Ball moving upward hits the bottom of a wall.
this.y = liney + this.radius + 1.0f;
} else { // Ball moving downward hits the top of a wall.
this.y = liney - this.radius - 1.0f;
}
this.dy *= -1.0f;
} else { // VERTICAL EDGE
if (this.x > linex) { // Ball moving leftward hits right edge of a wall.
this.x = linex + this.radius + 1.0f;
} else { // Ball moving rightward hits left edge of a wall.
this.x = linex - this.radius - 1.0f;
}
this.dx *= -1.0f;
}
So when I run this right now, the ball will bounce off a wall the first time it hits it, and then that line (edge of the wall) that it hit will be shifted elsewhere, but is not visible because the Wall is drawn as one unit so the Lines that comprise it don't affect the drawing.
If I comment out the lines for "this.x = ..." and "this.y = ...", then this problem doesn't happen anymore. Also, if I uncomment the test RESET lines for setting the ball's position in the above function, then the line doesn't shift then either. But as soon as I run this, it happens again.
I'm going insane looking for why this would happen. Please give me suggestions.
Thank you!
Did you intend to use bitwise &? (See ** in code) Your test for "!hadCollision" will fail and you will also be masking your wall length. I believe you meant to use &&
for (i = 0; i < walls.length **&** !hadCollision; i++) {
lines = walls[i].getLines();
for (j = 0; j < lines.length **&** !hadCollision; j++) {
lineBounds = lines[j].getBounds();
if (lineBounds.intersect(point)) {
paint.setColor(Color.BLUE); // Colour ball blue.
reactToCollision3(lines[j]);
// TEST RESET!!!
//this.x = (float)(648+40);
//this.y = (float)(900-30);
hadCollision = true;
//printWallsLines();
}
}
}
I'm making a android game for a school project. I'm familiar with java, but not experienced with making games. In my game a ball is controlled by the player. This ball needs to bounce of of walls.
I've tried this in two ways, but both unsuccessful. First try: I'm able to detect overlap, but not able to detect the side the ball hits.
c = the ball, r = the wall
float closestX = c.center.x;
float closestY = c.center.y;
if(c.center.x < r.topLeft.x) {
closestX = r.topLeft.x;
}
else if(c.center.x > r.topLeft.x + r.width) {
closestX = r.topLeft.x + r.width;
}
if(c.center.y < r.topLeft.y) {
closestY = r.topLeft.y;
}
else if(c.center.y > r.topLeft.y + r.height) {
closestY = r.topLeft.y + r.height;
}
return c.center.distSquared(closestX, closestY) < c.radius * c.radius;
So I tried a new approach. But this approach is unstable and treats the ball like a square.
cNew = the ball with the next position, cOld = the ball with the current position, r = wall
if (cNew.center.x + cNew.radius >= r.topLeft.x && cNew.center.x - cNew.radius <= r.topLeft.x + r.width)
{
if (cOld.center.y + cOld.radius < r.topLeft.y && cNew.center.y + cNew.radius >= r.topLeft.y)
{
return Side.TOP;
}
else if (cOld.center.y - cOld.radius > r.topLeft.y + r.height && cNew.center.y - cNew.radius <= r.topLeft.y + r.height)
{
return Side.BOTTOM;
}
}
if (cNew.center.y + cNew.radius >= r.topLeft.y && cNew.center.y - cNew.radius <= r.topLeft.y + r.height)
{
if (cOld.center.x + cOld.radius < r.topLeft.x && cNew.center.x + cNew.radius >= r.topLeft.x)
{
return Side.LEFT;
}
else if (cOld.center.x - cOld.radius > r.topLeft.x + r.width && cNew.center.x - cNew.radius <= r.topLeft.x + r.width)
{
return Side.RIGHT;
}
}
return null;
I need to combine these two is some way, but I haven't been able to find out how.
Help is much appreciated.
Didn't go very carefully with the code (and considering it is your school project, probably I shouldn't be doing your homework), but I believe treating the ball as a square would not have any negative effects if it is just going to bounce off walls. Is there something else you want to do with it?
Your first code is missing out on the fact that the surface of the ball will collide with the wall before its center. You might want to take that into account. And in what sense is your second code unstable?
Some more details would be useful here.
I am going to tell you here how I did :
for the player(and every enemy as well) you need :
x
y
w
h
and :
x velocity
y velocity
and the following point array(lists) :
outline :
upper side
lower side
left side
right side
all together
-all points that are in your ball, every pixel that hasnt alpha=0, for checking collision with walls
Walls :
walls are given as point array(list). For example, analyze the level image, every black pixel is added
Now, do the following :
in your class, have a method for moving
there you need the following logic :
int miny=Integer.MAX_VALUE;
for (Point p:walls) { //For every point in the walls
if (p.x >= (int)x && p.x <= (int)x+w && (int)p.x-(int)x < lower_side.length) {
try {
Point p2=lower_side[(int)p.x-(int)x]; //Get the point that is on the same height as the walls point
if (p.y >= (int)(y+p2.y) && (int)(y+p2.y+yvel) >= p.y && p.y-p2.y-1 < miny) { //Check if you are going to hit the wall, and if it is earlier as the earliest point determined.
miny=p.y-p2.y-1d; //Where is the earliest point where this can happen
}
} catch (Exception bug) {
System.out.println(bug);
}
}
}
apply this to all directions and dimensions.
if (miny != Integer.MAX_VALUE) {
y=miny; //Set position over the wall
yvel=-(yvel*0.75); //Bounce off
}
If you have any questions, feel free to comment.
I have two squares that moves around on the screen, both of the squares are from the same class (it's the same square that was drawn two times). I have already figured out how to do the collision detection between them so thats not a problem. The problem is that the squares can go through each other so I was thinking that I could make it so that when the squares hit each other they will teleport to the latest x and y position they were on before they collided. I have tried some things but non of them works. In my thread I have this code for now.
for(int i = 0; i < rectangles.size(); i++){
Rectangle rect = (Rectangle) rectangles.get(i);
x = rect.getXPos();
y = rect.getYPos();
checkRectCollisionAndMovement();
for(int j = i + 1; j < rectangles.size(); j++){
Rectangle rect2 = (Rectangle) rectangles.get(j);
Rectangle r1 = rect.getBounds();
Rectangle r2 = rect2.getBounds();
if(r1.intersects(r2)){
rect.setXPos(x);
rect.setYPos(y);
}
}
}
How would I make it so that it gets the x and y position before they colided and not the one they had while they were colliding?
This is the checkCollisionAndMovement method
public void checkRectCollisionAndMovement(){
for(int i = 0; i < rectangles.size(); i++){
Rectangle rect = (Rectangle) rectangles.get(i);
if(rect.getYPos() > 500){
rect.setYPos(rect.getYPos() - .1);
}
if(rect.getYPos() < 500){
rect.setYPos(rect.getYPos() + .1);
}
if(rect.getXPos() > 500){
rect.setXPos(rect.getXPos() - .1);
}
if(rect.getXPos() < 500){
rect.setXPos(rect.getXPos() + .1);
}
if(rect.isVisibe()){
rect.move();
}else{
rect.remove(i);
}
}
}
You can either store all previous x,y positions in a list and traceback one step when there is a collision or Store only last co-ordinates in temporary variables.
But as Duncan has mentioned I feel your new path should reflect along the axis orthogonal to the impact