I am writing a Java program that closely mimics Microsoft Paint. It can draw four different shapes: Lines, Ovals, Rectangles, and Squares. I am very close to finishing this but I am stuck on the logic for drawing squares.
There are two Points involved while drawing these shapes. The first Point(point1) is when the user presses the mouse button and the second Point(point2) is while the user drags the mouse across the canvas. I believe drawing Rectangles and Squares should be quite similar but the part that has confused me is when drawing a square the sides are equal length so point2 isn't exactly where the mouse is.
Here is the fillRect() method header for reference:
fillRect(x, y, width, height)
My functioning code for drawing rectangles is as follows:
g.fillRect((((point1.x < point2.x) ? point1.x : point2.x)),
((point1.y < point2.y) ? point1.y : point2.y),
Math.abs(point2.x - point1.x),
Math.abs(point2.y - point1.y));
I tried using the same code for drawing squares except changing the height parameter to be equal to the width parameter because squares have equal length sides:
g.fillRect((((point1.x < point2.x) ? point1.x : point2.x)),
((point1.y < point2.y) ? point1.y : point2.y),
Math.abs(point2.x - point1.x),
Math.abs(point2.x - point1.x)); //same as width
I don't know what the problem is with making both width and height equal. It works when drawing downwards to the left or right but of course the shape does not expand if you pull straight down. Clicking and dragging up does not work; the square simply moves up with the mouse along the Y axis instead of expanding.
Could anyone point me in the right direction regarding the logic for drawing square from two points?
I can explain my code a bit better if need be.
If I were using a tool to draw a square, I would expect that my mouse cursor would remain on one of the sides of the square while drawing. If you always use the x distance as the side, then if I've drawn farther down than across, the cursor will be outside the square.
I think, while the dragging is going on, the code would need to calculate whether the x distance or the y distance to the origin is the longer, and use that as the side of the square-in-progress. Then the cursor will be on one of the sides, and that side will extend out beyond the cursor to the corner of the square-in-progress.
I don't know why the drawing is going awry -- it is difficult to be sure I understand what you say is going wrong.
You should do two calculations in your MouseDragged method -- first you should calculate the two corner Points of the rectangle, p1, and p2, and only then should you calculate the width. Point p1 is easy -- it's always the first Point pressed, but p2 will require a simple calculation. Once these are clarified, your calculations should fall out correctly.
i.e., something like:
int width = Math.abs(pointA.x - pointB.x);
int height = Math.abs(pointA.y - pointB.y);
width = Math.max(width, height);
height = width;
int x = pointA.x > pointB.x ? pointA.x - width : pointA.x;
int y = pointA.y > pointB.y ? pointA.y - width : pointA.y;
g.fillRect(x, y, width, height);
Related
I have some fixed position images at every screen edge and I want to find a way to be able to point at them correctly, I get both my old and new mouse points from MouseMoved and with those 2 points and the angle I can draw a line that reaches the end of the screen but unfortunately I can't make that line point correctly at the images
What your program is trying to do is:
Find the angle that the line is supposed to have.
Start by assuming the line is going to be very long so that it crosses the edge of the rectangle.
Then cut it off at the point of crossing.
For example, assume the rectangle is 180 by 120, and that your angle is 45ยบ. The larger of the dimensions is 180, so you draw a line of length 180 at that angle:
So you want to cut the line where the arrow is. Both your newX and your newY are outside of the frame. According to the logic of your program, you see that newX is greater than 1750, and so you cut it to 180 (the frame max y in my example). And the value of newY is greater than 850, and so you cut it to 120 (the rectangle's max Y in my example).
This means that almost always, you'll end up with the line end being at (180,120) instead of where the arrow is. This is because you just adjusted one coordinate, but you failed to find the corresponding Y on the line before continuing.
Basically, when you cut down newX to getWidth() - 100, you also need to find Y that will go with it and is on the same line. So you need to calculate Y again. Instead of:
if (newX > 1720)
{
newX = getWidth() - 100;
}
You need to have
if (newX > 1720)
{
newX = getWidth() - 100;
newY = Math.round(oldY + (newX - oldX)*Math.tan(angle));
}
The new value of newY may still be outside of the rectangle. In fact, the new point is this:
So now you will adjust the value of Y - but again, you have to be careful, and match the value of X to that Y according to the same angle.
But beware: the method is not very good to begin with. Taking Math.max(getWidth(), getHeight()) as the initial length of the line is only going to work for certain points. But what if your point is near one corner and the other point is near the opposite corner? The diagonal of the rectangle is longer than either its width and height. So you'll get a line that is too short and won't reach the edge.
You could calculate the diagonal instead of max, but perhaps you should adopt a different method:
Calculate the linear formula of the line (any line is ).
Calculate the Y for x=100 and x=width-100
Calculate the X for y=100 and y=height-100
Now you have four pairs of X and Y, find out which one of them is the correct one. Only two are going to be inside the frame, and only one of these is in the right direction.
In fact, you don't need to calculate four points. If the original newX from the mouse event was to the right of the oldX, only calculate the formula at the right edge. The left edge doesn't interest you. If it was on the left, only calculate at the left edge. If the original newY from the mouse event was below the oldY, only calculate the formula at the lower edge, and if it was higher, only at the top edge. You'll end up with two points. Only one of them is "legal" (both x and y are in the rectangle), and you use that.
I've implemented a kind of Pong where the paddles (Rectangle2D) can rotate.
To obtain more accuracy, many things are managed by Graphics2D.
The rotation too is managed by the methods rotate(...) of the previous told class.
To reach a realistic bounce, I need to know where the ball hits the paddle (only the side, not the particular point).
I've tried to define (and rotate) two Rectangle2D that represent the back and the front side of the paddle and then recognize the bounce in one of these two by the method hit(Rectangle2D r, Shape s, boolean onStroke), but it doesn't work properly.
Here is the java class Graphics2D:
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html
Have you any idea?
Assuming you have one rectangle for your paddle and know the center of rectangle and circle and the rotation of your rectangle.
Assuming a rotation of zero means, your rectangle is aligned horizontally (width > height).
Calculate the difference vector (center of circle) - (center of rectangle)
Get the angle of that vector and subtract the rotation of your rectangle (angle of vector is Math.atan2(y, x))
The resulting value a tells you the relative direction of your circle
Make sure a lies between 0 and 2*pi
q = Math.atan2(height of rectangle, width of rectangle)
If a is between q and pi-q, your circle has hit on the front long (upper) side.
If a is lower than q or bigger than 2*pi-q it's on the right side.
If a is between pi-q and pi+q it's on the left side.
If a is between pi+q and 2pi-q it's hit the bottom of your rectangle
I am having to draw recursively a sierpinski triangle by drawing three one-pixel squares on top of each other to make a triangle. He tells us, and im assuming this will be my recursive base case, that "The draw algorithm will take the coordinates of a square area of the screen as input. If that square is the size of a single pizel, it should call drawRect() on the object passed into paintComponent, drawing a one-pixel square somehwhere on the screen."
How do i find out if the square area of the screen is the size of a single pixel? Do i just send in the width of the area when i call the method and do width^2. If the area is 1, does that mean its 1 pixel?
The square (or probably the Rectangle) has size of one Pixel if:
java.awt.Rectangle rect;
// ....
boolean isOnePixel = (rect.width == 1 && rect.height == 1);
To simplify things we asume the witdh and height cannot be negative.
Altough Java rectangle classes permits that.
I'm making a breakout/brick-breaker/arkanoid clone (opengl-es/android) and I've been stuck on my collision detection code for quite some time. As the title suggests: How do I figure out which side of a brick has been hit by the ball ?
Since I only need to invert the speed in a certain direction, x or y, when a brick is hit I could think of:
if(speedY < 0) : left, upper or right
else : left, bottom or right
if(speedX < 0) : bottom, right or upper
else : bottom, left or upper
however this doesn't bring me far in deciding if it collided vertical or horizontal, and with that, which direction I should send the ball next.
I've looked at some code examples on the internet, however those often are very vague, complicated or off-topic for me.
Well, if you know the position of the Brick and the position of the ball you can do tests on each object to determine the side of the brick.
Assuming the standard Java origin in the top-left:
+----+
( )| |
+----+
If the ball's Max-X is < the Min-X of the brick, you know that it has to be on the left side, and vice versa with the right and left. You would also test the Y values for top and bottom collisions.
Of course this assumes you've gotten the collision detection working first.
EDIT
This is an excerpt from my Collision engine, this is just a small bit for an example, but this is how I test if the object is to the left of the thing it's colliding with.
else if ((oCenter.getX() < sCenter.getX())
&& ((oCenter.getY() < (sCenter.getY() + sourceHalfHeight))
&& (oCenter.getY() > (sCenter.getY() - sourceHalfHeight))))
return LEFT;
In my example here oCenter is a Point2D and it's the center of the ball. sCenter is a Point2D and it's the center of a rectangular shape. sourceHalfHeight is half the height of the rectangular shape (the object with the center point sCenter).
The Pseudo-code algorithm:
if (the center X of the ball < the center X of the rectangle
AND the center Y of the ball is BETWEEN the max Y and min Y of the rectangle)
then the ball is to the LEFT of the rectangle
end if
The thing is, you cannot know it with the speed only, as the ball could hit 2 different sides at 2 different times, both times with the same speed in the same direction.
Ex:
First line hits the top, second one hits the side, but both have the same speed and direction
/
/ /
_____ /
|_____|
You would have to use the ball's position and compare it with each sides of the brick
I need ideas about how to move an object (a circle which represents a robot in my application).
The surface the object will be moving on consists of Tiles of BufferedImage of 3 rows and 3 columns ( represented in arrays). All the Tiles are equal in sizes (160 X 160).The 3rd row and the 3rd column are the track rails on which the object must be moving on.
It means that the object(robot) can move horizontal (forward and backward) and vertical (upwards and downwards).
The Tile at the position [2][2] (please am counting from top. so the top row will be 0 the next afterward is 1 etc.. ) is a crossing which the robot will use to change to the vertical track rails or to the horizontal track rails.
My problem now is how to move the object to a specific Tile after the crossing has turned. For instance the robot will be in the Tile at position [2][1] and want to move to the tile at position [1][2] after the crossing is turned and then move further upwards. Or it can be at [1][2] and want to move to [2][1] after the crossing is turned and then move further backwards .
How can i move the robot from one Tile to another Tile? Which way can i refer to a specific Tile in the BufferedImage that i can place the object. All what i want is give me the ideas how i can do it.
Please this is my first time of doing such project so forgive me if my question is too elementary. With your explanation and help i will learn more from it.
Thank you very much.
In order to display your image you need to figure out the bounds of the grid you want to put your image into. I usually create two helper methods, one to translate grid coordinates into display coordinates and the other one to go the other direction.
private Point convertGridToDisplay(int x, int y) {
return new Point(x * 160, y * 160);
}
private Point convertDisplayToGrid(int x, int y) {
return new Point(x / 160, y / 160);
}
convertGridToDisplay() will give you the upper left hand coordinate where you should draw your image to.
For example:
Point point = convertGridToDisplay(2, 1);
graphics.drawImage(img, null, point.x, point.y)
will draw your image at grid (2, 1).
convertDisplayToGrid() will come in handy when you want to figure out which grid a mouse click was made in.