I am using Java's Rectangle class in a program.
I have two Rectangle objects:
Rectangle big = new Rectangle(...);
Rectangle small = new Rectangle(...);
The specific sizes of the rectangles are not important. However, big will always be larger than small (in both width and height).
Usually, small is entirely contained within big. I can use Rectangle#contains to verify this. However, when this is not the case, I would like to move small to be entirely contained within big. The dimensions of neither rectangle should change.
For example:
I know could use four conditionals with Math.max and Math.min, but is there a more elegant way of doing this?
You could do it with only Math.max and Math.min. Try something like this:
small.setLocation(
Math.max(Math.min(small.getX(),big.getX() - small.getWidth()),big.getX()),
Math.max(Math.min(small.getY(),big.getY() - small.getHeight()),big.getY())
);
You'd have to consider readability though.
You need a stronger design. If you extend upon the Rectangle class, you can add the exact functionality you're looking for. Apparently the "big rectangle" should act as a container, containing the smaller rectangle:
class BigRectangle extends Rectangle {
//reference to or list of rectangle(s) here
private boolean isAlignedWith(Rectangle rect) {
return /* bounds logic */;
}
private void align(Rectangle rect) {
//move rectangle to proper position
}
public void add(Rectangle rect) {
if(!isAlignedWith(rect)) {
align(rect);
}
//store in reference or add to list
}
}
Now, you can simply add the smaller rectangle to the bigger one:
Rectangle smallRectangle = new Rectangle();
BigRectangle bigRectangle = new BigRectangle();
bigRectangle.add(smallRectangle); //automatically aligns if needed
You are now hiding the (needed) logic, keeping your central unit of code clean. This is my opinion of the most elegant way to handle this. (I would also probably create an interface RectangleContainer or ShapeContainer, having BigRectangle implement that. The interface would contain a method add(Rectangle) or add(SmallShape))
Related
sorry for the badly worded question, I'm not exactly sure how to ask this. I'm making a small game with LibGDX and I'm having trouble with collisions.
Basically, my original idea was to simply check whether or not the terrain rectangle and the player rectangle overlapped each other, and if they did, I would move the player rectangle so that it wouldn't overlap the terrain. However, I did this and it wasn't working how I had expected, and it was basically thinking that the top and bottom of the player rectangle were also colliding with the side of the terrain, and then it slides the rectangle along the terrain.
So, I was recommended to try to make a sort of box cast and honestly it hasn't really been working either. I'm new to libgdx so I'm not sure if there's an easier way to do this or not but I've tried looking around. Here's my code:
void handleCollisions() {
Rectangle pRect = player.getRect();
for(Rectangle mapRect : mapRects) { //mapRect is the terrain rectangle
//if(mapRect.overlaps(pRect)) {
float amountCollidedTop = 0f;
float amountCollidedBottom = 0f;
float amountCollidedLeft = 0f;
float amountCollidedRight = 0f;
float xCollided = 0;
float yCollided = 0;
if(mapRect.overlaps(player.boxCastTop)) {
}
if(mapRect.overlaps(player.boxCastRight)) {
xCollided = player.boxCastRight.x + player.boxCastRight.width - mapRect.x;
if(mapRect.y > player.boxCastRight.y) {
yCollided = mapRect.height-(mapRect.y - player.boxCastRight.y);
} else {
yCollided = mapRect.height-(player.boxCastRight.y-mapRect.y);
}
//what percentage of the box cast is being collided with?
amountCollidedRight = (xCollided*yCollided)/player.boxCastRight.area();
System.out.println(amountCollidedRight);
}
//}
}
}
Here's what the collision looks like
Here is what is appearing in the console
Maybe this isn't the way to go with collisions? If it isn't, is there another way that works better? If anyone needs anything clarified please let me know. Thanks!
You should have a look at the libGDX Demo Projects for reference.
Especially libgdx-demo-cuboc could be interesting for you, since it is a platformer with a simple collision system (most of it is implemented in the class Bob I think).
Or if you want to use Box2D (a 2D physics library that many libGDX projects make use of) you can have a look at the libgdx-demo-vector-pinball project.
I've tried:
1.Creating a separate variable called "factor" and multiplying or dividing literally everything with it: entity velocities, object sizes, fonts, resolution etc..
(the factor is always relative to the resolution so the objects are scaled properly)
public class Player extends Entity{
float size;
public Player(needed variables) {
super(needed variables);
resize();
}
public void resize() {
/*
Resize everything.
This method is supposed to be called from a separate resizing
function located in another class when the JFrame size is changed.
the function has to play with the choice between divide or multiply
variables with the factor
*/
}
public void tick() {
x += velX*factor;
y += velY*factor;
}
etc..
}
By using this factor to multiply literally everything, it makes the code really messy and hard to read sometimes.
2.Rendering to a BufferedImage and scaling the BufferedImage to fit to the JFrame.
void render() {
//Render the game to a new BufferedImage
BufferedImage renderedFrame = new BufferedImage(1920, 1080, BufferedImage.TYPE_RGB);
renderedFrame.createGraphics();
Graphics g = renderedFrame.getGraphics();
//Render the game ....
//Scale the BufferedImage to fit the current resolution and render it to the Canvas
BufferStrategy bs = getBufferStrategy();
Graphics f = bs.getDrawGraphics();
f.drawImage(renderedFrame.getScaledInstance(1280, 720, Image.SCALE_FAST), 0, 0, null);
f.dispose();
bs.show();
}
Which makes the code much more readable but then there comes 2 problems:
Mouse input problems and resizing the BufferedImage is taking too much resources which makes the game laggy.
3.I could basically try to make a separate unit system for the game.. but then there's the same problem, when it comes to rendering strings or rectangles I'd have to multiply everything with the factor and the code is horrible after that.
Is there any better ways of rendering 2D games? If no then I'll think about moving on to OpenGL.
Thanks in advance.
The way I've done this most successfully is by scaling the graphics object. You end up with something like the following:
final int gameUnitsPerScreenDim = 32;
void render(JPanel panel, Graphics2D g2) {
double pixelHeight = panel.getHeight();
double pixelsPerGameUnit = pixelHeight / gameUnitsPerScreenDim;
g2.scale(pixelsPerGameUnit, pixelsPerGameUnit);
...
}
And then for the simulation, you use game units. How big a game unit actually is is a bit arbitrary, although if you're making a tiled game there's probably some obvious value that it should be.
Instead of using scale, you can also create an AffineTransform which lets you reuse it:
if (this.tf == null || /* image size changed since the last frame */) {
...
this.tf = AffineTransform.getScaleInstance(pxPerGu, pxPerGu);
}
g2.setTransform(this.tf);
(Calling scale creates a new AffineTransform every time you call it.)
That's even a little more efficient, although probably not by much.
(If you want, you can also use a transform to invert the y-axis and translate so the origin is at the center of the image. This makes a lot of trigonometry and stuff feel more natural. Inverting the y-axis makes working with text a pain, though.)
Also, using OpenGL is probably better. Having written a couple of simple games using Swing for fun, I don't see a good reason to do it.
I would like to group/merge/union rectangles that are close (similar) to each other. There is no particular reason why I tried this recursively but it seemed appropriate.
However I am missing something here. The output is not correct and I did not consider the fact that rectangles that are merged later down the road might be close now to rectangles that I considered "un-mergeable" and put into the finalList
The merging and the check closeness method are working properly.
public static ArrayList<Rect> mergeCloseRects(ArrayList<Rect> sourceList, ArrayList<Rect> finalList) {
Rect rect = sourceList.get(0).clone();
sourceList.remove(0);
for (int i = 0; i < sourceList.size(); i++) {
if (rectsAreClose(rect, sourceList.get(i)) {
// put merged rectangle on top of the list
sourceList.add(0, getMergeRect(rect, sourceList.get(i)));
// remove rectangle that was merged with rect
sourceList.remove(i + 1);
mergeCloseRects(sourceList, finalList);
}
}
// if rect has no close neighbours
finalList.add(rect);
return finalList;
}
Input
Output
As you can see the rectangles are not really merged. The lower rectangle stayed in the list. The green outline tells where the new rectangle(s) will be.
This seems to me to be a better fit for iteration than recursion: you can naturally keep going until there is nothing left to merge. I would think your code should look something like:
while(!getListCloseRectangles(sourceList).isEmpty()) {
List<Rect> rectanglesToMerge = getListCloseRectangles(sourceList);
sourceList.removeAll(rectanglesToMerge);
sourceList.add(createMergedRect(rectanglesToMerge));
}
This also allows for the situation in which getListCloseRectangles can return more than two rectangles at a time. But it will still work fine if it only ever returns two items in the list.
I am making a sort of command based application to draw geometric figures. So if a user enters something like RECT 100, 50, 200, 120 I draw a rectangle at specified location on the drawing panel.
So for this i need to map RECT to g.drawRect(100, 50, 200, 120); and all such similar functions to draw geometric figures.
I will use a hash map for mapping, but i don't know how to build a array of functions in java. In C++ i have done this though.
The key can be 'RECT' and the value the offset of the index.
Please show me how can i index these functions. Or is there a still better way to address the primary concern?
There are no function pointers in Java, you need to do it through inheritance and/or interfaces. Here is an example:
interface Shape {
void draw(int[] data);
}
class Polygon implements Shape {
public void draw(int[] data) {
// Draw polygon using points data[i], data[i+1] for points
}
}
class Circle implements Shape {
public void draw(int[] data) {
// Draw circle using data[0], data[1] for the center, and data[2] for radius
}
}
In your main program's constructor or static initializer:
Map<String,Shape> shapes = new HashMap<String,Shape>();
shapes.put("POLY", new Polygon());
shapes.put("CIRC", new Circle());
In your drawing code:
shapes.get("CIRC").draw(new int[] {100, 100, 50});
I have to admit, I didn't really got your design, I'm not sure why do you need an array of functions as you said, but this is how this thing can be done in java.
Since Function (method in java terms) is not a "first-class-sitizen" in Java, you can't build an array of methods (at least in java 7) . What you can do instead is to use a more object oriented approach - define an interface, each method will be an implementation of the interface ( a class) so that you'll be able to store an array of interface implementation.
I would use a design pattern Command instead of array of methods or something... Hope this helps
I have a task to draw a circle and then fill in with the most amount of circles without touching the sides. I can draw the circle, and I can make loops to pack the circle in a hexagonal/honeycomb format, but can't control whether they are inside or outside the circle.
I have used this: g.drawOval(50, 50, 300, 300); to specify my circle. Given I'm actually specifying a square as my boundaries I can't actually determine where the circle boundaries are. So I'm basically packing the square full of circles rather than the circle full of circles.
Can some please point me in the right direction? I'm new to java so not sure if I have done this the complete wrong way. My code is below. I have another class for the frame and another with the main in it.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class DrawCircle extends JPanel
{
private int width, height, diameter;
public DrawFrame d;
public DrawCircle()
{
width = 400;
height = 400;
diameter = 300;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawOval(50, 50, 300, 300);
for(int i=50; i<200; i=i+20)
{
for(int j=50; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=60; i<200; i=i+20)
{
for(int j=55; j<350; j=j+10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=330; i>190; i=i-20)
{
for(int j=340; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
for(int i=340; i>190; i=i-20)
{
for(int j=345; j>40; j=j-10)
{
g.drawOval(j, i, 10, 10);
}
}
}
}
All those magic numbers make me cringe a bit. You're new to Java, and it's homework, so I understand why you're doing it, but I would not recommend it if you do much programming in the future.
You need an algorithm or recipe for deciding when a small circle on the inside falls outside the big one you're trying to pack. Think about the ways you might do this:
If the distance between the center of the big circle and the small circle is is greater than the difference in their radii, the small circle will overlap the big circle or fall completely outside it.
You can add this check to your code: Just before you draw the circle, perform this check. Only draw if that circle passes.
Don't worry about Java for a second; draw yourself a picture on a piece of paper, draw that enclosing and packed circle, and see if that statement is correct. Then think about any corner situations that it might not cover, just as a check.
I'll make two more recommendations. First, do this by hand without a computer once so you'll see what the "right" answer might look like. Second, see if you can separate the calculation of the circles from the drawing part. It might make your job easier, because you can concentrate on one thing at a time. It's called "decomposition". You solve complex problems by breaking them up into smaller, more manageable pieces. In this case, it's also called "model-view separation". You might need to know that someday.
Maybe another way to think about this problem would be to imagine a 2D arrangement of circles, packed in their closest arrangement, extending to infinity in both the x- and y-directions. Now take your enclosing circle, put it on top of the 2D arrangement, and eliminate all the circles that overlap the big circle. I don't know if it'll be optimal, but it's easy to visualize.