Java - Scaling a canvas about a particular point - java

I am more or less finished a very simple planetary gravity simulator using Newtonian physics. It can transform and scale the planets for pan and zoom. This works fine, mouse input and everything. The problem I have is more aesthetic than anything else. Since the origin of the canvas is at the top left corner of the window (within a JPanel, within a JFrame), everything scales about that point. I was wondering is there any way to either set the origin to the center of the screen, or to scale about a particular point? (Even though AffineTransform.scale() only has one constructor, with scaleX and scaleY as the args). I have tried setting the bounds of the canvas as negative numbers as such:
canvas.setBounds(-width/2, -height/2, width/2, height/2);
(Width and height are the screen size).
This obviously doesn't work as negative numbers are outside the co-ords of the panel.
So does anyone know anyway of accomplishing this? Either setting the centre of the screen as the origin or scaling about a particular point rather than the origin?

The trick here is to concatenate instances of AffineTransform.
Move the entire rendering so the center is at the origin.
Scale the rendering.
Move the center of the rendering (now at the origin) back to the center of the view.

Related

Libgdx - Android - My coordinates have not the origin in the very bottom

I have a 480x800 resolution and I'm using the following code to set it:
cam = new OrthographicCamera();
cam.setToOrtho(false, VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
viewport = new FitViewport(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, cam);
nothing strange further in my code but my issue is that the origin point (0,0) is not on the very bottom but something like 20 pixels upper.
How can I fix it?
#Tenfour04 should be right here, but i try to explain it a bit:
The FitViewport is there to guarantee, that the virtual aspect ratio (VIRTUAL_HEIGHT/VIRTUAL_WIDTH) is the same as the aspect ratio on screen. Therefore, if your "real" aspect ratio (of the screen) is different, then the virtual one, black borders are shown, to create a "window" which matches the virtual aspect ratio.
Therefore the P(0/0) is not the bottom left corner of the screen, but the bottom left corner of the new "window".
If thats not what you want, there are other Viewports, which may fit your needs.
The StretchViewport for example supports virtual screen sizes and simply stretches the image to fit the screens real aspect ratio. This could be better in your case, but in some other cases the stretched images just don't look good...
FitViewport does not guarantee that 0,0 will be in the corner when you center it. All other existing Viewport subclasses do, so use one of those. And make sure you are calling update on the viewport in the resize method of you Game or Screen subclass.
Edit:
Actually, FillViewport also doesn't guarantee 0,0 in the corner, because 0,0 could be cropped off.

Get coordinates of displayed rectangle

I'm trying to create a game for Android device and I have a small question about the rendering of the scene. Effectively I want to draw a square of a precise size but I'm not pretty sure about the way I can get the coordinates of the border of the screen in openGL dimension. My application is set in landscape mode, so computation looks easier.
I have drawn a square with a border size of 2 and I have the impression that the square takes all the height of the screen. Since I know the resolution of my screen which is equal to 1920*1080, I can compute the width of my scene. Then, by drawing several squares I found the coordinates of on corner.
This way of computing the coordinates are a bit weird and I'm not pretty sure that the computation will always lead to a good answer. Is there a nicer way and obviously a better way to compute those coordinates ?
Thank you in advance !

How would I create Horizontally centered “Gravity” ? - libGDX -

This is a seemingly simple game mechanic that I've been trying to figure out how to do.
To try and explain I will describe a idea (problem):
Basically we say there's a vertical line that is centered in the
screen.
We have a sprite object that changes it's horizontal velocity to
dodge missiles, however in doing that the object would just drift
away.
How can I add a strong gravity force to the horizontal "center line"
of my screen so that my sprite will "fall" back into it every time it
boosts its velocity outwards?
I could post my source code but it wouldn't be too helpful to solving the question in this particular situation.
I've searched around for days trying to figure this out so any help especially with code examples would be very helpful!
I've programmed this type of thing in the past. Gravity (in physics) is an acceleration, so
1) if the sprite is to the right of the line you subtract from its horizontal velocity every 1/n seconds, and
2) if the sprite is to the left of the line you add to its horizontal velocity every 1/n seconds.
Experiment with adding/subtracting a constant, or with adding/subtracting a number that increases the farther the sprite is from the center line.
Either way you do it, that's going to create a pendulum effect. You'll also have to add a dampening factor if you don't want that. One simple approach is that if the sprite is headed away from the center line, the value you add/subtract is larger than if the sprite is heading back towards the center line. So the "gravity" that pulls the sprite to a stop is greater than the gravitational acceleration that brings the sprite back to the center line.
As you are using libgdx you should also use camera. So you don't have to calculate verything in pixels. So for example you say my screen is 16 worldunits width and 9 world units height (16/9 aspect ratio). So you can say the center of gravity is in the center of that 16, so at 8.5 if i am not wrong. Now you can say: if (player.center.x < 8.5f) { player.xSpeed += GRAVITY_HORIZONTAL } and if (player.center.x > 8.5) { player.xSpeed -= GRAVITY_HORIZONTAL }. In this case the gravity is a constant value. But as #BrettFromLA said you can also let the value grow if the distance to the center grows.

