2d coordinate system: Math vs. Screen - java

We're working on a library that does calculations in 2D space. However, the 'natural' interpretation of the 2D coordinate system is where increasing Y values represent points that lie higher, while the awt coordinates do the reverse. This reflects in Rectangle(10,100).maxY() returning 0, while the mathematician would expect it to return 100.
How can we properly deal with that difference? Is there another java library to do geometrical calculations?

You should try things before asking. The following code prints 100, so there is no problem :)
import java.awt.*;
public class A {
public static void main(String[] args) {
double maxX = new Rectangle(10, 100).getMaxY();
System.out.println("A::main: maxX = " + maxX);
}
}

I turns out that maxY returns 'the biggest y-coordinate`, which is exactly the intuitive behavior. I was confused: only when actually drawing it to screen the objects have a 'top-left' and a 'bottom-right' are merely conventions when visualizing it.

Related

What is the most efficient way of rendering 2D game with the possibility of changing the resolution?

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.

.getWidth(), .getHeight() in Java

So I just started learning Java yesterday coming from a different language, and I am reading through my textbook and finding it to be pretty nice so far. However I did an exercise that basically required me to create a new Object use Rectangle and find the area. Below is the working code I came up with.
Now coming from other programming languages I was just toying around with this and did int area,width,height;and then it gave me an error saying that I had to use double in order to utilize .getWidth();, .getHeight(). I couldn't find anything in my book telling me why I had to make this a double and I started looking online and found this link
Now I found some documentation online where It told me to use double as well, but I'm not really sure why would I need to set these as doubles. Is it because the people who made Java, knew that precision is needed when we are working with coordinates and doing math with widths, heights and coordinates? My book says that it takes more memory to make a double variable rather than an int ( I come from doing lots of javascript and PHP, so reading on what a float and double does was something good for me).
I.E. Why do I need to make my area,height,width variable doubles in order to use .getWidth,.getHeight
package keepo;
import java.awt.Rectangle;
public class tuna{
public static void main(String [] args){
Rectangle rect = new Rectangle(10,20,50,40);
double area,width,height;
width = rect.getWidth();
height = rect.getHeight();
area = width * height;
System.out.println("Width is : " + width + "Height is : " + height);
System.out.println("Area is : " + area);
}
}
It is because this is how these methods have been defined in the java api. As you can see under the modifier and type column that the methods getWidth(), getHeight() all return value of type double.
Because in this case, you should not use those methods. The AWT class Rectangle does store coordinates as ints. You can easily read them back as ints if that's what you want to do, by accessing the fields instead of calling the getter methods:
int area, width, height;
width = rect.width; // not getWidth()
height = rect.height; // not getHeight()
area = width * height;
The getWidth() and getHeight() methods serve zero purpose here, as they will always return the same value as the fields, except as a different type (and you can already assign any int value to a double anyway, when a double is what you want to use).
So why do those two methods (along with getX() and getY()) exist at all? Because in Java 1.2 the geometry stuff in the API was expanded. People wanted to be able to work with floating-point coordinates, which Rectangle cannot do. And the Java maintainers couldn't change the fields of Rectangle from int to double because that would break backwards compatibility with how old code was already using it. So two new classes, Rectangle2D.Float and Rectangle2D.Double were added, which store coordinates as floats and doubles respectively.
But what if you want to work generically with any rectangle, without writing separate code for all the rectangle flavors? A new abstract class, Rectangle2D was also added, as the superclass of the three rectangle classes. This class is abstract (meaning it cannot be created on its own, as it is incomplete) and it does not store any coordinates itself. It does however, specify a contract that its subclasses follow (meaning that any Rectangle2D method is available in all three of its implementations). That includes the getWidth() and getHeight() methods that return doubles, regardless of the actual storage type of the particular rectangle.
Taking the abstraction an extra, perhaps superfluous, level, they also added RectangularShape as the superclass of several shapes with rectangular bounds: Rectangle2D, RoundRectangle2D, Ellipse2D and Arc2D. That is the class that actually declares the getWidth() and getHeight() methods, which all RectangularShape subclasses must provide:
// What's this shape? A rectangle? An ellipse? Does it use ints? floats? doubles?
RectangularShape something = ......;
// We don't care!
System.out.println("The shape (whatever it is) occupies an area of:");
System.out.println(something.getWidth() + " × " + something.getHeight());
So you can call those getter methods on any rectangle (or "rectangular shape") to get its coordinates, but if you know you have a particular shape class, you can/should access its fields directly, as that is simpler, and it gives you the values without converting them to a different type.
P.S. It is a similar story with Point, which uses int coordinates, but provides double getX() and double getY() methods, because of the later-added classes Point2D.Float, and Point2D.Double, and the abstract superclass Point2D.
P.P.S. There is actually a small advantage to using double (or long) for your rectangle's area, even if your rectangle coordinates are ints. Large multiplications could overflow the 32-bit range of an int, producing the wrong result. If you convert at least one of the values to a larger type, it will cause the multiplication to be done in that larger type, which you can then safely store without overflow:
Rectangle big = new Rectangle(0, 0, 1000000, 1000000);
int area = big.width * big.height;
long bigArea = (long)big.width * big.height;
System.out.println(area); // -727379968 (uh oh!)
System.out.println(bigArea); // 1000000000000
Imran Ali is right.
This is java documentations for getHeight() and for getWidth() it's same.
java.​awt.​Rectangle
public double getHeight()
Returns the height of the bounding Rectangle in double precisionReturns:
the height of the bounding Rectangle.
But if you want/need to use int instead of double, use following codes for height and repeat them for width too:
using getSize() method which returns rectangle dimension then use it's fields (width and height)
int height = rect.getSize().height;
using data type casting
int height = (int) rect.getHeight();
int height = (int) rect.getSize().getHeight();
The Rectangle.getWidth() and Rectangle.getHeight()methods both return their values with double precision, as stated by others. It is easier if you just keep using them, in order to prevent the Rectangle's values from being changed on accident, by simply casting the value to an int:
int width = (int)rect.getWidth()
and int height = (int)rect.getHeight()

