I'm currently trying to make a small Entity-Relationship-Modell creating tool for Databases.
To avoid errors I try to don't allow the rectangles to overlap with a other rectangle.
I got most of my code working and it detects almost every collusion but in one case I can still overlap them and I don't know how to fix this error.
The problem is that it will look on only on rectangle not on both. But I really don't know how to intercept that case.
The strange thing to me is that my Debug line
System.out.println("still intersects?");
never triggers. Can somebody help me out in this error?
Image to the error in my Colision
This Function gets triggered every time I move a Rectangle.
The attribute Selected is a Boolean which says me which Rectangle I'm moving.
Then I check on which side its overlapping and revert back to the old position.
boolean Move(Point point) {
boolean moved = false;
boolean foundone = false;
for (ERMRectangle rectangle : Rectangles) {
if (rectangle.selected) {
foundone = true;
moved = true;
//calculated new Rectangle after Move
Rectangle Temp = new Rectangle();
Temp.x = point.x + rectangle.click.x;
Temp.width = rectangle.position.width;
Temp.height = rectangle.position.height;
Temp.y = point.y + rectangle.click.y;
for (ERMRectangle rectangle2 : Rectangles) {
if (rectangle != rectangle2 && rectangle2.position.intersects(Temp))//prevent overlapping
{
Rectangle intersection = rectangle2.position.intersection(Temp);
if (intersection.height > intersection.width) {
Temp.x = rectangle2.position.x - rectangle2.position.width;
if (intersection.x != rectangle2.position.x) {
Temp.x = rectangle2.position.x + rectangle2.position.width;
}
} else {
Temp.y = rectangle2.position.y - rectangle2.position.height;
if (intersection.y != rectangle2.position.y) {
Temp.y = rectangle2.position.y + rectangle2.position.height;
}
}
}
if(rectangle != rectangle2 && rectangle2.position.intersects(Temp))
{
System.out.println("still intersects?");
}
}
rectangle.position = Temp;
}
}
return moved;
}
ERMRectangle class:
import java.awt.Rectangle;
public class ERMRectangle {
public Rectangle position;
public boolean selected;
public Point click;
}
Edit: i resolved it by adding one more for loop into my methode which checks if it still interselects the rectangle and reverts both x and y cordinnates.
If at any moment, there will only be one rectangle moving (dragged by the user) there is no need to use nested loops to check for collision n-square times.
All you need is a method like this in your ERMRectangle class:
These codes assume your ERMRectangle class extends Rectangle class from Java
public boolean isColliding(ArrayList<ERMRectangle> rects)
{
for(ERMRectangle r : rects)
if(this != r && this.intersects(r))
return true;
return false;
}
You can then invoke isColliding() in the mouseReleased(MouseEvent e) in the mouse listener for your rectangles, and trigger the necessary actions when collision is detected. So, upon every mouse release after dragging, it will check for collisions on the rectangle which you have just moved.
To check for collision as you drag, place the similar codes as you would in mouseReleased(MouseEvent e) into mouseDragged(MouseEvent e). This will do a real-time collision detection check as you drag the rectangle.
Related
I´m building my own Space Invaders in Java with Greenfoot and I have a Spaceship which shoots the Aliens, but the Bullets stop at the top of the map and stay there so I wrote this method which should remove a bullet if it hits the top of the but it doesn't work. What´s the problem?
public void disappearIfOnTop() {
Actor Bullet = getOneIntersectingObject(Actor.class);
getY();
if(getY() == 0) {
World world;
world = getWorld();
world.removeObject(Bullet);
}
}
Edit: they are getting removed if they hit another bullet which is stuck on the top.
The method getOneIntersectingObject() returns a null if there is no other actor.
You might want to check this to be sure:
public void disappearIfOnTop() {
if (getY() == 0) {
Actor bullet = getOneIntersectingObject(Actor.class);
if (bullet == null) {
setLocation(getX(), 50); // move down if no other is around
} else {
setLocation(getX(), 100); // move further down if another is around
}
}
}
If the method getOneIntersectingObject() returns a reference to an actor, your current method is removing that one, not the one who is at Y=0. (BTW, don't use variable names starting with uppercase letters. By convention, this is reserved for classes.)
You can simplify your method to:
public void disappearIfOnTop() {
if (getY() == 0) {
getWorld().removeObject(this);
}
}
Did a lot of googling but was not able to solve this problem.
I want to generate n Number rectangles and draw them on a screen. X,Y are generated randomly and the width and height are based on the font size. My goal is to draw a n number of words on a screen positioned randomly without overlapping existing rectangle. I am using Rectangle for collision detection.
private List<Rectangle> rectList = new ArrayList<Rectangle>();
public boolean checkForCollision(Rectangle r) {
boolean collision = false;
if (rectList.size() == 0) {
rectList.add(r);
System.out.println("Adding First");
return collision;
} else {
// loop through the list
Rectangle currRectangle;
for (int i = 0; i < rectList.size(); i++) {
currRectangle = rectList.get(i);
if (r.intersects(currRectangle)) {
System.out.println(r.toString());
System.out.println(currRectangle.toString());
System.out.println("=========================");
return collision;
}
}
System.out.println("No collision");
rectList.add(r);
return !collision;
}
}
This is what I have done to create rectangle and draw a word on it. I am using a loop here.
int width = graphics.getFontMetrics().stringWidth(temp.getWord());
int height = graphics.getFontMetrics().getHeight();
Rectangle newRectangle = new Rectangle(rand.nextInt(1250)+1, rand.nextInt(650)+1, width, height);
int xCordinate = (int)newRectangle.getX();
int yCordinate = (int) newRectangle.getY();
while(collisonChecker.checkForCollision(newRectangle)){
//newRectangle = new Rectangle(rand.nextInt(1250)+1, rand.nextInt(650)+1, width, height);
newRectangle.setLocation(rand.nextInt(1250)+1,rand.nextInt(650)+1);
collisonChecker.checkForCollision(newRectangle);
}
graphics.drawRect((int)newRectangle.getX(), (int)newRectangle.getY(), (int)newRectangle.getWidth(), (int)newRectangle.getHeight());
newRectangle.setLocation(rand.nextInt(1250)+1,rand.nextInt(650)+1);
graphics.drawString(temp.getWord().trim(), (int)newRectangle.getX(),(int)newRectangle.getY() );
You Never change your return value. No matter, if there's a collision or not , the method returns false. set your return value to true idle there's a collision in the for-loop , that should fix the problem
I hope that helped at least a bit
Okay, so this seems "weird" to me...
while(collisonChecker.checkForCollision(newRectangle)){
//newRectangle = new Rectangle(rand.nextInt(1250)+1, rand.nextInt(650)+1, width, height);
newRectangle.setLocation(rand.nextInt(1250)+1,rand.nextInt(650)+1);
collisonChecker.checkForCollision(newRectangle);
}
graphics.drawRect((int)newRectangle.getX(), (int)newRectangle.getY(), (int)newRectangle.getWidth(), (int)newRectangle.getHeight());
newRectangle.setLocation(rand.nextInt(1250)+1,rand.nextInt(650)+1);
graphics.drawString(temp.getWord().trim(), (int)newRectangle.getX(),(int)newRectangle.getY() );
You create a new Rectangle, you check for a collision and start looping while it's true, in the loop you change the location of the of the Rectangle and check the for a collision but ignore the return result ...? But that's not the worse part...
Once the loop finishes, you randomly generate a new location of Rectangle, completely ignoring all the work you did in the loop ...?
Perhaps you should do something more like...
while(collisonChecker.checkForCollision(newRectangle)){
newRectangle.setLocation(rand.nextInt(1250)+1,rand.nextInt(650)+1);
}
graphics.drawRect((int)newRectangle.getX(), (int)newRectangle.getY(), (int)newRectangle.getWidth(), (int)newRectangle.getHeight());
graphics.drawString(temp.getWord().trim(), (int)newRectangle.getX(),(int)newRectangle.getY() );
I have been using android's RectF in my game to detect collisions on movement. When an entity moves, it gets the object in the world at the position it would like to move. If this object is an instance of a RectF or my Entity class, the entity is told it cannot move there. Here is the code for my map checking method:
public Object getCollisionObject(Entity ent){
for(Entity e : entities){
if(e == ent)continue;
if(e.collides(ent.getBoundsF())return e;
}
for(RectF r : collisions){
if(ent.collides(r))return r;
}
return null;
}
public void moveHere(Entity e, float x, float y){
float originalX = e.getX();
float originalY = e.getY();
e.setX(x);
e.setY(y);
Object o = getCollisionObject(e):
boolean moved = true;
if(o instanceof RectF || o instanceof Entity)moved = false;
e.setX(originalX);//actual movement is done in the entity class if this method returns true
e.setY(originalY);
return moved;
}
Here are the relevant methods in the Entity class:
public RectF getBoundsF(){
return new RectF(x, y, x + width, y + height);
}
public boolean collides(RectF rect){
return RectF.intersects(getBoundsF(), rect);
}
Here is a quick video to demonstrate my problem (the red boxes are drawn around collisions and the blue ones are drawn around bitmap bounds):
VidMe Link
From the video, it seems that on the bottom and right walls, the entity cannot move closer than its width (32 pixels) to the wall. However, on the left and top walls, the entity is able to successfully move as close as possible. The same problem happens on the left and top sides of the walls (on every wall). I am very confused and have spent hours trying to solve this but to no avail. If any more information is required, please do ask in the comments.
I'm trying to make a little game, where you have a little cube you can control with the arrows. When the cube intersects with another block object, I want it to go back and stop by the edge of the block object. So basically I want my block to stop when it intersects the block object, instead, it moves a bit in to it, and then when I move it again it jumps back. How can I make it so first checks if it will intersect, and if it will not move into it?
My drawing class extends JPanel and I'm painting with paintComponent.
if(keyCode == e.VK_RIGHT) {
if(xRightCollision()){
hero.x -= xVel;
}
else {
hero.x += xVel;
}
}
So let's say the cube is at the edge of the block object, but it's not intersecting it yet, so I press right and it moves into it, I press right again and it jumps back 5 pixels(xVel = 5).
public boolean xRightCollision(){
for(int i = 0; i < obstacles.size(); i++) {
if (hero.intersects(obstacles.get(i))) {
return true;
}
}
return false;
}
I've actually tried a similar thing with paint() on the JFrame, and since you have to call repaint() there, I could check first and then repaint. I don't really understand how paintComponent works since you can't control when it should be repainted.
Just use a temporary value to check, if the cube intersects with an obstacle, and reset to the original position, if necessary:
if(keyCode == e.VK_RIGHT) {
//backup of the cubes position
int tmp = hero.x;
//move the hero to the right
hero.x += xVel;
if(xRightCollision())
//cube intersects with an obstacle -> restore original position
hero.x = tmp;
}
I am coding a Java game that uses mouse actions. I have a point msc in my main class - it gets changed whenever I press the mouse and gets set to (0, 0) whenever I release the mouse. For the buttons, they check if msc is inside their rectangle, and if so, call click.
One of the buttons is supposed to toggle a boolean; when I click on it though, it switches true and false very fast because msc gets updated every time paintComponent is called.
Here is the code for the button click method:
if (button.contains(Screen.msc)) {
beenClicked = true;
this.width = this.width - 2;
this.height = this.height - 2;
this.x = this.x + 1;
this.y = this.y + 1;
g.setColor(currColor);
textColor = Color.YELLOW;
}
but that is not where the problem is I think. Here is the code that changes msc:
public void mouseReleased(MouseEvent e) {
Screen.msc = new Point(0, 0);
}
public void mousePressed(MouseEvent e) {
Screen.msc = new Point((e.getX()) - ((Frame.size.width - Screen.myWidth) / 2), e.getY() - ((Frame.size.height - (Screen.myHeight)) - (Frame.size.width - Screen.myWidth) / 2));
}
and the code for what happens when the specific toggle button is clicked:
if (toggleToolTips.clicked()) {
if (Screen.canDrawTooltip) {
Screen.canDrawTooltip = false;
} else if(!Screen.canDrawTooltip){
Screen.canDrawTooltip = true;
}
}
The problem is every time I go and click the button, the boolean switches back and forth real fast. When I hold it, it just rapidly and continually switches. I would like to make it so that I click once and it switches once.
Your setting the boolean beenClicked but are not checking it anywhere. I would suggest trying
if (!beenClicked && toggleToolTips.clicked())
{
Screen.canDrawTooltip = !Screen.canDrawTooltip);
}
And setting beenClicked back to false somewhere such as mouseReleased.