Setting the pivot point of a JPanel to its center

I am building a Java application that is going to feature two circles of random sizes that need to be clicked by the user. The time between the click on the first and the second circle is going to be measured. Unfortunately, since I am new to Java so things have been slow for me. Currently I have my application draw circles and measure time between clicks using System.nanoTime() but now I am running into a problem.
Because the circles need to be a fixed distance away from eachother I want to use the center of the circles as the origin points. So basically I want to be able to provide coordinates for the circle so that the center of the circle should be at those coordinates. The distance between the circles then describes the distance between the centers. My circle currently is embedded into a JPanel but if I set the JPanel's position it moves the top left to that position.
Of course I have done some searching read that I may need to play around with either AffineTransform or Graphics2D.translate() which I have tried in paintComponent() but this got a bit confusing so then I tried to override setlocation and subtract the radius from the position. It sort of works but it is not the most clean solution. Can aonyone give me some pointers on how to do this?
Thanks in advance.
If I understand the problem statement, all such pairs of circles will lie on opposite sides of a circle centered in the enclosing panel, as shown here. Simply choose a random 0 ≤ θ < π and find its opposite at π - θ. Note how the example's rendering scales as the panel is resized.
As an aside, the example uses setPreferredSize() to establish the dimensions of the drawing panel, but you may want to override getPreferredSize() instead.
Addendum: The example uses fillOval() to render the circles, but you can use draw() with any desired Shape; the latter provides several contains() methods suitable for hit testing, as mentioned here.
You have the coordinates for the two center for the circle (x1, y1) and (x2, y2).
The size of the radius is random.
Once you have the radius of the two, r1 and r2, simply position them at (x1-r1, y1-r1) and (x2-r2, y2-r2).
You can use java.awt.Point to represent the center, and use
center.translate(-radius, -radius)
and use the new translated value as position for the drawing.
Maybe you think it is not a clean solution, but why not? Everything in Java is painted by giving the top left corner for the position, so is the use of the center that is not clean :).
To calculate the left top position by doing -radius is clean :)

Zooming in Slick2D

I'm working on a really low res game that I need to zoom in to make it visible. I know I can use Graphics.scale(float x, float y) but I'd like to zoom into the center. How can I scale the Graphics in the center? Is there an easier way to do low res games?
I think you could translate(float x, float y) your drawing surface (so the origin (0, 0) is in the center) and then zoom in. Then you can use resetTransform() to remove the effect.
If that doesn't work, just move your upper/left rendering offset while you're zooming in via experimentation until you get it right. Once you get it figured out, put that logic into a method called zoomOverPoint(float x, float y) and then you'll be set.
It's a fairly crude solution, but what if you just make everything bigger and move it?
For example, let's say you had a square and a circle,
You want to zoom in on the square which is at coordinates 200, 100
The circle is at coordinates 500, 400
So to zoom in on the square you move it towards the center of the screen and increase the size of it gradually as you zoom in, at the same time, the circle will also be moving off the screen and getting relatively bigger. I don't know if that makes any sense, but you'd probably have to figure out some complicated VecMath for that.

Categories