Translating Imperative Java to Functional Java (A Game)

I'm learning a lot more about Java 8 and its functional capabilities, and I wanted to do some more practice with it. Say, for example, I have the following imperative code which is for wrapping a circle around the bounds of the screen:
if (circle.getPosition().getX() > width + circle.getRadius()){
circle.getPosition().setX(-circle.getRadius());
}else if (circle.getPosition().getX() < -circle.getRadius()){
circle.getPosition().setX(width + circle.getRadius());
}
if (circle.getPosition().getY() > height + circle.getRadius()){
circle.getPosition().setY(-circle.getRadius());
}else if (circle.getPosition().getY() < -circle.getRadius()){
circle.getPosition().setY(height + circle.getRadius());
}
How could I go about trying to "Functionalize" it? Maybe some pseudo-code? It seems to me that mutability and state seem inherent in this example.
Is functional programming not a good fit for game development? I love the both, so I'm trying to combine them.
There is nothing inherent about the requirement for mutability in this example. The imperative approach is to modify an existing circles by applying side-effects which alter the state of an existing circle.
The functional approach is to have an immutable data structure and create a function that takes data from the first structure and creates a new structure. In your example, a functional approach would have the circle being immutable, i.e. no setX() or setY() methods.
private Circle wrapCircleAroundBounds(Circle circle, double width, double height) {
double newx = (circle.getPosition().getX() > width + circle.getRadius()) ? -circle.getRadius() : width + circle.getRadius()
double newy = (circle.getPosition().getY() > height + circle.getRadius()) ? -circle.getRadius() : height + circle.getRadius()
return new Circle(newx, newy)
}
Using Java8's functional features, you could then imagine mapping a list of circles to wrapped circles:
circles.stream().map(circ -> wrapCircleAroundBounds(circ, width, height))
The imperative and functional approaches have different advantages, the functional approach, for example, is intrisicaly threadsafe because of the immutability so you should be able to more readily parallelise this kind of code. For instance, one could equally safely write:
circles.parallelStream().map(circ -> wrapCircleAroundBounds(circ, width, height))
I don't think that functional programming is necessarily badly suited to game development but, although it has be done, it's certainly not a standard approach so you won't get the same level of library support if you're using a functional language.
As dfeuer states in his answer, Java's functional features are pretty primitive - you don't have support for algebraic data types, pattern matching, etc which will make it much easier to express problems in a functional style (at least once you get used to those idioms). I agree that at least reading a bit about Haskell, which has an excellent tutorial: http://learnyouahaskell.com/chapters would be a good way to get started. Unlike Scala, which is very much a multiparadigm language, you won't have OOP features to fall back on while you're learning the new style.
For your first point: You "functionalize" your example by thinking about what the code ought to achieve. And this is, you have a circle, and want to compute another circle based on some conditions. But for some reason your imperative upbringing makes you assume that the input circle and the output circle should be stored in the same memory locations!
For being functional, the first thing is to forget memory locations and embrace values. Think of every type the same way you think of int or java.lang.Integer or the other numeric types.
For an example, assume some newbie shows you some code like this:
double x = 3.765;
sin(x);
System.out.println("The square root of x is " + x);
and complains that sin doesn't seem to work. What would you think then?
Now consider this:
Circle myCircle = ....;
wrapAroundBoundsOfScreen(myCircle);
System.out.println("The wrapped-around circle is now " + myCircle);
You will have climbed the first step to functional programming when the latter code seems as absurd to you as the former. And yes, this does mean not to use certain features of the imperative language you are using, or use them extremely sparingly.
Here not much 'functionalization' applicable. But at least we can fight with mutability.
First of all pure functions. This will help to separate logic. Make it clear and easy to test.
Answer the question: what is your code do? It accepts some params and returns two params new x and y.
Next samples will be written with pseudo scala.
So you need a function that will be invoked two times for both x and y calculation.
def (xOrY: Int, widthOrHeight: Int, radius: Int): Int = {
if (x > widthOrHeight + radius) -1*radius else widthOrHeight + radius
// do your calculation here - return x or y values.
}
P.S> so far no matter where you want to apply functional style: as you need to do some business logic it's good to go with functional approach.
But do not try overcomplicate it as it does not help.
So what I would not do for this sample is next (pseudo scala goes next):
def tryToMakeMove(conditions: => Boolean, move: => Unit) = if (conditions) move()
/// DO NOT DO IT AT HOME :)
tryToMakeMove(circle.getPosition().getX() > width + circle.getRadius(), circle.getPosition().setX(-circle.getRadius())).andThen()
tryToMakeMove(circle.getPosition().getX() < -circle.getRadius()), circle.getPosition().setX(width + circle.getRadius()))
).andThen ... so on.
That how functional programs can looks like. I've created the higher-order function (that accepts other functions as an arguments and invoke it inside).
With this functions, i've invoked one be one operations you have to do...
But such functional style does not really help. At all. You should apply it properly only in a places where it's simplify the code.
You can write functional code in just about any programming language, but you can't easily learn functional programming in any language. Java in particular makes functional programming sufficiently painful that people who wanted to do functional programming in the JVM came up with Clojure and Scalaz. If you want to learn the functional way of thinking (what problems it deals with naturally and how, what problems are more awkward and how it manages them, etc.), I strongly recommend that you spend some time with a functional or mostly-functional language. Based on a combination of language quality, ease of sticking to functional idioms, learning resources, and community, my top pick would be Haskell and my next would be Racket. Others will of course have other opinions.
How could I go about trying to "Functionalize" it? Maybe some
pseudo-code? It seems to me that mutability and state seem inherent in
this example.
You could try to limit the mutability to a few functions, and also use final variables inside the functions (which forces you to use expressions rather than statements). Here's one possible way:
Position wrapCircle(Circle circle, int width, int height) {
final int radius = circle.getRadius();
final Position pos = circle.getPosition();
final int oldX = pos.getX();
final int x = (oldX > width + radius) ? -radius : (
(oldX < -radius) ? (width + radius) : oldX);
final int y = // similar
return new Position(x, y);
}
circle.setPosition(wrapCircle(circle, width, height));
Aside, I would make wrapCircle a method of the Circle class, to get:
circle.wrapCircle(width, height);
Or I could go one step further and define a getWrappedCircle method, that returns me a new circle instance:
Circle getWrappedCircle(width, height) {
newCircle = this.clone();
newCircle.wrapCircle(width, height);
return newCircle();
}
.. depending on how you intend to structure the rest of the code.
Tip: Use final keyword as often as you can in Java. It automatically lends to a more functional style.
Is functional programming not a good fit for game development? I love the both, so I'm trying to combine them.
Pure functional programming is slower, because it requires lots of copying / cloning of data. If performance is important, then you could definitely try a mixed approach, as shown above.
I would suggest using as much immutability as possible, followed by benchmarking, and then converting to mutability in only the performance critical sections.
Functional programming fits game development (why would not it?). The question is usually more about performance and memory consumption or even if any functional game engine can beat an existing non-functional one in those metrics. You are not the only person who loves functional programming and game development. Seems like John Carmack does too, watch his keynotes about the topics at Quakecon 2013 starting from 02:05. His notes here and here even give insight on how a functional game engine can be structured.
Setting theoretical foundation aside, there are usually two concepts perceived inherent in functional programming by a newcomer and from a practical prospect. They are data immutability and state absence. The former means that data never changes and the latter means every task is performed as if for the first time with no prior knowledge.
Considering that, you imperative code has two problems: the setters mutate the circle position and the code relies on outside values (a global state) of width and height. To fix them make your function return a new circle on each update and take the screen resolutions as arguments. Let's apply the first clue from the video and pass a reference to the static snapshot of the world and a reference to an entity being "updated" (it is simply this here) to an update function:
class Circle extends ImmutableEntity {
private int radius;
public Circle(State state, Position position, int radius) {
super(state, position);
this.radius = radius;
}
public int getRadius() {
return radius;
}
#Override
public ImmutableEntity update(World world) {
int updatedX = getPosition().getX();
if (getPosition().getX() > world.getWidth() + radius){
updatedX = -radius;
} else if (getPosition().getX() < -radius){
updatedX = world.getWidth() + radius;
}
int updatedY = getPosition().getX();
if (getPosition().getY() > world.getHeight() + radius){
updatedY = -radius;
} else if (getPosition().getY() < -radius) {
updatedY = world.getHeight() + radius;
}
return new Circle(getState(), new Position(updatedX, updatedY), radius);
}
}
class Position {
private int x;
private int y;
//here can be other quantities like speed, velocity etc.
public Position(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
class State { /*...*/ }
abstract class ImmutableEntity {
private State state;
private Position position;
public ImmutableEntity(State state, Position position) {
this.state = state;
this.position = position;
}
public State getState() {
return state;
}
public Position getPosition() {
return position;
}
public abstract ImmutableEntity update(World world);
}
class World {
private int width;
private int height;
public World(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
Now the tricky part is how to affect the state of the world and other entities. You can follow the second clue from the video and use event passing mechanism to pass such changes to and fro so the rest of the game knows about all the effects.
Obviously, you can keep only events and rely completely on them even when changing your circle positions. So, if you introduce sort of an id to your entities you will be able to pass MoveEntity(id, newPosition).
OK, it's time for us all to get over how new and shiny Java 8's functional features look. "Functionalizing" something is really not a valid goal to have.
However, the original code here has a good ol' object-oriented problem:
When you say circle.getPosition().setX(...), you are messing with the internal state of the circle (its position) without involving the object itself. That breaks encapsulation. If the circle class were properly designed, then the getPosition() method would return a copy of the position or an immutable position so that you couldn't do this.
That is the problem you really need to fix with this code...
How, then, should you do that?
Well, you could certainly come up with some functional interface in Circle, but honestly your code will be more readable if you just have circle.move(double x, double y);

How to walk stairs and slopes?

We use jme3 and a problem with the BetterCharacterControl is that setMaxSlope is not implemented. The developer of the engine says that we can solve it ourselves using the new controller:
http://hub.jmonkeyengine.org/forum/topic/setmaxslope-for-bettercharactercontrol/
And I would really like a solution since my game needs it. I asked about it before but we didn't solve it:
How to improve character control for my 3D game?
Can you help us progress? I've recorded a video with the problem:
http://www.youtube.com/watch?v=PF_UzoOXD0E
Some documentation is here:
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:walking_character?s[]=bettercharactercontrol#bettercharactercontrol
My effort to add the functionality to the controller:
package adventure;
import com.jme3.math.Vector3f;
import com.jme3.bullet.control.BetterCharacterControl;
public class GameCharControl extends BetterCharacterControl {
protected Vector3f lastlocation = new Vector3f();
public GameCharControl(float x, float y, float z) {
super(x, y, z);
}
#Override
public void update(float tpf) {
super.update(tpf);
System.out.println("location " + location);
System.out.println("lastlocation " + lastlocation);
if (location.equals(lastlocation)) {
System.out.println("update2");
this.setHeightPercent(101);
}
rigidBody.getPhysicsLocation(location);
applyPhysicsTransform(location, rotation);
lastlocation = location;
}
}
But the above is not making any change or if I set height to 101 then it gets difficult to move for the game character. Can you help us see what should be done?
Since movement treats the character as a PhysicsRigidBody made of PhysicsJoints, there probably isn't enough upward oomph in his leg or knee. Hopefully the parameters there just weren't set up to accommodate that size of stair.
Since you had the most trouble with navigating an angled stair, a secondary measure might be to adjust the walk direction. I doubt you can rely on location.equals(lastlocation) but within a short distance is a good check to see if the character ran into an obstacle. Once you know there is a step you want to scale it cleanly or stay stuck below.
Why not use KinematicCharacterController which has setMaxSlope implemented?
Not sure which JME you are using, but here's the source to that controller:
https://code.google.com/p/jbullet-jme/source/browse/branches/jbullet/src/com/bulletphysics/dynamics/character/KinematicCharacterController.java

circle packing - java

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.

Categories

Resources